2025-04-27 07:49:33 -04:00

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;
}