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.
356 lines
8.6 KiB
356 lines
8.6 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sendrecv.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the SPUDSendAndRecv service.
|
|
|
|
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, SPUDSendAndRecv )
|
|
#endif
|
|
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
SPUDSendAndRecv(
|
|
HANDLE hSocket,
|
|
struct _AFD_SEND_INFO *sendInfo,
|
|
struct _AFD_RECV_INFO *recvInfo,
|
|
PSPUD_REQ_CONTEXT reqContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Batch send & receive request.
|
|
|
|
Arguments:
|
|
|
|
hSocket - The target socket for the request.
|
|
|
|
sendInfo - Information describing the send.
|
|
|
|
recvInfo - Information describing the receive.
|
|
|
|
reqContext - The user-mode context for the request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PFILE_OBJECT fileObject;
|
|
IO_STATUS_BLOCK localIoStatus;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PSPUD_AFD_REQ_CONTEXT SpudReqContext;
|
|
PVOID completionPort;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
status = SPUD_ENTER_SERVICE( "SPUDSendAndRecv", TRUE );
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
BumpCount( CtrSendAndRecv );
|
|
|
|
//
|
|
// SPUD doesn't support kernel-mode callers. In fact, we don't
|
|
// even build the "system stubs" necessary to invoke SPUD from
|
|
// kernel-mode.
|
|
//
|
|
|
|
ASSERT( ExGetPreviousMode() == UserMode );
|
|
|
|
try {
|
|
|
|
//
|
|
// Make sure we can write to reqContext
|
|
//
|
|
|
|
ProbeForWrite(
|
|
reqContext,
|
|
sizeof(SPUD_REQ_CONTEXT),
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
//
|
|
// Make initial status invalid
|
|
//
|
|
|
|
reqContext->IoStatus1.Status = 0xffffffff;
|
|
reqContext->IoStatus1.Information = 0;
|
|
reqContext->IoStatus2.Status = 0xffffffff;
|
|
reqContext->IoStatus2.Information = 0;
|
|
reqContext->ReqType = SendAndRecv;
|
|
reqContext->KernelReqInfo = SPUD_INVALID_REQ_HANDLE;
|
|
|
|
//
|
|
// Make sure the buffer looks good
|
|
//
|
|
|
|
ProbeForRead(
|
|
recvInfo,
|
|
sizeof(*recvInfo),
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
if( recvInfo->BufferCount < 1 ) {
|
|
ExRaiseStatus( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
ProbeForRead(
|
|
recvInfo->BufferArray,
|
|
sizeof(*recvInfo->BufferArray),
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
ProbeForRead(
|
|
recvInfo->BufferArray->buf,
|
|
recvInfo->BufferArray->len,
|
|
sizeof(UCHAR)
|
|
);
|
|
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
status = GetExceptionCode();
|
|
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Reference the socket handle
|
|
//
|
|
|
|
status = ObReferenceObjectByHandle(
|
|
hSocket,
|
|
0L,
|
|
*IoFileObjectType,
|
|
UserMode,
|
|
(PVOID *)&fileObject,
|
|
NULL
|
|
);
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
|
|
return status;
|
|
}
|
|
|
|
TRACE_OB_REFERENCE( fileObject );
|
|
|
|
//
|
|
// If we haven't already cached the Device Object and FastIoControl
|
|
// pointers, then do so now.
|
|
//
|
|
|
|
if( !SpudAfdDeviceObject ) {
|
|
|
|
status = SpudGetAfdDeviceObject( fileObject );
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
TRACE_OB_DEREFERENCE( fileObject );
|
|
ObDereferenceObject( fileObject );
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
|
|
return status;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Reference the completion port.
|
|
//
|
|
|
|
completionPort = SpudReferenceCompletionPort();
|
|
|
|
if( completionPort == NULL ) {
|
|
TRACE_OB_DEREFERENCE( fileObject );
|
|
ObDereferenceObject( fileObject );
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Let's check to see if fast io will work
|
|
//
|
|
|
|
if( SpudAfdFastIoDeviceControl(
|
|
fileObject,
|
|
TRUE,
|
|
(PVOID)sendInfo,
|
|
sizeof(AFD_SEND_INFO),
|
|
NULL,
|
|
0,
|
|
IOCTL_AFD_SEND,
|
|
&localIoStatus,
|
|
SpudAfdDeviceObject
|
|
)) {
|
|
|
|
BumpCount( CtrSendRecvFastSend );
|
|
|
|
//
|
|
// 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
|
|
);
|
|
}
|
|
|
|
//
|
|
// If everything completed without pending then we can queue
|
|
// a completion packet to the port now.
|
|
//
|
|
// Note that we must not queue a completion packet if the
|
|
// request is failing in-line.
|
|
//
|
|
|
|
if( localIoStatus.Status != STATUS_PENDING ) {
|
|
|
|
if( NT_SUCCESS(localIoStatus.Status) ) {
|
|
localIoStatus.Status = IoSetIoCompletion(
|
|
SpudCompletionPort, // IoCompletion
|
|
reqContext, // KeyContext
|
|
NULL, // ApcContext
|
|
STATUS_SUCCESS, // IoStatus
|
|
0xFFFFFFFF, // IoStatusInformation
|
|
TRUE // Quota
|
|
);
|
|
}
|
|
|
|
TRACE_OB_DEREFERENCE( fileObject );
|
|
ObDereferenceObject( fileObject );
|
|
|
|
}
|
|
|
|
//
|
|
// At this point, we know the fast-path send has completed
|
|
// in-line and the receive either completed in-line or has pended.
|
|
// Since it is the receive code's responsibility to add any necessary
|
|
// references to the completion port (and since we know the send
|
|
// has not pended) we can remove the reference we added above.
|
|
//
|
|
|
|
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", localIoStatus.Status, TRUE );
|
|
return localIoStatus.Status;
|
|
|
|
}
|
|
|
|
BumpCount( CtrSendRecvSlowSend );
|
|
|
|
//
|
|
// 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( SpudAfdDeviceObject->StackSize, TRUE );
|
|
|
|
if( !irp ) {
|
|
TRACE_OB_DEREFERENCE( fileObject );
|
|
ObDereferenceObject( fileObject );
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, TRUE );
|
|
return status;
|
|
}
|
|
|
|
status = SpudAllocateRequestContext(
|
|
&SpudReqContext,
|
|
reqContext,
|
|
recvInfo,
|
|
irp,
|
|
NULL
|
|
);
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
TRACE_OB_DEREFERENCE( fileObject );
|
|
ObDereferenceObject( fileObject );
|
|
IoFreeIrp( irp );
|
|
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, TRUE );
|
|
return status;
|
|
}
|
|
|
|
BumpCount( CtrSendRecvSlowRecv );
|
|
|
|
irp->RequestorMode = UserMode;
|
|
irp->Tail.Overlay.OriginalFileObject = fileObject;
|
|
irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
|
IoQueueThreadIrp( irp );
|
|
|
|
irpSp = IoGetNextIrpStackLocation( irp );
|
|
|
|
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
|
irpSp->FileObject = fileObject;
|
|
irpSp->DeviceObject = SpudAfdDeviceObject;
|
|
|
|
// irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
|
|
irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(AFD_SEND_INFO);
|
|
irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_AFD_SEND;
|
|
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = sendInfo;
|
|
|
|
IoSetCompletionRoutine(
|
|
irp,
|
|
SpudAfdContinueRecv,
|
|
SpudReqContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
IoCallDriver( SpudAfdDeviceObject, irp );
|
|
|
|
status = STATUS_PENDING;
|
|
SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
|
|
return status;
|
|
|
|
} // SPUDSendAndRecv
|