Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1245 lines
39 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
receive.c
Abstract:
This module contains the code for passing on receive IRPs to
TDI providers.
Author:
David Treadwell (davidtr) 13-Mar-1992
Revision History:
--*/
#include "afdp.h"
NTSTATUS
AfdRestartReceive (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGEAFD, AfdReceive )
#pragma alloc_text( PAGEAFD, AfdRestartReceive )
#pragma alloc_text( PAGEAFD, AfdReceiveEventHandler )
#pragma alloc_text( PAGEAFD, AfdReceiveExpeditedEventHandler )
#pragma alloc_text( PAGEAFD, AfdQueryReceiveInformation )
#endif
NTSTATUS
AfdReceive (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
{
NTSTATUS status;
KIRQL oldIrql;
PAFD_ENDPOINT endpoint;
PAFD_CONNECTION connection;
PTDI_REQUEST_RECEIVE receiveRequest;
BOOLEAN allocatedReceiveRequest = FALSE;
BOOLEAN peek;
LARGE_INTEGER bytesExpected;
BOOLEAN isDataOnConnection;
BOOLEAN isExpeditedDataOnConnection;
PAFD_RECV_INFO recvInfo;
ULONG recvFlags;
ULONG afdFlags;
ULONG recvLength;
//
// Make sure that the endpoint is in the correct state.
//
endpoint = IrpSp->FileObject->FsContext;
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
if ( endpoint->State != AfdEndpointStateConnected ) {
status = STATUS_INVALID_CONNECTION;
goto complete;
}
//
// If receive has been shut down or the endpoint aborted, fail.
//
if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) ) {
status = STATUS_PIPE_DISCONNECTED;
goto complete;
}
if ( (endpoint->DisconnectMode & AFD_ABORTIVE_DISCONNECT) ) {
status = STATUS_LOCAL_DISCONNECT;
goto complete;
}
//
// If this is an IOCTL_AFD_RECEIVE, then grab the parameters from the
// supplied AFD_RECV_INFO structure, build an MDL chain describing
// the WSABUF array, and attach the MDL chain to the IRP.
//
// If this is an IRP_MJ_READ IRP, just grab the length from the IRP
// and set the flags to zero.
//
if ( IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL ) {
//
// Sanity check.
//
ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_AFD_RECEIVE );
if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(*recvInfo) ) {
try {
//
// Probe the input structure.
//
recvInfo = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
if( Irp->RequestorMode != KernelMode ) {
ProbeForRead(
recvInfo,
sizeof(*recvInfo),
sizeof(ULONG)
);
}
//
// Snag the receive flags.
//
recvFlags = recvInfo->TdiFlags;
afdFlags = recvInfo->AfdFlags;
//
// Validate the receive flags & WSABUF parameters.
// Note that either TDI_RECEIVE_NORMAL or
// TDI_RECEIVE_EXPEDITED (but not both) must be set
// in the receive flags.
//
if ( ( recvFlags & TDI_RECEIVE_EITHER ) != 0 &&
( recvFlags & TDI_RECEIVE_EITHER ) != TDI_RECEIVE_EITHER &&
recvInfo->BufferArray != NULL &&
recvInfo->BufferCount > 0 ) {
//
// Create the MDL chain describing the WSABUF array.
//
status = AfdAllocateMdlChain(
Irp,
recvInfo->BufferArray,
recvInfo->BufferCount,
IoWriteAccess,
&recvLength
);
} else {
//
// Invalid receive flags, BufferArray, or
// BufferCount fields.
//
status = STATUS_INVALID_PARAMETER;
}
} except ( EXCEPTION_EXECUTE_HANDLER ) {
//
// Exception accessing input structure.
//
status = GetExceptionCode();
}
} else {
//
// Invalid input buffer length.
//
status = STATUS_INVALID_PARAMETER;
}
if( !NT_SUCCESS(status) ) {
goto complete;
}
} else {
ASSERT( IrpSp->MajorFunction == IRP_MJ_READ );
recvFlags = TDI_RECEIVE_NORMAL;
afdFlags = AFD_OVERLAPPED;
recvLength = IrpSp->Parameters.Read.Length;
//
// Convert this stack location to a proper one for a receive
// request.
//
IrpSp->Parameters.DeviceIoControl.OutputBufferLength =
IrpSp->Parameters.Read.Length;
IrpSp->Parameters.DeviceIoControl.InputBufferLength =
sizeof(*receiveRequest);
}
//
// If this is a datagram endpoint, format up a receive datagram request
// and pass it on to the TDI provider.
//
if ( IS_DGRAM_ENDPOINT(endpoint) ) {
return AfdReceiveDatagram( Irp, IrpSp, recvFlags, afdFlags );
}
//
// If this is an endpoint on a nonbufferring transport, use another
// routine to handle the request.
//
if ( !endpoint->TdiBufferring ) {
return AfdBReceive( Irp, IrpSp, recvFlags, afdFlags, recvLength );
}
//
// Allocate a buffer for the receive request structure.
//
receiveRequest = AFD_ALLOCATE_POOL(
NonPagedPool,
sizeof(TDI_REQUEST_RECEIVE),
AFD_TDI_POOL_TAG
);
if ( receiveRequest == NULL ) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto complete;
}
allocatedReceiveRequest = TRUE;
//
// Set up the receive request structure.
//
RtlZeroMemory(
receiveRequest,
sizeof(*receiveRequest)
);
receiveRequest->ReceiveFlags = (USHORT)recvFlags;
connection = endpoint->Common.VcConnecting.Connection;
ASSERT( connection != NULL );
ASSERT( connection->Type == AfdBlockTypeConnection );
//
// If this endpoint is set up for inline reception of expedited data,
// change the receive flags to use either normal or expedited data.
//
if ( endpoint->InLine ) {
receiveRequest->ReceiveFlags |= TDI_RECEIVE_EITHER;
}
//
// Determine whether this is a request to just peek at the data.
//
peek = (BOOLEAN)( (receiveRequest->ReceiveFlags & TDI_RECEIVE_PEEK) != 0 );
AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
if ( endpoint->NonBlocking ) {
isDataOnConnection = IS_DATA_ON_CONNECTION( connection );
isExpeditedDataOnConnection = IS_EXPEDITED_DATA_ON_CONNECTION( connection );
}
if ( endpoint->InLine ) {
//
// If the endpoint is nonblocking, check whether the receive can
// be performed immediately. Note that if the endpoint is set
// up for inline reception of expedited data we don't fail just
// yet--there may be expedited data available to be read.
//
if ( endpoint->NonBlocking && !( afdFlags & AFD_OVERLAPPED ) ) {
if ( !isDataOnConnection &&
!isExpeditedDataOnConnection &&
!connection->AbortIndicated &&
!connection->DisconnectIndicated ) {
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdReceive: failing nonblocking IL receive, ind %ld, "
"taken %ld, out %ld\n",
connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart ));
KdPrint(( " EXP ind %ld, taken %ld, out %ld\n",
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
}
AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
status = STATUS_DEVICE_NOT_READY;
goto complete;
}
}
//
// If this is a nonblocking endpoint for a message-oriented
// transport, limit the number of bytes that can be received to the
// amount that has been indicated. This prevents the receive
// from blocking in the case where only part of a message has been
// received.
//
if ( endpoint->EndpointType != AfdEndpointTypeStream &&
endpoint->NonBlocking ) {
LARGE_INTEGER expBytesExpected;
bytesExpected.QuadPart =
connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart -
(connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart);
ASSERT( bytesExpected.HighPart == 0 );
expBytesExpected.QuadPart =
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart -
(connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart);
ASSERT( expBytesExpected.HighPart == 0 );
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdReceive: %lx normal bytes expected, %ld exp bytes expected",
bytesExpected.LowPart, expBytesExpected.LowPart ));
}
//
// If expedited data exists on the connection, use the lower
// count between the available expedited and normal receive
// data.
//
if ( (isExpeditedDataOnConnection &&
bytesExpected.LowPart > expBytesExpected.LowPart) ||
!isDataOnConnection ) {
bytesExpected = expBytesExpected;
}
//
// If the request is for more bytes than are available, cut back
// the number of bytes requested to what we know is actually
// available.
//
if ( recvLength > bytesExpected.LowPart ) {
recvLength = bytesExpected.LowPart;
}
}
//
// Increment the count of posted receive bytes outstanding.
// This count is used for polling and nonblocking receives.
// Note that we do not increment this count if this is only
// a PEEK receive, since peeks do not actually take any data
// they should not affect whether data is available to be read
// on the endpoint.
//
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdReceive: conn %lx for %ld bytes, ind %ld, "
"taken %ld, out %ld %s\n",
connection,
recvLength,
connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart,
peek ? "PEEK" : "" ));
KdPrint(( " EXP ind %ld, taken %ld, out %ld\n",
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
}
if ( !peek ) {
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart +
recvLength;
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart +
recvLength;
}
}
if ( !endpoint->InLine &&
(receiveRequest->ReceiveFlags & TDI_RECEIVE_NORMAL) != 0 ) {
//
// If the endpoint is nonblocking, check whether the receive can
// be performed immediately.
//
if ( endpoint->NonBlocking && !( afdFlags & AFD_OVERLAPPED ) ) {
if ( !isDataOnConnection &&
!connection->AbortIndicated &&
!connection->DisconnectIndicated ) {
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdReceive: failing nonblocking receive, ind %ld, "
"taken %ld, out %ld\n",
connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart ));
}
AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
status = STATUS_DEVICE_NOT_READY;
goto complete;
}
}
//
// If this is a nonblocking endpoint for a message-oriented
// transport, limit the number of bytes that can be received to the
// amount that has been indicated. This prevents the receive
// from blocking in the case where only part of a message has been
// received.
//
if ( endpoint->EndpointType != AfdEndpointTypeStream &&
endpoint->NonBlocking ) {
bytesExpected.QuadPart =
connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart -
(connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart);
ASSERT( bytesExpected.HighPart == 0 );
//
// If the request is for more bytes than are available, cut back
// the number of bytes requested to what we know is actually
// available.
//
if ( recvLength > bytesExpected.LowPart ) {
recvLength = bytesExpected.LowPart;
}
}
//
// Increment the count of posted receive bytes outstanding.
// This count is used for polling and nonblocking receives.
// Note that we do not increment this count if this is only
// a PEEK receive, since peeks do not actually take any data
// they should not affect whether data is available to be read
// on the endpoint.
//
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdReceive: conn %lx for %ld bytes, ind %ld, "
"taken %ld, out %ld %s\n",
connection,
recvLength,
connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart,
peek ? "PEEK" : "" ));
}
if ( !peek ) {
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart +
recvLength;
}
}
if ( !endpoint->InLine &&
(receiveRequest->ReceiveFlags & TDI_RECEIVE_EXPEDITED) != 0 ) {
if ( endpoint->NonBlocking && !( afdFlags & AFD_OVERLAPPED ) &&
!isExpeditedDataOnConnection &&
!connection->AbortIndicated &&
!connection->DisconnectIndicated ) {
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdReceive: failing nonblocking EXP receive, ind %ld, "
"taken %ld, out %ld\n",
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
}
AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
status = STATUS_DEVICE_NOT_READY;
goto complete;
}
//
// If this is a nonblocking endpoint for a message-oriented
// transport, limit the number of bytes that can be received to the
// amount that has been indicated. This prevents the receive
// from blocking in the case where only part of a message has been
// received.
//
if ( endpoint->EndpointType != AfdEndpointTypeStream &&
endpoint->NonBlocking &&
IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
bytesExpected.QuadPart =
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart -
(connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart);
ASSERT( bytesExpected.HighPart == 0 );
ASSERT( bytesExpected.LowPart != 0 );
//
// If the request is for more bytes than are available, cut back
// the number of bytes requested to what we know is actually
// available.
//
if ( recvLength > bytesExpected.LowPart ) {
recvLength = bytesExpected.LowPart;
}
}
//
// Increment the count of posted expedited receive bytes
// outstanding. This count is used for polling and nonblocking
// receives. Note that we do not increment this count if this
// is only a PEEK receive.
//
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdReceive: conn %lx for %ld bytes, ind %ld, "
"taken %ld, out %ld EXP %s\n",
connection,
recvLength,
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart,
peek ? "PEEK" : "" ));
}
if ( !peek ) {
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart +
recvLength;
}
}
AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
//
// Build the TDI receive request.
//
TdiBuildReceive(
Irp,
connection->DeviceObject,
connection->FileObject,
AfdRestartReceive,
endpoint,
Irp->MdlAddress,
receiveRequest->ReceiveFlags,
recvLength
);
//
// Save a pointer to the receive request structure so that we
// can free it in our restart routine.
//
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = receiveRequest;
IrpSp->Parameters.DeviceIoControl.OutputBufferLength = recvLength;
//
// Call the transport to actually perform the connect operation.
//
return AfdIoCallDriver( endpoint, connection->DeviceObject, Irp );
complete:
if ( allocatedReceiveRequest ) {
AFD_FREE_POOL(
receiveRequest,
AFD_TDI_POOL_TAG
);
}
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = status;
IoCompleteRequest( Irp, AfdPriorityBoost );
return status;
} // AfdReceive
NTSTATUS
AfdRestartReceive (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PAFD_ENDPOINT endpoint = Context;
PAFD_CONNECTION connection;
PIO_STACK_LOCATION irpSp;
LARGE_INTEGER actualBytes;
LARGE_INTEGER requestedBytes;
KIRQL oldIrql1, oldIrql2;
ULONG receiveFlags;
ULONG eventMask;
BOOLEAN expedited;
PTDI_REQUEST_RECEIVE receiveRequest;
ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
ASSERT( endpoint->Common.VcConnecting.Connection != NULL );
ASSERT( endpoint->TdiBufferring );
irpSp = IoGetCurrentIrpStackLocation( Irp );
actualBytes = RtlConvertUlongToLargeInteger( Irp->IoStatus.Information );
requestedBytes = RtlConvertUlongToLargeInteger(
irpSp->Parameters.DeviceIoControl.OutputBufferLength
);
//
// Determine whether we received normal or expedited data.
//
receiveRequest = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
receiveFlags = receiveRequest->ReceiveFlags;
if ( Irp->IoStatus.Status == STATUS_RECEIVE_EXPEDITED ||
Irp->IoStatus.Status == STATUS_RECEIVE_PARTIAL_EXPEDITED ) {
expedited = TRUE;
} else {
expedited = FALSE;
}
//
// Free the receive request structure.
//
AFD_FREE_POOL(
receiveRequest,
AFD_TDI_POOL_TAG
);
//
// If this was a PEEK receive, don't update the counts of received
// data, just return.
//
if ( (receiveFlags & TDI_RECEIVE_PEEK) != 0 ) {
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdRestartReceive: IRP %lx, endpoint %lx, conn %lx, "
"status %X\n",
Irp, endpoint, endpoint->Common.VcConnecting.Connection,
Irp->IoStatus.Status ));
KdPrint(( " %s data, PEEKed only.\n",
expedited ? "expedited" : "normal" ));
}
AfdCompleteOutstandingIrp( endpoint, Irp );
return STATUS_SUCCESS;
}
//
// Update the count of bytes actually received on the connection.
//
AfdAcquireSpinLock( &AfdSpinLock, &oldIrql1 );
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql2 );
if( expedited ) {
eventMask = endpoint->InLine
? (ULONG)~AFD_POLL_RECEIVE
: (ULONG)~AFD_POLL_RECEIVE_EXPEDITED;
} else {
eventMask = (ULONG)~AFD_POLL_RECEIVE;
}
endpoint->EventsActive &= eventMask;
IF_DEBUG(EVENT_SELECT) {
KdPrint((
"AfdReceive: Endp %08lX, Active %08lX\n",
endpoint,
endpoint->EventsActive
));
}
connection = endpoint->Common.VcConnecting.Connection;
ASSERT( connection->Type == AfdBlockTypeConnection );
if ( !expedited ) {
if ( actualBytes.LowPart == 0 ) {
ASSERT( actualBytes.HighPart == 0 );
connection->VcZeroByteReceiveIndicated = FALSE;
} else {
connection->Common.Bufferring.ReceiveBytesTaken.QuadPart =
actualBytes.QuadPart +
connection->Common.Bufferring.ReceiveBytesTaken.QuadPart;
}
//
// If the number taken exceeds the number indicated, then this
// receive got some unindicated bytes because the receive was
// posted when the indication arrived. If this is the case, set
// the amount indicated equal to the amount received.
//
if ( connection->Common.Bufferring.ReceiveBytesTaken.QuadPart >
connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart ) {
connection->Common.Bufferring.ReceiveBytesIndicated =
connection->Common.Bufferring.ReceiveBytesTaken;
}
//
// Decrement the count of outstanding receive bytes on this connection
// by the receive size that was requested.
//
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart -
requestedBytes.QuadPart;
//
// If the endpoint is inline, decrement the count of outstanding
// expedited bytes.
//
if ( endpoint->InLine ) {
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart -
requestedBytes.QuadPart;
}
if( connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart > 0 ||
( endpoint->InLine &&
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart > 0 ) ) {
AfdIndicateEventSelectEvent(
endpoint,
AFD_POLL_RECEIVE_BIT,
STATUS_SUCCESS
);
}
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdRestartReceive: IRP %lx, endpoint %lx, conn %lx, "
"status %X\n",
Irp, endpoint, connection,
Irp->IoStatus.Status ));
KdPrint(( " req. bytes %ld, actual %ld, ind %ld, "
" taken %ld, out %ld\n",
requestedBytes.LowPart, actualBytes.LowPart,
connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart
));
}
} else {
connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart =
actualBytes.QuadPart +
connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart;
//
// If the number taken exceeds the number indicated, then this
// receive got some unindicated bytes because the receive was
// posted when the indication arrived. If this is the case, set
// the amount indicated equal to the amount received.
//
if ( connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart >
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart ) {
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated =
connection->Common.Bufferring.ReceiveExpeditedBytesTaken;
}
//
// Decrement the count of outstanding receive bytes on this connection
// by the receive size that was requested.
//
ASSERT( connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart > 0 ||
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.HighPart > 0 ||
requestedBytes.LowPart == 0 );
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart -
requestedBytes.QuadPart;
//
// If the endpoint is inline, decrement the count of outstanding
// normal bytes.
//
if ( endpoint->InLine ) {
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart -
requestedBytes.QuadPart;
if( connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart > 0 ||
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart > 0 ) {
AfdIndicateEventSelectEvent(
endpoint,
AFD_POLL_RECEIVE_BIT,
STATUS_SUCCESS
);
}
} else {
if( connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart > 0 ) {
AfdIndicateEventSelectEvent(
endpoint,
AFD_POLL_RECEIVE_EXPEDITED_BIT,
STATUS_SUCCESS
);
}
}
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdRestartReceive: (exp) IRP %lx, endpoint %lx, conn %lx, "
"status %X\n",
Irp, endpoint, connection,
Irp->IoStatus.Status ));
KdPrint(( " req. bytes %ld, actual %ld, ind %ld, "
" taken %ld, out %ld\n",
requestedBytes.LowPart, actualBytes.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart
));
}
}
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql2 );
AfdReleaseSpinLock( &AfdSpinLock, oldIrql1 );
AfdCompleteOutstandingIrp( endpoint, Irp );
//
// If pending has be returned for this irp then mark the current
// stack as pending.
//
if ( Irp->PendingReturned ) {
IoMarkIrpPending(Irp);
}
return STATUS_SUCCESS;
} // AfdRestartReceive
NTSTATUS
AfdReceiveEventHandler (
IN PVOID TdiEventContext,
IN CONNECTION_CONTEXT ConnectionContext,
IN ULONG ReceiveFlags,
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *BytesTaken,
IN PVOID Tsdu,
OUT PIRP *IoRequestPacket
)
{
PAFD_CONNECTION connection;
PAFD_ENDPOINT endpoint;
KIRQL oldIrql;
connection = (PAFD_CONNECTION)ConnectionContext;
ASSERT( connection != NULL );
endpoint = connection->Endpoint;
ASSERT( endpoint != NULL );
ASSERT( connection->Type == AfdBlockTypeConnection );
ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
endpoint->Type == AfdBlockTypeVcListening );
ASSERT( !connection->DisconnectIndicated );
ASSERT( !connection->AbortIndicated );
ASSERT( endpoint->TdiBufferring );
//
// Bump the count of bytes indicated on the connection to account for
// the bytes indicated by this event.
//
AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
if ( BytesAvailable == 0 ) {
connection->VcZeroByteReceiveIndicated = TRUE;
} else {
connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart =
connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart +
BytesAvailable;
}
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdReceiveEventHandler: conn %lx, bytes %ld, "
"ind %ld, taken %ld, out %ld\n",
connection, BytesAvailable,
connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart ));
}
//
// If the receive side of the endpoint has been shut down, tell the
// provider that we took all the data and reset the connection.
// Also, account for these bytes in our count of bytes taken from
// the transport.
//
if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ) {
#if DBG
DbgPrint( "AfdReceiveEventHandler: receive shutdown, "
"%ld bytes, aborting endp %lx\n",
BytesAvailable, endpoint );
#endif
connection->Common.Bufferring.ReceiveBytesTaken.QuadPart =
connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
BytesAvailable;
AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
*BytesTaken = BytesAvailable;
//
// Abort the connection. Note that if the abort attempt fails
// we can't do anything about it.
//
(VOID)AfdBeginAbort( connection );
return STATUS_SUCCESS;
} else {
AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
//
// Note to the TDI provider that we didn't take any of the data here.
//
// !!! needs bufferring for non-bufferring transports!
*BytesTaken = 0;
//
// If there are any outstanding poll IRPs for this endpoint/
// event, complete them.
//
AfdIndicatePollEvent(
endpoint,
AFD_POLL_RECEIVE_BIT,
STATUS_SUCCESS
);
return STATUS_DATA_NOT_ACCEPTED;
}
} // AfdReceiveEventHandler
NTSTATUS
AfdReceiveExpeditedEventHandler (
IN PVOID TdiEventContext,
IN CONNECTION_CONTEXT ConnectionContext,
IN ULONG ReceiveFlags,
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *BytesTaken,
IN PVOID Tsdu,
OUT PIRP *IoRequestPacket
)
{
PAFD_CONNECTION connection;
PAFD_ENDPOINT endpoint;
KIRQL oldIrql;
connection = (PAFD_CONNECTION)ConnectionContext;
ASSERT( connection != NULL );
endpoint = connection->Endpoint;
ASSERT( endpoint != NULL );
ASSERT( connection->Type == AfdBlockTypeConnection );
//
// Bump the count of bytes indicated on the connection to account for
// the expedited bytes indicated by this event.
//
AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart =
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart +
BytesAvailable;
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdReceiveExpeditedEventHandler: conn %lx, bytes %ld, "
"ind %ld, taken %ld, out %ld, offset %ld\n",
connection, BytesAvailable,
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
}
//
// If the receive side of the endpoint has been shut down, tell
// the provider that we took all the data. Also, account for these
// bytes in our count of bytes taken from the transport.
//
//
if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ) {
IF_DEBUG(RECEIVE) {
KdPrint(( "AfdReceiveExpeditedEventHandler: receive shutdown, "
"%ld bytes dropped.\n", BytesAvailable ));
}
connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart =
connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
BytesAvailable;
AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
*BytesTaken = BytesAvailable;
//
// Abort the connection. Note that if the abort attempt fails
// we can't do anything about it.
//
(VOID)AfdBeginAbort( connection );
} else {
AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
//
// Note to the TDI provider that we didn't take any of the data here.
//
// !!! needs bufferring for non-bufferring transports!
*BytesTaken = 0;
//
// If there are any outstanding poll IRPs for this endpoint/
// event, complete them. Indicate this data as normal data if
// this endpoint is set up for inline reception of expedited
// data.
//
AfdIndicatePollEvent(
endpoint,
endpoint->InLine
? AFD_POLL_RECEIVE_BIT
: AFD_POLL_RECEIVE_EXPEDITED_BIT,
STATUS_SUCCESS
);
}
return STATUS_DATA_NOT_ACCEPTED;
} // AfdReceiveExpeditedEventHandler
NTSTATUS
AfdQueryReceiveInformation (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
{
PAFD_RECEIVE_INFORMATION receiveInformation;
PAFD_ENDPOINT endpoint;
KIRQL oldIrql;
LARGE_INTEGER result;
PAFD_CONNECTION connection;
//
// Make sure that the output buffer is large enough.
//
if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(AFD_RECEIVE_INFORMATION) ) {
return STATUS_BUFFER_TOO_SMALL;
}
//
// If this endpoint has a connection block, use the connection block's
// information, else use the information from the endpoint itself.
//
endpoint = IrpSp->FileObject->FsContext;
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
receiveInformation = Irp->AssociatedIrp.SystemBuffer;
if ( endpoint->TdiBufferring ) {
AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
} else {
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
}
connection = AFD_CONNECTION_FROM_ENDPOINT( endpoint );
if ( connection != NULL ) {
ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
ASSERT( connection->Type == AfdBlockTypeConnection );
if ( !endpoint->TdiBufferring ) {
receiveInformation->BytesAvailable =
connection->VcBufferredReceiveBytes;
receiveInformation->ExpeditedBytesAvailable =
connection->VcBufferredExpeditedBytes;
} else {
//
// Determine the number of bytes available to be read.
//
result.QuadPart =
connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart -
(connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart);
ASSERT( result.HighPart == 0 );
receiveInformation->BytesAvailable = result.LowPart;
//
// Determine the number of expedited bytes available to be read.
//
result.QuadPart =
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart -
(connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart);
ASSERT( result.HighPart == 0 );
receiveInformation->ExpeditedBytesAvailable = result.LowPart;
}
} else {
//
// Determine the number of bytes available to be read.
//
if ( IS_DGRAM_ENDPOINT(endpoint) ) {
//
// Return the amount of bytes of datagrams that are
// bufferred on the endpoint.
//
receiveInformation->BytesAvailable = endpoint->BufferredDatagramBytes;
} else {
//
// This is an unconnected endpoint, hence no bytes are
// available to be read.
//
receiveInformation->BytesAvailable = 0;
}
//
// Whether this is a datagram endpoint or just unconnected,
// there are no expedited bytes available.
//
receiveInformation->ExpeditedBytesAvailable = 0;
}
if ( endpoint->TdiBufferring ) {
AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
} else {
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
}
Irp->IoStatus.Information = sizeof(AFD_RECEIVE_INFORMATION);
return STATUS_SUCCESS;
} // AfdQueryReceiveInformation