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