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