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