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.
1705 lines
57 KiB
1705 lines
57 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
socket.c
|
|
|
|
Abstract:
|
|
|
|
This module implements socket file object for ws2ifsl.sys driver.
|
|
|
|
Author:
|
|
|
|
Vadim Eydelman (VadimE) Dec-1996
|
|
|
|
Revision History:
|
|
|
|
Vadim Eydelman (VadimE) Oct-1997, rewrite to properly handle IRP
|
|
cancellation
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
|
|
VOID
|
|
SetSocketContext (
|
|
IN PFILE_OBJECT SocketFile,
|
|
IN KPROCESSOR_MODE RequestorMode,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PIO_STATUS_BLOCK IoStatus
|
|
);
|
|
|
|
|
|
VOID
|
|
CompletePvdRequest (
|
|
IN PFILE_OBJECT SocketFile,
|
|
IN KPROCESSOR_MODE RequestorMode,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PIO_STATUS_BLOCK IoStatus
|
|
);
|
|
|
|
VOID
|
|
ProcessedCancelRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
PIRP
|
|
GetProcessedRequest (
|
|
PIFSL_SOCKET_CTX SocketCtx,
|
|
ULONG UniqueId
|
|
);
|
|
|
|
VOID
|
|
CleanupProcessedRequests (
|
|
PIFSL_SOCKET_CTX SocketCtx,
|
|
PLIST_ENTRY IrpList
|
|
);
|
|
|
|
|
|
VOID
|
|
CancelSocketIo (
|
|
PFILE_OBJECT SocketFile
|
|
);
|
|
|
|
PFILE_OBJECT
|
|
GetSocketProcessReference (
|
|
IN PIFSL_SOCKET_CTX SocketCtx
|
|
);
|
|
|
|
PFILE_OBJECT
|
|
SetSocketProcessReference (
|
|
IN PIFSL_SOCKET_CTX SocketCtx,
|
|
IN PFILE_OBJECT NewProcessFile,
|
|
IN PVOID NewDllContext
|
|
);
|
|
|
|
NTSTATUS
|
|
CompleteTargetQuery (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, CreateSocketFile)
|
|
#pragma alloc_text(PAGE, CleanupSocketFile)
|
|
#pragma alloc_text(PAGE, CloseSocketFile)
|
|
#pragma alloc_text(PAGE, DoSocketReadWrite)
|
|
#pragma alloc_text(PAGE, DoSocketAfdIoctl)
|
|
#pragma alloc_text(PAGE, SetSocketContext)
|
|
#pragma alloc_text(PAGE, CompleteDrvRequest)
|
|
#pragma alloc_text(PAGE, CompletePvdRequest)
|
|
#pragma alloc_text(PAGE, SocketPnPTargetQuery)
|
|
//#pragma alloc_text (PAGE, CompleteTargetQuery) - should never be paged.
|
|
#endif
|
|
|
|
ULONG SocketIoctlCodeMap[2] = {
|
|
#if WS2IFSL_IOCTL_FUNCTION(SOCKET,IOCTL_WS2IFSL_SET_SOCKET_CONTEXT)!=0
|
|
#error Mismatch between IOCTL function code and SocketIoControlMap
|
|
#endif
|
|
IOCTL_WS2IFSL_SET_SOCKET_CONTEXT,
|
|
#if WS2IFSL_IOCTL_FUNCTION(SOCKET,IOCTL_WS2IFSL_COMPLETE_PVD_REQ)!=1
|
|
#error Mismatch between IOCTL function code and SocketIoControlMap
|
|
#endif
|
|
IOCTL_WS2IFSL_COMPLETE_PVD_REQ
|
|
};
|
|
|
|
PSOCKET_DEVICE_CONTROL SocketIoControlMap[2] = {
|
|
SetSocketContext,
|
|
CompletePvdRequest
|
|
};
|
|
|
|
|
|
#define GenerateUniqueId(curId) \
|
|
((ULONG)InterlockedIncrement (&(curId)))
|
|
|
|
|
|
NTSTATUS
|
|
CreateSocketFile (
|
|
IN PFILE_OBJECT SocketFile,
|
|
IN KPROCESSOR_MODE RequestorMode,
|
|
IN PFILE_FULL_EA_INFORMATION eaInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates and initializes socket file context structure.
|
|
|
|
Arguments:
|
|
SocketFile - socket file object
|
|
eaInfo - EA for socket file
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - operation completed OK
|
|
STATUS_INSUFFICIENT_RESOURCES - not enough memory to allocate context
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
HANDLE hProcessFile;
|
|
PFILE_OBJECT ProcessFile;
|
|
PVOID DllContext;
|
|
|
|
PAGED_CODE ();
|
|
|
|
if (eaInfo->EaValueLength!=WS2IFSL_SOCKET_EA_VALUE_LENGTH) {
|
|
WsPrint (DBG_SOCKET|DBG_FAILURES,
|
|
("WS2IFSL-%04lx CreateSocketFile: Invalid ea info size (%ld)"
|
|
" for process file %p.\n",
|
|
PsGetCurrentProcessId(),
|
|
eaInfo->EaValueLength,
|
|
SocketFile));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
hProcessFile = GET_WS2IFSL_SOCKET_EA_VALUE(eaInfo)->ProcessFile;
|
|
DllContext = GET_WS2IFSL_SOCKET_EA_VALUE(eaInfo)->DllContext;
|
|
// Get reference to the process file with which this context is associated
|
|
status = ObReferenceObjectByHandle(
|
|
hProcessFile,
|
|
FILE_ALL_ACCESS,
|
|
*IoFileObjectType,
|
|
RequestorMode,
|
|
(PVOID *)&ProcessFile,
|
|
NULL
|
|
);
|
|
if (NT_SUCCESS (status)) {
|
|
// Verify that the file pointer is really our driver's process file
|
|
// and that it created for the current process
|
|
if ((IoGetRelatedDeviceObject (ProcessFile)
|
|
==DeviceObject)
|
|
&& ((*((PULONG)ProcessFile->FsContext))
|
|
==PROCESS_FILE_EANAME_TAG)
|
|
&& (((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId
|
|
==PsGetCurrentProcessId())) {
|
|
// Allocate socket context and charge it to the process
|
|
try {
|
|
SocketCtx = (PIFSL_SOCKET_CTX) ExAllocatePoolWithQuotaTag (
|
|
NonPagedPool,
|
|
sizeof (IFSL_SOCKET_CTX),
|
|
SOCKET_FILE_CONTEXT_TAG);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
SocketCtx = NULL;
|
|
status = GetExceptionCode ();
|
|
}
|
|
|
|
if (SocketCtx!=NULL) {
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_SOCKET,
|
|
("WS2IFSL-%04lx CreateSocketFile: Created socket %p (ctx:%p)\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId, SocketFile, SocketCtx));
|
|
// Initialize socket context structure
|
|
SocketCtx->EANameTag = SOCKET_FILE_EANAME_TAG;
|
|
SocketCtx->DllContext = DllContext;
|
|
SocketCtx->ProcessRef = ProcessFile;
|
|
InitializeListHead (&SocketCtx->ProcessedIrps);
|
|
KeInitializeSpinLock (&SocketCtx->SpinLock);
|
|
SocketCtx->CancelCtx = NULL;
|
|
SocketCtx->IrpId = 0;
|
|
|
|
// Associate socket context with socket file
|
|
SocketFile->FsContext = SocketCtx;
|
|
|
|
return status;
|
|
}
|
|
else {
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_FAILURES|DBG_SOCKET,
|
|
("WS2IFSL-%04lx CreateSocketFile: Could not allocate socket context\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId));
|
|
if (NT_SUCCESS (status)) {
|
|
ASSERT (FALSE);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Handle refers to random file object
|
|
WsPrint (DBG_SOCKET|DBG_FAILURES,
|
|
("WS2IFSL-%04lx CreateSocketFile: Procees file handle %p (File:%p)"
|
|
" is not valid\n",
|
|
PsGetCurrentProcessId(),
|
|
ProcessFile, hProcessFile));
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
ObDereferenceObject (ProcessFile);
|
|
}
|
|
else {
|
|
WsPrint (DBG_SOCKET|DBG_FAILURES,
|
|
("WS2IFSL-%04lx CreateSocketFile: Could not get process file from handle %p,"
|
|
" status:%lx.\n",
|
|
PsGetCurrentProcessId(),
|
|
hProcessFile,
|
|
status));
|
|
}
|
|
|
|
return status;
|
|
} // CreateSocketFile
|
|
|
|
|
|
NTSTATUS
|
|
CleanupSocketFile (
|
|
IN PFILE_OBJECT SocketFile,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initiates socket file cleanup in context of current process.
|
|
|
|
Arguments:
|
|
SocketFile - socket file object
|
|
Irp - cleanup request
|
|
|
|
Return Value:
|
|
|
|
STATUS_PENDING - operation initiated OK
|
|
STATUS_INVALID_HANDLE - socket has not been initialized
|
|
in current process
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
PFILE_OBJECT ProcessFile;
|
|
LIST_ENTRY irpList;
|
|
PIFSL_CANCEL_CTX cancelCtx;
|
|
|
|
PAGED_CODE ();
|
|
SocketCtx = SocketFile->FsContext;
|
|
ProcessFile = GetSocketProcessReference (SocketCtx);
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)SocketCtx->ProcessRef->FsContext, DBG_SOCKET,
|
|
("WS2IFSL-%04lx CleanupSocketFile: Socket %p \n",
|
|
GET_SOCKET_PROCESSID(SocketCtx), SocketFile));
|
|
//
|
|
// Build the list of IRPS still panding on this socket
|
|
//
|
|
InitializeListHead (&irpList);
|
|
CleanupQueuedRequests (ProcessFile->FsContext,
|
|
SocketFile,
|
|
&irpList);
|
|
CleanupProcessedRequests (SocketCtx, &irpList);
|
|
|
|
//
|
|
// Complete the cancelled IRPS
|
|
//
|
|
while (!IsListEmpty (&irpList)) {
|
|
PLIST_ENTRY entry;
|
|
PIRP irp;
|
|
entry = RemoveHeadList (&irpList);
|
|
irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry);
|
|
irp->IoStatus.Status = STATUS_CANCELLED;
|
|
irp->IoStatus.Information = 0;
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_SOCKET,
|
|
("WS2IFSL-%04lx CleanupSocketFile: Cancelling Irp %p on socket %p \n",
|
|
GET_SOCKET_PROCESSID(SocketCtx), irp, SocketFile));
|
|
CompleteSocketIrp (irp);
|
|
}
|
|
|
|
//
|
|
// Indicate that cleanup routine is going to take care of the
|
|
// pending cancel request if any.
|
|
//
|
|
cancelCtx = InterlockedExchangePointer (
|
|
(PVOID *)&SocketCtx->CancelCtx,
|
|
NULL);
|
|
if (cancelCtx!=NULL) {
|
|
//
|
|
// We are going to try to free this request if it is still in the queue
|
|
//
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_SOCKET,
|
|
("WS2IFSL-%04lx CleanupSocketFile: Removing cancel ctx %p on socket %p \n",
|
|
GET_SOCKET_PROCESSID(SocketCtx), cancelCtx, SocketFile));
|
|
if (RemoveQueuedCancel (ProcessFile->FsContext, cancelCtx)) {
|
|
//
|
|
// Request was in the queue, it is safe to call regular free routine
|
|
// (no-one else will find it now, so it is safe to put the pointer
|
|
// back in place so that FreeSocketCancel can free it)
|
|
//
|
|
SocketCtx->CancelCtx = cancelCtx;
|
|
FreeSocketCancel (cancelCtx);
|
|
}
|
|
else {
|
|
//
|
|
// Someone else managed to remove the request from the queue before
|
|
// we did, let them or close routine free it. We aren't going to
|
|
// touch it after this.
|
|
//
|
|
SocketCtx->CancelCtx = cancelCtx;
|
|
}
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
ObDereferenceObject (ProcessFile);
|
|
return status;
|
|
} // CleanupSocketFile
|
|
|
|
|
|
VOID
|
|
CloseSocketFile (
|
|
IN PFILE_OBJECT SocketFile
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocates all resources associated with socket file
|
|
|
|
Arguments:
|
|
SocketFile - socket file object
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
PIFSL_SOCKET_CTX SocketCtx = SocketFile->FsContext;
|
|
|
|
PAGED_CODE ();
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)SocketCtx->ProcessRef->FsContext, DBG_SOCKET,
|
|
("WS2IFSL-%04lx CloseSocketFile: Socket %p \n",
|
|
GET_SOCKET_PROCESSID(SocketCtx), SocketFile));
|
|
|
|
// First dereference process file
|
|
ObDereferenceObject (SocketCtx->ProcessRef);
|
|
|
|
if (SocketCtx->CancelCtx!=NULL) {
|
|
ExFreePool (SocketCtx->CancelCtx);
|
|
}
|
|
|
|
// Free context
|
|
ExFreePool (SocketCtx);
|
|
|
|
} // CloseSocketFile
|
|
|
|
NTSTATUS
|
|
DoSocketReadWrite (
|
|
IN PFILE_OBJECT SocketFile,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initiates read and write request processing on socket file.
|
|
|
|
Arguments:
|
|
SocketFile - socket file object
|
|
Irp - read/write request
|
|
|
|
Return Value:
|
|
|
|
STATUS_PENDING - operation initiated OK
|
|
STATUS_INVALID_HANDLE - socket has not been initialized
|
|
in current process
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
PFILE_OBJECT ProcessFile;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
PAGED_CODE ();
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
SocketCtx = SocketFile->FsContext;
|
|
ProcessFile = GetSocketProcessReference (SocketCtx);
|
|
|
|
if (((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId==PsGetCurrentProcessId()) {
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_READWRITE,
|
|
("WS2IFSL-%04lx DoSocketReadWrite: %s irp %p on socket %p, len %ld.\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId,
|
|
irpSp->MajorFunction==IRP_MJ_READ ? "Read" : "Write",
|
|
Irp, SocketFile,
|
|
irpSp->MajorFunction==IRP_MJ_READ
|
|
? irpSp->Parameters.Read.Length
|
|
: irpSp->Parameters.Write.Length));
|
|
//
|
|
// Allocate MDL to describe the user buffer.
|
|
//
|
|
Irp->MdlAddress = IoAllocateMdl(
|
|
Irp->UserBuffer, // VirtualAddress
|
|
irpSp->Parameters.DeviceIoControl.OutputBufferLength,
|
|
// Length
|
|
FALSE, // SecondaryBuffer
|
|
TRUE, // ChargeQuota
|
|
NULL // Irp
|
|
);
|
|
if (Irp->MdlAddress!=NULL) {
|
|
|
|
// We are going to pend this request
|
|
IoMarkIrpPending (Irp);
|
|
|
|
// Prepare IRP for insertion into the queue
|
|
Irp->Tail.Overlay.IfslRequestId = UlongToPtr(GenerateUniqueId (SocketCtx->IrpId));
|
|
Irp->Tail.Overlay.IfslRequestFlags = (PVOID)0;
|
|
Irp->Tail.Overlay.IfslAddressLenPtr = NULL;
|
|
Irp->Tail.Overlay.IfslRequestQueue = NULL;
|
|
if (!QueueRequest (ProcessFile->FsContext, Irp)) {
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_READWRITE,
|
|
("WS2IFSL-%04lx DoSocketReadWrite: Cancelling Irp %p on socket %p.\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId,
|
|
Irp, SocketFile));
|
|
CompleteSocketIrp (Irp);
|
|
}
|
|
|
|
status = STATUS_PENDING;
|
|
}
|
|
else {
|
|
WsPrint (DBG_SOCKET|DBG_READWRITE|DBG_FAILURES,
|
|
("WS2IFSL-%04lx DoSocketReadWrite: Failed to allocate Mdl for Irp %p"
|
|
" on socket %p, status %lx.\n",
|
|
PsGetCurrentProcessId(), Irp, SocketFile));;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
else {
|
|
status = STATUS_INVALID_HANDLE;
|
|
WsPrint (DBG_SOCKET|DBG_READWRITE|DBG_FAILURES,
|
|
("WS2IFSL-%04lx DoSocketReadWrite: Socket %p has not"
|
|
" been setup in the process.\n",
|
|
PsGetCurrentProcessId(), SocketFile));
|
|
}
|
|
|
|
ObDereferenceObject (ProcessFile);
|
|
|
|
return status;
|
|
} // DoSocketReadWrite
|
|
|
|
NTSTATUS
|
|
DoSocketAfdIoctl (
|
|
IN PFILE_OBJECT SocketFile,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initiates read and write request processing on socket file.
|
|
|
|
Arguments:
|
|
SocketFile - socket file object
|
|
Irp - afd IOCTL request
|
|
|
|
Return Value:
|
|
|
|
STATUS_PENDING - operation initiated OK
|
|
STATUS_INVALID_HANDLE - socket has not been initialized
|
|
in current process
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
PFILE_OBJECT ProcessFile;
|
|
LPWSABUF bufferArray = NULL;
|
|
ULONG bufferCount = 0, length = 0, flags = 0;
|
|
PVOID address = NULL;
|
|
PULONG lengthPtr = NULL;
|
|
|
|
PAGED_CODE ();
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
Irp->IoStatus.Information = 0;
|
|
SocketCtx = SocketFile->FsContext;
|
|
ProcessFile = GetSocketProcessReference (SocketCtx);
|
|
|
|
if (((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId==PsGetCurrentProcessId()) {
|
|
|
|
try {
|
|
if (Irp->RequestorMode!=KernelMode) {
|
|
ProbeForRead (
|
|
irpSp->Parameters.DeviceIoControl.Type3InputBuffer,
|
|
irpSp->Parameters.DeviceIoControl.InputBufferLength,
|
|
sizeof (ULONG));
|
|
}
|
|
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
case IOCTL_AFD_RECEIVE_DATAGRAM: {
|
|
PAFD_RECV_DATAGRAM_INFO info;
|
|
|
|
if (irpSp->Parameters.DeviceIoControl.InputBufferLength
|
|
< sizeof (*info)) {
|
|
ExRaiseStatus( STATUS_INVALID_PARAMETER );
|
|
}
|
|
info = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
bufferArray = info->BufferArray;
|
|
bufferCount = info->BufferCount;
|
|
address = info->Address;
|
|
lengthPtr = info->AddressLength;
|
|
if ((address == NULL) ^ (lengthPtr == NULL)) {
|
|
ExRaiseStatus( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
if (Irp->RequestorMode!=KernelMode) {
|
|
ProbeForRead (
|
|
lengthPtr,
|
|
sizeof (*lengthPtr),
|
|
sizeof (ULONG));
|
|
}
|
|
|
|
length = *lengthPtr;
|
|
|
|
if (address != NULL ) {
|
|
//
|
|
// Bomb off if the user is trying to do something bad, like
|
|
// specify a zero-length address, or one that's unreasonably
|
|
// huge. Here, we (arbitrarily) define "unreasonably huge" as
|
|
// anything 64K or greater.
|
|
//
|
|
if( length == 0 ||
|
|
length >= 65536 ) {
|
|
|
|
ExRaiseStatus( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
}
|
|
flags = info->TdiFlags;
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_AFDIOCTL,
|
|
("WS2IFSL-%04lx DoSocketAfdIoctl: RecvFrom irp %p, socket %p,"
|
|
" arr %p, cnt %ld, addr %p, lenp %p, len %ld, flags %lx.\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId, Irp, SocketFile,
|
|
bufferArray, bufferCount, address, lengthPtr, length, flags));
|
|
break;
|
|
}
|
|
case IOCTL_AFD_RECEIVE: {
|
|
PAFD_RECV_INFO info;
|
|
if (irpSp->Parameters.DeviceIoControl.InputBufferLength
|
|
< sizeof (*info)) {
|
|
ExRaiseStatus( STATUS_INVALID_PARAMETER );
|
|
}
|
|
info = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
bufferArray = info->BufferArray;
|
|
bufferCount = info->BufferCount;
|
|
flags = info->TdiFlags;
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_AFDIOCTL,
|
|
("WS2IFSL-%04lx DoSocketAfdIoctl: Recv irp %p, socket %p,"
|
|
" arr %p, cnt %ld, flags %lx.\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId, Irp, SocketFile,
|
|
bufferArray, bufferCount, flags));
|
|
break;
|
|
}
|
|
|
|
case IOCTL_AFD_SEND_DATAGRAM: {
|
|
PAFD_SEND_DATAGRAM_INFO info;
|
|
|
|
if (irpSp->Parameters.DeviceIoControl.InputBufferLength
|
|
< sizeof (*info)) {
|
|
ExRaiseStatus( STATUS_INVALID_PARAMETER );
|
|
}
|
|
info = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
bufferArray = info->BufferArray;
|
|
bufferCount = info->BufferCount;
|
|
address = &(((PTRANSPORT_ADDRESS)
|
|
info->TdiConnInfo.RemoteAddress)->Address[0].AddressType);
|
|
length = info->TdiConnInfo.RemoteAddressLength
|
|
- FIELD_OFFSET (TRANSPORT_ADDRESS, Address[0].AddressType);
|
|
|
|
//
|
|
// Bomb off if the user is trying to do something bad, like
|
|
// specify a zero-length address, or one that's unreasonably
|
|
// huge. Here, we (arbitrarily) define "unreasonably huge" as
|
|
// anything 64K or greater.
|
|
//
|
|
|
|
if( length == 0 ||
|
|
length >= 65536 ) {
|
|
ExRaiseStatus( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
if( Irp->RequestorMode != KernelMode ) {
|
|
ProbeForRead (
|
|
address,
|
|
length,
|
|
sizeof (UCHAR));
|
|
}
|
|
|
|
flags = 0;
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_AFDIOCTL,
|
|
("WS2IFSL-%04lx DoSocketAfdIoctl: SendTo irp %p, socket %p,"
|
|
" arr %p, cnt %ld, addr %p, len %ld, flags %lx.\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId, Irp, SocketFile,
|
|
bufferArray, bufferCount, address, length, flags));
|
|
break;
|
|
}
|
|
default:
|
|
ASSERTMSG ("Unknown IOCTL!!!", FALSE);
|
|
ExRaiseStatus( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
AllocateMdlChain (Irp,
|
|
bufferArray,
|
|
bufferCount,
|
|
&irpSp->Parameters.DeviceIoControl.OutputBufferLength);
|
|
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_AFDIOCTL,
|
|
("WS2IFSL-%04lx DoSocketAfdIoctl: %s irp %p, socket %p,"
|
|
" arr %p, cnt %ld, addr %p, lenp %p, len %ld, flags %lx.\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId,
|
|
irpSp->Parameters.DeviceIoControl.IoControlCode==IOCTL_AFD_RECEIVE_DATAGRAM
|
|
? "RecvFrom"
|
|
: (irpSp->Parameters.DeviceIoControl.IoControlCode==IOCTL_AFD_RECEIVE
|
|
? "Recv"
|
|
: "SendTo"
|
|
),
|
|
Irp, SocketFile,
|
|
bufferArray, bufferCount, address, lengthPtr, length, flags));
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
status = GetExceptionCode ();
|
|
WsPrint (DBG_SOCKET|DBG_AFDIOCTL|DBG_FAILURES,
|
|
("WS2IFSL-%04lx DoSocketAfdIoctl: Failed to process Irp %p"
|
|
" on socket %p, status %lx.\n",
|
|
PsGetCurrentProcessId(), Irp, SocketFile, status));;
|
|
goto Exit;
|
|
}
|
|
|
|
// We are going to pend this request
|
|
IoMarkIrpPending (Irp);
|
|
|
|
// Prepare IRP for insertion into the queue
|
|
irpSp->Parameters.DeviceIoControl.IfslAddressBuffer = address;
|
|
irpSp->Parameters.DeviceIoControl.IfslAddressLength = length;
|
|
|
|
Irp->Tail.Overlay.IfslRequestId = UlongToPtr(GenerateUniqueId (SocketCtx->IrpId));
|
|
Irp->Tail.Overlay.IfslAddressLenPtr = lengthPtr;
|
|
Irp->Tail.Overlay.IfslRequestFlags = UlongToPtr(flags);
|
|
Irp->Tail.Overlay.IfslRequestQueue = NULL;
|
|
|
|
if (!QueueRequest (ProcessFile->FsContext, Irp)) {
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_AFDIOCTL,
|
|
("WS2IFSL-%04lx DoAfdIoctl: Cancelling Irp %p on socket %p.\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId,
|
|
Irp, SocketFile));
|
|
CompleteSocketIrp (Irp);
|
|
}
|
|
status = STATUS_PENDING;
|
|
}
|
|
else {
|
|
status = STATUS_INVALID_HANDLE;
|
|
WsPrint (DBG_SOCKET|DBG_AFDIOCTL|DBG_FAILURES,
|
|
("WS2IFSL-%04lx DoSocketAfdIoctl: Socket %p has not"
|
|
" been setup in the process\n",
|
|
PsGetCurrentProcessId(), SocketFile));
|
|
}
|
|
Exit:
|
|
ObDereferenceObject (ProcessFile);
|
|
return status;
|
|
} // DoSocketAfdIoctl
|
|
|
|
VOID
|
|
SetSocketContext (
|
|
IN PFILE_OBJECT SocketFile,
|
|
IN KPROCESSOR_MODE RequestorMode,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets up socket file in context of a current process: associates it with
|
|
process file and assigns context supplied by the caller
|
|
|
|
Arguments:
|
|
SocketFile - Socket file on which to operate
|
|
InputBuffer - input buffer pointer
|
|
InputBufferLength - size of the input buffer
|
|
OutputBuffer - output buffer pointer
|
|
OutputBufferLength - size of output buffer
|
|
IoStatus - IO status information block
|
|
|
|
Return Value:
|
|
None (result returned via IoStatus block)
|
|
--*/
|
|
{
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
HANDLE hProcessFile;
|
|
PFILE_OBJECT ProcessFile;
|
|
PVOID DllContext;
|
|
|
|
PAGED_CODE ();
|
|
|
|
IoStatus->Information = 0;
|
|
|
|
SocketCtx = SocketFile->FsContext;
|
|
|
|
// First check arguments
|
|
if (InputBufferLength<sizeof (WS2IFSL_SOCKET_CTX)) {
|
|
IoStatus->Status = STATUS_INVALID_PARAMETER;
|
|
WsPrint (DBG_SOCKET|DBG_FAILURES,
|
|
("WS2IFSL-%04lx SetSocketContext: Invalid input buffer size (%ld)"
|
|
" for socket file %p.\n",
|
|
PsGetCurrentProcessId(),
|
|
InputBufferLength,
|
|
SocketFile));
|
|
return;
|
|
}
|
|
|
|
try {
|
|
if (RequestorMode!=KernelMode) {
|
|
ProbeForRead (InputBuffer,
|
|
sizeof (WS2IFSL_SOCKET_CTX),
|
|
sizeof (ULONG));
|
|
}
|
|
hProcessFile = ((PWS2IFSL_SOCKET_CTX)InputBuffer)->ProcessFile;
|
|
DllContext = ((PWS2IFSL_SOCKET_CTX)InputBuffer)->DllContext;
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
IoStatus->Status = GetExceptionCode ();
|
|
WsPrint (DBG_SOCKET|DBG_FAILURES,
|
|
("WS2IFSL-%04lx SetSocketContext: Invalid input buffer (%p)"
|
|
" for socket file %p.\n",
|
|
PsGetCurrentProcessId(),
|
|
InputBuffer,
|
|
SocketFile));
|
|
return;
|
|
}
|
|
|
|
// Get reference to the process file with which this context is associated
|
|
IoStatus->Status = ObReferenceObjectByHandle(
|
|
hProcessFile,
|
|
FILE_ALL_ACCESS,
|
|
*IoFileObjectType,
|
|
RequestorMode,
|
|
(PVOID *)&ProcessFile,
|
|
NULL
|
|
);
|
|
if (NT_SUCCESS (IoStatus->Status)) {
|
|
// Verify that the file pointer is really our driver's process file
|
|
// and that it created for the current process
|
|
if ((IoGetRelatedDeviceObject (ProcessFile)
|
|
==DeviceObject)
|
|
&& ((*((PULONG)ProcessFile->FsContext))
|
|
==PROCESS_FILE_EANAME_TAG)
|
|
&& (((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId
|
|
==PsGetCurrentProcessId())) {
|
|
|
|
PFILE_OBJECT oldProcessFile;
|
|
|
|
oldProcessFile = SetSocketProcessReference (
|
|
SocketCtx,
|
|
ProcessFile,
|
|
DllContext);
|
|
|
|
if (oldProcessFile==ProcessFile) {
|
|
// Old socket, just reset DLL context
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_SOCKET,
|
|
("WS2IFSL-%04lx ResetSocketContext:"
|
|
" Socket %p (h:%p->%p)\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId, SocketFile,
|
|
SocketCtx->DllContext, DllContext));
|
|
}
|
|
else {
|
|
LIST_ENTRY irpList;
|
|
// Socket moved to a different process
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_SOCKET,
|
|
("WS2IFSL-%04lx ResetSocketContext:"
|
|
" Socket %p (f:%p->%p(h:%p)\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId, SocketFile,
|
|
oldProcessFile, ProcessFile, DllContext));
|
|
|
|
InitializeListHead (&irpList);
|
|
|
|
// Make sure we do not keep IRPs that are queued to
|
|
// the old object as it may go away as soon as we
|
|
// dereference it below. Note that processed IRPs
|
|
// do not reference process file object in any way.
|
|
CleanupQueuedRequests (oldProcessFile->FsContext, SocketFile, &irpList);
|
|
while (!IsListEmpty (&irpList)) {
|
|
PLIST_ENTRY entry;
|
|
PIRP irp;
|
|
entry = RemoveHeadList (&irpList);
|
|
irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry);
|
|
irp->IoStatus.Status = STATUS_CANCELLED;
|
|
irp->IoStatus.Information = 0;
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_SOCKET,
|
|
("WS2IFSL-%04lx ResetSocketContext: Cancelling Irp %p on socket %p \n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId, irp, SocketFile));
|
|
CompleteSocketIrp (irp);
|
|
}
|
|
|
|
|
|
// Dereference the old object below
|
|
ProcessFile = oldProcessFile;
|
|
|
|
}
|
|
}
|
|
else {
|
|
// Handle refers to random file object
|
|
WsPrint (DBG_SOCKET|DBG_FAILURES,
|
|
("WS2IFSL-%04lx SetSocketContext: Procees file handle %p (File:%p)"
|
|
" is not valid in the process.\n",
|
|
PsGetCurrentProcessId(),
|
|
ProcessFile, hProcessFile));
|
|
IoStatus->Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ObDereferenceObject (ProcessFile);
|
|
}
|
|
else {
|
|
WsPrint (DBG_SOCKET|DBG_FAILURES,
|
|
("WS2IFSL-%04lx SetSocketContext: Could not get process file from handle %p,"
|
|
" status:%lx.\n",
|
|
PsGetCurrentProcessId(),
|
|
hProcessFile,
|
|
IoStatus->Status));
|
|
}
|
|
|
|
} //SetSocketContext
|
|
|
|
|
|
|
|
VOID
|
|
CompletePvdRequest (
|
|
IN PFILE_OBJECT SocketFile,
|
|
IN KPROCESSOR_MODE RequestorMode,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes this IOCTL to allow completion port usage by non-IFS providers
|
|
Arguments:
|
|
SocketFile - Socket file on which to operate
|
|
InputBuffer - input buffer pointer
|
|
contains IoStatus structure to be returned
|
|
as the result of this call
|
|
InputBufferLength - size of the input buffer
|
|
OutputBuffer - NULL
|
|
OutputBufferLength - 0
|
|
IoStatus - IO status information block
|
|
|
|
Return Value:
|
|
None (result returned via IoStatus block)
|
|
--*/
|
|
{
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
PFILE_OBJECT ProcessFile;
|
|
PAGED_CODE();
|
|
|
|
IoStatus->Information = 0;
|
|
// First check arguments
|
|
if (InputBufferLength<sizeof (IO_STATUS_BLOCK)) {
|
|
IoStatus->Status = STATUS_INVALID_PARAMETER;
|
|
WsPrint (DBG_PVD_COMPLETE|DBG_FAILURES,
|
|
("WS2IFSL-%04lx CompletePvdRequest: Invalid input buffer size (%ld)"
|
|
" for socket file %p.\n",
|
|
PsGetCurrentProcessId(),
|
|
InputBufferLength,
|
|
SocketFile));
|
|
return;
|
|
}
|
|
|
|
SocketCtx = SocketFile->FsContext;
|
|
ProcessFile = GetSocketProcessReference (SocketCtx);
|
|
|
|
if (((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId==PsGetCurrentProcessId()) {
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_PVD_COMPLETE,
|
|
("WS2IFSL-%04lx CompletePvdRequest: Socket %p (h:%p,cport:%p)\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId,
|
|
SocketFile, SocketCtx->DllContext,
|
|
SocketFile->CompletionContext));
|
|
|
|
// Carefully write status info
|
|
try {
|
|
if (RequestorMode!=KernelMode)
|
|
ProbeForRead (InputBuffer,
|
|
sizeof (IO_STATUS_BLOCK),
|
|
sizeof (ULONG));
|
|
*IoStatus = *((PIO_STATUS_BLOCK)InputBuffer);
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
IoStatus->Status = GetExceptionCode ();
|
|
WsPrint (DBG_SOCKET|DBG_FAILURES,
|
|
("WS2IFSL-%04lx CompletePvdRequest: Invalid input buffer (%p)"
|
|
" for socket file %p.\n",
|
|
PsGetCurrentProcessId(),
|
|
InputBuffer,
|
|
SocketFile));
|
|
}
|
|
}
|
|
else {
|
|
IoStatus->Status = STATUS_INVALID_HANDLE;
|
|
WsPrint (DBG_SOCKET|DBG_PVD_COMPLETE|DBG_FAILURES,
|
|
("WS2IFSL-%04lx CompletePvdRequest: Socket %p has not"
|
|
" been setup in the process\n",
|
|
PsGetCurrentProcessId(), SocketFile));
|
|
}
|
|
|
|
ObDereferenceObject (ProcessFile);
|
|
|
|
} //CompletePvdRequest
|
|
|
|
VOID
|
|
CompleteDrvRequest (
|
|
IN PFILE_OBJECT SocketFile,
|
|
IN PWS2IFSL_CMPL_PARAMS Params,
|
|
IN PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Complete request that was prviously passed to user mode DLL
|
|
Arguments:
|
|
SocketFile - Socket file on which to operate
|
|
Params - description of the parameters
|
|
OutputBuffer - Request results (data and address)
|
|
OutputBufferLength - sizeof result buffer
|
|
IoStatus - IO status information block
|
|
Status: STATUS_SUCCESS - request was completed OK
|
|
STATUS_CANCELLED - request was already cancelled
|
|
|
|
Return Value:
|
|
None (result returned via IoStatus block)
|
|
--*/
|
|
{
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
PIRP irp = NULL;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
PAGED_CODE();
|
|
|
|
SocketCtx = SocketFile->FsContext;
|
|
|
|
|
|
// Check and copy parameters
|
|
try {
|
|
|
|
//
|
|
// Try to find matching IRP in the processed list.
|
|
//
|
|
irp = GetProcessedRequest (SocketCtx, Params->UniqueId);
|
|
if (irp!=NULL) {
|
|
NTSTATUS status = Params->Status , status2 = 0;
|
|
ULONG bytesCopied;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (irp);
|
|
|
|
//
|
|
// Copy data based on the function we performed
|
|
//
|
|
|
|
switch (irpSp->MajorFunction) {
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
case IOCTL_AFD_RECEIVE_DATAGRAM:
|
|
//
|
|
// Copy address buffer and length
|
|
//
|
|
if (irpSp->Parameters.DeviceIoControl.IfslAddressBuffer!=NULL) {
|
|
ULONG addrOffset = ADDR_ALIGN(irpSp->Parameters.DeviceIoControl.OutputBufferLength);
|
|
if (addrOffset+Params->AddrLen > OutputBufferLength) {
|
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|
}
|
|
if (Params->AddrLen
|
|
<=irpSp->Parameters.DeviceIoControl.IfslAddressLength) {
|
|
RtlCopyMemory (
|
|
irpSp->Parameters.DeviceIoControl.IfslAddressBuffer,
|
|
(PUCHAR)OutputBuffer+addrOffset,
|
|
Params->AddrLen);
|
|
}
|
|
else {
|
|
RtlCopyMemory (
|
|
irpSp->Parameters.DeviceIoControl.IfslAddressBuffer,
|
|
(PUCHAR)OutputBuffer+addrOffset,
|
|
irpSp->Parameters.DeviceIoControl.IfslAddressLength);
|
|
status2 = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
if (NT_SUCCESS (status2) && irp->UserBuffer) {
|
|
*((PULONG)(irp->Tail.Overlay.IfslAddressLenPtr)) = Params->AddrLen;
|
|
}
|
|
|
|
//
|
|
// Drop through to copy data as well
|
|
//
|
|
|
|
case IOCTL_AFD_RECEIVE:
|
|
break;
|
|
case IOCTL_AFD_SEND_DATAGRAM:
|
|
goto NoCopy;
|
|
break;
|
|
default:
|
|
ASSERTMSG ("Unsupported IOCTL!!!", FALSE);
|
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Drop through to copy data as well
|
|
//
|
|
|
|
case IRP_MJ_READ:
|
|
if (irp->MdlAddress!=NULL) {
|
|
bytesCopied = CopyBufferToMdlChain (
|
|
OutputBuffer,
|
|
Params->DataLen,
|
|
irp->MdlAddress);
|
|
}
|
|
else
|
|
bytesCopied = 0;
|
|
|
|
if ((bytesCopied<Params->DataLen)
|
|
&& NT_SUCCESS (status))
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
break;
|
|
case IRP_MJ_WRITE:
|
|
bytesCopied = Params->DataLen;
|
|
// goto NoCopy; // same as break;
|
|
break;
|
|
case IRP_MJ_PNP:
|
|
if (OutputBufferLength>=sizeof (HANDLE)) {
|
|
PDEVICE_OBJECT targetDevice;
|
|
PIRP targetIrp;
|
|
PIO_STACK_LOCATION targetSp;
|
|
|
|
status = ObReferenceObjectByHandle (
|
|
*((PHANDLE)OutputBuffer),
|
|
MAXIMUM_ALLOWED,
|
|
*IoFileObjectType,
|
|
irp->RequestorMode,
|
|
(PVOID *)&irpSp->FileObject,
|
|
NULL
|
|
);
|
|
if (NT_SUCCESS (status)) {
|
|
targetDevice = IoGetRelatedDeviceObject (irpSp->FileObject);
|
|
targetIrp = IoBuildAsynchronousFsdRequest (
|
|
IRP_MJ_PNP,
|
|
targetDevice,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (targetIrp!=NULL) {
|
|
targetSp = IoGetNextIrpStackLocation (targetIrp);
|
|
*targetSp = *irpSp;
|
|
targetSp->FileObject = irpSp->FileObject;
|
|
IoSetCompletionRoutine( targetIrp, CompleteTargetQuery, irp, TRUE, TRUE, TRUE );
|
|
IoCallDriver (targetDevice, targetIrp);
|
|
goto NoCompletion;
|
|
}
|
|
else {
|
|
ObDereferenceObject (irpSp->FileObject);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
break;
|
|
default:
|
|
ASSERTMSG ("Unsupported MJ code!!!", FALSE);
|
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|
break;
|
|
}
|
|
|
|
NoCopy:
|
|
irp->IoStatus.Information = bytesCopied;
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
irp->IoStatus.Status = status2;
|
|
}
|
|
else {
|
|
irp->IoStatus.Status = status;
|
|
}
|
|
|
|
WsProcessPrint (
|
|
(PIFSL_PROCESS_CTX)SocketCtx->ProcessRef->FsContext,
|
|
DBG_DRV_COMPLETE,
|
|
("WS2IFSL-%04lx CompleteDrvRequest: Irp %p, status %lx, info %ld,"
|
|
" on socket %p (h:%p).\n",
|
|
GET_SOCKET_PROCESSID(SocketCtx),
|
|
irp, irp->IoStatus.Status,
|
|
irp->IoStatus.Information,
|
|
SocketFile, SocketCtx->DllContext));
|
|
CompleteSocketIrp (irp);
|
|
NoCompletion:
|
|
IoStatus->Status = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
IoStatus->Status = STATUS_CANCELLED;
|
|
WsProcessPrint (
|
|
(PIFSL_PROCESS_CTX)SocketCtx->ProcessRef->FsContext,
|
|
DBG_DRV_COMPLETE|DBG_FAILURES,
|
|
("WS2IFSL-%04lx CompleteDrvRequest:"
|
|
" Request id %ld is not in the list"
|
|
" for socket %p.\n",
|
|
GET_SOCKET_PROCESSID(SocketCtx),
|
|
Params->UniqueId,
|
|
SocketFile));
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
IoStatus->Status = GetExceptionCode ();
|
|
WsProcessPrint (
|
|
(PIFSL_PROCESS_CTX)SocketCtx->ProcessRef->FsContext,
|
|
DBG_DRV_COMPLETE|DBG_FAILURES,
|
|
("WS2IFSL-%04lx CompleteDrvRequest: Failed to process"
|
|
" Irp %p (id %ld) for socket %p, status %lx.\n",
|
|
GET_SOCKET_PROCESSID(SocketCtx),
|
|
irp, Params->UniqueId,
|
|
SocketFile, IoStatus->Status));
|
|
if (irp!=NULL) {
|
|
//
|
|
// Cleanup and complete the irp
|
|
//
|
|
irp->IoStatus.Status = IoStatus->Status;
|
|
irp->IoStatus.Information = 0;
|
|
if (irpSp->MajorFunction==IRP_MJ_DEVICE_CONTROL) {
|
|
irp->UserBuffer = NULL;
|
|
}
|
|
CompleteSocketIrp (irp);
|
|
}
|
|
}
|
|
} //CompleteDrvRequest
|
|
|
|
NTSTATUS
|
|
CompleteTargetQuery (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PIRP irp = Context;
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
|
|
|
|
//
|
|
// If pending has be returned for this irp then mark the current
|
|
// stack as pending.
|
|
//
|
|
|
|
if ( Irp->PendingReturned ) {
|
|
IoMarkIrpPending(Irp);
|
|
}
|
|
|
|
ObDereferenceObject (irpSp->FileObject);
|
|
//
|
|
// Copy the status info returned by target device
|
|
//
|
|
irp->IoStatus = Irp->IoStatus;
|
|
|
|
//
|
|
// Free the target irp;
|
|
//
|
|
IoFreeIrp (Irp);
|
|
|
|
//
|
|
// Complete the original IRP.
|
|
//
|
|
CompleteSocketIrp (irp);
|
|
|
|
//
|
|
// Make sure IO subsystem does not touch the IRP we freed
|
|
//
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SocketPnPTargetQuery (
|
|
IN PFILE_OBJECT SocketFile,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Passes target device relation query to the underlying
|
|
socket if any.
|
|
|
|
Arguments:
|
|
SocketFile - socket file object
|
|
Irp - query target device relation request
|
|
|
|
Return Value:
|
|
|
|
STATUS_PENDING - operation initiated OK
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
PFILE_OBJECT ProcessFile;
|
|
|
|
PAGED_CODE ();
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
Irp->IoStatus.Information = 0;
|
|
SocketCtx = SocketFile->FsContext;
|
|
ProcessFile = GetSocketProcessReference (SocketCtx);
|
|
|
|
|
|
// We are going to pend this request
|
|
IoMarkIrpPending (Irp);
|
|
|
|
// Prepare IRP for insertion into the queue
|
|
irpSp->Parameters.DeviceIoControl.IfslAddressBuffer = NULL;
|
|
irpSp->Parameters.DeviceIoControl.IfslAddressLength = 0;
|
|
|
|
Irp->Tail.Overlay.IfslRequestId = UlongToPtr(GenerateUniqueId (SocketCtx->IrpId));
|
|
Irp->Tail.Overlay.IfslAddressLenPtr = NULL;
|
|
Irp->Tail.Overlay.IfslRequestFlags = (PVOID)0;
|
|
Irp->Tail.Overlay.IfslRequestQueue = NULL;
|
|
|
|
if (!QueueRequest (ProcessFile->FsContext, Irp)) {
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)ProcessFile->FsContext, DBG_AFDIOCTL,
|
|
("WS2IFSL-%04lx DoAfdIoctl: Cancelling Irp %p on socket %p.\n",
|
|
((PIFSL_PROCESS_CTX)ProcessFile->FsContext)->UniqueId,
|
|
Irp, SocketFile));
|
|
CompleteSocketIrp (Irp);
|
|
}
|
|
status = STATUS_PENDING;
|
|
|
|
ObDereferenceObject (ProcessFile);
|
|
return status;
|
|
}
|
|
|
|
BOOLEAN
|
|
InsertProcessedRequest (
|
|
PIFSL_SOCKET_CTX SocketCtx,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inserts request that was processed to be passed to user mode
|
|
DLL into socket list. Checks if request is cancelled
|
|
Arguments:
|
|
SocketCtx - contex of the socket into which insert the request
|
|
Irp - request to insert
|
|
Return Value:
|
|
TRUE - request was inserted
|
|
FALSE - request is being cancelled
|
|
--*/
|
|
{
|
|
KIRQL oldIRQL;
|
|
IoSetCancelRoutine (Irp, ProcessedCancelRoutine);
|
|
KeAcquireSpinLock (&SocketCtx->SpinLock, &oldIRQL);
|
|
if (!Irp->Cancel) {
|
|
InsertTailList (&SocketCtx->ProcessedIrps,
|
|
&Irp->Tail.Overlay.ListEntry);
|
|
Irp->Tail.Overlay.IfslRequestQueue = &SocketCtx->ProcessedIrps;
|
|
KeReleaseSpinLock (&SocketCtx->SpinLock, oldIRQL);
|
|
return TRUE;
|
|
}
|
|
else {
|
|
KeReleaseSpinLock (&SocketCtx->SpinLock, oldIRQL);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ProcessedCancelRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Driver cancel routine for socket request waiting in the list
|
|
(being processed by the user mode DLL).
|
|
Arguments:
|
|
DeviceObject - WS2IFSL device object
|
|
Irp - Irp to be cancelled
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpSp;
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
SocketCtx = irpSp->FileObject->FsContext;
|
|
WsProcessPrint ((PIFSL_PROCESS_CTX)SocketCtx->ProcessRef->FsContext,
|
|
DBG_SOCKET,
|
|
("WS2IFSL-%04lx ProcessedCancel: Socket %p, Irp %p\n",
|
|
GET_SOCKET_PROCESSID(SocketCtx),
|
|
irpSp->FileObject, Irp));
|
|
KeAcquireSpinLockAtDpcLevel (&SocketCtx->SpinLock);
|
|
if (Irp->Tail.Overlay.IfslRequestQueue!=NULL) {
|
|
ASSERT (Irp->Tail.Overlay.IfslRequestQueue==&SocketCtx->ProcessedIrps);
|
|
RemoveEntryList (&Irp->Tail.Overlay.ListEntry);
|
|
Irp->Tail.Overlay.IfslRequestQueue = NULL;
|
|
KeReleaseSpinLockFromDpcLevel (&SocketCtx->SpinLock);
|
|
IoReleaseCancelSpinLock (Irp->CancelIrql);
|
|
|
|
CancelSocketIo (irpSp->FileObject);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
CompleteSocketIrp (Irp);
|
|
}
|
|
else {
|
|
KeReleaseSpinLockFromDpcLevel (&SocketCtx->SpinLock);
|
|
IoReleaseCancelSpinLock (Irp->CancelIrql);
|
|
//
|
|
// Don't touch IRP after this as we do not own it anymore
|
|
//
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CleanupProcessedRequests (
|
|
IN PIFSL_SOCKET_CTX SocketCtx,
|
|
OUT PLIST_ENTRY IrpList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleans up all requests on the socket which are being
|
|
processed by the user mode DLL
|
|
|
|
Arguments:
|
|
SocketCtx - context of the socket
|
|
IrpList - list to insert cleaned up request (to be completed
|
|
by the caller)
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
PLIST_ENTRY entry;
|
|
KIRQL oldIRQL;
|
|
|
|
KeAcquireSpinLock (&SocketCtx->SpinLock, &oldIRQL);
|
|
while (!IsListEmpty(&SocketCtx->ProcessedIrps)) {
|
|
entry = RemoveHeadList (&SocketCtx->ProcessedIrps);
|
|
irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry);
|
|
ASSERT (irp->Tail.Overlay.IfslRequestQueue==&SocketCtx->ProcessedIrps);
|
|
irp->Tail.Overlay.IfslRequestQueue = NULL;
|
|
InsertTailList (IrpList, &irp->Tail.Overlay.ListEntry);
|
|
}
|
|
KeReleaseSpinLock (&SocketCtx->SpinLock, oldIRQL);
|
|
}
|
|
|
|
VOID
|
|
CompleteSocketIrp (
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes IRP and properly synchronizes with cancel routine
|
|
if necessary (it has already been called).
|
|
Arguments:
|
|
Irp - irp to complete
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Reset cancel routine (it wont complete the IRP as it
|
|
// won't be able to find it)
|
|
//
|
|
|
|
if (IoSetCancelRoutine (Irp, NULL)==NULL) {
|
|
KIRQL oldIRQL;
|
|
//
|
|
// Cancel routine has been called.
|
|
// Synchronize with cancel routine (it won't touch the
|
|
// IRP after it releases cancel spinlock)
|
|
|
|
IoAcquireCancelSpinLock (&oldIRQL);
|
|
IoReleaseCancelSpinLock (oldIRQL);
|
|
}
|
|
|
|
if (Irp->MdlAddress!=NULL) {
|
|
ASSERT ((Irp->MdlAddress->MdlFlags & MDL_PAGES_LOCKED) == 0);
|
|
IoFreeMdl (Irp->MdlAddress);
|
|
Irp->MdlAddress = NULL;
|
|
}
|
|
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
PIRP
|
|
GetProcessedRequest (
|
|
PIFSL_SOCKET_CTX SocketCtx,
|
|
ULONG UniqueId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds and returns matching IRP from the processed IRP list
|
|
|
|
Arguments:
|
|
SocketCtx - socket context to search for the IRP in
|
|
UniqueId - id assigned to the request to distinguish identify
|
|
it case it was cancelled and IRP was reused
|
|
Return Value:
|
|
IRP
|
|
NULL - irp was not found
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
PLIST_ENTRY entry;
|
|
KIRQL oldIRQL;
|
|
|
|
//
|
|
// We do not usually have many request sumulteneously pending
|
|
// on a socket, so the linear search should suffice.
|
|
//
|
|
|
|
KeAcquireSpinLock (&SocketCtx->SpinLock, &oldIRQL);
|
|
entry = SocketCtx->ProcessedIrps.Flink;
|
|
while (entry!=&SocketCtx->ProcessedIrps) {
|
|
irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry);
|
|
entry = entry->Flink;
|
|
if (irp->Tail.Overlay.IfslRequestId==UlongToPtr(UniqueId)) {
|
|
ASSERT (irp->Tail.Overlay.IfslRequestQueue==&SocketCtx->ProcessedIrps);
|
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|
irp->Tail.Overlay.IfslRequestQueue = NULL;
|
|
KeReleaseSpinLock (&SocketCtx->SpinLock, oldIRQL);
|
|
return irp;
|
|
}
|
|
}
|
|
KeReleaseSpinLock (&SocketCtx->SpinLock, oldIRQL);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
CancelSocketIo (
|
|
PFILE_OBJECT SocketFile
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Queue a request to user mode DLL to cancel all io on the socket
|
|
|
|
Arguments:
|
|
SocketCtx - socket context on which IO is to be cancelled
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
PIFSL_SOCKET_CTX SocketCtx = SocketFile->FsContext;
|
|
PIFSL_PROCESS_CTX ProcessCtx = SocketCtx->ProcessRef->FsContext;
|
|
PIFSL_CANCEL_CTX cancelCtx;
|
|
|
|
try {
|
|
cancelCtx = (PIFSL_CANCEL_CTX) ExAllocatePoolWithQuotaTag (
|
|
NonPagedPool,
|
|
sizeof (IFSL_CANCEL_CTX),
|
|
CANCEL_CTX_TAG);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
cancelCtx = NULL;
|
|
}
|
|
|
|
|
|
if (cancelCtx!=NULL) {
|
|
//
|
|
// Make sure socket does not go away while this request exists
|
|
//
|
|
ObReferenceObject (SocketFile);
|
|
cancelCtx->SocketFile = SocketFile;
|
|
cancelCtx->UniqueId = GenerateUniqueId (ProcessCtx->CancelId);
|
|
|
|
//
|
|
// We do not want to queue another cancel request if we have
|
|
// one pending or being executed
|
|
//
|
|
if (InterlockedCompareExchangePointer ((PVOID *)&SocketCtx->CancelCtx,
|
|
cancelCtx,
|
|
NULL)==NULL) {
|
|
WsProcessPrint (
|
|
ProcessCtx,
|
|
DBG_CANCEL,
|
|
("WS2IFSL-%04lx CancelSocketIo: Context %p, socket %p\n",
|
|
ProcessCtx->UniqueId,
|
|
cancelCtx, SocketFile));
|
|
QueueCancel (ProcessCtx, cancelCtx);
|
|
return;
|
|
}
|
|
|
|
WsProcessPrint (
|
|
ProcessCtx,
|
|
DBG_CANCEL,
|
|
("WS2IFSL-%04lx CancelSocketIo: Another cancel active"
|
|
" context %p, socket %p\n",
|
|
ProcessCtx->UniqueId,
|
|
SocketCtx->CancelCtx, SocketFile));
|
|
ObDereferenceObject (SocketFile);
|
|
ExFreePool (cancelCtx);
|
|
}
|
|
else {
|
|
WsPrint (DBG_SOCKET|DBG_CANCEL|DBG_FAILURES,
|
|
("WS2IFSL-%04lx CancelSocketIo: Could not allocate cancel"
|
|
" context for socket %p\n",
|
|
PsGetCurrentProcessId(),
|
|
SocketFile));
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FreeSocketCancel (
|
|
PIFSL_CANCEL_CTX CancelCtx
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees resources associated with cancel request
|
|
|
|
Arguments:
|
|
CancelCtx - cancel request context
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
PFILE_OBJECT SocketFile = CancelCtx->SocketFile;
|
|
PIFSL_SOCKET_CTX SocketCtx = SocketFile->FsContext;
|
|
|
|
ASSERT (IoGetRelatedDeviceObject (SocketFile)==DeviceObject);
|
|
ASSERT (SocketCtx->EANameTag==SOCKET_FILE_EANAME_TAG);
|
|
ASSERT (CancelCtx->ListEntry.Flink==NULL);
|
|
|
|
//
|
|
// We are going to dereference the file object whether
|
|
// free the structure or not
|
|
//
|
|
CancelCtx->SocketFile = NULL;
|
|
ObDereferenceObject (SocketFile);
|
|
|
|
//
|
|
// During socket closure, the cleanup routine may be in
|
|
// process of freeing this cancel context and will set
|
|
// the pointer to it to NULL to indicate the fact
|
|
//
|
|
if (InterlockedCompareExchangePointer ((PVOID *)&SocketCtx->CancelCtx,
|
|
NULL,
|
|
CancelCtx)) {
|
|
WsProcessPrint (
|
|
(PIFSL_PROCESS_CTX)SocketCtx->ProcessRef->FsContext,
|
|
DBG_CANCEL,
|
|
("WS2IFSL-%04lx FreeSocketCancel: Freeing cancel"
|
|
" context %p, socket %p\n",
|
|
GET_SOCKET_PROCESSID(SocketCtx),
|
|
CancelCtx, SocketFile));
|
|
ExFreePool (CancelCtx);
|
|
}
|
|
else {
|
|
//
|
|
// The close routine will take care of freeing the request
|
|
//
|
|
WsProcessPrint (
|
|
(PIFSL_PROCESS_CTX)SocketCtx->ProcessRef->FsContext,
|
|
DBG_CANCEL,
|
|
("WS2IFSL-%04lx FreeSocketCancel: Cleanup owns cancel"
|
|
" context %p, socket %p\n",
|
|
GET_SOCKET_PROCESSID(SocketCtx),
|
|
CancelCtx, SocketFile));
|
|
}
|
|
}
|
|
|
|
|
|
PFILE_OBJECT
|
|
GetSocketProcessReference (
|
|
IN PIFSL_SOCKET_CTX SocketCtx
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads and references process file currently associated with
|
|
the socket under the lock to protect in case socket is moved
|
|
to a different process
|
|
|
|
Arguments:
|
|
SocketCtx - socket context to read process file from
|
|
|
|
Return Value:
|
|
Referenced pointer to process file object currently associated
|
|
with the socket.
|
|
|
|
--*/
|
|
{
|
|
KIRQL oldIRQL;
|
|
PFILE_OBJECT ProcessFile;
|
|
|
|
KeAcquireSpinLock (&SocketCtx->SpinLock, &oldIRQL);
|
|
ObReferenceObject (SocketCtx->ProcessRef);
|
|
ProcessFile = SocketCtx->ProcessRef;
|
|
KeReleaseSpinLock (&SocketCtx->SpinLock, oldIRQL);
|
|
|
|
return ProcessFile;
|
|
}
|
|
|
|
|
|
PFILE_OBJECT
|
|
SetSocketProcessReference (
|
|
IN PIFSL_SOCKET_CTX SocketCtx,
|
|
IN PFILE_OBJECT NewProcessFile,
|
|
IN PVOID NewDllContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets new process context for the socket object under the protection
|
|
of a lock.
|
|
|
|
Arguments:
|
|
SocketCtx - socket context to set
|
|
NewProcessFile - process file reference
|
|
NewDllContext - context to be associated with the socket
|
|
in the process
|
|
|
|
Return Value:
|
|
Previous process file reference
|
|
--*/
|
|
{
|
|
KIRQL oldIRQL;
|
|
PFILE_OBJECT ProcessFile;
|
|
|
|
KeAcquireSpinLock (&SocketCtx->SpinLock, &oldIRQL);
|
|
ProcessFile = SocketCtx->ProcessRef;
|
|
SocketCtx->ProcessRef = NewProcessFile;
|
|
SocketCtx->DllContext = NewDllContext;
|
|
KeReleaseSpinLock (&SocketCtx->SpinLock, oldIRQL);
|
|
return ProcessFile;
|
|
}
|