330 lines
9.8 KiB
C
330 lines
9.8 KiB
C
|
|
|
|
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tranrecv.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the TransmitFileAndRecv code for SPUD.
|
|
|
|
Author:
|
|
|
|
John Ballard (jballard) 21-Oct-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "spudp.h"
|
|
|
|
|
|
NTSTATUS
|
|
SPUDTransmitFileAndRecv(
|
|
HANDLE hSocket, // Socket handle to use for operation
|
|
PAFD_TRANSMIT_FILE_INFO transmitInfo, // transmit file req info
|
|
PAFD_RECV_INFO recvInfo, // recv req info
|
|
PSPUD_REQ_CONTEXT reqContext // context info for req
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
KPROCESSOR_MODE requestorMode;
|
|
PFILE_OBJECT fileObject;
|
|
IO_STATUS_BLOCK localIoStatus;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PULONG majorFunction;
|
|
PSPUD_AFD_REQ_CONTEXT SpudReqContext;
|
|
|
|
|
|
if (!DriverInitialized) {
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
#if USE_SPUD_COUNTERS
|
|
BumpCount(CtrTransmitfileAndRecv);
|
|
#endif
|
|
|
|
requestorMode = KeGetPreviousMode();
|
|
|
|
if (requestorMode != KernelMode) {
|
|
try {
|
|
|
|
//
|
|
// Make sure we can write to reqContext
|
|
//
|
|
|
|
//
|
|
// Make initial status invalid
|
|
//
|
|
|
|
reqContext->IoStatus1.Status = 0xffffffff;
|
|
reqContext->IoStatus1.Information = 0;
|
|
reqContext->IoStatus2.Status = 0xffffffff;
|
|
reqContext->IoStatus2.Information = 0;
|
|
reqContext->ReqType = TransmitFileAndRecv;
|
|
reqContext->KernelReqInfo = NULL;
|
|
|
|
//
|
|
// Make sure the buffer looks good
|
|
//
|
|
|
|
if ( recvInfo->BufferCount < 1 ) {
|
|
ExRaiseStatus(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
ProbeForWrite( recvInfo->BufferArray->buf,
|
|
recvInfo->BufferArray->len,
|
|
sizeof(UCHAR) );
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
//
|
|
// An exception has occurred while trying to probe one
|
|
// of the callers parameters. Simply return the error
|
|
// status code.
|
|
//
|
|
|
|
return GetExceptionCode();
|
|
|
|
}
|
|
} else {
|
|
reqContext->IoStatus1.Status = 0xffffffff;
|
|
reqContext->IoStatus1.Information = 0;
|
|
reqContext->IoStatus2.Status = 0xffffffff;
|
|
reqContext->IoStatus2.Information = 0;
|
|
reqContext->ReqType = TransmitFileAndRecv;
|
|
reqContext->KernelReqInfo = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Reference the socket handle
|
|
//
|
|
|
|
Status = ObReferenceObjectByHandle( hSocket,
|
|
0L,
|
|
NULL,
|
|
requestorMode,
|
|
(PVOID *) &fileObject,
|
|
NULL );
|
|
if (Status != STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// If we haven't already cached the Device Object and FastIoControl
|
|
// pointers, then do so now.
|
|
//
|
|
|
|
if (!AfdDeviceObject) {
|
|
|
|
if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
|
|
AfdDeviceObject = IoGetRelatedDeviceObject( fileObject );
|
|
} else {
|
|
AfdDeviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
|
|
}
|
|
|
|
if (!AfdDeviceObject) {
|
|
ObDereferenceObject( fileObject );
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
AfdFastIoDeviceControl =
|
|
AfdDeviceObject->DriverObject->FastIoDispatch->FastIoDeviceControl;
|
|
|
|
if (!AfdFastIoDeviceControl) {
|
|
AfdDeviceObject = NULL;
|
|
ObDereferenceObject( fileObject );
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Let's check to see if fast io will work
|
|
//
|
|
|
|
if (AfdFastIoDeviceControl( fileObject,
|
|
TRUE,
|
|
(PVOID) transmitInfo,
|
|
sizeof(AFD_TRANSMIT_FILE_INFO),
|
|
NULL,
|
|
0,
|
|
IOCTL_AFD_TRANSMIT_FILE,
|
|
&localIoStatus,
|
|
AfdDeviceObject
|
|
)) {
|
|
|
|
|
|
#if USE_SPUD_COUNTERS
|
|
BumpCount(CtrTransRecvFastTrans);
|
|
#endif
|
|
|
|
//
|
|
// Lets remember the completion status for this operation
|
|
//
|
|
|
|
try {
|
|
reqContext->IoStatus1 = localIoStatus;
|
|
} except( EXCEPTION_EXECUTE_HANDLER) {
|
|
localIoStatus.Status = GetExceptionCode();
|
|
localIoStatus.Information = 0;
|
|
}
|
|
|
|
if (localIoStatus.Status == STATUS_SUCCESS) {
|
|
localIoStatus.Status = SpudAfdRecvFastReq( fileObject,
|
|
recvInfo,
|
|
reqContext,
|
|
requestorMode );
|
|
}
|
|
|
|
//
|
|
// If everything completed without pending then we can queue
|
|
// a completion packet to the port now.
|
|
//
|
|
|
|
if (localIoStatus.Status != STATUS_PENDING) {
|
|
|
|
PIO_MINI_COMPLETION_PACKET miniPacket = NULL;
|
|
|
|
try {
|
|
miniPacket = ExAllocatePoolWithQuotaTag( NonPagedPool,
|
|
sizeof( *miniPacket ),
|
|
'pcUI' );
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
NOTHING;
|
|
}
|
|
|
|
if (miniPacket) {
|
|
miniPacket->TypeFlag = 0xffffffff;
|
|
miniPacket->KeyContext = (ULONG)reqContext;
|
|
miniPacket->ApcContext = NULL;
|
|
miniPacket->IoStatus = 0;
|
|
miniPacket->IoStatusInformation = 0xffffffff;
|
|
|
|
KeInsertQueue( (PKQUEUE) ATQIoCompletionPort,
|
|
&miniPacket->ListEntry );
|
|
|
|
} else {
|
|
localIoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
ObDereferenceObject( fileObject );
|
|
}
|
|
|
|
return localIoStatus.Status;
|
|
}
|
|
|
|
#if USE_SPUD_COUNTERS
|
|
BumpCount(CtrTransRecvSlowTrans);
|
|
#endif
|
|
|
|
//
|
|
// It looks like we will have to it the hard way
|
|
// We will now build an irp for AFD
|
|
//
|
|
|
|
KeClearEvent( &fileObject->Event );
|
|
|
|
//
|
|
// Allocate and initialize the irp
|
|
//
|
|
|
|
irp = IoAllocateIrp( AfdDeviceObject->StackSize, TRUE );
|
|
|
|
if (!irp) {
|
|
ObDereferenceObject( fileObject );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
SpudReqContext = ExAllocateFromNPagedLookasideList(
|
|
&SpudLookasideLists->ReqContextList);
|
|
|
|
if (!SpudReqContext) {
|
|
ObDereferenceObject( fileObject );
|
|
IoFreeIrp( irp );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
#if STATUS_SUPPORTED
|
|
KeInitializeSpinLock( &SpudReqContext->Lock );
|
|
#endif
|
|
SpudReqContext->Signature = SPUD_REQ_CONTEXT_SIGNATURE;
|
|
SpudReqContext->Irp = irp;
|
|
SpudReqContext->AtqContext = reqContext;
|
|
reqContext->KernelReqInfo = SpudReqContext;
|
|
|
|
//
|
|
// Allocate MDL for receive buffer and Probe and Lock it.
|
|
//
|
|
|
|
try {
|
|
|
|
if (recvInfo != NULL) {
|
|
SpudReqContext->IoStatus2.Information = recvInfo->BufferArray->len;
|
|
SpudReqContext->Mdl = IoAllocateMdl( recvInfo->BufferArray->buf,
|
|
recvInfo->BufferArray->len,
|
|
FALSE,
|
|
FALSE,
|
|
NULL );
|
|
|
|
if ( SpudReqContext->Mdl == NULL ) {
|
|
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
MmProbeAndLockPages( SpudReqContext->Mdl,
|
|
requestorMode,
|
|
IoWriteAccess );
|
|
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
ObDereferenceObject( fileObject );
|
|
IoFreeIrp( irp );
|
|
ExFreeToNPagedLookasideList( &SpudLookasideLists->ReqContextList,
|
|
SpudReqContext );
|
|
return GetExceptionCode();
|
|
}
|
|
|
|
#if USE_SPUD_COUNTERS
|
|
BumpCount(CtrTransRecvSlowRecv);
|
|
#endif
|
|
|
|
IoSetCompletionRoutine( irp, SpudAfdContinueRecv, SpudReqContext, TRUE, TRUE, TRUE);
|
|
|
|
irp->Tail.Overlay.OriginalFileObject = fileObject;
|
|
irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
|
irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)NULL;
|
|
irp->RequestorMode = requestorMode;
|
|
irp->PendingReturned = FALSE;
|
|
irp->Cancel = FALSE;
|
|
irp->CancelRoutine = (PDRIVER_CANCEL)NULL;
|
|
irp->UserEvent = NULL;
|
|
irp->UserIosb = &reqContext->IoStatus1;
|
|
irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
|
|
irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
|
|
|
|
irpSp = IoGetNextIrpStackLocation( irp );
|
|
|
|
majorFunction = (PULONG) (&irpSp->MajorFunction);
|
|
*majorFunction = IRP_MJ_DEVICE_CONTROL;
|
|
irpSp->FileObject = fileObject;
|
|
irpSp->Control = SL_INVOKE_ON_SUCCESS |
|
|
SL_INVOKE_ON_ERROR |
|
|
SL_INVOKE_ON_CANCEL;
|
|
irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
|
|
irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(AFD_TRANSMIT_FILE_INFO);
|
|
irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_AFD_TRANSMIT_FILE;
|
|
irp->UserBuffer = NULL;
|
|
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = transmitInfo;
|
|
|
|
IoCallDriver( AfdDeviceObject, irp );
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
|