ajay
Tue Sep 12 05:08:54 CDT 2006
I am posting some code from USBSnoop. I need to send URB from
MyDispatchInternalIOCTL to user mode application. User mode app will
receieve all these URB in one worker therad. I am not getting how
should I send all these URB to user mode applications. You can see
MyDispatchInternalIOCTL and let me know which mechanism shoudl I use to
send the URB. Lot of discussion is happening here but it seems that my
problem left undiscussed. Could anyone explaine how to send URB to user
mode application and how user mode app will receive the data. It woul
be really helpful from me if someone explain me with help of example
and some source code.
NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT
pdo)
{
NTSTATUS status;
PDEVICE_OBJECT fido, fdo;
PDEVICE_EXTENSION pdx;
PDRIVER_OBJECT d;
status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),NULL,
FILE_DEVICE_UNKNOWN, 0, FALSE, &fido);
if (!NT_SUCCESS(status))
{
// can't create device object
LogPrintf("UsbSnoop - IoCreateDevice failed - %x\n", status);
return status;
}
// can't create device object
// Benoit PAPILLAULT 13/07/2001
// fido->DeviceExtension is a user define structure whose size is
passed
// to IoCreateDevice(). We can store whatever we want inside.
pdx = (PDEVICE_EXTENSION) fido->DeviceExtension;
// From this point forward, any error will have side effects that need
to
// be cleaned up. Using a try-finally block allows us to modify the
program
// easily without losing track of the side effects.
__try
{
IoInitializeRemoveLock(&pdx->RemoveLock, 0, 0, 255);
pdx->DeviceObject = fido;
pdx->Pdo = pdo;
fdo = IoAttachDeviceToDeviceStack(fido, pdo);
pdx->LowerDeviceObject = fdo;
fido->Flags |= fdo->Flags & (DO_DIRECT_IO | DO_BUFFERED_IO |
DO_POWER_PAGABLE | DO_POWER_INRUSH);
fido->DeviceType = fdo->DeviceType;
fido->Characteristics = fdo->Characteristics;
fido->AlignmentRequirement = fdo->AlignmentRequirement;
// Clear the "initializing" flag so that we can get IRPs
fido->Flags &= ~DO_DEVICE_INITIALIZING;
// we make a copy of fdo->DriverObject
d =
(PDRIVER_OBJECT)ExAllocatePool(NonPagedPool,sizeof(DRIVER_OBJECT));
if (d != NULL)
{
*d = *fdo->DriverObject;
// we make some changes to this copy
d->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
MyDispatchInternalIOCTL;
d->MajorFunction[IRP_MJ_PNP] = MyDispatchPnp;
// here is the trick : we save the original DriverObject
// and next, it points to our modified copy
pdx->OriginalDriverObject = fdo->DriverObject;
fdo->DriverObject = d;
}
else
}
__finally
{
if (!NT_SUCCESS(status))
{
IoDeleteDevice(fido);
}
}
return status;
}
NTSTATUS MyDispatchInternalIOCTL(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
{
// we want to recover OriginalDriverObject which is stored in fido,
// so we need to recover fido first, by the AttachedDevice field from
FDO.
PDEVICE_OBJECT fido = fdo->AttachedDevice;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fido->DeviceExtension;
// try to print the URB
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
ULONG dwControlCode = stack->Parameters.DeviceIoControl.IoControlCode;
if (dwControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB)
{
struct Buffer b;
ULONG uSequenceNumber =
InterlockedIncrement((PLONG)&pdx->uSequenceNumber);
BufferInit(&b);
BufferPrintf(&b," >>> URB %d going down >>> \n", uSequenceNumber);
// we cannot call ZwWriteFile() cause it must be running at
// IRQL_PASSIVE_LEVEL (0) and most of the time,
MyDispatchInternalIOCTL
// is running at IRQL_DISPATCH_LEVEL (2).
// LogPrintf(" KeGetCurrentIrql() = %d\n",KeGetCurrentIrql()));
// here we get URB
PURB pUrb = (PURB) stack->Parameters.Others.Argument1;
// inspired from the macro code of IoSetCompletionRoutine
// it just makes a big BSOD
// ok. in fact, it worked, but that particular case,
// the first parameter of the IoCompletionRoutine is NULL instead of
being fido !!!
// normally, there should be a call to
IoCopyCurrentIrpStackLocationToNext()
// which might not be there. So, we are surely replacing other
callbacks.
// first, we saved every information we'll modify later
PCONTEXT Context =
(PCONTEXT)ExAllocatePool(NonPagedPool,sizeof(CONTEXT));
if (Context != NULL)
{
Context->CompletionRoutine = stack->CompletionRoutine;
Context->Context = stack->Context;
Context->Control = stack->Control;
Context->pUrb = pUrb;
Context->uSequenceNumber = uSequenceNumber;
Context->Stack = stack;
stack->CompletionRoutine = MyInternalIOCTLCompletion;
stack->Context = Context;
stack->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR |
SL_INVOKE_ON_CANCEL;
}
else
LogPrintf(" ExAllocatePool failed! Can't redirect
CompletionRoutine\n");
LogBuffer(&b);
BufferDone(&b);
}
return
pdx->OriginalDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL](fdo,Irp);
}
-AJay
soviet_bloke@hotmail.com wrote:
> Doron,
>
>
> > many events? no, you can reuse the same event for the same sequence for the
> > same query since the 2 IOCTLs do not necessary need to be pended at the same
> > time. you can also use an IOCP to maximum CPU usage.
>
>
> You cannot do all that with a single event. First of all, there cannot
> be more than one outstanding IRP for IOCTL1 (because there is only one
> thread that deals with the user and sends IOCTLs), but multiple threads
> may be trying to create a section. Therefore, you need event1 to make
> sure that only one of them may complete IRP. After some thread has
> completed it, it has to wait for the reply, while all other threads
> keep on waiting one event1 . It cannot wait on event1, can it????
>
> In fact, it does not really matter how many events are there - the only
> thing that matters is that it the event may get signalled only in
> context of a thread that is owned by controller application, but
> threads that have nothing to do with our application wait on it. What
> happens if our application gets terminated abnormally????? The answer
> is obvious - from now on not a single process can get launched, so that
> we cannot even restart our app . The only way out is to reboot the
> machine
>
> > tightly spinning on a piece of memory is tremendously inefficient.
>
> Fully agree. However, don't forget that we deal with the HUMAN(!!!)
> response, so that we measure time in terms of SECONDS here. Therefore,
> we don't need to poll our buffer that tightly - say, twice a second is
> more than enough
>
> >and it
> > doesn't scale at all while the IRP solution easily scales to many
> > applications.
>
> Well, in fact we have to deal only with controller here......
>
> Anton Bassov
>
>
> Doron Holan [MS] wrote:
> > globals? no, you can use pseudo handles.
> > many events? no, you can reuse the same event for the same sequence for the
> > same query since the 2 IOCTLs do not necessary need to be pended at the same
> > time. you can also use an IOCP to maximum CPU usage.
> >
> > tightly spinning on a piece of memory is tremendously inefficient. and it
> > doesn't scale at all while the IRP solution easily scales to many
> > applications.
> >
> > d
> >
> > --
> > Please do not send e-mail directly to this alias. this alias is for
> > newsgroup purposes only.
> > This posting is provided "AS IS" with no warranties, and confers no rights.
> >
> >
> > <soviet_bloke@hotmail.com> wrote in message
> > news:1158039132.682453.121050@i3g2000cwc.googlegroups.com...
> > > Maxim,
> > >
> > >
> > > If you do it this way, you will need 2 IOCTLs and 3 synchronization
> > > events(all are originally in unsignalled state). When your driver
> > > receives IOCTL1, it signals event1, marks IRP as pending, and returns
> > > STATUS_PENDING. When some thread tries to create executable section, it
> > > waits on event1, then completes IRP and waits on event2. App gets the
> > > data, asks user's permission and sends IOCTL2 with the response. Driver
> > > writes a response into some global variable, signals event2 and waits
> > > on event3. The thread that tries to create a section checks the status
> > > of the variable, signals event3 and then either proceeds with the
> > > original request or aborts it. Once event3 gets signalled, your driver
> > > completes IOCTL2 request, and, at this point, app sends IOCTL1 again,
> > > so that the whole process starts over again.
> > >
> > > Seems to be fine and dandy, but consider what happens if app
> > > terminates......
> > >
> > > Now compare it to polling a shared buffer(certainly, with
> > > KeDelayExecutionTHread())from your driver in context of a thread that
> > > tries to create executable section. You have to poll it in _TRY block.
> > > If app terminates, the address of a buffer becomes meaningless, so that
> > > exception gets raised if you access it. Therefore,
> > > in such case you break out of the polling loop, and that's it (writing
> > > to the buffer also has to get done in _TRY block - if exception gets
> > > raised, you will never enter the polling loop, in the first place). I
> > > know polling is supposed to be bad design, due to performance reasons.
> > > However, in our case it just does not matter - we have to wait for the
> > > HUMAN(!!!) response, so that we measure time in terms of seconds
> > >
> > > In other words, everything depends on the situation - sometimes even
> > > "improper" design can have its own advantages
> > >
> > > Anton Bassov
> > >
> > >
> > >
> > >
> > >
> > > Maxim S. Shatskih wrote:
> > >> > Therefore, the question is following - how can it all be done by
> > >> > pending IRP, without
> > >> > any exchange buffer that is shared by app and driver????
> > >>
> > >> Pending IRP - data portion (request) from driver to app.
> > >> Some other IOCTL - data portion (response) from app to driver.
> > >>
> > >> --
> > >> Maxim Shatskih, Windows DDK MVP
> > >> StorageCraft Corporation
> > >> maxim@storagecraft.com
> > >>
http://www.storagecraft.com
> > >