029043574a19ff8d8d0055e5eea50ee850b6cf39
[reactos.git] / reactos / drivers / ksfilter / ks / property.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/ksfilter/ks/event.c
5 * PURPOSE: KS property handling functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "precomp.h"
10
11 /* SEH support with PSEH */
12 #include <pseh/pseh2.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 const GUID KSPROPTYPESETID_General = {0x97E99BA0L, 0xBDEA, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
18
19 NTSTATUS
20 FindPropertyHandler(
21 IN PIO_STATUS_BLOCK IoStatus,
22 IN const KSPROPERTY_SET* PropertySet,
23 IN ULONG PropertySetCount,
24 IN PKSPROPERTY Property,
25 IN ULONG InputBufferLength,
26 IN ULONG OutputBufferLength,
27 OUT PVOID OutputBuffer,
28 OUT PFNKSHANDLER *PropertyHandler,
29 OUT PKSPROPERTY_SET * Set,
30 OUT PKSPROPERTY_ITEM *PropertyItem)
31 {
32 ULONG Index, ItemIndex;
33
34 for(Index = 0; Index < PropertySetCount; Index++)
35 {
36 ASSERT(PropertySet[Index].Set);
37
38 if (IsEqualGUIDAligned(&Property->Set, PropertySet[Index].Set))
39 {
40 for(ItemIndex = 0; ItemIndex < PropertySet[Index].PropertiesCount; ItemIndex++)
41 {
42 if (PropertySet[Index].PropertyItem[ItemIndex].PropertyId == Property->Id)
43 {
44 if (PropertySet[Index].PropertyItem[ItemIndex].MinProperty > InputBufferLength)
45 {
46 /* too small input buffer */
47 IoStatus->Information = PropertySet[Index].PropertyItem[ItemIndex].MinProperty;
48 return STATUS_INVALID_PARAMETER;
49 }
50
51 if (PropertySet[Index].PropertyItem[ItemIndex].MinData > OutputBufferLength)
52 {
53 /* too small output buffer */
54 IoStatus->Information = PropertySet[Index].PropertyItem[ItemIndex].MinData;
55 return STATUS_MORE_ENTRIES;
56 }
57
58 /* store property set */
59 *Set = (PKSPROPERTY_SET)&PropertySet[Index];
60 *PropertyItem = (PKSPROPERTY_ITEM)&PropertySet[Index].PropertyItem[ItemIndex];
61
62 if (Property->Flags & KSPROPERTY_TYPE_SET)
63 {
64 /* store property handler */
65 *PropertyHandler = PropertySet[Index].PropertyItem[ItemIndex].SetPropertyHandler;
66 return STATUS_SUCCESS;
67 }
68
69 if (Property->Flags & KSPROPERTY_TYPE_GET)
70 {
71 /* store property handler */
72 *PropertyHandler = PropertySet[Index].PropertyItem[ItemIndex].GetPropertyHandler;
73 return STATUS_SUCCESS;
74 }
75
76
77 if (Property->Flags & KSPROPERTY_TYPE_BASICSUPPORT)
78 {
79 PULONG Flags;
80 PKSPROPERTY_DESCRIPTION Description;
81
82 if (sizeof(ULONG) > OutputBufferLength)
83 {
84 /* too small buffer */
85 return STATUS_INVALID_PARAMETER;
86 }
87
88 /* get output buffer */
89 Flags = (PULONG)OutputBuffer;
90
91 /* clear flags */
92 *Flags = 0;
93
94 IoStatus->Information = sizeof(ULONG);
95
96 if (PropertySet[Index].PropertyItem[ItemIndex].SupportHandler)
97 {
98 /* use support handler from driver */
99 *PropertyHandler = PropertySet[Index].PropertyItem[ItemIndex].SupportHandler;
100 return STATUS_SUCCESS;
101 }
102
103 if (PropertySet[Index].PropertyItem[ItemIndex].GetSupported)
104 *Flags |= KSPROPERTY_TYPE_GET;
105
106 if (PropertySet[Index].PropertyItem[ItemIndex].SetSupported)
107 *Flags |= KSPROPERTY_TYPE_SET;
108
109 if (OutputBufferLength >= sizeof(KSPROPERTY_DESCRIPTION))
110 {
111 /* get output buffer */
112 Description = (PKSPROPERTY_DESCRIPTION)OutputBuffer;
113
114 /* store result */
115 Description->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
116 Description->PropTypeSet.Set = KSPROPTYPESETID_General;
117 Description->PropTypeSet.Id = 0;
118 Description->PropTypeSet.Flags = 0;
119 Description->MembersListCount = 0;
120 Description->Reserved = 0;
121
122 IoStatus->Information = sizeof(KSPROPERTY_DESCRIPTION);
123 }
124 return STATUS_SUCCESS;
125 }
126 }
127 }
128 }
129 }
130 return STATUS_NOT_FOUND;
131 }
132
133
134 NTSTATUS
135 KspPropertyHandler(
136 IN PIRP Irp,
137 IN ULONG PropertySetsCount,
138 IN const KSPROPERTY_SET* PropertySet,
139 IN PFNKSALLOCATOR Allocator OPTIONAL,
140 IN ULONG PropertyItemSize OPTIONAL)
141 {
142 PKSPROPERTY Property;
143 PKSPROPERTY_ITEM PropertyItem;
144 PKSPROPERTY_SET Set;
145 PIO_STACK_LOCATION IoStack;
146 NTSTATUS Status;
147 PFNKSHANDLER PropertyHandler = NULL;
148 ULONG Index, InputBufferLength, OutputBufferLength, TotalSize;
149 LPGUID Guid;
150 //UNICODE_STRING GuidBuffer;
151
152 /* get current irp stack */
153 IoStack = IoGetCurrentIrpStackLocation(Irp);
154
155 /* get parameters */
156 OutputBufferLength = (IoStack->Parameters.DeviceIoControl.OutputBufferLength + 7) & ~7;
157 InputBufferLength = IoStack->Parameters.DeviceIoControl.InputBufferLength;
158
159 /* check for invalid buffer length size */
160 if (OutputBufferLength < IoStack->Parameters.DeviceIoControl.OutputBufferLength)
161 {
162 /* unsigned overflow */
163 return STATUS_INVALID_BUFFER_SIZE;
164 }
165
166 /* check for integer overflow */
167 if (InputBufferLength + OutputBufferLength < IoStack->Parameters.DeviceIoControl.OutputBufferLength)
168 {
169 /* overflow */
170 return STATUS_INVALID_BUFFER_SIZE;
171 }
172
173 /* check if inputbuffer at least holds KSPROPERTY item */
174 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY))
175 {
176 /* invalid parameter */
177 return STATUS_INVALID_BUFFER_SIZE;
178 }
179
180 /* get total size */
181 TotalSize = InputBufferLength + OutputBufferLength;
182
183 /* get input property request */
184 Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
185
186 /* have the parameters been checked yet */
187 if (!Irp->AssociatedIrp.SystemBuffer)
188 {
189 /* is it from user mode */
190 if (Irp->RequestorMode == UserMode)
191 {
192 /* probe user buffer */
193 ProbeForRead(IoStack->Parameters.DeviceIoControl.Type3InputBuffer, InputBufferLength, 1);
194 }
195
196 /* do we have an allocator */
197 if ((Allocator) && (Property->Flags & (KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET)))
198 {
199 /* call allocator */
200 Status = Allocator(Irp, TotalSize, (Property->Flags & KSPROPERTY_TYPE_GET));
201
202 /* check for success */
203 if (!NT_SUCCESS(Status))
204 return Status;
205 }
206 else
207 {
208 /* allocate buffer */
209 Irp->AssociatedIrp.SystemBuffer = AllocateItem(NonPagedPool, TotalSize);
210
211 /* sanity check */
212 ASSERT(Irp->AssociatedIrp.SystemBuffer != NULL);
213
214 /* mark irp as buffered so that changes the stream headers are propagated back */
215 Irp->Flags |= IRP_DEALLOCATE_BUFFER | IRP_BUFFERED_IO;
216 }
217
218 /* now copy the buffer */
219 RtlCopyMemory((PVOID)((ULONG_PTR)Irp->AssociatedIrp.SystemBuffer + OutputBufferLength), IoStack->Parameters.DeviceIoControl.Type3InputBuffer, InputBufferLength);
220
221 /* use new property buffer */
222 Property = (PKSPROPERTY)((ULONG_PTR)Irp->AssociatedIrp.SystemBuffer + OutputBufferLength);
223
224 /* is it a set operation */
225 if (Property->Flags & KSPROPERTY_TYPE_SET)
226 {
227 /* for set operations, the output parameters need to be copied */
228 if (Irp->RequestorMode == UserMode)
229 {
230 /* probe user parameter */
231 ProbeForRead(Irp->UserBuffer, IoStack->Parameters.DeviceIoControl.OutputBufferLength, 1);
232 }
233
234 /* copy parameters, needs un-aligned parameter length */
235 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Irp->UserBuffer, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
236 }
237
238 /* is there an output buffer */
239 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength)
240 {
241 /* is it from user mode */
242 if (Irp->RequestorMode == UserMode)
243 {
244 /* probe buffer for writing */
245 ProbeForWrite(Irp->UserBuffer, IoStack->Parameters.DeviceIoControl.OutputBufferLength, 1);
246 }
247
248 if (!Allocator || !(Property->Flags & KSPROPERTY_TYPE_GET))
249 {
250 /* it is an input operation */
251 Irp->Flags |= IRP_INPUT_OPERATION;
252 }
253 }
254 }
255 else
256 {
257 /* use new property buffer */
258 Property = (PKSPROPERTY)((ULONG_PTR)Irp->AssociatedIrp.SystemBuffer + OutputBufferLength);
259 }
260
261 //RtlStringFromGUID(&Property->Set, &GuidBuffer);
262
263 //DPRINT("KspPropertyHandler Irp %p PropertySetsCount %u PropertySet %p Allocator %p PropertyItemSize %u ExpectedPropertyItemSize %u\n", Irp, PropertySetsCount, PropertySet, Allocator, PropertyItemSize, sizeof(KSPROPERTY_ITEM));
264 //DPRINT("PropertyId %lu PropertyFlags %x Guid %S\n", Property->Id, Property->Flags, GuidBuffer.Buffer);
265
266 //RtlFreeUnicodeString(&GuidBuffer);
267
268 /* sanity check */
269 ASSERT(PropertyItemSize == 0 || PropertyItemSize == sizeof(KSPROPERTY_ITEM));
270
271 /* find the property handler */
272 Status = FindPropertyHandler(&Irp->IoStatus, PropertySet, PropertySetsCount, Property, InputBufferLength, OutputBufferLength, Irp->AssociatedIrp.SystemBuffer, &PropertyHandler, &Set, &PropertyItem);
273
274 if (NT_SUCCESS(Status) && PropertyHandler)
275 {
276 /* store set */
277 KSPROPERTY_SET_IRP_STORAGE(Irp) = Set;
278
279 /* are any custom property item sizes used */
280 if (PropertyItemSize)
281 {
282 /* store custom property item */
283 KSPROPERTY_ITEM_IRP_STORAGE(Irp) = PropertyItem;
284 }
285
286 _SEH2_TRY
287 {
288 /* call property handler */
289 Status = PropertyHandler(Irp, Property, (OutputBufferLength > 0 ? Irp->AssociatedIrp.SystemBuffer : NULL));
290 }
291 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
292 {
293 _SEH2_YIELD(return _SEH2_GetExceptionCode());
294 }
295 _SEH2_END;
296
297 if (Status == STATUS_BUFFER_TOO_SMALL)
298 {
299 /* output buffer is too small */
300 if (Allocator)
301 {
302 /* allocate the requested amount */
303 Status = Allocator(Irp, (ULONG)Irp->IoStatus.Information, FALSE);
304
305 /* check if the block was allocated */
306 if (!NT_SUCCESS(Status))
307 {
308 /* no memory */
309 return STATUS_INSUFFICIENT_RESOURCES;
310 }
311 _SEH2_TRY
312 {
313 /* re-call property handler */
314 Status = PropertyHandler(Irp, Property, Irp->AssociatedIrp.SystemBuffer);
315 }
316 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
317 {
318 Status = _SEH2_GetExceptionCode();
319 }
320 _SEH2_END;
321 }
322 }
323 }
324 else if (IsEqualGUIDAligned(&Property->Set, &GUID_NULL) && Property->Id == 0 && (Property->Flags & KSPROPERTY_TYPE_SETSUPPORT) == KSPROPERTY_TYPE_SETSUPPORT)
325 {
326 // store output size
327 Irp->IoStatus.Information = sizeof(GUID) * PropertySetsCount;
328 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GUID) * PropertySetsCount)
329 {
330 // buffer too small
331 return STATUS_MORE_ENTRIES;
332 }
333
334 // get output buffer
335 Guid = (LPGUID)Irp->AssociatedIrp.SystemBuffer;
336
337 // copy property guids from property sets
338 for(Index = 0; Index < PropertySetsCount; Index++)
339 {
340 RtlMoveMemory(&Guid[Index], PropertySet[Index].Set, sizeof(GUID));
341 }
342 Status = STATUS_SUCCESS;
343 }
344
345 /* done */
346 return Status;
347 }
348
349 /*
350 @implemented
351 */
352 KSDDKAPI
353 NTSTATUS
354 NTAPI
355 KsPropertyHandler(
356 IN PIRP Irp,
357 IN ULONG PropertySetsCount,
358 IN const KSPROPERTY_SET* PropertySet)
359 {
360 return KspPropertyHandler(Irp, PropertySetsCount, PropertySet, NULL, 0);
361 }
362
363
364 /*
365 @implemented
366 */
367 _IRQL_requires_max_(PASSIVE_LEVEL)
368 KSDDKAPI
369 NTSTATUS
370 NTAPI
371 KsPropertyHandlerWithAllocator(
372 _In_ PIRP Irp,
373 _In_ ULONG PropertySetsCount,
374 _In_reads_(PropertySetsCount) const KSPROPERTY_SET* PropertySet,
375 _In_opt_ PFNKSALLOCATOR Allocator,
376 _In_opt_ ULONG PropertyItemSize)
377 {
378 return KspPropertyHandler(Irp, PropertySetsCount, PropertySet, Allocator, PropertyItemSize);
379 }
380
381 NTSTATUS
382 FindFastPropertyHandler(
383 IN ULONG FastIoCount,
384 IN const KSFASTPROPERTY_ITEM * FastIoTable,
385 IN PKSPROPERTY PropertyId,
386 OUT PFNKSFASTHANDLER * FastPropertyHandler)
387 {
388 ULONG Index;
389
390 /* iterate through all items */
391 for(Index = 0; Index < FastIoCount; Index++)
392 {
393 if (PropertyId->Id == FastIoTable[Index].PropertyId)
394 {
395 if (PropertyId->Flags & KSPROPERTY_TYPE_SET)
396 {
397 if (FastIoTable[Index].SetSupported)
398 {
399 *FastPropertyHandler = FastIoTable[Index].SetPropertyHandler;
400 return STATUS_SUCCESS;
401 }
402 }
403
404 if (PropertyId->Flags & KSPROPERTY_TYPE_GET)
405 {
406 if (FastIoTable[Index].GetSupported)
407 {
408 *FastPropertyHandler = FastIoTable[Index].GetPropertyHandler;
409 return STATUS_SUCCESS;
410 }
411 }
412 }
413
414 }
415 /* no fast property handler found */
416 return STATUS_NOT_FOUND;
417 }
418
419
420 /*
421 @implemented
422 */
423 KSDDKAPI
424 BOOLEAN
425 NTAPI
426 KsFastPropertyHandler(
427 IN PFILE_OBJECT FileObject,
428 IN PKSPROPERTY UNALIGNED Property,
429 IN ULONG PropertyLength,
430 IN OUT PVOID UNALIGNED Data,
431 IN ULONG DataLength,
432 OUT PIO_STATUS_BLOCK IoStatus,
433 IN ULONG PropertySetsCount,
434 IN const KSPROPERTY_SET* PropertySet)
435 {
436 KSPROPERTY PropRequest;
437 KPROCESSOR_MODE Mode;
438 NTSTATUS Status = STATUS_SUCCESS;
439 ULONG Index;
440 PFNKSFASTHANDLER FastPropertyHandler;
441
442 if (PropertyLength < sizeof(KSPROPERTY))
443 {
444 /* invalid request */
445 return FALSE;
446 }
447
448 /* get previous mode */
449 Mode = ExGetPreviousMode();
450
451 if (Mode == KernelMode)
452 {
453 /* just copy it */
454 RtlMoveMemory(&PropRequest, Property, sizeof(KSPROPERTY));
455 }
456 else
457 {
458 /* need to probe the buffer */
459 _SEH2_TRY
460 {
461 ProbeForRead(Property, sizeof(KSPROPERTY), sizeof(UCHAR));
462 RtlMoveMemory(&PropRequest, Property, sizeof(KSPROPERTY));
463 }
464 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
465 {
466 /* Exception, get the error code */
467 Status = _SEH2_GetExceptionCode();
468 }_SEH2_END;
469
470 if (!NT_SUCCESS(Status))
471 return FALSE;
472 }
473
474 /* are there any property sets provided */
475 if (PropertySetsCount)
476 {
477 /* iterate through all property sets count */
478 Index = 0;
479 do
480 {
481 /* does the property id match */
482 if (IsEqualGUIDAligned(PropertySet[Index].Set, &PropRequest.Set))
483 {
484 /* try to find a fast property handler */
485 Status = FindFastPropertyHandler(PropertySet[Index].FastIoCount, PropertySet[Index].FastIoTable, &PropRequest, &FastPropertyHandler);
486
487 if (NT_SUCCESS(Status))
488 {
489 /* call fast property handler */
490 ASSERT(PropertyLength == sizeof(KSPROPERTY)); /* FIXME check if property length is bigger -> copy params */
491 ASSERT(Mode == KernelMode); /* FIXME need to probe usermode output buffer */
492 return FastPropertyHandler(FileObject, &PropRequest, sizeof(KSPROPERTY), Data, DataLength, IoStatus);
493 }
494 }
495 /* move to next item */
496 Index++;
497 }while(Index < PropertySetsCount);
498 }
499 return FALSE;
500 }
501
502 /*
503 @implemented
504 */
505 KSDDKAPI
506 NTSTATUS
507 NTAPI
508 KsDispatchSpecificProperty(
509 IN PIRP Irp,
510 IN PFNKSHANDLER Handler)
511 {
512 PIO_STACK_LOCATION IoStack;
513
514 /* get current irp stack location */
515 IoStack = IoGetCurrentIrpStackLocation(Irp);
516
517 return Handler(Irp, IoStack->Parameters.DeviceIoControl.Type3InputBuffer, Irp->UserBuffer);
518 }
519