xref: /reactos/drivers/ksfilter/ks/methods.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/ksfilter/ks/methods.c
5  * PURPOSE:         KS Allocator functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 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)15 FindMethodHandler(
16     IN PIO_STATUS_BLOCK IoStatus,
17     IN  const KSMETHOD_SET* MethodSet,
18     IN ULONG MethodSetCount,
19     IN PKSMETHOD Method,
20     IN ULONG InputBufferLength,
21     IN ULONG OutputBufferLength,
22     OUT PVOID OutputBuffer,
23     OUT PFNKSHANDLER *MethodHandler,
24     OUT PKSMETHOD_SET * Set)
25 {
26     ULONG Index, ItemIndex;
27 
28     for(Index = 0; Index < MethodSetCount; Index++)
29     {
30         ASSERT(MethodSet[Index].Set);
31 
32         if (IsEqualGUIDAligned(&Method->Set, MethodSet[Index].Set))
33         {
34             for(ItemIndex = 0; ItemIndex < MethodSet[Index].MethodsCount; ItemIndex++)
35             {
36                 if (MethodSet[Index].MethodItem[ItemIndex].MethodId == Method->Id)
37                 {
38                     if (MethodSet[Index].MethodItem[ItemIndex].MinMethod > InputBufferLength)
39                     {
40                         /* too small input buffer */
41                         IoStatus->Information = MethodSet[Index].MethodItem[ItemIndex].MinMethod;
42                         return STATUS_INVALID_PARAMETER;
43                     }
44 
45                     if (MethodSet[Index].MethodItem[ItemIndex].MinData > OutputBufferLength)
46                     {
47                         /* too small output buffer */
48                         IoStatus->Information = MethodSet[Index].MethodItem[ItemIndex].MinData;
49                         return STATUS_MORE_ENTRIES;
50                     }
51                     if (Method->Flags & KSMETHOD_TYPE_BASICSUPPORT)
52                     {
53                         PULONG Flags;
54                         PKSPROPERTY_DESCRIPTION Description;
55 
56                         if (sizeof(ULONG) > OutputBufferLength)
57                         {
58                             /* too small buffer */
59                             return STATUS_INVALID_PARAMETER;
60                         }
61 
62                         /* get output buffer */
63                         Flags = (PULONG)OutputBuffer;
64 
65                         /* set flags flags */
66                         *Flags = MethodSet[Index].MethodItem[ItemIndex].Flags;
67 
68                         IoStatus->Information = sizeof(ULONG);
69 
70                         if (OutputBufferLength >= sizeof(KSPROPERTY_DESCRIPTION))
71                         {
72                             /* get output buffer */
73                             Description = (PKSPROPERTY_DESCRIPTION)OutputBuffer;
74 
75                             /* store result */
76                             Description->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
77                             Description->PropTypeSet.Set = KSPROPTYPESETID_General;
78                             Description->PropTypeSet.Id = 0;
79                             Description->PropTypeSet.Flags = 0;
80                             Description->MembersListCount = 0;
81                             Description->Reserved = 0;
82 
83                             IoStatus->Information = sizeof(KSPROPERTY_DESCRIPTION);
84                         }
85                         return STATUS_SUCCESS;
86                     }
87                     *MethodHandler = MethodSet[Index].MethodItem[ItemIndex].MethodHandler;
88                     *Set = (PKSMETHOD_SET)&MethodSet[Index];
89                     return STATUS_SUCCESS;
90                 }
91             }
92         }
93     }
94     return STATUS_NOT_FOUND;
95 }
96 
97 NTSTATUS
98 NTAPI
KspMethodHandlerWithAllocator(IN PIRP Irp,IN ULONG MethodSetsCount,IN const KSMETHOD_SET * MethodSet,IN PFNKSALLOCATOR Allocator OPTIONAL,IN ULONG MethodItemSize OPTIONAL)99 KspMethodHandlerWithAllocator(
100     IN  PIRP Irp,
101     IN  ULONG MethodSetsCount,
102     IN  const KSMETHOD_SET *MethodSet,
103     IN  PFNKSALLOCATOR Allocator OPTIONAL,
104     IN  ULONG MethodItemSize OPTIONAL)
105 {
106     PKSMETHOD Method;
107     PKSMETHOD_SET Set;
108     PIO_STACK_LOCATION IoStack;
109     NTSTATUS Status;
110     PFNKSHANDLER MethodHandler = NULL;
111     ULONG Index;
112     LPGUID Guid;
113 
114     /* get current irp stack */
115     IoStack = IoGetCurrentIrpStackLocation(Irp);
116 
117     /* check if inputbuffer at least holds KSMETHOD item */
118     if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSMETHOD))
119     {
120         /* invalid parameter */
121         Irp->IoStatus.Information = sizeof(KSPROPERTY);
122         return STATUS_INVALID_BUFFER_SIZE;
123     }
124 
125     /* FIXME probe the input / output buffer if from user mode */
126 
127     /* get input property request */
128     Method = (PKSMETHOD)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
129 
130 //    DPRINT("KspMethodHandlerWithAllocator Irp %p PropertySetsCount %u PropertySet %p Allocator %p PropertyItemSize %u ExpectedPropertyItemSize %u\n", Irp, PropertySetsCount, PropertySet, Allocator, PropertyItemSize, sizeof(KSPROPERTY_ITEM));
131 
132     /* sanity check */
133     ASSERT(MethodItemSize == 0 || MethodItemSize == sizeof(KSMETHOD_ITEM));
134 
135     /* find the method handler */
136     Status = FindMethodHandler(&Irp->IoStatus, MethodSet, MethodSetsCount, Method, IoStack->Parameters.DeviceIoControl.InputBufferLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength, Irp->UserBuffer, &MethodHandler, &Set);
137 
138     if (NT_SUCCESS(Status) && MethodHandler)
139     {
140         /* call method handler */
141         KSMETHOD_SET_IRP_STORAGE(Irp) = Set;
142         Status = MethodHandler(Irp, Method, Irp->UserBuffer);
143 
144         if (Status == STATUS_BUFFER_TOO_SMALL)
145         {
146             /* output buffer is too small */
147             if (Allocator)
148             {
149                 /* allocate the requested amount */
150                 Status = Allocator(Irp, (ULONG)Irp->IoStatus.Information, FALSE);
151 
152                 /* check if the block was allocated */
153                 if (!NT_SUCCESS(Status))
154                 {
155                     /* no memory */
156                     return STATUS_INSUFFICIENT_RESOURCES;
157                 }
158 
159                 /* re-call method handler */
160                 Status = MethodHandler(Irp, Method, Irp->UserBuffer);
161             }
162         }
163     }
164     else if (IsEqualGUIDAligned(&Method->Set, &GUID_NULL) && Method->Id == 0 && Method->Flags == KSMETHOD_TYPE_SETSUPPORT)
165     {
166         // store output size
167         Irp->IoStatus.Information = sizeof(GUID) * MethodSetsCount;
168         if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GUID) * MethodSetsCount)
169         {
170             // buffer too small
171             return STATUS_MORE_ENTRIES;
172         }
173 
174         // get output buffer
175         Guid = (LPGUID)Irp->UserBuffer;
176 
177        // copy property guids from property sets
178        for(Index = 0; Index < MethodSetsCount; Index++)
179        {
180            RtlMoveMemory(&Guid[Index], MethodSet[Index].Set, sizeof(GUID));
181        }
182        return STATUS_SUCCESS;
183     }
184 
185     /* done */
186     return Status;
187 }
188 
189 /*
190     @implemented
191 */
_IRQL_requires_max_(PASSIVE_LEVEL)192 _IRQL_requires_max_(PASSIVE_LEVEL)
193 KSDDKAPI
194 NTSTATUS
195 NTAPI
196 KsMethodHandler(
197     _In_ PIRP Irp,
198     _In_ ULONG MethodSetsCount,
199     _In_reads_(MethodSetsCount) const KSMETHOD_SET* MethodSet)
200 {
201     return KspMethodHandlerWithAllocator(Irp, MethodSetsCount, MethodSet, NULL, 0);
202 }
203 
204 /*
205     @implemented
206 */
_IRQL_requires_max_(PASSIVE_LEVEL)207 _IRQL_requires_max_(PASSIVE_LEVEL)
208 KSDDKAPI
209 NTSTATUS
210 NTAPI
211 KsMethodHandlerWithAllocator(
212     _In_ PIRP Irp,
213     _In_ ULONG MethodSetsCount,
214     _In_reads_(MethodSetsCount) const KSMETHOD_SET* MethodSet,
215     _In_opt_ PFNKSALLOCATOR Allocator,
216     _In_opt_ ULONG MethodItemSize)
217 {
218     return KspMethodHandlerWithAllocator(Irp, MethodSetsCount, MethodSet, Allocator, MethodItemSize);
219 }
220 
221 
222 NTSTATUS
FindFastMethodHandler(IN ULONG FastIoCount,IN const KSFASTMETHOD_ITEM * FastIoTable,IN PKSMETHOD MethodId,OUT PFNKSFASTHANDLER * FastPropertyHandler)223 FindFastMethodHandler(
224     IN ULONG FastIoCount,
225     IN const KSFASTMETHOD_ITEM * FastIoTable,
226     IN PKSMETHOD MethodId,
227     OUT PFNKSFASTHANDLER * FastPropertyHandler)
228 {
229     ULONG Index;
230 
231     /* iterate through all items */
232     for(Index = 0; Index < FastIoCount; Index++)
233     {
234         if (MethodId->Id == FastIoTable[Index].MethodId)
235         {
236             if (FastIoTable[Index].MethodSupported)
237             {
238                 *FastPropertyHandler = FastIoTable[Index].MethodHandler;
239                 return STATUS_SUCCESS;
240             }
241         }
242 
243     }
244     /* no fast property handler found */
245     return STATUS_NOT_FOUND;
246 }
247 
248 
249 /*
250     @implemented
251 */
252 KSDDKAPI
253 BOOLEAN
254 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)255 KsFastMethodHandler(
256     IN  PFILE_OBJECT FileObject,
257     IN  PKSMETHOD UNALIGNED Method,
258     IN  ULONG MethodLength,
259     IN  OUT PVOID UNALIGNED Data,
260     IN  ULONG DataLength,
261     OUT PIO_STATUS_BLOCK IoStatus,
262     IN  ULONG MethodSetsCount,
263     IN  const KSMETHOD_SET* MethodSet)
264 {
265     KSMETHOD MethodRequest;
266     KPROCESSOR_MODE Mode;
267     NTSTATUS Status = STATUS_SUCCESS;
268     ULONG Index;
269     PFNKSFASTHANDLER FastMethodHandler;
270 
271     if (MethodLength < sizeof(KSPROPERTY))
272     {
273         /* invalid request */
274         return FALSE;
275     }
276 
277     /* get previous mode */
278     Mode = ExGetPreviousMode();
279 
280     if (Mode == KernelMode)
281     {
282         /* just copy it */
283         RtlMoveMemory(&MethodRequest, Method, sizeof(KSMETHOD));
284     }
285     else
286     {
287         /* need to probe the buffer */
288         _SEH2_TRY
289         {
290             ProbeForRead(Method, sizeof(KSPROPERTY), sizeof(UCHAR));
291             RtlMoveMemory(&MethodRequest, Method, sizeof(KSMETHOD));
292         }
293         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
294         {
295             /* Exception, get the error code */
296             Status = _SEH2_GetExceptionCode();
297         }_SEH2_END;
298 
299         if (!NT_SUCCESS(Status))
300             return FALSE;
301     }
302 
303     /* are there any property sets provided */
304     if (MethodSetsCount)
305     {
306         /* iterate through all property sets count */
307         Index = 0;
308         do
309         {
310             /* does the property id match */
311             if (IsEqualGUIDAligned(MethodSet[Index].Set, &MethodRequest.Set))
312             {
313                 /* try to find a fast property handler */
314                 Status = FindFastMethodHandler(MethodSet[Index].FastIoCount, MethodSet[Index].FastIoTable, &MethodRequest, &FastMethodHandler);
315 
316                 if (NT_SUCCESS(Status))
317                 {
318                     /* call fast property handler */
319                     ASSERT(MethodLength == sizeof(KSMETHOD)); /* FIXME check if property length is bigger -> copy params */
320                     ASSERT(Mode == KernelMode); /* FIXME need to probe usermode output buffer */
321                     return FastMethodHandler(FileObject, &MethodRequest, sizeof(KSMETHOD), Data, DataLength, IoStatus);
322                 }
323             }
324             /* move to next item */
325             Index++;
326         }while(Index < MethodSetsCount);
327     }
328     return FALSE;
329 }
330