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