mirror of
https://github.com/reactos/reactos.git
synced 2024-08-21 10:53:15 +00:00
330 lines
10 KiB
C
330 lines
10 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel Streaming
|
|
* FILE: drivers/ksfilter/ks/methods.c
|
|
* PURPOSE: KS Allocator functions
|
|
* PROGRAMMER: Johannes Anderwald
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
NTSTATUS
|
|
FindMethodHandler(
|
|
IN PIO_STATUS_BLOCK IoStatus,
|
|
IN const KSMETHOD_SET* MethodSet,
|
|
IN ULONG MethodSetCount,
|
|
IN PKSMETHOD Method,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
OUT PFNKSHANDLER *MethodHandler,
|
|
OUT PKSMETHOD_SET * Set)
|
|
{
|
|
ULONG Index, ItemIndex;
|
|
|
|
for(Index = 0; Index < MethodSetCount; Index++)
|
|
{
|
|
ASSERT(MethodSet[Index].Set);
|
|
|
|
if (IsEqualGUIDAligned(&Method->Set, MethodSet[Index].Set))
|
|
{
|
|
for(ItemIndex = 0; ItemIndex < MethodSet[Index].MethodsCount; ItemIndex++)
|
|
{
|
|
if (MethodSet[Index].MethodItem[ItemIndex].MethodId == Method->Id)
|
|
{
|
|
if (MethodSet[Index].MethodItem[ItemIndex].MinMethod > InputBufferLength)
|
|
{
|
|
/* too small input buffer */
|
|
IoStatus->Information = MethodSet[Index].MethodItem[ItemIndex].MinMethod;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (MethodSet[Index].MethodItem[ItemIndex].MinData > OutputBufferLength)
|
|
{
|
|
/* too small output buffer */
|
|
IoStatus->Information = MethodSet[Index].MethodItem[ItemIndex].MinData;
|
|
return STATUS_MORE_ENTRIES;
|
|
}
|
|
if (Method->Flags & KSMETHOD_TYPE_BASICSUPPORT)
|
|
{
|
|
PULONG Flags;
|
|
PKSPROPERTY_DESCRIPTION Description;
|
|
|
|
if (sizeof(ULONG) > OutputBufferLength)
|
|
{
|
|
/* too small buffer */
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* get output buffer */
|
|
Flags = (PULONG)OutputBuffer;
|
|
|
|
/* set flags flags */
|
|
*Flags = MethodSet[Index].MethodItem[ItemIndex].Flags;
|
|
|
|
IoStatus->Information = sizeof(ULONG);
|
|
|
|
if (OutputBufferLength >= sizeof(KSPROPERTY_DESCRIPTION))
|
|
{
|
|
/* get output buffer */
|
|
Description = (PKSPROPERTY_DESCRIPTION)OutputBuffer;
|
|
|
|
/* store result */
|
|
Description->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
|
|
Description->PropTypeSet.Set = KSPROPTYPESETID_General;
|
|
Description->PropTypeSet.Id = 0;
|
|
Description->PropTypeSet.Flags = 0;
|
|
Description->MembersListCount = 0;
|
|
Description->Reserved = 0;
|
|
|
|
IoStatus->Information = sizeof(KSPROPERTY_DESCRIPTION);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
*MethodHandler = MethodSet[Index].MethodItem[ItemIndex].MethodHandler;
|
|
*Set = (PKSMETHOD_SET)&MethodSet[Index];
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KspMethodHandlerWithAllocator(
|
|
IN PIRP Irp,
|
|
IN ULONG MethodSetsCount,
|
|
IN const KSMETHOD_SET *MethodSet,
|
|
IN PFNKSALLOCATOR Allocator OPTIONAL,
|
|
IN ULONG MethodItemSize OPTIONAL)
|
|
{
|
|
PKSMETHOD Method;
|
|
PKSMETHOD_SET Set;
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
PFNKSHANDLER MethodHandler = NULL;
|
|
ULONG Index;
|
|
LPGUID Guid;
|
|
|
|
/* get current irp stack */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* check if inputbuffer at least holds KSMETHOD item */
|
|
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSMETHOD))
|
|
{
|
|
/* invalid parameter */
|
|
Irp->IoStatus.Information = sizeof(KSPROPERTY);
|
|
return STATUS_INVALID_BUFFER_SIZE;
|
|
}
|
|
|
|
/* FIXME probe the input / output buffer if from user mode */
|
|
|
|
/* get input property request */
|
|
Method = (PKSMETHOD)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
// DPRINT("KspMethodHandlerWithAllocator Irp %p PropertySetsCount %u PropertySet %p Allocator %p PropertyItemSize %u ExpectedPropertyItemSize %u\n", Irp, PropertySetsCount, PropertySet, Allocator, PropertyItemSize, sizeof(KSPROPERTY_ITEM));
|
|
|
|
/* sanity check */
|
|
ASSERT(MethodItemSize == 0 || MethodItemSize == sizeof(KSMETHOD_ITEM));
|
|
|
|
/* find the method handler */
|
|
Status = FindMethodHandler(&Irp->IoStatus, MethodSet, MethodSetsCount, Method, IoStack->Parameters.DeviceIoControl.InputBufferLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength, Irp->UserBuffer, &MethodHandler, &Set);
|
|
|
|
if (NT_SUCCESS(Status) && MethodHandler)
|
|
{
|
|
/* call method handler */
|
|
KSMETHOD_SET_IRP_STORAGE(Irp) = Set;
|
|
Status = MethodHandler(Irp, Method, Irp->UserBuffer);
|
|
|
|
if (Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
/* output buffer is too small */
|
|
if (Allocator)
|
|
{
|
|
/* allocate the requested amount */
|
|
Status = Allocator(Irp, (ULONG)Irp->IoStatus.Information, FALSE);
|
|
|
|
/* check if the block was allocated */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* no memory */
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* re-call method handler */
|
|
Status = MethodHandler(Irp, Method, Irp->UserBuffer);
|
|
}
|
|
}
|
|
}
|
|
else if (IsEqualGUIDAligned(&Method->Set, &GUID_NULL) && Method->Id == 0 && Method->Flags == KSMETHOD_TYPE_SETSUPPORT)
|
|
{
|
|
// store output size
|
|
Irp->IoStatus.Information = sizeof(GUID) * MethodSetsCount;
|
|
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GUID) * MethodSetsCount)
|
|
{
|
|
// buffer too small
|
|
return STATUS_MORE_ENTRIES;
|
|
}
|
|
|
|
// get output buffer
|
|
Guid = (LPGUID)Irp->UserBuffer;
|
|
|
|
// copy property guids from property sets
|
|
for(Index = 0; Index < MethodSetsCount; Index++)
|
|
{
|
|
RtlMoveMemory(&Guid[Index], MethodSet[Index].Set, sizeof(GUID));
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* done */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsMethodHandler(
|
|
_In_ PIRP Irp,
|
|
_In_ ULONG MethodSetsCount,
|
|
_In_reads_(MethodSetsCount) const KSMETHOD_SET* MethodSet)
|
|
{
|
|
return KspMethodHandlerWithAllocator(Irp, MethodSetsCount, MethodSet, NULL, 0);
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsMethodHandlerWithAllocator(
|
|
_In_ PIRP Irp,
|
|
_In_ ULONG MethodSetsCount,
|
|
_In_reads_(MethodSetsCount) const KSMETHOD_SET* MethodSet,
|
|
_In_opt_ PFNKSALLOCATOR Allocator,
|
|
_In_opt_ ULONG MethodItemSize)
|
|
{
|
|
return KspMethodHandlerWithAllocator(Irp, MethodSetsCount, MethodSet, Allocator, MethodItemSize);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
FindFastMethodHandler(
|
|
IN ULONG FastIoCount,
|
|
IN const KSFASTMETHOD_ITEM * FastIoTable,
|
|
IN PKSMETHOD MethodId,
|
|
OUT PFNKSFASTHANDLER * FastPropertyHandler)
|
|
{
|
|
ULONG Index;
|
|
|
|
/* iterate through all items */
|
|
for(Index = 0; Index < FastIoCount; Index++)
|
|
{
|
|
if (MethodId->Id == FastIoTable[Index].MethodId)
|
|
{
|
|
if (FastIoTable[Index].MethodSupported)
|
|
{
|
|
*FastPropertyHandler = FastIoTable[Index].MethodHandler;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
}
|
|
/* no fast property handler found */
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
BOOLEAN
|
|
NTAPI
|
|
KsFastMethodHandler(
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PKSMETHOD UNALIGNED Method,
|
|
IN ULONG MethodLength,
|
|
IN OUT PVOID UNALIGNED Data,
|
|
IN ULONG DataLength,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN ULONG MethodSetsCount,
|
|
IN const KSMETHOD_SET* MethodSet)
|
|
{
|
|
KSMETHOD MethodRequest;
|
|
KPROCESSOR_MODE Mode;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG Index;
|
|
PFNKSFASTHANDLER FastMethodHandler;
|
|
|
|
if (MethodLength < sizeof(KSPROPERTY))
|
|
{
|
|
/* invalid request */
|
|
return FALSE;
|
|
}
|
|
|
|
/* get previous mode */
|
|
Mode = ExGetPreviousMode();
|
|
|
|
if (Mode == KernelMode)
|
|
{
|
|
/* just copy it */
|
|
RtlMoveMemory(&MethodRequest, Method, sizeof(KSMETHOD));
|
|
}
|
|
else
|
|
{
|
|
/* need to probe the buffer */
|
|
_SEH2_TRY
|
|
{
|
|
ProbeForRead(Method, sizeof(KSPROPERTY), sizeof(UCHAR));
|
|
RtlMoveMemory(&MethodRequest, Method, sizeof(KSMETHOD));
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Exception, get the error code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}_SEH2_END;
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
return FALSE;
|
|
}
|
|
|
|
/* are there any property sets provided */
|
|
if (MethodSetsCount)
|
|
{
|
|
/* iterate through all property sets count */
|
|
Index = 0;
|
|
do
|
|
{
|
|
/* does the property id match */
|
|
if (IsEqualGUIDAligned(MethodSet[Index].Set, &MethodRequest.Set))
|
|
{
|
|
/* try to find a fast property handler */
|
|
Status = FindFastMethodHandler(MethodSet[Index].FastIoCount, MethodSet[Index].FastIoTable, &MethodRequest, &FastMethodHandler);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* call fast property handler */
|
|
ASSERT(MethodLength == sizeof(KSMETHOD)); /* FIXME check if property length is bigger -> copy params */
|
|
ASSERT(Mode == KernelMode); /* FIXME need to probe usermode output buffer */
|
|
return FastMethodHandler(FileObject, &MethodRequest, sizeof(KSMETHOD), Data, DataLength, IoStatus);
|
|
}
|
|
}
|
|
/* move to next item */
|
|
Index++;
|
|
}while(Index < MethodSetsCount);
|
|
}
|
|
return FALSE;
|
|
}
|