mirror of https://github.com/tongzx/nt5src
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.
395 lines
7.7 KiB
395 lines
7.7 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
recv.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the Recv code for SPUD.
|
|
|
|
Author:
|
|
|
|
John Ballard (jballard) 21-Oct-1996
|
|
|
|
Revision History:
|
|
|
|
Keith Moore (keithmo) 04-Feb-1998
|
|
Cleanup, added much needed comments.
|
|
|
|
--*/
|
|
|
|
|
|
#include "spudp.h"
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, SpudAfdRecvFastReq )
|
|
#endif
|
|
#if 0
|
|
NOT PAGEABLE -- SpudAfdContinueRecv
|
|
NOT PAGEABLE -- SpudAfdCompleteRecv
|
|
#endif
|
|
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
|
|
NTSTATUS
|
|
SpudAfdRecvFastReq(
|
|
PFILE_OBJECT fileObject,
|
|
PAFD_RECV_INFO recvInfo,
|
|
PSPUD_REQ_CONTEXT reqContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempts a fast-path AFD receive.
|
|
|
|
Arguments:
|
|
|
|
fileObject - The file object for the target socket.
|
|
|
|
recvInfo - Information describing the receive.
|
|
|
|
reqContext - The user-mode context for the request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK localIoStatus;
|
|
PSPUD_AFD_REQ_CONTEXT SpudReqContext;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PVOID completionPort;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Let's check to see if fast I/O will work.
|
|
//
|
|
|
|
if( SpudAfdFastIoDeviceControl(
|
|
fileObject,
|
|
TRUE,
|
|
(PVOID)recvInfo,
|
|
sizeof(AFD_RECV_INFO),
|
|
NULL,
|
|
0,
|
|
IOCTL_AFD_RECEIVE,
|
|
&localIoStatus,
|
|
SpudAfdDeviceObject
|
|
) ) {
|
|
|
|
//
|
|
// Fast I/O succeeded.
|
|
//
|
|
|
|
if( reqContext->ReqType == TransmitFileAndRecv ) {
|
|
BumpCount(CtrTransRecvFastRecv);
|
|
} else {
|
|
BumpCount(CtrSendRecvFastRecv);
|
|
}
|
|
|
|
//
|
|
// Remember the completion status for this operation.
|
|
//
|
|
|
|
try {
|
|
reqContext->IoStatus2 = localIoStatus;
|
|
} except( EXCEPTION_EXECUTE_HANDLER) {
|
|
localIoStatus.Status = GetExceptionCode();
|
|
localIoStatus.Information = 0;
|
|
}
|
|
|
|
return localIoStatus.Status;
|
|
|
|
}
|
|
|
|
//
|
|
// Fast I/O failed.
|
|
//
|
|
|
|
if (reqContext->ReqType == TransmitFileAndRecv) {
|
|
BumpCount(CtrTransRecvSlowRecv);
|
|
} else {
|
|
BumpCount(CtrSendRecvSlowRecv);
|
|
}
|
|
|
|
//
|
|
// It looks like we will have to it the hard way.
|
|
// We will now build an IRP for AFD.
|
|
//
|
|
|
|
KeClearEvent( &fileObject->Event );
|
|
|
|
//
|
|
// Reference the completion port.
|
|
//
|
|
|
|
completionPort = SpudReferenceCompletionPort();
|
|
|
|
if( completionPort == NULL ) {
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
//
|
|
// Allocate the IRP.
|
|
//
|
|
|
|
irp = IoAllocateIrp( SpudAfdDeviceObject->StackSize, TRUE );
|
|
|
|
if (!irp) {
|
|
SpudDereferenceCompletionPort();
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize a kernel-mode context for this request.
|
|
//
|
|
|
|
status = SpudAllocateRequestContext(
|
|
&SpudReqContext,
|
|
reqContext,
|
|
recvInfo,
|
|
irp,
|
|
&reqContext->IoStatus1
|
|
);
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
IoFreeIrp( irp );
|
|
SpudDereferenceCompletionPort();
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Initialize the IRP, call the driver.
|
|
//
|
|
|
|
irp->RequestorMode = UserMode;
|
|
irp->Tail.Overlay.OriginalFileObject = fileObject;
|
|
irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
|
IoQueueThreadIrp( irp );
|
|
|
|
irpSp = IoGetNextIrpStackLocation( irp );
|
|
|
|
irp->MdlAddress = SpudReqContext->Mdl;
|
|
SpudReqContext->Mdl = NULL;
|
|
|
|
irpSp->MajorFunction = IRP_MJ_READ;
|
|
irpSp->FileObject = fileObject;
|
|
irpSp->DeviceObject = SpudAfdDeviceObject;
|
|
|
|
irpSp->Parameters.Read.Length = (ULONG)SpudReqContext->IoStatus2.Information;
|
|
// irpSp->Parameters.Read.Key = 0;
|
|
// irpSp->Parameters.Read.ByteOffset.QuadPart = 0;
|
|
|
|
IoSetCompletionRoutine(
|
|
irp,
|
|
SpudAfdCompleteRecv,
|
|
SpudReqContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
IoCallDriver( SpudAfdDeviceObject, irp );
|
|
|
|
return STATUS_PENDING;
|
|
|
|
} // SpudAfdRecvFastReq
|
|
|
|
|
|
NTSTATUS
|
|
SpudAfdContinueRecv(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion handler for IOCTL_AFD_SEND and IOCTL_AFD_TRANSMIT_FILE
|
|
IRPs. This completion handler is responsible for initiating the
|
|
receive part of the XxxAndRecv() API.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The device object completing the request (unused).
|
|
|
|
Irp - The IRP being completed.
|
|
|
|
Context - The context associated with the request. This is actually
|
|
the kernel-mode SPUD_REQ_CONTEXT for this request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PSPUD_AFD_REQ_CONTEXT SpudReqContext = Context;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PULONG majorFunction;
|
|
PMDL mdl, nextMdl;
|
|
|
|
//
|
|
// Snag the completion status.
|
|
//
|
|
|
|
SpudReqContext->IoStatus1 = Irp->IoStatus;
|
|
status = Irp->IoStatus.Status;
|
|
|
|
//
|
|
// Cleanup the IRP.
|
|
//
|
|
|
|
if( Irp->MdlAddress != NULL ) {
|
|
for( mdl = Irp->MdlAddress ; mdl != NULL ; mdl = nextMdl ) {
|
|
nextMdl = mdl->Next;
|
|
MmUnlockPages( mdl );
|
|
IoFreeMdl( mdl );
|
|
}
|
|
|
|
Irp->MdlAddress = NULL;
|
|
}
|
|
|
|
//
|
|
// If the initial operation failed, then complete the request now
|
|
// without issuing the receive.
|
|
//
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
SpudReqContext->IoStatus2.Status = 0;
|
|
SpudReqContext->IoStatus2.Information = 0;
|
|
|
|
SpudCompleteRequest( SpudReqContext );
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
//
|
|
// Reinitialize the IRP and initiate the receive operation.
|
|
//
|
|
|
|
Irp->MdlAddress = SpudReqContext->Mdl;
|
|
SpudReqContext->Mdl = NULL;
|
|
|
|
irpSp = IoGetNextIrpStackLocation( Irp );
|
|
|
|
irpSp->MajorFunction = IRP_MJ_READ;
|
|
irpSp->MinorFunction = 0;
|
|
irpSp->FileObject = Irp->Tail.Overlay.OriginalFileObject;
|
|
irpSp->DeviceObject = SpudAfdDeviceObject;
|
|
|
|
irpSp->Parameters.Read.Length = (ULONG)SpudReqContext->IoStatus2.Information;
|
|
irpSp->Parameters.Read.Key = 0;
|
|
irpSp->Parameters.Read.ByteOffset.QuadPart = 0;
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
SpudAfdCompleteRecv,
|
|
SpudReqContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
IoCallDriver( SpudAfdDeviceObject, Irp );
|
|
|
|
//
|
|
// Tell IO to stop processing this IRP.
|
|
//
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
} // SpudAfdContinueRecv
|
|
|
|
|
|
NTSTATUS
|
|
SpudAfdCompleteRecv(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for receive IRPs issued as part of an XxxAndRecv().
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The device object completing the request (unused).
|
|
|
|
Irp - The IRP being completed.
|
|
|
|
Context - The context associated with the request. This is actually
|
|
the kernel-mode SPUD_REQ_CONTEXT for this request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PSPUD_AFD_REQ_CONTEXT SpudReqContext = Context;
|
|
PMDL mdl, nextMdl;
|
|
|
|
//
|
|
// Snag the completion status.
|
|
//
|
|
|
|
SpudReqContext->IoStatus2 = Irp->IoStatus;
|
|
status = Irp->IoStatus.Status;
|
|
|
|
//
|
|
// Cleanup the IRP.
|
|
//
|
|
|
|
if( Irp->MdlAddress != NULL ) {
|
|
for( mdl = Irp->MdlAddress ; mdl != NULL ; mdl = nextMdl ) {
|
|
nextMdl = mdl->Next;
|
|
MmUnlockPages( mdl );
|
|
IoFreeMdl( mdl );
|
|
}
|
|
|
|
Irp->MdlAddress = NULL;
|
|
}
|
|
|
|
//
|
|
// Complete the original request.
|
|
//
|
|
|
|
SpudCompleteRequest( SpudReqContext );
|
|
|
|
//
|
|
// Tell IO to stop processing this IRP.
|
|
//
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
} // SpudAfdCompleteRecv
|