xref: /reactos/drivers/ksfilter/ks/irp.c (revision d8c6ef5e)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/ksfilter/ks/factory.c
5  * PURPOSE:         KS Allocator functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 #include <ntifs.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /*
17     @implemented
18 */
19 KSDDKAPI
20 NTSTATUS
21 NTAPI
22 KsDispatchQuerySecurity(
23     IN PDEVICE_OBJECT DeviceObject,
24     IN PIRP Irp)
25 {
26     PKSOBJECT_CREATE_ITEM CreateItem;
27     PIO_STACK_LOCATION IoStack;
28     NTSTATUS Status;
29     ULONG Length;
30 
31     /* get current irp stack */
32     IoStack = IoGetCurrentIrpStackLocation(Irp);
33 
34     /* get create item */
35     CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
36 
37     if (!CreateItem || !CreateItem->SecurityDescriptor)
38     {
39         /* no create item */
40         Irp->IoStatus.Status = STATUS_NO_SECURITY_ON_OBJECT;
41         CompleteRequest(Irp, IO_NO_INCREMENT);
42         return STATUS_NO_SECURITY_ON_OBJECT;
43     }
44 
45 
46     /* get input length */
47     Length = IoStack->Parameters.QuerySecurity.Length;
48 
49     /* clone the security descriptor */
50     Status = SeQuerySecurityDescriptorInfo(&IoStack->Parameters.QuerySecurity.SecurityInformation, (PSECURITY_DESCRIPTOR)Irp->UserBuffer, &Length, &CreateItem->SecurityDescriptor);
51 
52     DPRINT("SeQuerySecurityDescriptorInfo Status %x\n", Status);
53     /* store result */
54     Irp->IoStatus.Status = Status;
55     Irp->IoStatus.Information = Length;
56 
57     CompleteRequest(Irp, IO_NO_INCREMENT);
58     return Status;
59 }
60 
61 /*
62     @implemented
63 */
64 KSDDKAPI
65 NTSTATUS
66 NTAPI
67 KsDispatchSetSecurity(
68     IN PDEVICE_OBJECT DeviceObject,
69     IN PIRP Irp)
70 {
71     PKSOBJECT_CREATE_ITEM CreateItem;
72     PIO_STACK_LOCATION IoStack;
73     PGENERIC_MAPPING Mapping;
74     PSECURITY_DESCRIPTOR Descriptor;
75     NTSTATUS Status;
76 
77     /* get current irp stack */
78     IoStack = IoGetCurrentIrpStackLocation(Irp);
79 
80     /* get create item */
81     CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
82 
83     if (!CreateItem || !CreateItem->SecurityDescriptor)
84     {
85         /* no create item */
86         Irp->IoStatus.Status = STATUS_NO_SECURITY_ON_OBJECT;
87         CompleteRequest(Irp, IO_NO_INCREMENT);
88         return STATUS_NO_SECURITY_ON_OBJECT;
89     }
90 
91     /* backup old descriptor */
92     Descriptor = CreateItem->SecurityDescriptor;
93 
94     /* get generic mapping */
95     Mapping = IoGetFileObjectGenericMapping();
96 
97     /* change security descriptor */
98     Status = SeSetSecurityDescriptorInfo(NULL, /*FIXME */
99                                          &IoStack->Parameters.SetSecurity.SecurityInformation,
100                                          IoStack->Parameters.SetSecurity.SecurityDescriptor,
101                                          &CreateItem->SecurityDescriptor,
102                                          NonPagedPool,
103                                          Mapping);
104 
105     if (NT_SUCCESS(Status))
106     {
107         /* free old descriptor */
108         FreeItem(Descriptor);
109 
110        /* mark create item as changed */
111        CreateItem->Flags |= KSCREATE_ITEM_SECURITYCHANGED;
112     }
113 
114     /* store result */
115     Irp->IoStatus.Status = Status;
116     CompleteRequest(Irp, IO_NO_INCREMENT);
117 
118     return Status;
119 }
120 
121 /*
122     @unimplemented
123 */
124 KSDDKAPI
125 NTSTATUS
126 NTAPI
127 KsDispatchSpecificMethod(
128     IN  PIRP Irp,
129     IN  PFNKSHANDLER Handler)
130 {
131     UNIMPLEMENTED;
132     return STATUS_UNSUCCESSFUL;
133 }
134 
135 
136 /*
137     @implemented
138 */
139 KSDDKAPI
140 NTSTATUS
141 NTAPI
142 KsReadFile(
143     IN  PFILE_OBJECT FileObject,
144     IN  PKEVENT Event OPTIONAL,
145     IN  PVOID PortContext OPTIONAL,
146     OUT PIO_STATUS_BLOCK IoStatusBlock,
147     OUT PVOID Buffer,
148     IN  ULONG Length,
149     IN  ULONG Key OPTIONAL,
150     IN  KPROCESSOR_MODE RequestorMode)
151 {
152     PDEVICE_OBJECT DeviceObject;
153     PIRP Irp;
154     NTSTATUS Status;
155     BOOLEAN Result;
156     KEVENT LocalEvent;
157 
158     if (Event)
159     {
160         /* make sure event is reset */
161         KeClearEvent(Event);
162     }
163 
164     if (RequestorMode == UserMode)
165     {
166         /* probe the user buffer */
167         _SEH2_TRY
168         {
169             ProbeForWrite(Buffer, Length, sizeof(UCHAR));
170             Status = STATUS_SUCCESS;
171         }
172         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
173         {
174             /* Exception, get the error code */
175             Status = _SEH2_GetExceptionCode();
176         }
177         _SEH2_END;
178 
179          if (!NT_SUCCESS(Status))
180          {
181              DPRINT1("Invalid user buffer provided\n");
182              return Status;
183          }
184     }
185 
186     /* get corresponding device object */
187     DeviceObject = IoGetRelatedDeviceObject(FileObject);
188 
189     /* fast-io read is only available for kernel mode clients */
190     if (RequestorMode == KernelMode && ExGetPreviousMode() == KernelMode &&
191         DeviceObject->DriverObject->FastIoDispatch->FastIoRead)
192     {
193         /* call fast io write */
194         Result = DeviceObject->DriverObject->FastIoDispatch->FastIoRead(FileObject, &FileObject->CurrentByteOffset, Length, TRUE, Key, Buffer, IoStatusBlock, DeviceObject);
195 
196         if (Result && NT_SUCCESS(IoStatusBlock->Status))
197         {
198             /* request was handled and succeeded */
199             return STATUS_SUCCESS;
200         }
201     }
202 
203     /* do the slow way */
204     if (!Event)
205     {
206         /* initialize temp event */
207         KeInitializeEvent(&LocalEvent, NotificationEvent, FALSE);
208         Event = &LocalEvent;
209     }
210 
211     /* build the irp packet */
212     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, Buffer, Length, &FileObject->CurrentByteOffset, Event, IoStatusBlock);
213     if (!Irp)
214     {
215         /* not enough resources */
216         return STATUS_INSUFFICIENT_RESOURCES;
217     }
218 
219     /* send the packet */
220     Status = IoCallDriver(DeviceObject, Irp);
221 
222     if (Status == STATUS_PENDING)
223     {
224         /* operation is pending, is sync file object */
225         if (FileObject->Flags & FO_SYNCHRONOUS_IO)
226         {
227             /* it is so wait */
228             KeWaitForSingleObject(Event, Executive, RequestorMode, FALSE, NULL);
229             Status = IoStatusBlock->Status;
230         }
231     }
232     /* return result */
233     return Status;
234 }
235 
236 /*
237     @implemented
238 */
239 KSDDKAPI
240 NTSTATUS
241 NTAPI
242 KsWriteFile(
243     IN  PFILE_OBJECT FileObject,
244     IN  PKEVENT Event OPTIONAL,
245     IN  PVOID PortContext OPTIONAL,
246     OUT PIO_STATUS_BLOCK IoStatusBlock,
247     IN  PVOID Buffer,
248     IN  ULONG Length,
249     IN  ULONG Key OPTIONAL,
250     IN  KPROCESSOR_MODE RequestorMode)
251 {
252     PDEVICE_OBJECT DeviceObject;
253     PIRP Irp;
254     NTSTATUS Status;
255     BOOLEAN Result;
256     KEVENT LocalEvent;
257 
258     if (Event)
259     {
260         /* make sure event is reset */
261         KeClearEvent(Event);
262     }
263 
264     if (RequestorMode == UserMode)
265     {
266         /* probe the user buffer */
267         _SEH2_TRY
268         {
269             ProbeForRead(Buffer, Length, sizeof(UCHAR));
270             Status = STATUS_SUCCESS;
271         }
272         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
273         {
274             /* Exception, get the error code */
275             Status = _SEH2_GetExceptionCode();
276         }
277         _SEH2_END;
278 
279          if (!NT_SUCCESS(Status))
280          {
281              DPRINT1("Invalid user buffer provided\n");
282              return Status;
283          }
284     }
285 
286     /* get corresponding device object */
287     DeviceObject = IoGetRelatedDeviceObject(FileObject);
288 
289     /* fast-io write is only available for kernel mode clients */
290     if (RequestorMode == KernelMode && ExGetPreviousMode() == KernelMode &&
291         DeviceObject->DriverObject->FastIoDispatch->FastIoWrite)
292     {
293         /* call fast io write */
294         Result = DeviceObject->DriverObject->FastIoDispatch->FastIoWrite(FileObject, &FileObject->CurrentByteOffset, Length, TRUE, Key, Buffer, IoStatusBlock, DeviceObject);
295 
296         if (Result && NT_SUCCESS(IoStatusBlock->Status))
297         {
298             /* request was handled and succeeded */
299             return STATUS_SUCCESS;
300         }
301     }
302 
303     /* do the slow way */
304     if (!Event)
305     {
306         /* initialize temp event */
307         KeInitializeEvent(&LocalEvent, NotificationEvent, FALSE);
308         Event = &LocalEvent;
309     }
310 
311     /* build the irp packet */
312     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, Buffer, Length, &FileObject->CurrentByteOffset, Event, IoStatusBlock);
313     if (!Irp)
314     {
315         /* not enough resources */
316         return STATUS_INSUFFICIENT_RESOURCES;
317     }
318 
319     /* send the packet */
320     Status = IoCallDriver(DeviceObject, Irp);
321 
322     if (Status == STATUS_PENDING)
323     {
324         /* operation is pending, is sync file object */
325         if (FileObject->Flags & FO_SYNCHRONOUS_IO)
326         {
327             /* it is so wait */
328             KeWaitForSingleObject(Event, Executive, RequestorMode, FALSE, NULL);
329             Status = IoStatusBlock->Status;
330         }
331     }
332     /* return result */
333     return Status;
334 }
335 
336 /*
337     @implemented
338 */
339 KSDDKAPI
340 NTSTATUS
341 NTAPI
342 KsQueryInformationFile(
343     IN  PFILE_OBJECT FileObject,
344     OUT PVOID FileInformation,
345     IN  ULONG Length,
346     IN  FILE_INFORMATION_CLASS FileInformationClass)
347 {
348     PDEVICE_OBJECT DeviceObject;
349     PFAST_IO_DISPATCH FastIoDispatch;
350     PIRP Irp;
351     PIO_STACK_LOCATION IoStack;
352     IO_STATUS_BLOCK IoStatusBlock;
353     KEVENT Event;
354     LARGE_INTEGER Offset;
355     NTSTATUS Status;
356 
357     /* get related file object */
358     DeviceObject = IoGetRelatedDeviceObject(FileObject);
359 
360     /* get fast i/o table */
361     FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
362 
363     /* is there a fast table */
364     if (FastIoDispatch)
365     {
366         /* check the class */
367         if (FileInformationClass == FileBasicInformation)
368         {
369             /* use FastIoQueryBasicInfo routine */
370             if (FastIoDispatch->FastIoQueryBasicInfo != NULL &&
371                 FastIoDispatch->FastIoQueryBasicInfo(
372                   FileObject,
373                   TRUE,
374                   (PFILE_BASIC_INFORMATION)FileInformation,
375                   &IoStatusBlock,
376                   DeviceObject))
377             {
378                 /* request was handled */
379                 return IoStatusBlock.Status;
380             }
381         }
382         else if (FileInformationClass == FileStandardInformation)
383         {
384             /* use FastIoQueryStandardInfo routine */
385             if (FastIoDispatch->FastIoQueryStandardInfo != NULL &&
386                 FastIoDispatch->FastIoQueryStandardInfo(
387                   FileObject,
388                   TRUE,
389                   (PFILE_STANDARD_INFORMATION)FileInformation,
390                   &IoStatusBlock,
391                   DeviceObject))
392             {
393                 /* request was handled */
394                 return IoStatusBlock.Status;
395             }
396         }
397     }
398 
399     /* clear event */
400     KeClearEvent(&FileObject->Event);
401 
402     /* initialize event */
403     KeInitializeEvent(&Event, NotificationEvent, FALSE);
404 
405     /* set offset to zero */
406     Offset.QuadPart = 0L;
407 
408     /* build the request */
409     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_QUERY_INFORMATION, IoGetRelatedDeviceObject(FileObject), NULL, 0, &Offset, &Event, &IoStatusBlock);
410     if (!Irp)
411         return STATUS_INSUFFICIENT_RESOURCES;
412 
413     /* get next stack location */
414     IoStack = IoGetNextIrpStackLocation(Irp);
415 
416     /* setup parameters */
417     IoStack->Parameters.QueryFile.FileInformationClass = FileInformationClass;
418     IoStack->Parameters.QueryFile.Length = Length;
419     Irp->AssociatedIrp.SystemBuffer = FileInformation;
420 
421 
422     /* call the driver */
423     Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
424 
425     if (Status == STATUS_PENDING)
426     {
427         /* wait for the operation to complete */
428         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
429 
430        /* is object sync */
431        if (FileObject->Flags & FO_SYNCHRONOUS_IO)
432            Status = FileObject->FinalStatus;
433        else
434            Status = IoStatusBlock.Status;
435     }
436 
437     /* done */
438     return Status;
439 }
440 
441 /*
442     @implemented
443 */
444 KSDDKAPI
445 NTSTATUS
446 NTAPI
447 KsSetInformationFile(
448     IN  PFILE_OBJECT FileObject,
449     IN  PVOID FileInformation,
450     IN  ULONG Length,
451     IN  FILE_INFORMATION_CLASS FileInformationClass)
452 {
453     PIO_STACK_LOCATION IoStack;
454     PDEVICE_OBJECT DeviceObject;
455     PIRP Irp;
456     PVOID Buffer;
457     KEVENT Event;
458     LARGE_INTEGER Offset;
459     IO_STATUS_BLOCK IoStatus;
460     NTSTATUS Status;
461 
462     /* get related device object */
463     DeviceObject = IoGetRelatedDeviceObject(FileObject);
464 
465     /* copy file information */
466     Buffer = AllocateItem(NonPagedPool, Length);
467     if (!Buffer)
468         return STATUS_INSUFFICIENT_RESOURCES;
469 
470     _SEH2_TRY
471     {
472         ProbeForRead(Buffer, Length, sizeof(UCHAR));
473         RtlMoveMemory(Buffer, FileInformation, Length);
474         Status = STATUS_SUCCESS;
475     }
476     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
477     {
478         /* Exception, get the error code */
479         Status = _SEH2_GetExceptionCode();
480     }
481     _SEH2_END;
482 
483     if (!NT_SUCCESS(Status))
484     {
485         /* invalid user buffer */
486         FreeItem(Buffer);
487         return Status;
488     }
489 
490     /* initialize the event */
491     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
492 
493     /* zero offset */
494     Offset.QuadPart = 0LL;
495 
496     /* build the irp */
497     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SET_INFORMATION, DeviceObject, NULL, 0, &Offset, &Event, &IoStatus);
498     if (!Irp)
499     {
500         /* failed to allocate irp */
501         FreeItem(Buffer);
502         return STATUS_INSUFFICIENT_RESOURCES;
503     }
504 
505     /* get next stack location */
506     IoStack = IoGetNextIrpStackLocation(Irp);
507 
508     /* set irp parameters */
509     IoStack->Parameters.SetFile.FileInformationClass = FileInformationClass;
510     IoStack->Parameters.SetFile.Length = Length;
511     IoStack->Parameters.SetFile.FileObject = FileObject;
512     Irp->AssociatedIrp.SystemBuffer = Buffer;
513     Irp->UserBuffer = FileInformation;
514 
515     /* dispatch the irp */
516     Status = IoCallDriver(DeviceObject, Irp);
517 
518     if (Status == STATUS_PENDING)
519     {
520         /* wait untill the operation has completed */
521         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
522         /* is a sync file object */
523         if (FileObject->Flags & FO_SYNCHRONOUS_IO)
524             Status = FileObject->FinalStatus;
525         else
526             Status = IoStatus.Status;
527     }
528     /* done */
529     return Status;
530 }
531 
532 /*
533     @implemented
534 */
535 KSDDKAPI
536 NTSTATUS
537 NTAPI
538 KsStreamIo(
539     IN  PFILE_OBJECT FileObject,
540     IN  PKEVENT Event OPTIONAL,
541     IN  PVOID PortContext OPTIONAL,
542     IN  PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
543     IN  PVOID CompletionContext OPTIONAL,
544     IN  KSCOMPLETION_INVOCATION CompletionInvocationFlags OPTIONAL,
545     OUT PIO_STATUS_BLOCK IoStatusBlock,
546     IN  OUT PVOID StreamHeaders,
547     IN  ULONG Length,
548     IN  ULONG Flags,
549     IN  KPROCESSOR_MODE RequestorMode)
550 {
551     PIRP Irp;
552     PIO_STACK_LOCATION IoStack;
553     PDEVICE_OBJECT DeviceObject;
554     NTSTATUS Status;
555     LARGE_INTEGER Offset;
556     PKSIOBJECT_HEADER ObjectHeader;
557     BOOLEAN Ret;
558 
559     /* get related device object */
560     DeviceObject = IoGetRelatedDeviceObject(FileObject);
561     /* sanity check */
562     ASSERT(DeviceObject != NULL);
563 
564     /* is there a event provided */
565     if (Event)
566     {
567         /* reset event */
568         KeClearEvent(Event);
569     }
570 
571     if (RequestorMode || ExGetPreviousMode() == KernelMode)
572     {
573         /* requestor is from kernel land */
574         ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext2;
575 
576         if (ObjectHeader)
577         {
578             /* there is a object header */
579             if (Flags == KSSTREAM_READ)
580             {
581                 /* is fast read supported */
582                 if (ObjectHeader->DispatchTable.FastRead)
583                 {
584                     /* call fast read dispatch routine */
585                     Ret = ObjectHeader->DispatchTable.FastRead(FileObject, NULL, Length, FALSE, 0, StreamHeaders, IoStatusBlock, DeviceObject);
586 
587                     if (Ret)
588                     {
589                         /* the request was handled */
590                         return IoStatusBlock->Status;
591                     }
592                 }
593             }
594             else if (Flags == KSSTREAM_WRITE)
595             {
596                 /* is fast write supported */
597                 if (ObjectHeader->DispatchTable.FastWrite)
598                 {
599                     /* call fast write dispatch routine */
600                     Ret = ObjectHeader->DispatchTable.FastWrite(FileObject, NULL, Length, FALSE, 0, StreamHeaders, IoStatusBlock, DeviceObject);
601 
602                     if (Ret)
603                     {
604                         /* the request was handled */
605                         return IoStatusBlock->Status;
606                     }
607                 }
608             }
609         }
610     }
611 
612     /* clear file object event */
613     KeClearEvent(&FileObject->Event);
614 
615     /* set the offset to zero */
616     Offset.QuadPart = 0LL;
617 
618     /* now build the irp */
619     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_DEVICE_CONTROL,
620                                        DeviceObject, (PVOID)StreamHeaders, Length, &Offset, Event, IoStatusBlock);
621     if (!Irp)
622     {
623         /* not enough memory */
624         return STATUS_INSUFFICIENT_RESOURCES;
625     }
626 
627     /* setup irp parameters */
628     Irp->RequestorMode = RequestorMode;
629     Irp->Overlay.AsynchronousParameters.UserApcContext = PortContext;
630     Irp->Tail.Overlay.OriginalFileObject = FileObject;
631     Irp->UserBuffer = StreamHeaders;
632 
633     /* get next irp stack location */
634     IoStack = IoGetNextIrpStackLocation(Irp);
635     /* setup stack parameters */
636     IoStack->FileObject = FileObject;
637     IoStack->Parameters.DeviceIoControl.InputBufferLength = Length;
638     IoStack->Parameters.DeviceIoControl.Type3InputBuffer = StreamHeaders;
639     IoStack->Parameters.DeviceIoControl.IoControlCode = (Flags == KSSTREAM_READ ? IOCTL_KS_READ_STREAM : IOCTL_KS_WRITE_STREAM);
640 
641     if (CompletionRoutine)
642     {
643         /* setup completion routine for async processing */
644         IoSetCompletionRoutine(Irp, CompletionRoutine, CompletionContext, (CompletionInvocationFlags & KsInvokeOnSuccess), (CompletionInvocationFlags & KsInvokeOnError), (CompletionInvocationFlags & KsInvokeOnCancel));
645     }
646 
647     /* now call the driver */
648     Status = IoCallDriver(DeviceObject, Irp);
649     /* done */
650     return Status;
651 }
652 
653 /*
654     @implemented
655 */
656 KSDDKAPI
657 NTSTATUS
658 NTAPI
659 KsProbeStreamIrp(
660     IN  PIRP Irp,
661     IN  ULONG ProbeFlags,
662     IN  ULONG HeaderSize)
663 {
664     PMDL Mdl;
665     PVOID Buffer;
666     LOCK_OPERATION Operation;
667     NTSTATUS Status = STATUS_SUCCESS;
668     PKSSTREAM_HEADER StreamHeader;
669     PIO_STACK_LOCATION IoStack;
670     ULONG Length;
671     //BOOLEAN AllocateMdl = FALSE;
672 
673     /* get current irp stack */
674     IoStack = IoGetCurrentIrpStackLocation(Irp);
675 
676     Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
677 
678     if (Irp->RequestorMode == KernelMode || Irp->AssociatedIrp.SystemBuffer)
679     {
680         if (Irp->RequestorMode == KernelMode)
681         {
682             /* no need to allocate stream header */
683             Irp->AssociatedIrp.SystemBuffer = Irp->UserBuffer;
684         }
685 AllocMdl:
686         /* check if alloc mdl flag is passed */
687         if (!(ProbeFlags & KSPROBE_ALLOCATEMDL))
688         {
689             /* nothing more to do */
690             return STATUS_SUCCESS;
691         }
692         if (Irp->MdlAddress)
693         {
694 ProbeMdl:
695             if (ProbeFlags & KSPROBE_PROBEANDLOCK)
696             {
697                 if (Irp->MdlAddress->MdlFlags & (MDL_PAGES_LOCKED | MDL_SOURCE_IS_NONPAGED_POOL))
698                 {
699                     if (ProbeFlags & KSPROBE_SYSTEMADDRESS)
700                     {
701                         _SEH2_TRY
702                         {
703                             /* loop through all mdls and probe them */
704                             Mdl = Irp->MdlAddress;
705                             do
706                             {
707                                 /* the mapping can fail */
708                                 Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
709 
710                                 if (Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL))
711                                 {
712                                     /* no need to probe these pages */
713                                     Buffer = Mdl->MappedSystemVa;
714                                 }
715                                 else
716                                 {
717                                     /* probe that mdl */
718                                     Buffer = MmMapLockedPages(Mdl, KernelMode);
719                                 }
720 
721                                 /* check if the mapping succeeded */
722                                 if (!Buffer)
723                                 {
724                                     /* raise exception we'll catch */
725                                     ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
726                                 }
727 
728                                 /* iterate to next mdl */
729                                 Mdl = Mdl->Next;
730 
731                             }while(Mdl);
732                         }
733                         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
734                         {
735                             /* Exception, get the error code */
736                             Status = _SEH2_GetExceptionCode();
737                         } _SEH2_END;
738                     }
739                 }
740                 else
741                 {
742                     _SEH2_TRY
743                     {
744                         /* loop through all mdls and probe them */
745                         Mdl = Irp->MdlAddress;
746 
747                         /* determine operation */
748                         if (!(ProbeFlags & KSPROBE_STREAMWRITE) || (ProbeFlags & KSPROBE_MODIFY))
749                         {
750                             /* operation is read / modify stream, need write access */
751                             Operation = IoWriteAccess;
752                         }
753                         else
754                         {
755                             /* operation is write to device, so we need read access */
756                             Operation = IoReadAccess;
757                         }
758 
759                         do
760                         {
761                             /* probe the pages */
762                             MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
763 
764                             if (ProbeFlags & KSPROBE_SYSTEMADDRESS)
765                             {
766                                 /* the mapping can fail */
767                                 Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
768 
769                                 if (Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL))
770                                 {
771                                     /* no need to probe these pages */
772                                     Buffer = Mdl->MappedSystemVa;
773                                 }
774                                 else
775                                 {
776                                     /* probe that mdl */
777                                     Buffer = MmMapLockedPages(Mdl, KernelMode);
778                                 }
779 
780                                 /* check if the mapping succeeded */
781                                 if (!Buffer)
782                                 {
783                                     /* raise exception we'll catch */
784                                     ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
785                                 }
786                             }
787 
788                             /* iterate to next mdl */
789                             Mdl = Mdl->Next;
790 
791                         }while(Mdl);
792                     }
793                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
794                     {
795                         /* Exception, get the error code */
796                         Status = _SEH2_GetExceptionCode();
797                     } _SEH2_END;
798                 }
799             }
800             return Status;
801         }
802 
803         /* check all stream headers */
804         StreamHeader = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
805         ASSERT(StreamHeader);
806         _SEH2_TRY
807         {
808             do
809             {
810                 if (HeaderSize)
811                 {
812                     /* does the supplied header size match stream header size and no type changed */
813                     if (StreamHeader->Size != HeaderSize && !(StreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED))
814                     {
815                         /* invalid stream header */
816                         ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
817                     }
818                 }
819                 else
820                 {
821                     /* stream must be at least of size KSSTREAM_HEADER and size must be 8-byte block aligned */
822                     if (StreamHeader->Size < sizeof(KSSTREAM_HEADER) || (StreamHeader->Size & 7))
823                     {
824                         /* invalid stream header */
825                         ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
826                     }
827                 }
828 
829                 if (Length < StreamHeader->Size)
830                 {
831                     /* length is too short */
832                     ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
833                 }
834 
835                 if (ProbeFlags & KSPROBE_STREAMWRITE)
836                 {
837                     if (StreamHeader->DataUsed > StreamHeader->FrameExtent)
838                     {
839                         /* frame extend can never be smaller */
840                         ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
841                     }
842 
843                     /* is this stream change packet */
844                     if (StreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED)
845                     {
846                         if (Length != sizeof(KSSTREAM_HEADER) || (PVOID)StreamHeader != Irp->AssociatedIrp.SystemBuffer)
847                         {
848                             /* stream changed - must be send in a single packet */
849                             ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
850                         }
851 
852                         if (!(ProbeFlags & KSPROBE_ALLOWFORMATCHANGE))
853                         {
854                             /* caller does not permit format changes */
855                             ExRaiseStatus(STATUS_INVALID_PARAMETER);
856                         }
857 
858                         if (StreamHeader->FrameExtent)
859                         {
860                             /* allocate an mdl */
861                             Mdl = IoAllocateMdl(StreamHeader->Data, StreamHeader->FrameExtent, FALSE, TRUE, Irp);
862 
863                             if (!Mdl)
864                             {
865                                 /* not enough memory */
866                                 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
867                             }
868 
869                             /* break-out to probe for the irp */
870                             break;
871                         }
872                     }
873                 }
874                 else
875                 {
876                     if (StreamHeader->DataUsed)
877                     {
878                         /* DataUsed must be zero for stream read operation */
879                         ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
880                     }
881 
882                     if (StreamHeader->OptionsFlags)
883                     {
884                         /* no flags supported for reading */
885                         ExRaiseStatus(STATUS_INVALID_PARAMETER);
886                     }
887                 }
888 
889                 if (StreamHeader->FrameExtent)
890                 {
891                     /* allocate an mdl */
892                     ASSERT(Irp->MdlAddress == NULL);
893                     Mdl = IoAllocateMdl(StreamHeader->Data, StreamHeader->FrameExtent, FALSE, TRUE, Irp);
894                     if (!Mdl)
895                     {
896                         /* not enough memory */
897                         ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
898                     }
899                 }
900 
901                 /* move to next stream header */
902                 Length -= StreamHeader->Size;
903                 StreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)StreamHeader + StreamHeader->Size);
904             }while(Length);
905         }
906         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
907         {
908             /* Exception, get the error code */
909             Status = _SEH2_GetExceptionCode();
910         }_SEH2_END;
911 
912         /* now probe the allocated mdl's */
913         if (!NT_SUCCESS(Status))
914         {
915             DPRINT("Status %x\n", Status);
916             return Status;
917         }
918         else
919             goto ProbeMdl;
920     }
921 
922     /* probe user mode buffers */
923     if (Length && ( (!HeaderSize) || (Length % HeaderSize == 0) || ((ProbeFlags & KSPROBE_ALLOWFORMATCHANGE) && (Length == sizeof(KSSTREAM_HEADER))) ) )
924     {
925         /* allocate stream header buffer */
926         Irp->AssociatedIrp.SystemBuffer = AllocateItem(NonPagedPool, Length);
927 
928         if (!Irp->AssociatedIrp.SystemBuffer)
929         {
930             /* no memory */
931             return STATUS_INSUFFICIENT_RESOURCES;
932         }
933 
934         /* mark irp as buffered so that changes the stream headers are propagated back */
935         Irp->Flags = IRP_DEALLOCATE_BUFFER | IRP_BUFFERED_IO;
936 
937         _SEH2_TRY
938         {
939             if (ProbeFlags & KSPROBE_STREAMWRITE)
940             {
941                 if (ProbeFlags & KSPROBE_MODIFY)
942                     ProbeForWrite(Irp->UserBuffer, Length, sizeof(UCHAR));
943                 else
944                     ProbeForRead(Irp->UserBuffer, Length, sizeof(UCHAR));
945             }
946             else
947             {
948                 /* stream reads means writing */
949                 ProbeForWrite(Irp->UserBuffer, Length, sizeof(UCHAR));
950 
951                 /* set input operation flags */
952                 Irp->Flags |= IRP_INPUT_OPERATION;
953             }
954 
955             /* copy stream buffer */
956             RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, Irp->UserBuffer, Length);
957         }
958         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
959         {
960             /* Exception, get the error code */
961             Status = _SEH2_GetExceptionCode();
962         }_SEH2_END;
963 
964         if (!NT_SUCCESS(Status))
965         {
966             /* failed */
967             return Status;
968         }
969 
970         if (ProbeFlags & KSPROBE_ALLOCATEMDL)
971         {
972             /* alloc mdls */
973             goto AllocMdl;
974         }
975 
976         /* check all stream headers */
977         StreamHeader = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
978 
979         _SEH2_TRY
980         {
981             do
982             {
983                 if (HeaderSize)
984                 {
985                     /* does the supplied header size match stream header size and no type changed */
986                     if (StreamHeader->Size != HeaderSize && !(StreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED))
987                     {
988                         /* invalid stream header */
989                         ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
990                     }
991                 }
992                 else
993                 {
994                     /* stream must be at least of size KSSTREAM_HEADER and size must be 8-byte block aligned */
995                     if (StreamHeader->Size < sizeof(KSSTREAM_HEADER) || (StreamHeader->Size & 7))
996                     {
997                         /* invalid stream header */
998                         ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
999                     }
1000                 }
1001 
1002                 if (Length < StreamHeader->Size)
1003                 {
1004                     /* length is too short */
1005                     ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
1006                 }
1007 
1008                 if (ProbeFlags & KSPROBE_STREAMWRITE)
1009                 {
1010                     if (StreamHeader->DataUsed > StreamHeader->FrameExtent)
1011                     {
1012                         /* frame extend can never be smaller */
1013                         ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
1014                     }
1015 
1016                     /* is this stream change packet */
1017                     if (StreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED)
1018                     {
1019                         if (Length != sizeof(KSSTREAM_HEADER) || (PVOID)StreamHeader != Irp->AssociatedIrp.SystemBuffer)
1020                         {
1021                             /* stream changed - must be send in a single packet */
1022                             ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
1023                         }
1024 
1025                         if (!(ProbeFlags & KSPROBE_ALLOWFORMATCHANGE))
1026                         {
1027                             /* caller does not permit format changes */
1028                             ExRaiseStatus(STATUS_INVALID_PARAMETER);
1029                         }
1030 
1031                         if (StreamHeader->FrameExtent)
1032                         {
1033                             /* allocate an mdl */
1034                             Mdl = IoAllocateMdl(StreamHeader->Data, StreamHeader->FrameExtent, FALSE, TRUE, Irp);
1035 
1036                             if (!Mdl)
1037                             {
1038                                 /* not enough memory */
1039                                 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
1040                             }
1041 
1042                             /* break out to probe for the irp */
1043                             //AllocateMdl = TRUE;
1044                             break;
1045                         }
1046                     }
1047                 }
1048                 else
1049                 {
1050                     if (StreamHeader->DataUsed)
1051                     {
1052                         /* DataUsed must be zero for stream read operation */
1053                         ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
1054                     }
1055 
1056                     if (StreamHeader->OptionsFlags)
1057                     {
1058                         /* no flags supported for reading */
1059                         ExRaiseStatus(STATUS_INVALID_PARAMETER);
1060                     }
1061                 }
1062 
1063                 /* move to next stream header */
1064                 Length -= StreamHeader->Size;
1065                 StreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)StreamHeader + StreamHeader->Size);
1066             }while(Length);
1067 
1068         }_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1069         {
1070             /* Exception, get the error code */
1071             Status = _SEH2_GetExceptionCode();
1072         }_SEH2_END;
1073 
1074         /* now probe the allocated mdl's */
1075         if (NT_SUCCESS(Status))
1076             goto AllocMdl;
1077         else
1078             return Status;
1079     }
1080 
1081     return STATUS_INVALID_BUFFER_SIZE;
1082 }
1083 
1084 /*
1085     @implemented
1086 */
1087 KSDDKAPI
1088 NTSTATUS
1089 NTAPI
1090 KsAllocateExtraData(
1091     IN  PIRP Irp,
1092     IN  ULONG ExtraSize,
1093     OUT PVOID* ExtraBuffer)
1094 {
1095     PIO_STACK_LOCATION IoStack;
1096     ULONG Count, Index;
1097     PUCHAR Buffer, BufferOrg;
1098     PKSSTREAM_HEADER Header;
1099     NTSTATUS Status = STATUS_SUCCESS;
1100 
1101     /* get current irp stack */
1102     IoStack = IoGetCurrentIrpStackLocation(Irp);
1103 
1104     /* sanity check */
1105     ASSERT(IoStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(KSSTREAM_HEADER));
1106 
1107     /* get total length */
1108     Count = IoStack->Parameters.DeviceIoControl.InputBufferLength / sizeof(KSSTREAM_HEADER);
1109 
1110     /* allocate buffer */
1111     Buffer = BufferOrg = AllocateItem(NonPagedPool, Count * (sizeof(KSSTREAM_HEADER) + ExtraSize));
1112     if (!Buffer)
1113         return STATUS_INSUFFICIENT_RESOURCES;
1114 
1115     _SEH2_TRY
1116     {
1117         /* get input buffer */
1118         Header = (PKSSTREAM_HEADER)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
1119         for(Index = 0; Index < Count; Index++)
1120         {
1121             /* copy stream header */
1122             RtlMoveMemory(Buffer, Header, sizeof(KSSTREAM_HEADER));
1123 
1124             /* move to next header */
1125             Header++;
1126             /* increment output buffer offset */
1127             Buffer += sizeof(KSSTREAM_HEADER) + ExtraSize;
1128         }
1129     }
1130     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1131     {
1132         /* Exception, get the error code */
1133         Status = _SEH2_GetExceptionCode();
1134     }
1135     _SEH2_END;
1136 
1137     if (!NT_SUCCESS(Status))
1138     {
1139         /* free buffer on exception */
1140         FreeItem(Buffer);
1141         return Status;
1142     }
1143 
1144     /* store result */
1145     *ExtraBuffer = BufferOrg;
1146 
1147     /* done */
1148     return STATUS_SUCCESS;
1149 }
1150 
1151 /*
1152     @implemented
1153 */
1154 KSDDKAPI
1155 VOID
1156 NTAPI
1157 KsNullDriverUnload(
1158     IN  PDRIVER_OBJECT DriverObject)
1159 {
1160 }
1161 
1162 /*
1163     @implemented
1164 */
1165 KSDDKAPI
1166 NTSTATUS
1167 NTAPI
1168 KsDispatchInvalidDeviceRequest(
1169     IN  PDEVICE_OBJECT DeviceObject,
1170     IN  PIRP Irp)
1171 {
1172     Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1173     CompleteRequest(Irp, IO_NO_INCREMENT);
1174 
1175     return STATUS_INVALID_DEVICE_REQUEST;
1176 }
1177 
1178 /*
1179     @implemented
1180 */
1181 KSDDKAPI
1182 NTSTATUS
1183 NTAPI
1184 KsDefaultDeviceIoCompletion(
1185     IN  PDEVICE_OBJECT DeviceObject,
1186     IN  PIRP Irp)
1187 {
1188     PIO_STACK_LOCATION IoStack;
1189     NTSTATUS Status;
1190 
1191     /* get current irp stack */
1192     IoStack = IoGetCurrentIrpStackLocation(Irp);
1193 
1194     if (IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_PROPERTY &&
1195         IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_METHOD &&
1196         IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_ENABLE_EVENT &&
1197         IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_DISABLE_EVENT)
1198     {
1199         if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_RESET_STATE)
1200         {
1201             /* fake success */
1202             Status = STATUS_SUCCESS;
1203         }
1204         else
1205         {
1206             /* request unsupported */
1207             Status = STATUS_INVALID_DEVICE_REQUEST;
1208         }
1209     }
1210     else
1211     {
1212         /* property / method / event not found */
1213         Status = STATUS_PROPSET_NOT_FOUND;
1214     }
1215 
1216     /* complete request */
1217     Irp->IoStatus.Status = Status;
1218     CompleteRequest(Irp, IO_NO_INCREMENT);
1219 
1220 
1221     return Status;
1222 }
1223 
1224 /*
1225     @implemented
1226 */
1227 KSDDKAPI
1228 BOOLEAN
1229 NTAPI
1230 KsDispatchFastIoDeviceControlFailure(
1231     IN  PFILE_OBJECT FileObject,
1232     IN  BOOLEAN Wait,
1233     IN  PVOID InputBuffer  OPTIONAL,
1234     IN  ULONG InputBufferLength,
1235     OUT PVOID OutputBuffer  OPTIONAL,
1236     IN  ULONG OutputBufferLength,
1237     IN  ULONG IoControlCode,
1238     OUT PIO_STATUS_BLOCK IoStatus,
1239     IN  PDEVICE_OBJECT DeviceObject)
1240 {
1241     return FALSE;
1242 }
1243 
1244 /*
1245     @implemented
1246 */
1247 KSDDKAPI
1248 BOOLEAN
1249 NTAPI
1250 KsDispatchFastReadFailure(
1251     IN  PFILE_OBJECT FileObject,
1252     IN  PLARGE_INTEGER FileOffset,
1253     IN  ULONG Length,
1254     IN  BOOLEAN Wait,
1255     IN  ULONG LockKey,
1256     OUT PVOID Buffer,
1257     OUT PIO_STATUS_BLOCK IoStatus,
1258     IN  PDEVICE_OBJECT DeviceObject)
1259 {
1260     return FALSE;
1261 }
1262 
1263 
1264 /*
1265     @implemented
1266 */
1267 KSDDKAPI
1268 VOID
1269 NTAPI
1270 KsCancelIo(
1271     IN  OUT PLIST_ENTRY QueueHead,
1272     IN  PKSPIN_LOCK SpinLock)
1273 {
1274     PDRIVER_CANCEL OldDriverCancel;
1275     PIO_STACK_LOCATION IoStack;
1276     PLIST_ENTRY Entry;
1277     PLIST_ENTRY NextEntry;
1278     PIRP Irp;
1279     KIRQL OldLevel;
1280 
1281     /* acquire spinlock */
1282     KeAcquireSpinLock(SpinLock, &OldLevel);
1283     /* point to first entry */
1284     Entry = QueueHead->Flink;
1285     /* loop all items */
1286     while(Entry != QueueHead)
1287     {
1288         /* get irp offset */
1289         Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
1290 
1291         /* get next entry */
1292         NextEntry = Entry->Flink;
1293 
1294         /* set cancelled bit */
1295         Irp->Cancel = TRUE;
1296 
1297         /* now set the cancel routine */
1298         OldDriverCancel = IoSetCancelRoutine(Irp, NULL);
1299         if (OldDriverCancel)
1300         {
1301             /* this irp hasnt been yet used, so free to cancel */
1302             KeReleaseSpinLock(SpinLock, OldLevel);
1303 
1304             /* get current irp stack */
1305             IoStack = IoGetCurrentIrpStackLocation(Irp);
1306 
1307             /* acquire cancel spinlock */
1308             IoAcquireCancelSpinLock(&Irp->CancelIrql);
1309 
1310             /* call provided cancel routine */
1311             OldDriverCancel(IoStack->DeviceObject, Irp);
1312 
1313             /* re-acquire spinlock */
1314             KeAcquireSpinLock(SpinLock, &OldLevel);
1315         }
1316 
1317         /* move on to next entry */
1318         Entry = NextEntry;
1319     }
1320 
1321     /* the irp has already been canceled */
1322     KeReleaseSpinLock(SpinLock, OldLevel);
1323 
1324 }
1325 
1326 /*
1327     @implemented
1328 */
1329 KSDDKAPI
1330 VOID
1331 NTAPI
1332 KsReleaseIrpOnCancelableQueue(
1333     IN  PIRP Irp,
1334     IN  PDRIVER_CANCEL DriverCancel OPTIONAL)
1335 {
1336     PKSPIN_LOCK SpinLock;
1337     PDRIVER_CANCEL OldDriverCancel;
1338     PIO_STACK_LOCATION IoStack;
1339     KIRQL OldLevel;
1340 
1341     /* check for required parameters */
1342     if (!Irp)
1343         return;
1344 
1345     if (!DriverCancel)
1346     {
1347         /* default to KsCancelRoutine */
1348         DriverCancel = KsCancelRoutine;
1349     }
1350 
1351     /* get current irp stack */
1352     IoStack = IoGetCurrentIrpStackLocation(Irp);
1353 
1354     /* get internal queue lock */
1355     SpinLock = KSQUEUE_SPINLOCK_IRP_STORAGE(Irp);
1356 
1357     /* acquire spinlock */
1358     KeAcquireSpinLock(SpinLock, &OldLevel);
1359 
1360     /* now set the cancel routine */
1361     OldDriverCancel = IoSetCancelRoutine(Irp, DriverCancel);
1362 
1363     if (Irp->Cancel && OldDriverCancel == NULL)
1364     {
1365         /* the irp has already been canceled */
1366         KeReleaseSpinLock(SpinLock, OldLevel);
1367 
1368         /* cancel routine requires that cancel spinlock is held */
1369         IoAcquireCancelSpinLock(&Irp->CancelIrql);
1370 
1371         /* cancel irp */
1372         DriverCancel(IoStack->DeviceObject, Irp);
1373     }
1374     else
1375     {
1376         /* done */
1377         KeReleaseSpinLock(SpinLock, OldLevel);
1378     }
1379 }
1380 
1381 /*
1382     @implemented
1383 */
1384 KSDDKAPI
1385 PIRP
1386 NTAPI
1387 KsRemoveIrpFromCancelableQueue(
1388     IN  OUT PLIST_ENTRY QueueHead,
1389     IN  PKSPIN_LOCK SpinLock,
1390     IN  KSLIST_ENTRY_LOCATION ListLocation,
1391     IN  KSIRP_REMOVAL_OPERATION RemovalOperation)
1392 {
1393     PIRP Irp;
1394     PLIST_ENTRY CurEntry;
1395     KIRQL OldIrql;
1396 
1397     DPRINT("KsRemoveIrpFromCancelableQueue ListHead %p SpinLock %p ListLocation %x RemovalOperation %x\n", QueueHead, SpinLock, ListLocation, RemovalOperation);
1398 
1399     /* check parameters */
1400     if (!QueueHead || !SpinLock)
1401         return NULL;
1402 
1403     /* check if parameter ListLocation is valid */
1404     if (ListLocation != KsListEntryTail && ListLocation != KsListEntryHead)
1405         return NULL;
1406 
1407     /* acquire list lock */
1408     KeAcquireSpinLock(SpinLock, &OldIrql);
1409 
1410     /* point to queue head */
1411     CurEntry = QueueHead;
1412 
1413     do
1414     {
1415         /* reset irp to null */
1416         Irp = NULL;
1417 
1418         /* iterate to next entry */
1419         if (ListLocation == KsListEntryHead)
1420             CurEntry = CurEntry->Flink;
1421         else
1422             CurEntry = CurEntry->Blink;
1423 
1424         /* is the end of list reached */
1425         if (CurEntry == QueueHead)
1426         {
1427             /* reached end of list */
1428             break;
1429         }
1430 
1431         /* get irp offset */
1432         Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
1433 
1434         if (Irp->Cancel)
1435         {
1436             /* irp has been canceled */
1437             break;
1438         }
1439 
1440         if (Irp->CancelRoutine)
1441         {
1442             /* remove cancel routine */
1443             Irp->CancelRoutine = NULL;
1444 
1445             if (RemovalOperation == KsAcquireAndRemove || RemovalOperation == KsAcquireAndRemoveOnlySingleItem)
1446             {
1447                 /* remove irp from list */
1448                 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
1449             }
1450 
1451             if (RemovalOperation == KsAcquireAndRemoveOnlySingleItem || RemovalOperation == KsAcquireOnlySingleItem)
1452                 break;
1453         }
1454 
1455     }while(TRUE);
1456 
1457     /* release lock */
1458     KeReleaseSpinLock(SpinLock, OldIrql);
1459 
1460     if (!Irp || Irp->CancelRoutine == NULL)
1461     {
1462         /* either an irp has been acquired or nothing found */
1463         return Irp;
1464     }
1465 
1466     /* time to remove the canceled irp */
1467     IoAcquireCancelSpinLock(&OldIrql);
1468     /* acquire list lock */
1469     KeAcquireSpinLockAtDpcLevel(SpinLock);
1470 
1471     if (RemovalOperation == KsAcquireAndRemove || RemovalOperation == KsAcquireAndRemoveOnlySingleItem)
1472     {
1473         /* remove it */
1474         RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
1475     }
1476 
1477     /* release list lock */
1478     KeReleaseSpinLockFromDpcLevel(SpinLock);
1479 
1480     /* release cancel spinlock */
1481     IoReleaseCancelSpinLock(OldIrql);
1482     /* no non canceled irp has been found */
1483     return NULL;
1484 }
1485 
1486 /*
1487     @implemented
1488 */
1489 KSDDKAPI
1490 NTSTATUS
1491 NTAPI
1492 KsMoveIrpsOnCancelableQueue(
1493     IN  OUT PLIST_ENTRY SourceList,
1494     IN  PKSPIN_LOCK SourceLock,
1495     IN  OUT PLIST_ENTRY DestinationList,
1496     IN  PKSPIN_LOCK DestinationLock OPTIONAL,
1497     IN  KSLIST_ENTRY_LOCATION ListLocation,
1498     IN  PFNKSIRPLISTCALLBACK ListCallback,
1499     IN  PVOID Context)
1500 {
1501     KIRQL OldLevel;
1502     PLIST_ENTRY SrcEntry;
1503     PIRP Irp;
1504     NTSTATUS Status = STATUS_SUCCESS;
1505 
1506     if (!DestinationLock)
1507     {
1508         /* no destination lock just acquire the source lock */
1509         KeAcquireSpinLock(SourceLock, &OldLevel);
1510     }
1511     else
1512     {
1513         /* acquire cancel spinlock */
1514         IoAcquireCancelSpinLock(&OldLevel);
1515 
1516         /* now acquire source lock */
1517         KeAcquireSpinLockAtDpcLevel(SourceLock);
1518 
1519         /* now acquire destination lock */
1520         KeAcquireSpinLockAtDpcLevel(DestinationLock);
1521     }
1522 
1523     /* point to list head */
1524     SrcEntry = SourceList;
1525 
1526     /* now move all irps */
1527     while(TRUE)
1528     {
1529         if (ListLocation == KsListEntryTail)
1530         {
1531             /* move queue downwards */
1532             SrcEntry = SrcEntry->Flink;
1533         }
1534         else
1535         {
1536             /* move queue upwards */
1537             SrcEntry = SrcEntry->Blink;
1538         }
1539 
1540         if (SrcEntry == SourceList)
1541         {
1542             /* eof list reached */
1543             break;
1544         }
1545 
1546         /* get irp offset */
1547         Irp = (PIRP)CONTAINING_RECORD(SrcEntry, IRP, Tail.Overlay.ListEntry);
1548 
1549         /* now check if irp can be moved */
1550         Status = ListCallback(Irp, Context);
1551 
1552         /* check if irp can be moved */
1553         if (Status == STATUS_SUCCESS)
1554         {
1555             /* remove irp from src list */
1556             RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
1557 
1558             if (ListLocation == KsListEntryTail)
1559             {
1560                 /* insert irp end of list */
1561                 InsertTailList(DestinationList, &Irp->Tail.Overlay.ListEntry);
1562             }
1563             else
1564             {
1565                 /* insert irp head of list */
1566                 InsertHeadList(DestinationList, &Irp->Tail.Overlay.ListEntry);
1567             }
1568 
1569             /* do we need to update the irp lock */
1570             if (DestinationLock)
1571             {
1572                 /* update irp lock */
1573                 KSQUEUE_SPINLOCK_IRP_STORAGE(Irp) = DestinationLock;
1574             }
1575         }
1576         else
1577         {
1578             if (Status != STATUS_NO_MATCH)
1579             {
1580                 /* callback decided to stop enumeration */
1581                 break;
1582             }
1583 
1584             /* reset return value */
1585             Status = STATUS_SUCCESS;
1586         }
1587     }
1588 
1589     if (!DestinationLock)
1590     {
1591         /* release source lock */
1592         KeReleaseSpinLock(SourceLock, OldLevel);
1593     }
1594     else
1595     {
1596         /* now release destination lock */
1597         KeReleaseSpinLockFromDpcLevel(DestinationLock);
1598 
1599         /* now release source lock */
1600         KeReleaseSpinLockFromDpcLevel(SourceLock);
1601 
1602 
1603         /* now release cancel spinlock */
1604         IoReleaseCancelSpinLock(OldLevel);
1605     }
1606 
1607     /* done */
1608     return Status;
1609 }
1610 
1611 /*
1612     @implemented
1613 */
1614 KSDDKAPI
1615 VOID
1616 NTAPI
1617 KsRemoveSpecificIrpFromCancelableQueue(
1618     IN  PIRP Irp)
1619 {
1620     PKSPIN_LOCK SpinLock;
1621     KIRQL OldLevel;
1622 
1623     DPRINT("KsRemoveSpecificIrpFromCancelableQueue %p\n", Irp);
1624 
1625     /* get internal queue lock */
1626     SpinLock = KSQUEUE_SPINLOCK_IRP_STORAGE(Irp);
1627 
1628     /* acquire spinlock */
1629     KeAcquireSpinLock(SpinLock, &OldLevel);
1630 
1631     /* remove the irp from the list */
1632     RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
1633 
1634     /* release spinlock */
1635     KeReleaseSpinLock(SpinLock, OldLevel);
1636 }
1637 
1638 
1639 /*
1640     @implemented
1641 */
1642 KSDDKAPI
1643 VOID
1644 NTAPI
1645 KsAddIrpToCancelableQueue(
1646     IN  OUT PLIST_ENTRY QueueHead,
1647     IN  PKSPIN_LOCK SpinLock,
1648     IN  PIRP Irp,
1649     IN  KSLIST_ENTRY_LOCATION ListLocation,
1650     IN  PDRIVER_CANCEL DriverCancel OPTIONAL)
1651 {
1652     PDRIVER_CANCEL OldDriverCancel;
1653     PIO_STACK_LOCATION IoStack;
1654     KIRQL OldLevel;
1655 
1656     /* check for required parameters */
1657     if (!QueueHead || !SpinLock || !Irp)
1658         return;
1659 
1660     /* get current irp stack */
1661     IoStack = IoGetCurrentIrpStackLocation(Irp);
1662 
1663     DPRINT("KsAddIrpToCancelableQueue QueueHead %p SpinLock %p Irp %p ListLocation %x DriverCancel %p\n", QueueHead, SpinLock, Irp, ListLocation, DriverCancel);
1664 
1665     // HACK for ms portcls
1666     if (IoStack->MajorFunction == IRP_MJ_CREATE)
1667     {
1668         // complete the request
1669         DPRINT1("MS HACK\n");
1670         Irp->IoStatus.Status = STATUS_SUCCESS;
1671         CompleteRequest(Irp, IO_NO_INCREMENT);
1672 
1673         return;
1674     }
1675 
1676 
1677     if (!DriverCancel)
1678     {
1679         /* default to KsCancelRoutine */
1680         DriverCancel = KsCancelRoutine;
1681     }
1682 
1683 
1684     /* acquire spinlock */
1685     KeAcquireSpinLock(SpinLock, &OldLevel);
1686 
1687     if (ListLocation == KsListEntryTail)
1688     {
1689         /* insert irp to tail of list */
1690         InsertTailList(QueueHead, &Irp->Tail.Overlay.ListEntry);
1691     }
1692     else
1693     {
1694         /* insert irp to head of list */
1695         InsertHeadList(QueueHead, &Irp->Tail.Overlay.ListEntry);
1696     }
1697 
1698     /* store internal queue lock */
1699     KSQUEUE_SPINLOCK_IRP_STORAGE(Irp) = SpinLock;
1700 
1701     /* now set the cancel routine */
1702     OldDriverCancel = IoSetCancelRoutine(Irp, DriverCancel);
1703 
1704     if (Irp->Cancel && OldDriverCancel == NULL)
1705     {
1706         /* the irp has already been canceled */
1707         KeReleaseSpinLock(SpinLock, OldLevel);
1708 
1709         /* cancel routine requires that cancel spinlock is held */
1710         IoAcquireCancelSpinLock(&Irp->CancelIrql);
1711 
1712         /* cancel irp */
1713         DriverCancel(IoStack->DeviceObject, Irp);
1714     }
1715     else
1716     {
1717         /* done */
1718         KeReleaseSpinLock(SpinLock, OldLevel);
1719     }
1720 }
1721 
1722 /*
1723     @implemented
1724 */
1725 KSDDKAPI
1726 VOID
1727 NTAPI
1728 KsCancelRoutine(
1729     IN  PDEVICE_OBJECT DeviceObject,
1730     IN  PIRP Irp)
1731 {
1732     PKSPIN_LOCK SpinLock;
1733 
1734     /* get internal queue lock */
1735     SpinLock = KSQUEUE_SPINLOCK_IRP_STORAGE(Irp);
1736 
1737     /* acquire spinlock */
1738     KeAcquireSpinLockAtDpcLevel(SpinLock);
1739 
1740     /* sanity check */
1741     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1742 
1743     /* release cancel spinlock */
1744     IoReleaseCancelSpinLock(Irp->CancelIrql);
1745 
1746     /* remove the irp from the list */
1747     RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
1748 
1749     /* release spinlock */
1750     KeReleaseSpinLock(SpinLock, Irp->CancelIrql);
1751 
1752     /* has the irp already been canceled */
1753     if (Irp->IoStatus.Status != STATUS_CANCELLED)
1754     {
1755         /* let's complete it */
1756         Irp->IoStatus.Status = STATUS_CANCELLED;
1757         CompleteRequest(Irp, IO_NO_INCREMENT);
1758     }
1759 }
1760 
1761 NTSTATUS
1762 FindMatchingCreateItem(
1763     PLIST_ENTRY ListHead,
1764     PUNICODE_STRING String,
1765     OUT PCREATE_ITEM_ENTRY *OutCreateItem)
1766 {
1767     PLIST_ENTRY Entry;
1768     PCREATE_ITEM_ENTRY CreateItemEntry;
1769     UNICODE_STRING RefString;
1770     LPWSTR pStr;
1771     ULONG Count;
1772 
1773     /* Copy the input string */
1774     RefString = *String;
1775 
1776     /* Check if the string starts with a backslash */
1777     if (String->Buffer[0] == L'\\')
1778     {
1779         /* Skip backslash */
1780         RefString.Buffer++;
1781         RefString.Length -= sizeof(WCHAR);
1782     }
1783     else
1784     {
1785         /* get terminator */
1786         pStr = String->Buffer;
1787         Count = String->Length / sizeof(WCHAR);
1788         while ((Count > 0) && (*pStr != L'\\'))
1789         {
1790             pStr++;
1791             Count--;
1792         }
1793 
1794         /* sanity check */
1795         ASSERT(Count != 0);
1796 
1797         // request is for pin / node / allocator
1798         RefString.Length = (USHORT)((PCHAR)pStr - (PCHAR)String->Buffer);
1799     }
1800 
1801     /* point to first entry */
1802     Entry = ListHead->Flink;
1803 
1804     /* loop all device items */
1805     while (Entry != ListHead)
1806     {
1807         /* get create item entry */
1808         CreateItemEntry = (PCREATE_ITEM_ENTRY)CONTAINING_RECORD(Entry,
1809                                                                 CREATE_ITEM_ENTRY,
1810                                                                 Entry);
1811 
1812         ASSERT(CreateItemEntry->CreateItem);
1813 
1814         if(CreateItemEntry->CreateItem->Flags & KSCREATE_ITEM_WILDCARD)
1815         {
1816             /* create item is default */
1817             *OutCreateItem = CreateItemEntry;
1818             return STATUS_SUCCESS;
1819         }
1820 
1821         if (!CreateItemEntry->CreateItem->Create)
1822         {
1823             /* skip free create item */
1824             Entry = Entry->Flink;
1825             continue;
1826         }
1827 
1828         DPRINT("CreateItem %S Length %u Request %wZ %u\n",
1829                CreateItemEntry->CreateItem->ObjectClass.Buffer,
1830                CreateItemEntry->CreateItem->ObjectClass.Length,
1831                &RefString,
1832                RefString.Length);
1833 
1834         if (CreateItemEntry->CreateItem->ObjectClass.Length > RefString.Length)
1835         {
1836             /* create item doesnt match in length */
1837             Entry = Entry->Flink;
1838             continue;
1839         }
1840 
1841          /* now check if the object class is the same */
1842         if (!RtlCompareUnicodeString(&CreateItemEntry->CreateItem->ObjectClass,
1843                                      &RefString,
1844                                      TRUE))
1845         {
1846             /* found matching create item */
1847             *OutCreateItem = CreateItemEntry;
1848             return STATUS_SUCCESS;
1849         }
1850         /* iterate to next */
1851         Entry = Entry->Flink;
1852     }
1853 
1854     return STATUS_NOT_FOUND;
1855 }
1856 
1857 NTSTATUS
1858 NTAPI
1859 KspCreate(
1860     IN  PDEVICE_OBJECT DeviceObject,
1861     IN  PIRP Irp)
1862 {
1863     PCREATE_ITEM_ENTRY CreateItemEntry;
1864     PIO_STACK_LOCATION IoStack;
1865     PDEVICE_EXTENSION DeviceExtension;
1866     PKSIDEVICE_HEADER DeviceHeader;
1867     PKSIOBJECT_HEADER ObjectHeader;
1868     NTSTATUS Status;
1869 
1870     DPRINT("KS / CREATE\n");
1871 
1872     /* get current stack location */
1873     IoStack = IoGetCurrentIrpStackLocation(Irp);
1874     /* get device extension */
1875     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1876     /* get device header */
1877     DeviceHeader = DeviceExtension->DeviceHeader;
1878 
1879 
1880     if (IoStack->FileObject->FileName.Buffer == NULL)
1881     {
1882         /* FIXME Pnp-Issue */
1883         DPRINT("Using reference string hack\n");
1884         Irp->IoStatus.Information = 0;
1885         /* set return status */
1886         Irp->IoStatus.Status = STATUS_SUCCESS;
1887         CompleteRequest(Irp, IO_NO_INCREMENT);
1888         return STATUS_SUCCESS;
1889     }
1890 
1891     if (IoStack->FileObject->RelatedFileObject != NULL)
1892     {
1893         /* request is to instantiate a pin / node / clock / allocator */
1894         ObjectHeader = (PKSIOBJECT_HEADER)IoStack->FileObject->RelatedFileObject->FsContext2;
1895 
1896         /* sanity check */
1897         ASSERT(ObjectHeader);
1898 
1899         /* find a matching a create item */
1900         Status = FindMatchingCreateItem(&ObjectHeader->ItemList,
1901                                         &IoStack->FileObject->FileName,
1902                                         &CreateItemEntry);
1903     }
1904     else
1905     {
1906         /* request to create a filter */
1907         Status = FindMatchingCreateItem(&DeviceHeader->ItemList,
1908                                         &IoStack->FileObject->FileName,
1909                                         &CreateItemEntry);
1910     }
1911 
1912     if (NT_SUCCESS(Status))
1913     {
1914         /* set object create item */
1915         KSCREATE_ITEM_IRP_STORAGE(Irp) = CreateItemEntry->CreateItem;
1916 
1917         /* call create function */
1918         Status = CreateItemEntry->CreateItem->Create(DeviceObject, Irp);
1919 
1920         if (NT_SUCCESS(Status))
1921         {
1922             /* increment create item reference count */
1923             InterlockedIncrement(&CreateItemEntry->ReferenceCount);
1924         }
1925         return Status;
1926     }
1927 
1928     Irp->IoStatus.Information = 0;
1929     /* set return status */
1930     Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1931     CompleteRequest(Irp, IO_NO_INCREMENT);
1932     return STATUS_UNSUCCESSFUL;
1933 }
1934 
1935 NTSTATUS
1936 NTAPI
1937 KspDispatchIrp(
1938     IN  PDEVICE_OBJECT DeviceObject,
1939     IN  PIRP Irp)
1940 {
1941     PIO_STACK_LOCATION IoStack;
1942     //PDEVICE_EXTENSION DeviceExtension;
1943     PKSIOBJECT_HEADER ObjectHeader;
1944     //PKSIDEVICE_HEADER DeviceHeader;
1945     PDRIVER_DISPATCH Dispatch;
1946     NTSTATUS Status;
1947 
1948     /* get current stack location */
1949     IoStack = IoGetCurrentIrpStackLocation(Irp);
1950 
1951     /* get device extension */
1952     //DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1953     /* get device header */
1954     //DeviceHeader = DeviceExtension->DeviceHeader;
1955 
1956     ASSERT(IoStack->FileObject);
1957 
1958     /* get object header */
1959     ObjectHeader = (PKSIOBJECT_HEADER) IoStack->FileObject->FsContext2;
1960 
1961     if (!ObjectHeader)
1962     {
1963         /* FIXME Pnp-Issue*/
1964         Irp->IoStatus.Status = STATUS_SUCCESS;
1965         Irp->IoStatus.Information = 0;
1966         /* complete and forget */
1967         CompleteRequest(Irp, IO_NO_INCREMENT);
1968         return STATUS_SUCCESS;
1969     }
1970 
1971     /* sanity check */
1972     ASSERT(ObjectHeader);
1973     /* store create item */
1974     //KSCREATE_ITEM_IRP_STORAGE(Irp) = (PKSOBJECT_CREATE_ITEM)0x12345678; //ObjectHeader->CreateItem;
1975 
1976     /* retrieve matching dispatch function */
1977     switch(IoStack->MajorFunction)
1978     {
1979         case IRP_MJ_CLOSE:
1980             Dispatch = ObjectHeader->DispatchTable.Close;
1981             break;
1982         case IRP_MJ_DEVICE_CONTROL:
1983             Dispatch = ObjectHeader->DispatchTable.DeviceIoControl;
1984             break;
1985         case IRP_MJ_READ:
1986             Dispatch = ObjectHeader->DispatchTable.Read;
1987             break;
1988         case IRP_MJ_WRITE:
1989             Dispatch = ObjectHeader->DispatchTable.Write;
1990             break;
1991         case IRP_MJ_FLUSH_BUFFERS :
1992             Dispatch = ObjectHeader->DispatchTable.Flush;
1993             break;
1994         case IRP_MJ_QUERY_SECURITY:
1995             Dispatch = ObjectHeader->DispatchTable.QuerySecurity;
1996             break;
1997         case IRP_MJ_SET_SECURITY:
1998             Dispatch = ObjectHeader->DispatchTable.SetSecurity;
1999             break;
2000         case IRP_MJ_PNP:
2001             Dispatch = KsDefaultDispatchPnp;
2002             break;
2003         default:
2004             Dispatch = NULL;
2005     }
2006 
2007     /* is the request supported */
2008     if (Dispatch)
2009     {
2010         /* now call the dispatch function */
2011         Status = Dispatch(DeviceObject, Irp);
2012     }
2013     else
2014     {
2015         /* not supported request */
2016         Status = KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
2017     }
2018 
2019     /* done */
2020     return Status;
2021 }
2022 
2023 /*
2024     @implemented
2025 */
2026 KSDDKAPI
2027 NTSTATUS
2028 NTAPI
2029 KsSetMajorFunctionHandler(
2030     IN  PDRIVER_OBJECT DriverObject,
2031     IN  ULONG MajorFunction)
2032 {
2033     DPRINT("KsSetMajorFunctionHandler Function %x\n", MajorFunction);
2034 
2035     switch ( MajorFunction )
2036     {
2037         case IRP_MJ_CREATE:
2038             DriverObject->MajorFunction[MajorFunction] = KspCreate;
2039             break;
2040         case IRP_MJ_DEVICE_CONTROL:
2041         case IRP_MJ_CLOSE:
2042         case IRP_MJ_READ:
2043         case IRP_MJ_WRITE:
2044         case IRP_MJ_FLUSH_BUFFERS :
2045         case IRP_MJ_QUERY_SECURITY:
2046         case IRP_MJ_SET_SECURITY:
2047             DriverObject->MajorFunction[MajorFunction] = KspDispatchIrp;
2048             break;
2049         default:
2050             DPRINT1("NotSupported %x\n", MajorFunction);
2051             return STATUS_INVALID_PARAMETER;
2052     };
2053 
2054     return STATUS_SUCCESS;
2055 }
2056 
2057 /*
2058     @implemented
2059 */
2060 KSDDKAPI
2061 NTSTATUS
2062 NTAPI
2063 KsDispatchIrp(
2064     IN  PDEVICE_OBJECT DeviceObject,
2065     IN  PIRP Irp)
2066 {
2067     PIO_STACK_LOCATION IoStack;
2068     PKSIDEVICE_HEADER DeviceHeader;
2069     PDEVICE_EXTENSION DeviceExtension;
2070 
2071     DPRINT("KsDispatchIrp DeviceObject %p Irp %p\n", DeviceObject, Irp);
2072 
2073     /* get device extension */
2074     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
2075 
2076     /* get device header */
2077     DeviceHeader = DeviceExtension->DeviceHeader;
2078 
2079 
2080     /* get current irp stack */
2081     IoStack = IoGetCurrentIrpStackLocation(Irp);
2082 
2083     if (IoStack->MajorFunction <= IRP_MJ_DEVICE_CONTROL)
2084     {
2085         if (IoStack->MajorFunction == IRP_MJ_CREATE)
2086         {
2087             /* check internal type */
2088             if (DeviceHeader->BasicHeader.OuterUnknown) /* FIXME improve check */
2089             {
2090                 /* AVStream client */
2091                 return IKsDevice_Create(DeviceObject, Irp);
2092             }
2093             else
2094             {
2095                 /* external client (portcls) */
2096                 return KspCreate(DeviceObject, Irp);
2097             }
2098         }
2099 
2100         switch (IoStack->MajorFunction)
2101         {
2102             case IRP_MJ_CLOSE:
2103             case IRP_MJ_READ:
2104             case IRP_MJ_WRITE:
2105             case IRP_MJ_FLUSH_BUFFERS:
2106             case IRP_MJ_QUERY_SECURITY:
2107             case IRP_MJ_SET_SECURITY:
2108             case IRP_MJ_PNP:
2109             case IRP_MJ_DEVICE_CONTROL:
2110                 return KspDispatchIrp(DeviceObject, Irp);
2111             default:
2112                 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
2113         }
2114     }
2115 
2116     /* dispatch power */
2117     if (IoStack->MajorFunction == IRP_MJ_POWER)
2118     {
2119         /* check internal type */
2120         if (DeviceHeader->BasicHeader.OuterUnknown) /* FIXME improve check */
2121         {
2122             /* AVStream client */
2123             return IKsDevice_Power(DeviceObject, Irp);
2124         }
2125         else
2126         {
2127             /* external client (portcls) */
2128             return KsDefaultDispatchPower(DeviceObject, Irp);
2129         }
2130     }
2131     else if (IoStack->MajorFunction == IRP_MJ_PNP) /* dispatch pnp */
2132     {
2133         /* check internal type */
2134         if (DeviceHeader->BasicHeader.OuterUnknown) /* FIXME improve check */
2135         {
2136             /* AVStream client */
2137             return IKsDevice_Pnp(DeviceObject, Irp);
2138         }
2139         else
2140         {
2141             /* external client (portcls) */
2142             return KsDefaultDispatchPnp(DeviceObject, Irp);
2143         }
2144     }
2145     else if (IoStack->MajorFunction == IRP_MJ_SYSTEM_CONTROL)
2146     {
2147         /* forward irp */
2148         return KsDefaultForwardIrp(DeviceObject, Irp);
2149     }
2150     else
2151     {
2152         /* not supported */
2153         return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
2154     }
2155 }
2156 
2157 /*
2158     @unimplemented
2159 */
2160 KSDDKAPI
2161 ULONG
2162 NTAPI
2163 KsGetNodeIdFromIrp(
2164     IN PIRP Irp)
2165 {
2166     UNIMPLEMENTED;
2167     return KSFILTER_NODE;
2168 }
2169 
2170