/*++ 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