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