Sync with trunk rev.61910 to get latest improvements and bugfixes.
[reactos.git] / drivers / ksfilter / ks / methods.c
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
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
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, 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 */
192 KSDDKAPI
193 NTSTATUS
194 NTAPI
195 KsMethodHandler(
196 IN PIRP Irp,
197 IN ULONG MethodSetsCount,
198 IN PKSMETHOD_SET MethodSet)
199 {
200 return KspMethodHandlerWithAllocator(Irp, MethodSetsCount, MethodSet, NULL, 0);
201 }
202
203 /*
204 @implemented
205 */
206 KSDDKAPI
207 NTSTATUS
208 NTAPI
209 KsMethodHandlerWithAllocator(
210 IN PIRP Irp,
211 IN ULONG MethodSetsCount,
212 IN PKSMETHOD_SET MethodSet,
213 IN PFNKSALLOCATOR Allocator OPTIONAL,
214 IN ULONG MethodItemSize OPTIONAL)
215 {
216 return KspMethodHandlerWithAllocator(Irp, MethodSetsCount, MethodSet, Allocator, MethodItemSize);
217 }
218
219
220 NTSTATUS
221 FindFastMethodHandler(
222 IN ULONG FastIoCount,
223 IN const KSFASTMETHOD_ITEM * FastIoTable,
224 IN PKSMETHOD MethodId,
225 OUT PFNKSFASTHANDLER * FastPropertyHandler)
226 {
227 ULONG Index;
228
229 /* iterate through all items */
230 for(Index = 0; Index < FastIoCount; Index++)
231 {
232 if (MethodId->Id == FastIoTable[Index].MethodId)
233 {
234 if (FastIoTable[Index].MethodSupported)
235 {
236 *FastPropertyHandler = FastIoTable[Index].MethodHandler;
237 return STATUS_SUCCESS;
238 }
239 }
240
241 }
242 /* no fast property handler found */
243 return STATUS_NOT_FOUND;
244 }
245
246
247 /*
248 @implemented
249 */
250 KSDDKAPI
251 BOOLEAN
252 NTAPI
253 KsFastMethodHandler(
254 IN PFILE_OBJECT FileObject,
255 IN PKSMETHOD UNALIGNED Method,
256 IN ULONG MethodLength,
257 IN OUT PVOID UNALIGNED Data,
258 IN ULONG DataLength,
259 OUT PIO_STATUS_BLOCK IoStatus,
260 IN ULONG MethodSetsCount,
261 IN const KSMETHOD_SET* MethodSet)
262 {
263 KSMETHOD MethodRequest;
264 KPROCESSOR_MODE Mode;
265 NTSTATUS Status = STATUS_SUCCESS;
266 ULONG Index;
267 PFNKSFASTHANDLER FastMethodHandler;
268
269 if (MethodLength < sizeof(KSPROPERTY))
270 {
271 /* invalid request */
272 return FALSE;
273 }
274
275 /* get previous mode */
276 Mode = ExGetPreviousMode();
277
278 if (Mode == KernelMode)
279 {
280 /* just copy it */
281 RtlMoveMemory(&MethodRequest, Method, sizeof(KSMETHOD));
282 }
283 else
284 {
285 /* need to probe the buffer */
286 _SEH2_TRY
287 {
288 ProbeForRead(Method, sizeof(KSPROPERTY), sizeof(UCHAR));
289 RtlMoveMemory(&MethodRequest, Method, sizeof(KSMETHOD));
290 }
291 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
292 {
293 /* Exception, get the error code */
294 Status = _SEH2_GetExceptionCode();
295 }_SEH2_END;
296
297 if (!NT_SUCCESS(Status))
298 return FALSE;
299 }
300
301 /* are there any property sets provided */
302 if (MethodSetsCount)
303 {
304 /* iterate through all property sets count */
305 Index = 0;
306 do
307 {
308 /* does the property id match */
309 if (IsEqualGUIDAligned(MethodSet[Index].Set, &MethodRequest.Set))
310 {
311 /* try to find a fast property handler */
312 Status = FindFastMethodHandler(MethodSet[Index].FastIoCount, MethodSet[Index].FastIoTable, &MethodRequest, &FastMethodHandler);
313
314 if (NT_SUCCESS(Status))
315 {
316 /* call fast property handler */
317 ASSERT(MethodLength == sizeof(KSMETHOD)); /* FIXME check if property length is bigger -> copy params */
318 ASSERT(Mode == KernelMode); /* FIXME need to probe usermode output buffer */
319 return FastMethodHandler(FileObject, &MethodRequest, sizeof(KSMETHOD), Data, DataLength, IoStatus);
320 }
321 }
322 /* move to next item */
323 Index++;
324 }while(Index < MethodSetsCount);
325 }
326 return FALSE;
327 }