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