860 lines
25 KiB
C
860 lines
25 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
transfer.c
|
||
|
||
Abstract:
|
||
|
||
This module implements data transfer 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
|
||
VOID
|
||
CompleteReceive (
|
||
IN PIRP ReceiveIrp,
|
||
IN PIRP SendIrp
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
IndicateReceive (
|
||
IN PLOOP_CONNECTION ReceivingConnection,
|
||
IN PIRP InitialSendIrp
|
||
);
|
||
|
||
|
||
NTSTATUS
|
||
LoopReceive (
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine processes a Receive request.
|
||
|
||
Arguments:
|
||
|
||
Irp - Pointer to I/O request packet
|
||
|
||
IrpSp - Pointer to current stack location in IRP
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of request
|
||
|
||
--*/
|
||
|
||
{
|
||
PLOOP_CONNECTION receivingConnection;
|
||
PLOOP_CONNECTION sendingConnection;
|
||
|
||
IF_DEBUG(LOOP1) DbgPrint( " Receive request\n" );
|
||
|
||
//
|
||
// Verify that the receiving connection is connected.
|
||
//
|
||
|
||
receivingConnection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
|
||
|
||
if ( receivingConnection == NULL ) {
|
||
IF_DEBUG(LOOP2) DbgPrint( " Can't Receive on control channel\n" );
|
||
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||
IoCompleteRequest( Irp, 0 );
|
||
IF_DEBUG(LOOP1) DbgPrint( " Receive request complete\n" );
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
sendingConnection = receivingConnection->RemoteConnection;
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Receiving connection: %lx\n", receivingConnection );
|
||
DbgPrint( " Sending connection: %lx\n", sendingConnection );
|
||
}
|
||
|
||
ACQUIRE_LOOP_LOCK( "Receive initial" );
|
||
|
||
if ( (sendingConnection == NULL) ||
|
||
(GET_BLOCK_STATE(receivingConnection) != BlockStateActive) ) {
|
||
RELEASE_LOOP_LOCK( "Receive closing" );
|
||
IF_DEBUG(LOOP2) DbgPrint( " Connection not connected\n" );
|
||
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||
IoCompleteRequest( Irp, 0 );
|
||
IF_DEBUG(LOOP1) DbgPrint( " Receive request complete\n" );
|
||
return STATUS_DISCONNECTED;
|
||
}
|
||
|
||
//
|
||
// Queue the Receive to the connection's Pending Receive list.
|
||
//
|
||
|
||
InsertTailList(
|
||
&receivingConnection->PendingReceiveList,
|
||
&Irp->Tail.Overlay.ListEntry
|
||
);
|
||
|
||
IoMarkIrpPending( Irp );
|
||
|
||
//
|
||
// Check for pending data.
|
||
//
|
||
|
||
if ( (receivingConnection->IndicatingSendIrp != NULL) ||
|
||
(receivingConnection->IncomingSendList.Flink ==
|
||
&receivingConnection->IncomingSendList) ) {
|
||
|
||
//
|
||
// There is no pending Send, or an indication is already in
|
||
// progress. Reference the connection to account for the
|
||
// Receive IRP.
|
||
//
|
||
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " No pending Send; leaving IRP %lx queued \n", Irp );
|
||
}
|
||
receivingConnection->BlockHeader.ReferenceCount++;
|
||
IF_DEBUG(LOOP3) {
|
||
DbgPrint( " New refcnt on connection %lx is %lx\n",
|
||
receivingConnection,
|
||
receivingConnection->BlockHeader.ReferenceCount );
|
||
}
|
||
|
||
RELEASE_LOOP_LOCK( "Receive no Send" );
|
||
|
||
} else {
|
||
|
||
//
|
||
// There is pending data. Call IndicateReceive to satisfy
|
||
// the Receive.
|
||
//
|
||
// *** Note that IndicateReceive returns with the loopback
|
||
// driver spin lock released.
|
||
//
|
||
|
||
IF_DEBUG(LOOP2) DbgPrint( " LoopReceive indicating receive\n" );
|
||
IndicateReceive( receivingConnection, NULL );
|
||
|
||
}
|
||
|
||
IF_DEBUG(LOOP1) DbgPrint( " Receive request %lx complete\n", Irp );
|
||
return STATUS_PENDING;
|
||
|
||
} // LoopReceive
|
||
|
||
|
||
NTSTATUS
|
||
LoopSend (
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine processes a Send request.
|
||
|
||
Arguments:
|
||
|
||
Irp - Pointer to I/O request packet
|
||
|
||
IrpSp - Pointer to current stack location in IRP
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of request
|
||
|
||
--*/
|
||
|
||
{
|
||
PLOOP_CONNECTION sendingConnection;
|
||
PLOOP_CONNECTION receivingConnection;
|
||
BOOLEAN firstSend;
|
||
|
||
IF_DEBUG(LOOP1) DbgPrint( " Send request\n" );
|
||
|
||
//
|
||
// Verify that the sending connection is connected.
|
||
//
|
||
|
||
sendingConnection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
|
||
|
||
if ( sendingConnection == NULL ) {
|
||
IF_DEBUG(LOOP2) DbgPrint( " Can't Send on control channel\n" );
|
||
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||
IoCompleteRequest( Irp, 0 );
|
||
IF_DEBUG(LOOP1) DbgPrint( " Send request complete\n" );
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
receivingConnection = sendingConnection->RemoteConnection;
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Sending connection: %lx\n", sendingConnection );
|
||
DbgPrint( " Receiving connection: %lx\n", receivingConnection );
|
||
}
|
||
|
||
ACQUIRE_LOOP_LOCK( "Send initial" );
|
||
|
||
if ( (receivingConnection == NULL) ||
|
||
(GET_BLOCK_STATE(sendingConnection) != BlockStateActive) ) {
|
||
RELEASE_LOOP_LOCK( "Send closing" );
|
||
IF_DEBUG(LOOP2) DbgPrint( " Connection not connected\n" );
|
||
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||
IoCompleteRequest( Irp, 0 );
|
||
IF_DEBUG(LOOP1) DbgPrint( " Send request complete\n" );
|
||
return STATUS_DISCONNECTED;
|
||
}
|
||
|
||
//
|
||
// Reference both ends.
|
||
//
|
||
|
||
sendingConnection->BlockHeader.ReferenceCount++;
|
||
receivingConnection->BlockHeader.ReferenceCount++;
|
||
IF_DEBUG(LOOP3) {
|
||
DbgPrint( " New refcnt on connection %lx is %lx\n",
|
||
sendingConnection,
|
||
sendingConnection->BlockHeader.ReferenceCount );
|
||
DbgPrint( " New refcnt on connection %lx is %lx\n",
|
||
receivingConnection,
|
||
receivingConnection->BlockHeader.ReferenceCount );
|
||
}
|
||
|
||
//
|
||
// Determine whether this is the first active incoming Send for the
|
||
// receiving connection.
|
||
//
|
||
|
||
firstSend = (BOOLEAN)( receivingConnection->IncomingSendList.Flink ==
|
||
&receivingConnection->IncomingSendList );
|
||
|
||
//
|
||
// Queue the Send to the receiving connection's Incoming Send list,
|
||
// in order to prevent another Send from getting ahead of this one.
|
||
//
|
||
|
||
InsertTailList(
|
||
&receivingConnection->IncomingSendList,
|
||
&Irp->Tail.Overlay.ListEntry
|
||
);
|
||
|
||
IoMarkIrpPending( Irp );
|
||
|
||
if ( !firstSend || (receivingConnection->IndicatingSendIrp != NULL) ) {
|
||
|
||
//
|
||
// Pending data already exists, or an indication is already in
|
||
// progress. This Send remains behind the already pending data.
|
||
//
|
||
|
||
IF_DEBUG(LOOP2) DbgPrint( " Data already pending\n" );
|
||
|
||
RELEASE_LOOP_LOCK( "Send sends pending" );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Indicate the incoming data.
|
||
//
|
||
// *** Note that IndicateReceive returns with the loopback
|
||
// driver spin lock released.
|
||
//
|
||
|
||
IF_DEBUG(LOOP2) DbgPrint( " LoopSend indicating receive\n" );
|
||
IndicateReceive( receivingConnection, Irp );
|
||
|
||
}
|
||
|
||
IF_DEBUG(LOOP1) DbgPrint( " Send request %lx complete\n", Irp );
|
||
return STATUS_PENDING;
|
||
|
||
} // LoopSend
|
||
|
||
|
||
VOID
|
||
CompleteReceive (
|
||
IN PIRP ReceiveIrp,
|
||
IN PIRP SendIrp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine completes the process of sending a message. It copies
|
||
the message from the source buffer into the destination buffer.
|
||
|
||
The reference counts on the owning connections must have been
|
||
incremented to account for the requesting IRPs in order to prevent
|
||
their deletion.
|
||
|
||
Arguments:
|
||
|
||
ReceiveIrp - Pointer to IRP used for Receive request
|
||
|
||
SendIrp - Pointer to IRP used for Send request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Indicates whether the connection was successfully created
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION sendIrpSp;
|
||
PIO_STACK_LOCATION receiveIrpSp;
|
||
ULONG copyLength;
|
||
PTDI_REQUEST_KERNEL_SEND sendRequest;
|
||
PTDI_REQUEST_KERNEL_RECEIVE receiveRequest;
|
||
PLOOP_CONNECTION sendingConnection;
|
||
PLOOP_CONNECTION receivingConnection;
|
||
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Send IRP %lx completes receive IRP %lx\n",
|
||
SendIrp, ReceiveIrp );
|
||
}
|
||
|
||
//
|
||
// Copy the data from the source buffer into the destination buffer.
|
||
//
|
||
// *** Note that we special-case zero-length copies. We don't
|
||
// bother to call LoopCopyData. Part of the reason for this
|
||
// is that a zero-length send or receive issued from user mode
|
||
// yields an IRP that has a NULL MDL address.
|
||
//
|
||
|
||
sendIrpSp = IoGetCurrentIrpStackLocation( SendIrp );
|
||
sendRequest = (PTDI_REQUEST_KERNEL_SEND)&sendIrpSp->Parameters;
|
||
copyLength = sendRequest->SendLength;
|
||
IF_DEBUG(LOOP4) {
|
||
DbgPrint( " Send request at %lx, send length %lx\n",
|
||
sendRequest, copyLength );
|
||
}
|
||
receiveIrpSp = IoGetCurrentIrpStackLocation( ReceiveIrp );
|
||
receiveRequest = (PTDI_REQUEST_KERNEL_RECEIVE)&receiveIrpSp->Parameters;
|
||
IF_DEBUG(LOOP4) {
|
||
DbgPrint( " Receive request at %lx, receive length %lx\n",
|
||
receiveRequest, receiveRequest->ReceiveLength );
|
||
}
|
||
status = STATUS_SUCCESS;
|
||
if ( copyLength > receiveRequest->ReceiveLength ) {
|
||
status = STATUS_BUFFER_OVERFLOW;
|
||
copyLength = receiveRequest->ReceiveLength;
|
||
}
|
||
|
||
if ( copyLength != 0 ) {
|
||
|
||
ASSERT( ReceiveIrp->MdlAddress != NULL );
|
||
ASSERT( SendIrp->MdlAddress != NULL );
|
||
|
||
LoopCopyData(
|
||
ReceiveIrp->MdlAddress,
|
||
SendIrp->MdlAddress,
|
||
copyLength
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Complete the Receive and Send requests.
|
||
//
|
||
|
||
receivingConnection =
|
||
(PLOOP_CONNECTION)receiveIrpSp->FileObject->FsContext;
|
||
sendingConnection =
|
||
(PLOOP_CONNECTION)sendIrpSp->FileObject->FsContext;
|
||
|
||
ReceiveIrp->IoStatus.Status = status;
|
||
ReceiveIrp->IoStatus.Information = copyLength;
|
||
|
||
SendIrp->IoStatus.Status = STATUS_SUCCESS;
|
||
SendIrp->IoStatus.Information = copyLength;
|
||
|
||
IoCompleteRequest( ReceiveIrp, 2 );
|
||
IoCompleteRequest( SendIrp, 2 );
|
||
|
||
//
|
||
// Dereference the connections.
|
||
//
|
||
|
||
ACQUIRE_LOOP_LOCK( "CompleteReceive dereference" );
|
||
LoopDereferenceConnection( receivingConnection );
|
||
LoopDereferenceConnection( sendingConnection );
|
||
RELEASE_LOOP_LOCK( "CompleteReceive dereference" );
|
||
|
||
return;
|
||
|
||
} // CompleteReceive
|
||
|
||
|
||
VOID
|
||
IndicateReceive (
|
||
IN PLOOP_CONNECTION ReceivingConnection,
|
||
IN PIRP InitialSendIrp
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
PLOOP_ENDPOINT receivingEndpoint;
|
||
PLOOP_CONNECTION sendingConnection;
|
||
PLIST_ENTRY listEntry;
|
||
PIRP receiveIrp;
|
||
PIRP sendIrp;
|
||
PTDI_IND_RECEIVE receiveHandler;
|
||
PVOID receiveContext;
|
||
PIO_STACK_LOCATION sendIrpSp;
|
||
PTDI_REQUEST_KERNEL_SEND sendRequest;
|
||
ULONG length;
|
||
PMDL mdl;
|
||
PVOID address;
|
||
ULONG bytesTaken;
|
||
|
||
receivingEndpoint = ReceivingConnection->Endpoint;
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Receiving endpoint: %lx\n", receivingEndpoint );
|
||
}
|
||
|
||
//
|
||
// Reference the receiving connection to prevent it from going away
|
||
// while this routine is running.
|
||
//
|
||
|
||
ReceivingConnection->BlockHeader.ReferenceCount++;
|
||
IF_DEBUG(LOOP3) {
|
||
DbgPrint( " New refcnt on connection %lx is %lx\n",
|
||
ReceivingConnection,
|
||
ReceivingConnection->BlockHeader.ReferenceCount );
|
||
}
|
||
|
||
//
|
||
// Capture the address of the sending connection, as the receiving
|
||
// connection's pointer can be zeroed if a Disconnect occurs.
|
||
//
|
||
|
||
sendingConnection = ReceivingConnection->RemoteConnection;
|
||
ASSERT( sendingConnection != NULL );
|
||
|
||
//
|
||
// If the receiving connection has a pending Receive, satisfy it
|
||
// with this Send. If there is no pending Receive, and a Receive
|
||
// handler has been enabled on the receiving connection, call it.
|
||
// If the Receive handler returns with a Receive IRP, use it to
|
||
// satisfy this Send. If the Receive handler doesn't return an IRP,
|
||
// leave this Send pending.
|
||
//
|
||
// !!! Note that the current implementation only works because
|
||
// partial sends are not supported.
|
||
//
|
||
|
||
while ( TRUE ) {
|
||
|
||
//
|
||
// We have a Send pending. Is there a pending Receive?
|
||
//
|
||
|
||
listEntry = RemoveHeadList( &ReceivingConnection->PendingReceiveList );
|
||
|
||
if ( listEntry != &ReceivingConnection->PendingReceiveList ) {
|
||
|
||
//
|
||
// Found a pending Receive. Use it to satisfy the first
|
||
// incoming Send.
|
||
//
|
||
|
||
receiveIrp = CONTAINING_RECORD(
|
||
listEntry,
|
||
IRP,
|
||
Tail.Overlay.ListEntry
|
||
);
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Receive IRP pending: %lx\n", receiveIrp );
|
||
}
|
||
|
||
listEntry = RemoveHeadList(
|
||
&ReceivingConnection->IncomingSendList
|
||
);
|
||
ASSERT( listEntry != &ReceivingConnection->IncomingSendList );
|
||
sendIrp = CONTAINING_RECORD(
|
||
listEntry,
|
||
IRP,
|
||
Tail.Overlay.ListEntry
|
||
);
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Send IRP pending: %lx\n", sendIrp );
|
||
}
|
||
|
||
//
|
||
// If this is the first time through the loop, and we were
|
||
// called to process a newly queued Send, dereference the
|
||
// receiving connection -- LoopSend referenced the
|
||
// connection an extra time in case the Send had to remain
|
||
// queued.
|
||
//
|
||
|
||
if ( InitialSendIrp != NULL ) {
|
||
LoopDereferenceConnection( ReceivingConnection );
|
||
}
|
||
|
||
RELEASE_LOOP_LOCK( "IndicateReceive pending Receive" );
|
||
|
||
CompleteReceive( receiveIrp, sendIrp );
|
||
|
||
ACQUIRE_LOOP_LOCK( "IndicateReceive pending Receive completed" );
|
||
|
||
//
|
||
// Fall to bottom of loop to handle more incoming Sends.
|
||
//
|
||
|
||
} else {
|
||
|
||
//
|
||
// No pending Receive. Is there a Receive handler?
|
||
//
|
||
|
||
receiveHandler = receivingEndpoint->ReceiveHandler;
|
||
receiveContext = receivingEndpoint->ReceiveContext;
|
||
|
||
if ( receiveHandler == NULL ) {
|
||
|
||
//
|
||
// No Receive handler. The Send must remain queued.
|
||
//
|
||
|
||
IF_DEBUG(LOOP2) DbgPrint( " No Receive handler\n" );
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// The receiving endpoint has a Receive handler. Call it.
|
||
// If it returns STATUS_SUCCESS, it completely handled the
|
||
// data. If it returns STATUS_MORE_PROCESSING_REQUIRED, it
|
||
// also returns a Receive IRP describing where to put the
|
||
// data. Any other return status means the receiver can't
|
||
// take the data just now, so we leave the Send queued and
|
||
// wait for the receiver to post a Receive IRP.
|
||
//
|
||
// !!! Note that we don't currently handle partial data
|
||
// acceptance.
|
||
//
|
||
// First, remove the first Send from the Incoming Send list,
|
||
// and make it the Indicating Send. It must be removed from
|
||
// the list to ensure that it isn't completed by
|
||
// LoopDoDisconnection while we're indicating it.
|
||
//
|
||
|
||
listEntry = RemoveHeadList(
|
||
&ReceivingConnection->IncomingSendList
|
||
);
|
||
ASSERT( listEntry != &ReceivingConnection->IncomingSendList );
|
||
sendIrp = CONTAINING_RECORD(
|
||
listEntry,
|
||
IRP,
|
||
Tail.Overlay.ListEntry
|
||
);
|
||
ReceivingConnection->IndicatingSendIrp = sendIrp;
|
||
|
||
RELEASE_LOOP_LOCK( "IndicateReceive calling Receive handler" );
|
||
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Receive handler: %lx\n", receiveHandler );
|
||
DbgPrint( " Send IRP: %lx\n", sendIrp );
|
||
}
|
||
|
||
sendIrpSp = IoGetCurrentIrpStackLocation( sendIrp );
|
||
sendRequest = (PTDI_REQUEST_KERNEL_SEND)&sendIrpSp->Parameters;
|
||
|
||
length = sendRequest->SendLength;
|
||
ASSERTMSG(
|
||
"Loopback driver doesn't handle partial or expedited sends",
|
||
sendRequest->SendFlags == 0
|
||
);
|
||
|
||
//
|
||
// Map the send buffer, if necessary.
|
||
//
|
||
|
||
mdl = sendIrp->MdlAddress;
|
||
if ( MmGetMdlByteCount(mdl) == 0 ) {
|
||
address = NULL;
|
||
} else {
|
||
address = MmGetSystemAddressForMdl( mdl );
|
||
}
|
||
|
||
//
|
||
// Call the Receive handler.
|
||
//
|
||
|
||
status = receiveHandler(
|
||
receiveContext,
|
||
ReceivingConnection->ConnectionContext,
|
||
0,
|
||
MmGetMdlByteCount( mdl ),
|
||
length,
|
||
&bytesTaken,
|
||
address,
|
||
&receiveIrp
|
||
);
|
||
|
||
ACQUIRE_LOOP_LOCK( "IndicateReceive after calling handler" );
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Indication for send IRP %lx done\n", sendIrp );
|
||
}
|
||
|
||
ReceivingConnection->IndicatingSendIrp = NULL;
|
||
|
||
if ( status == STATUS_SUCCESS ) {
|
||
|
||
//
|
||
// The Receive handler completely handled the data.
|
||
// Complete the Send.
|
||
//
|
||
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Receive handler handled data\n" );
|
||
}
|
||
|
||
ASSERTMSG(
|
||
"Loopback driver doesn't handle partial acceptance "
|
||
"of indications",
|
||
bytesTaken == length
|
||
);
|
||
|
||
//
|
||
// Dereference the sending and receiving connections --
|
||
// LoopSend referenced the connections when it queued
|
||
// the Send.
|
||
//
|
||
|
||
LoopDereferenceConnection( ReceivingConnection );
|
||
LoopDereferenceConnection( sendingConnection );
|
||
|
||
RELEASE_LOOP_LOCK( "IndicateReceive completely handled" );
|
||
|
||
//
|
||
// Complete the Send IRP.
|
||
//
|
||
|
||
sendIrp->IoStatus.Status = STATUS_SUCCESS;
|
||
sendIrp->IoStatus.Information = sendRequest->SendLength;
|
||
|
||
IoCompleteRequest( sendIrp, 2 );
|
||
|
||
ACQUIRE_LOOP_LOCK( "IndicateReceive send completed" );
|
||
|
||
//
|
||
// Fall to bottom of loop to handle more incoming
|
||
// Sends.
|
||
//
|
||
|
||
} else if ( status == STATUS_MORE_PROCESSING_REQUIRED ) {
|
||
|
||
//
|
||
// The Receive handler returned a Receive IRP to be used
|
||
// to satisfy the Send.
|
||
//
|
||
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Receive handler returned IRP: %lx\n",
|
||
receiveIrp );
|
||
}
|
||
|
||
ASSERTMSG(
|
||
"Loopback driver doesn't handle partial acceptance "
|
||
"of indications",
|
||
bytesTaken == 0
|
||
);
|
||
|
||
//
|
||
// Complete the Receive using the current Send.
|
||
//
|
||
// *** Note that the pending Send references both the
|
||
// sending and receiving connections.
|
||
|
||
RELEASE_LOOP_LOCK( "IndicateReceive complete new Receive" );
|
||
|
||
CompleteReceive( receiveIrp, sendIrp );
|
||
|
||
ACQUIRE_LOOP_LOCK( "IndicateReceive new receive completed" );
|
||
|
||
//
|
||
// Fall to bottom of loop to handle more incoming
|
||
// Sends.
|
||
//
|
||
|
||
} else {
|
||
|
||
//
|
||
// The Receive handler couldn't take the data. This
|
||
// Send will have to wait until receiver can post a
|
||
// Receive IRP.
|
||
//
|
||
// *** Because we didn't hold the spin lock around the
|
||
// call to the Receive handler, it's possible that
|
||
// the receiver has already posted a Receive IRP.
|
||
// Because we were in the middle of an indication,
|
||
// that Receive would have been queued to the
|
||
// Pending Receive list, and we should go get it
|
||
// now. If the receiver hasn't posted a Receive
|
||
// yet, then this Send will be put back on the
|
||
// Incoming Send list before the Receive does come
|
||
// in (since we're now holding the lock).
|
||
//
|
||
|
||
ASSERT( status == STATUS_DATA_NOT_ACCEPTED );
|
||
|
||
IF_DEBUG(LOOP2) DbgPrint( " Data not accepted\n" );
|
||
|
||
if ( GET_BLOCK_STATE(ReceivingConnection) !=
|
||
BlockStateActive ) {
|
||
|
||
//
|
||
// The connection is closing. Abort the current
|
||
// Send and leave.
|
||
//
|
||
|
||
LoopDereferenceConnection( ReceivingConnection );
|
||
LoopDereferenceConnection( sendingConnection );
|
||
|
||
RELEASE_LOOP_LOCK( "IndicateReceive disconnecting" );
|
||
|
||
sendIrp->IoStatus.Status = STATUS_DISCONNECTED;
|
||
IoCompleteRequest( sendIrp, 2 );
|
||
|
||
ACQUIRE_LOOP_LOCK( "IndicateReceive send aborted" );
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
listEntry = RemoveHeadList(
|
||
&ReceivingConnection->PendingReceiveList
|
||
);
|
||
|
||
if ( listEntry !=
|
||
&ReceivingConnection->PendingReceiveList ) {
|
||
|
||
//
|
||
// A Receive has been posted. Use it to satisfy
|
||
// this Send.
|
||
//
|
||
|
||
receiveIrp = CONTAINING_RECORD(
|
||
listEntry,
|
||
IRP,
|
||
Tail.Overlay.ListEntry
|
||
);
|
||
IF_DEBUG(LOOP2) {
|
||
DbgPrint( " Receive IRP pending: %lx\n",
|
||
receiveIrp );
|
||
}
|
||
|
||
//
|
||
// Complete the Receive using the current Send.
|
||
//
|
||
//
|
||
// If this is the first time through the loop, and
|
||
// we were called to process a newly queued Send,
|
||
// dereference the receiving connection -- LoopSend
|
||
// referenced the connection an extra time in case
|
||
// the Send had to remain queued.
|
||
//
|
||
|
||
if ( InitialSendIrp != NULL ) {
|
||
LoopDereferenceConnection( ReceivingConnection );
|
||
}
|
||
|
||
RELEASE_LOOP_LOCK(
|
||
"IndicateReceive complete posted Receive"
|
||
);
|
||
|
||
CompleteReceive( receiveIrp, sendIrp );
|
||
|
||
ACQUIRE_LOOP_LOCK(
|
||
"IndicateReceive posted receive completed"
|
||
);
|
||
|
||
//
|
||
// Fall to bottom of loop to handle more incoming
|
||
// Sends.
|
||
//
|
||
|
||
} else {
|
||
|
||
//
|
||
// The handler didn't take the data, and it didn't
|
||
// post a Receive IRP. Requeue the current send and
|
||
// get out.
|
||
//
|
||
|
||
InsertHeadList(
|
||
&ReceivingConnection->IncomingSendList,
|
||
&sendIrp->Tail.Overlay.ListEntry
|
||
);
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
} // pending receive?
|
||
|
||
//
|
||
// If we get here, we need to indicate the next incoming Send,
|
||
// if there is one.
|
||
//
|
||
|
||
InitialSendIrp = NULL;
|
||
|
||
if ( (GET_BLOCK_STATE(ReceivingConnection) != BlockStateActive) ||
|
||
(ReceivingConnection->IncomingSendList.Flink ==
|
||
&ReceivingConnection->IncomingSendList) ) {
|
||
|
||
//
|
||
// No more Sends, or connection no longer active. Leave.
|
||
//
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Process the next Send.
|
||
//
|
||
|
||
} // while ( TRUE )
|
||
|
||
//
|
||
// Remove the connection reference acquired at the start of this
|
||
// routine.
|
||
//
|
||
|
||
LoopDereferenceConnection( ReceivingConnection );
|
||
|
||
RELEASE_LOOP_LOCK( "IndicateReceive done" );
|
||
|
||
return;
|
||
|
||
} // IndicateReceive
|
||
|