* Sync to trunk HEAD (r53298).
[reactos.git] / 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 {
25 ULONG Index, ItemIndex;
26
27 for(Index = 0; Index < PropertySetCount; Index++)
28 {
29 ASSERT(PropertySet[Index].Set);
30
31 if (IsEqualGUIDAligned(&Property->Set, PropertySet[Index].Set))
32 {
33 for(ItemIndex = 0; ItemIndex < PropertySet[Index].PropertiesCount; ItemIndex++)
34 {
35 if (PropertySet[Index].PropertyItem[ItemIndex].PropertyId == Property->Id)
36 {
37 if (PropertySet[Index].PropertyItem[ItemIndex].MinProperty > InputBufferLength)
38 {
39 /* too small input buffer */
40 IoStatus->Information = PropertySet[Index].PropertyItem[ItemIndex].MinProperty;
41 return STATUS_INVALID_PARAMETER;
42 }
43
44 if (PropertySet[Index].PropertyItem[ItemIndex].MinData > OutputBufferLength)
45 {
46 /* too small output buffer */
47 IoStatus->Information = PropertySet[Index].PropertyItem[ItemIndex].MinData;
48 return STATUS_MORE_ENTRIES;
49 }
50
51 /* store property set */
52 *Set = (PKSPROPERTY_SET)&PropertySet[Index];
53
54 if (Property->Flags & KSPROPERTY_TYPE_SET)
55 {
56 /* store property handler */
57 *PropertyHandler = PropertySet[Index].PropertyItem[ItemIndex].SetPropertyHandler;
58 return STATUS_SUCCESS;
59 }
60
61 if (Property->Flags & KSPROPERTY_TYPE_GET)
62 {
63 /* store property handler */
64 *PropertyHandler = PropertySet[Index].PropertyItem[ItemIndex].GetPropertyHandler;
65 return STATUS_SUCCESS;
66 }
67
68
69 if (Property->Flags & KSPROPERTY_TYPE_BASICSUPPORT)
70 {
71 PULONG Flags;
72 PKSPROPERTY_DESCRIPTION Description;
73
74 if (sizeof(ULONG) > OutputBufferLength)
75 {
76 /* too small buffer */
77 return STATUS_INVALID_PARAMETER;
78 }
79
80 /* get output buffer */
81 Flags = (PULONG)OutputBuffer;
82
83 /* clear flags */
84 *Flags = 0;
85
86 IoStatus->Information = sizeof(ULONG);
87
88 if (PropertySet[Index].PropertyItem[ItemIndex].SupportHandler)
89 {
90 /* use support handler from driver */
91 *PropertyHandler = PropertySet[Index].PropertyItem[ItemIndex].SupportHandler;
92 return STATUS_SUCCESS;
93 }
94
95 if (PropertySet[Index].PropertyItem[ItemIndex].GetSupported)
96 *Flags |= KSPROPERTY_TYPE_GET;
97
98 if (PropertySet[Index].PropertyItem[ItemIndex].SetSupported)
99 *Flags |= KSPROPERTY_TYPE_SET;
100
101 if (OutputBufferLength >= sizeof(KSPROPERTY_DESCRIPTION))
102 {
103 /* get output buffer */
104 Description = (PKSPROPERTY_DESCRIPTION)OutputBuffer;
105
106 /* store result */
107 Description->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
108 Description->PropTypeSet.Set = KSPROPTYPESETID_General;
109 Description->PropTypeSet.Id = 0;
110 Description->PropTypeSet.Flags = 0;
111 Description->MembersListCount = 0;
112 Description->Reserved = 0;
113
114 IoStatus->Information = sizeof(KSPROPERTY_DESCRIPTION);
115 }
116 return STATUS_SUCCESS;
117 }
118 }
119 }
120 }
121 }
122 return STATUS_NOT_FOUND;
123 }
124
125
126 NTSTATUS
127 KspPropertyHandler(
128 IN PIRP Irp,
129 IN ULONG PropertySetsCount,
130 IN const KSPROPERTY_SET* PropertySet,
131 IN PFNKSALLOCATOR Allocator OPTIONAL,
132 IN ULONG PropertyItemSize OPTIONAL)
133 {
134 PKSPROPERTY Property;
135 PKSPROPERTY_SET Set;
136 PIO_STACK_LOCATION IoStack;
137 NTSTATUS Status;
138 PFNKSHANDLER PropertyHandler = NULL;
139 ULONG Index;
140 LPGUID Guid;
141
142 /* get current irp stack */
143 IoStack = IoGetCurrentIrpStackLocation(Irp);
144
145 /* check if inputbuffer at least holds KSPROPERTY item */
146 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY))
147 {
148 /* invalid parameter */
149 Irp->IoStatus.Information = sizeof(KSPROPERTY);
150 return STATUS_INVALID_BUFFER_SIZE;
151 }
152
153 /* FIXME probe the input / output buffer if from user mode */
154
155 /* get input property request */
156 Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
157
158 // DPRINT("KspPropertyHandler Irp %p PropertySetsCount %u PropertySet %p Allocator %p PropertyItemSize %u ExpectedPropertyItemSize %u\n", Irp, PropertySetsCount, PropertySet, Allocator, PropertyItemSize, sizeof(KSPROPERTY_ITEM));
159
160 /* sanity check */
161 ASSERT(PropertyItemSize == 0 || PropertyItemSize == sizeof(KSPROPERTY_ITEM));
162
163 /* find the property handler */
164 Status = FindPropertyHandler(&Irp->IoStatus, PropertySet, PropertySetsCount, Property, IoStack->Parameters.DeviceIoControl.InputBufferLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength, Irp->UserBuffer, &PropertyHandler, &Set);
165
166 if (NT_SUCCESS(Status) && PropertyHandler)
167 {
168 /* call property handler */
169 KSPROPERTY_SET_IRP_STORAGE(Irp) = Set;
170 Status = PropertyHandler(Irp, Property, Irp->UserBuffer);
171
172 if (Status == STATUS_BUFFER_TOO_SMALL)
173 {
174 /* output buffer is too small */
175 if (Allocator)
176 {
177 /* allocate the requested amount */
178 Status = Allocator(Irp, Irp->IoStatus.Information, FALSE);
179
180 /* check if the block was allocated */
181 if (!NT_SUCCESS(Status))
182 {
183 /* no memory */
184 return STATUS_INSUFFICIENT_RESOURCES;
185 }
186
187 /* re-call property handler */
188 Status = PropertyHandler(Irp, Property, Irp->UserBuffer);
189 }
190 }
191 }
192 else if (IsEqualGUIDAligned(&Property->Set, &GUID_NULL) && Property->Id == 0 && (Property->Flags & KSPROPERTY_TYPE_SETSUPPORT) == KSPROPERTY_TYPE_SETSUPPORT)
193 {
194 // store output size
195 Irp->IoStatus.Information = sizeof(GUID) * PropertySetsCount;
196 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GUID) * PropertySetsCount)
197 {
198 // buffer too small
199 return STATUS_MORE_ENTRIES;
200 }
201
202 // get output buffer
203 Guid = (LPGUID)Irp->UserBuffer;
204
205 // copy property guids from property sets
206 for(Index = 0; Index < PropertySetsCount; Index++)
207 {
208 RtlMoveMemory(&Guid[Index], PropertySet[Index].Set, sizeof(GUID));
209 }
210 Status = STATUS_SUCCESS;
211 }
212
213 /* done */
214 return Status;
215 }
216
217 /*
218 @implemented
219 */
220 KSDDKAPI
221 NTSTATUS
222 NTAPI
223 KsPropertyHandler(
224 IN PIRP Irp,
225 IN ULONG PropertySetsCount,
226 IN const KSPROPERTY_SET* PropertySet)
227 {
228 return KspPropertyHandler(Irp, PropertySetsCount, PropertySet, NULL, 0);
229 }
230
231
232 /*
233 @implemented
234 */
235 KSDDKAPI
236 NTSTATUS
237 NTAPI
238 KsPropertyHandlerWithAllocator(
239 IN PIRP Irp,
240 IN ULONG PropertySetsCount,
241 IN PKSPROPERTY_SET PropertySet,
242 IN PFNKSALLOCATOR Allocator OPTIONAL,
243 IN ULONG PropertyItemSize OPTIONAL)
244 {
245 return KspPropertyHandler(Irp, PropertySetsCount, PropertySet, Allocator, PropertyItemSize);
246 }
247
248 NTSTATUS
249 FindFastPropertyHandler(
250 IN ULONG FastIoCount,
251 IN const KSFASTPROPERTY_ITEM * FastIoTable,
252 IN PKSPROPERTY PropertyId,
253 OUT PFNKSFASTHANDLER * FastPropertyHandler)
254 {
255 ULONG Index;
256
257 /* iterate through all items */
258 for(Index = 0; Index < FastIoCount; Index++)
259 {
260 if (PropertyId->Id == FastIoTable[Index].PropertyId)
261 {
262 if (PropertyId->Flags & KSPROPERTY_TYPE_SET)
263 {
264 if (FastIoTable[Index].SetSupported)
265 {
266 *FastPropertyHandler = FastIoTable[Index].SetPropertyHandler;
267 return STATUS_SUCCESS;
268 }
269 }
270
271 if (PropertyId->Flags & KSPROPERTY_TYPE_GET)
272 {
273 if (FastIoTable[Index].GetSupported)
274 {
275 *FastPropertyHandler = FastIoTable[Index].GetPropertyHandler;
276 return STATUS_SUCCESS;
277 }
278 }
279 }
280
281 }
282 /* no fast property handler found */
283 return STATUS_NOT_FOUND;
284 }
285
286
287 /*
288 @implemented
289 */
290 KSDDKAPI
291 BOOLEAN
292 NTAPI
293 KsFastPropertyHandler(
294 IN PFILE_OBJECT FileObject,
295 IN PKSPROPERTY UNALIGNED Property,
296 IN ULONG PropertyLength,
297 IN OUT PVOID UNALIGNED Data,
298 IN ULONG DataLength,
299 OUT PIO_STATUS_BLOCK IoStatus,
300 IN ULONG PropertySetsCount,
301 IN const KSPROPERTY_SET* PropertySet)
302 {
303 KSPROPERTY PropRequest;
304 KPROCESSOR_MODE Mode;
305 NTSTATUS Status = STATUS_SUCCESS;
306 ULONG Index;
307 PFNKSFASTHANDLER FastPropertyHandler;
308
309 if (PropertyLength < sizeof(KSPROPERTY))
310 {
311 /* invalid request */
312 return FALSE;
313 }
314
315 /* get previous mode */
316 Mode = ExGetPreviousMode();
317
318 if (Mode == KernelMode)
319 {
320 /* just copy it */
321 RtlMoveMemory(&PropRequest, Property, sizeof(KSPROPERTY));
322 }
323 else
324 {
325 /* need to probe the buffer */
326 _SEH2_TRY
327 {
328 ProbeForRead(Property, sizeof(KSPROPERTY), sizeof(UCHAR));
329 RtlMoveMemory(&PropRequest, Property, sizeof(KSPROPERTY));
330 }
331 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
332 {
333 /* Exception, get the error code */
334 Status = _SEH2_GetExceptionCode();
335 }_SEH2_END;
336
337 if (!NT_SUCCESS(Status))
338 return FALSE;
339 }
340
341 /* are there any property sets provided */
342 if (PropertySetsCount)
343 {
344 /* iterate through all property sets count */
345 Index = 0;
346 do
347 {
348 /* does the property id match */
349 if (IsEqualGUIDAligned(PropertySet[Index].Set, &PropRequest.Set))
350 {
351 /* try to find a fast property handler */
352 Status = FindFastPropertyHandler(PropertySet[Index].FastIoCount, PropertySet[Index].FastIoTable, &PropRequest, &FastPropertyHandler);
353
354 if (NT_SUCCESS(Status))
355 {
356 /* call fast property handler */
357 ASSERT(PropertyLength == sizeof(KSPROPERTY)); /* FIXME check if property length is bigger -> copy params */
358 ASSERT(Mode == KernelMode); /* FIXME need to probe usermode output buffer */
359 return FastPropertyHandler(FileObject, &PropRequest, sizeof(KSPROPERTY), Data, DataLength, IoStatus);
360 }
361 }
362 /* move to next item */
363 Index++;
364 }while(Index < PropertySetsCount);
365 }
366 return FALSE;
367 }
368
369 /*
370 @implemented
371 */
372 KSDDKAPI
373 NTSTATUS
374 NTAPI
375 KsDispatchSpecificProperty(
376 IN PIRP Irp,
377 IN PFNKSHANDLER Handler)
378 {
379 PIO_STACK_LOCATION IoStack;
380
381 /* get current irp stack location */
382 IoStack = IoGetCurrentIrpStackLocation(Irp);
383
384 return Handler(Irp, IoStack->Parameters.DeviceIoControl.Type3InputBuffer, Irp->UserBuffer);
385 }
386