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