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.
386 lines
12 KiB
386 lines
12 KiB
// @doc
|
|
/**********************************************************************
|
|
*
|
|
* @module FLTR.c |
|
|
*
|
|
* Implementation of basic IRP handlers for Filter Device Objects
|
|
*
|
|
* History
|
|
* ----------------------------------------------------------
|
|
* Mitchell S. Dernis Original
|
|
*
|
|
* (c) 1986-1998 Microsoft Corporation. All right reserved.
|
|
*
|
|
* @topic FLTR |
|
|
* The non-Power and PnP IRP handler routines are handled in this module
|
|
* for all Device Objects created as filters for the raw HID-Pdos.
|
|
*
|
|
**********************************************************************/
|
|
#define __DEBUG_MODULE_IN_USE__ GCK_FLTR_C
|
|
|
|
#include <wdm.h>
|
|
#include "Debug.h"
|
|
#include "GckShell.h"
|
|
|
|
DECLARE_MODULE_DEBUG_LEVEL((DBG_WARN|DBG_ERROR|DBG_CRITICAL));
|
|
|
|
//
|
|
// Mark the pageable routines as such
|
|
//
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text (INIT, GCK_FLTR_DriverEntry)
|
|
#pragma alloc_text (PAGE, GCK_FLTR_Create)
|
|
#pragma alloc_text (PAGE, GCK_FLTR_Close)
|
|
#pragma alloc_text (PAGE, GCK_FLTR_Ioctl)
|
|
#pragma alloc_text (PAGE, GCK_FLTR_Unload)
|
|
#endif
|
|
/***********************************************************************************
|
|
**
|
|
** NTSTATUS GCK_FLTR_DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath )
|
|
**
|
|
** @func Initializing the portions of the driver related to the filter devices.
|
|
**
|
|
** @rdesc STATUS_SUCCESS
|
|
**
|
|
*************************************************************************************/
|
|
NTSTATUS GCK_FLTR_DriverEntry
|
|
(
|
|
IN PDRIVER_OBJECT pDriverObject, // @parm Driver Object
|
|
IN PUNICODE_STRING puniRegistryPath // @parm Path to driver specific registry section.
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(pDriverObject);
|
|
UNREFERENCED_PARAMETER(puniRegistryPath);
|
|
//
|
|
// Initialize Globals related to filter devices
|
|
//
|
|
GCK_DBG_TRACE_PRINT(("Initializing globals\n"));
|
|
Globals.ulFilteredDeviceCount = 0;
|
|
Globals.pFilterObjectList = NULL;
|
|
Globals.pSWVB_FilterExt=NULL; // Nobody owns the virtual bus yet.
|
|
Globals.pVirtualKeyboardPdo = NULL; // No keyboard object
|
|
Globals.ulVirtualKeyboardRefCount = 0; // No keyboard users
|
|
ExInitializeFastMutex(&Globals.FilterObjectListFMutex);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** NTSTATUS GCK_FLTR_Create ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp )
|
|
**
|
|
** @func Handles the IRP_MJ_CREATE for filter devices
|
|
** - Called generated by Win32 API CreateFile or OpenFile
|
|
**
|
|
** @rdesc STATUS_SUCCESS, or various error codes
|
|
**
|
|
*************************************************************************************/
|
|
NTSTATUS GCK_FLTR_Create (
|
|
IN PDEVICE_OBJECT pDeviceObject, // @parm DO target for IRP
|
|
IN PIRP pIrp // @parm IRP
|
|
)
|
|
{
|
|
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PGCK_FILTER_EXT pFilterExt;
|
|
PDEVICE_OBJECT pCurDeviceObject;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
KEVENT SyncEvent;
|
|
USHORT usShareAccess;
|
|
|
|
PAGED_CODE ();
|
|
|
|
GCK_DBG_ENTRY_PRINT (("Entering GCK_FLTR\n"));
|
|
|
|
//cast device extension to proper type
|
|
pFilterExt = (PGCK_FILTER_EXT) pDeviceObject->DeviceExtension;
|
|
|
|
// Just an extra sanity check
|
|
ASSERT( GCK_DO_TYPE_FILTER == pFilterExt->ulGckDevObjType);
|
|
|
|
//
|
|
// Increment IRP count, ASAP, note we couldn't do this until now, as we
|
|
// knew not whether the device extension was really a GCK_FILTER_EXT
|
|
//
|
|
GCK_IncRemoveLock(&pFilterExt->RemoveLock);
|
|
|
|
// Make sure we are not in the process of going away
|
|
if(
|
|
GCK_STATE_STARTED != pFilterExt->eDeviceState &&
|
|
GCK_STATE_STOP_PENDING != pFilterExt->eDeviceState
|
|
)
|
|
{
|
|
GCK_DBG_WARN_PRINT(("Create while remove pending\n"));
|
|
NtStatus = STATUS_DELETE_PENDING;
|
|
pIrp->IoStatus.Information = 0;
|
|
pIrp->IoStatus.Status = NtStatus;
|
|
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
|
|
}
|
|
else // process this
|
|
{
|
|
GCK_DBG_TRACE_PRINT(("GCK_Create calling lower driver\n"));
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
//
|
|
//We lie to hidclass about the desired share access,
|
|
//because it doesn't know not to count us.
|
|
//Notice below that we restore this before passing to our
|
|
//internal poll routines, so that we can track it there.
|
|
//
|
|
usShareAccess=pIrpStack->Parameters.Create.ShareAccess;
|
|
pIrpStack->Parameters.Create.ShareAccess = FILE_READ_DATA|FILE_WRITE_DATA;
|
|
|
|
//This is our internal poll trying to create a file object, just call down
|
|
if( pFilterExt->InternalPoll.InternalCreateThread == KeGetCurrentThread())
|
|
{
|
|
IoSkipCurrentIrpStackLocation(pIrp);
|
|
NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp);
|
|
}
|
|
//This is a request from above, capture on the way up
|
|
else
|
|
{
|
|
GCK_IP_AddFileObject(
|
|
pFilterExt,
|
|
pIrpStack->FileObject,
|
|
pIrpStack->Parameters.Create.ShareAccess,
|
|
pIrpStack->Parameters.Create.SecurityContext->DesiredAccess
|
|
);
|
|
|
|
GCKF_KickDeviceForData(pFilterExt);
|
|
|
|
// Call create synchronously
|
|
KeInitializeEvent(&SyncEvent, SynchronizationEvent, FALSE);
|
|
IoCopyCurrentIrpStackLocationToNext(pIrp);
|
|
IoSetCompletionRoutine(
|
|
pIrp,
|
|
GCK_FLTR_CreateComplete,
|
|
(PVOID)&SyncEvent,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
IoCallDriver (pFilterExt->pTopOfStack, pIrp);
|
|
KeWaitForSingleObject(&SyncEvent, Executive, KernelMode, FALSE, NULL);
|
|
NtStatus = pIrp->IoStatus.Status;
|
|
// If create succeeded, we need to remember the FileObject
|
|
GCK_IP_ConfirmFileObject(pFilterExt, pIrpStack->FileObject, (BOOLEAN)(NT_SUCCESS(pIrp->IoStatus.Status) ? TRUE : FALSE) );
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT); // This was misssing!!!
|
|
}
|
|
}
|
|
|
|
//
|
|
// We are done with this IRP, so decrement the outstanding count
|
|
// and signal remove if this was the last outstanding IRP
|
|
//
|
|
GCK_DecRemoveLock(&pFilterExt->RemoveLock);
|
|
|
|
GCK_DBG_EXIT_PRINT(("Exiting GCK_Create(2). Status: 0x%0.8x\n", NtStatus));
|
|
return NtStatus;
|
|
}
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** NTSTATUS GCK_FLTR_CreateComplete(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID pContext)
|
|
**
|
|
** @mfunc Completion Routine for IRP_MJ_CREATE
|
|
**
|
|
** @rdesc STATUS_SUCCESS
|
|
**
|
|
*************************************************************************************/
|
|
NTSTATUS
|
|
GCK_FLTR_CreateComplete
|
|
(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp,
|
|
IN PVOID pContext
|
|
)
|
|
{
|
|
PKEVENT pSyncEvent;
|
|
UNREFERENCED_PARAMETER(pDeviceObject);
|
|
UNREFERENCED_PARAMETER(pIrp);
|
|
|
|
// Cast context to device extension
|
|
pSyncEvent = (PKEVENT) pContext;
|
|
KeSetEvent(pSyncEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
//Done with this IRP, never need to see it again
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** NTSTATUS GCK_FLTR_Close ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp )
|
|
**
|
|
** @func Handles IRP_MJ_CLOSE for filter device objects - Call generated by Win32 API CloseFile
|
|
**
|
|
** @rdesc STATUS_SUCCESS or various errors
|
|
**
|
|
*************************************************************************************/
|
|
NTSTATUS GCK_FLTR_Close (
|
|
IN PDEVICE_OBJECT pDeviceObject, // @parm DO target for IRP
|
|
IN PIRP pIrp // @parm IRP
|
|
)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PGCK_FILTER_EXT pFilterExt;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
|
|
PAGED_CODE ();
|
|
|
|
GCK_DBG_ENTRY_PRINT (("GCK_Close, pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp));
|
|
|
|
//cast device extension to proper type
|
|
pFilterExt = (PGCK_FILTER_EXT) pDeviceObject->DeviceExtension;
|
|
|
|
// Just an extra sanity check
|
|
ASSERT( GCK_DO_TYPE_FILTER == pFilterExt->ulGckDevObjType);
|
|
|
|
//
|
|
// Increment IRP count, ASAP, note we couldn't do this until now, as we
|
|
// knew not whether the device extension was really a GCK_FILTER_EXT
|
|
//
|
|
GCK_IncRemoveLock(&pFilterExt->RemoveLock);
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
//cleanup pending IO and our tracking of the FileObject -
|
|
//however not applicable if it is our internal polling open, that is being close
|
|
if(pIrpStack->FileObject != pFilterExt->InternalPoll.pInternalFileObject)
|
|
{
|
|
//Complete pending I\O on FileObject
|
|
if(
|
|
GCK_STATE_STARTED == pFilterExt->eDeviceState ||
|
|
GCK_STATE_STOP_PENDING == pFilterExt->eDeviceState
|
|
)
|
|
{
|
|
//There is no pending I\O if the device is not started yet
|
|
GCKF_CompleteReadRequestsForFileObject(pFilterExt, pIrpStack->FileObject);
|
|
}
|
|
//forget file object
|
|
GCK_IP_RemoveFileObject(pFilterExt, pIrpStack->FileObject);
|
|
}
|
|
//send the Irp along
|
|
IoSkipCurrentIrpStackLocation (pIrp);
|
|
NtStatus = IoCallDriver(pFilterExt->pTopOfStack, pIrp);
|
|
|
|
|
|
// Decrement outstanding IO and signal if went to zero
|
|
GCK_DecRemoveLock(&pFilterExt->RemoveLock);
|
|
|
|
GCK_DBG_EXIT_PRINT(("Exiting GCK_Close(2). Status: 0x%0.8x\n", NtStatus));
|
|
return NtStatus;
|
|
}
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** NTSTATUS GCK_FLTR_Read (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
|
|
**
|
|
** @func Handles IRP_MJ_READ for filter device objects - Generated by Win32 ReadFile
|
|
**
|
|
** @rdesc STATUS_SUCCESS, or various errors
|
|
**
|
|
*************************************************************************************/
|
|
NTSTATUS GCK_FLTR_Read
|
|
(
|
|
IN PDEVICE_OBJECT pDeviceObject, // @parm Target of IRP
|
|
IN PIRP pIrp // @parm IRP to handle
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
LARGE_INTEGER lgiWaitTime;
|
|
PGCK_FILTER_EXT pFilterExt;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
PIO_STACK_LOCATION pPrivateIrpStack;
|
|
PVOID pvIrpBuffer;
|
|
PFILE_OBJECT pIrpsFileObject;
|
|
static int iEnterCount=0;
|
|
unsigned int i=0;
|
|
|
|
GCK_DBG_RT_ENTRY_PRINT(("Entering GCK_Read. pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp));
|
|
|
|
//cast device extension to proper type
|
|
pFilterExt = (PGCK_FILTER_EXT) pDeviceObject->DeviceExtension;
|
|
|
|
// Just an extra sanity check
|
|
ASSERT( GCK_DO_TYPE_FILTER == pFilterExt->ulGckDevObjType);
|
|
|
|
// Increment IRP count while we handle this one
|
|
GCK_IncRemoveLock(&pFilterExt->RemoveLock);
|
|
|
|
// If we have been removed, we shouldn't be getting read IRPs
|
|
if(
|
|
GCK_STATE_STARTED != pFilterExt->eDeviceState &&
|
|
GCK_STATE_STOP_PENDING != pFilterExt->eDeviceState
|
|
)
|
|
{
|
|
GCK_DBG_WARN_PRINT(( "GCK_Read called with delete pending\n"));
|
|
NtStatus = STATUS_DELETE_PENDING;
|
|
pIrp->IoStatus.Information = 0;
|
|
pIrp->IoStatus.Status = NtStatus;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
|
|
// Decrement outstanding IRP count, and signal if it want to zero
|
|
GCK_DecRemoveLock(&pFilterExt->RemoveLock);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Send Reqeust to filter, the filterhooks module is responsible
|
|
// for all the necessary Asynchronous IRP handling steps, we just
|
|
// return status pending.
|
|
//
|
|
NtStatus = GCKF_IncomingReadRequests(pFilterExt, pIrp);
|
|
|
|
// Poll the lower driver, if one is not yet pending.
|
|
GCK_IP_OneTimePoll(pFilterExt);
|
|
}
|
|
|
|
GCK_DBG_RT_EXIT_PRINT(("Exiting GCK_Read(2). Status: 0x%0.8x\n", NtStatus));
|
|
return NtStatus;
|
|
}
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** NTSTATUS GCK_FLTR_Ioctl (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
|
|
**
|
|
** @mfunc Handles all IOCTLs for the filter devices - this is just a straight pass through
|
|
**
|
|
** @rdesc STATUS_SUCCESS, various errors
|
|
**
|
|
*************************************************************************************/
|
|
NTSTATUS GCK_FLTR_Ioctl
|
|
(
|
|
IN PDEVICE_OBJECT pDeviceObject, // @parm pointer to Device Object
|
|
IN PIRP pIrp // @parm pointer to IRP
|
|
)
|
|
{
|
|
PGCK_FILTER_EXT pFilterExt;
|
|
NTSTATUS NtStatus;
|
|
|
|
PAGED_CODE ();
|
|
GCK_DBG_ENTRY_PRINT(("Entering GCK_FLTR_Ioctl, pDeviceObject = 0x%0.8x, pIRP = 0x%0.8x\n", pDeviceObject, pIrp));
|
|
//cast device extension to proper type
|
|
pFilterExt = (PGCK_FILTER_EXT) pDeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// If we have been removed we need to refuse this IRP
|
|
//
|
|
if (GCK_STATE_REMOVED == pFilterExt->eDeviceState) {
|
|
GCK_DBG_TRACE_PRINT(("GCK_FLTR_Ioctl called while delete pending\n"));
|
|
ASSERT(FALSE);
|
|
NtStatus = STATUS_DELETE_PENDING;
|
|
pIrp->IoStatus.Information = 0;
|
|
pIrp->IoStatus.Status = NtStatus;
|
|
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
|
|
}
|
|
else
|
|
{
|
|
// Send the IRP on unchanged.
|
|
IoSkipCurrentIrpStackLocation (pIrp);
|
|
NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp);
|
|
}
|
|
|
|
GCK_DBG_EXIT_PRINT(("Exiting GCK_FLTR_Ioctl, Status: 0x%0.8x\n", NtStatus));
|
|
return NtStatus;
|
|
}
|
|
|