Hi,
This is my first driver project. I need to write an upper filter
driver for a serial port which is dynamically loaded from a test
application when required. The driver will be loaded by means of the
Service Control Manager and the driver will connect to the serial port
by means of a special "start" IOCTL call from the test application
using the DeviceIoControl() function, this will pass the name of the
serial port device i.e. \??\COM4". The driver will attach to the named
device leaving it in a state where it can still be opened by a 3rd
party application.
When loaded the driver will monitor incoming and outgoing data on the
port and pass it back to the test application.
I have used two of Walt Oney's sample projects as a starting point for
my code.
My driver loads and unloads OK but when I attempt to open the serial
port from a 3rd party application (Hyperterminal in this case) I get a
bugcheck as described below.
I have included here the "bones" of the DriverEntry, AddDevice and
DispatchAny functions.
The bugcheck occurs at point XXX at the bottom of the DispatchControl
function. I guess I have "broken" the IRP in some way but I don't know
how.
I can't see what the problem is but I am hoping that someone on this
group will be able to see what I can't.
Any help will be gratefully received.
Sorry for such a long post.
Many thanks
O.C.
**** DriverEntry Funtion
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN
PUNICODE_STRING RegistryPath)
{
// Save the name of the service key
servkey.Buffer = (PWSTR) ExAllocatePool(PagedPool,
RegistryPath->Length + sizeof(WCHAR));
if(!servkey.Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
servkey.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
RtlCopyUnicodeString(&servkey, RegistryPath);
servkey.Buffer[RegistryPath->Length / 2] = 0;
// Initialize function pointers
DriverObject->DriverUnload = DriverUnload;
for (int i = 0; i < arraysize(DriverObject->MajorFunction); ++i)
DriverObject->MajorFunction[i] = DispatchControl;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
// Create a device object to allow an associated application to open
a handle
// in order to send us IOCTL requests
status = AddDevice(DriverObject);
if(!NT_SUCCESS(status))
DriverUnload(DriverObject);
return status;
}
**** AddDevice Function
NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject)
{
PAGED_CODE();
KdPrint((DRIVERNAME " AddDevice(%8.8lX) - Start\n", DriverObject));
NTSTATUS status;
// Create a function device object to represent the hardware we're
managing.
PDEVICE_OBJECT fdo;
UNICODE_STRING devname;
RtlInitUnicodeString(&devname, L"\\DosDevices\\NetMonSerW2kD");
status = IoCreateDevice(DriverObject,
sizeof(DEVICE_EXTENSION),
&devname,
FILE_DEVICE_SERIAL_PORT,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&fdo);
if (!NT_SUCCESS(status))
{
KdPrint((DRIVERNAME " - IoCreateDevice failed - %X\n", status));
return status;
}
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
// From this point forward, any error will have side effects that
need to
// be cleaned up.
do
{
pdx->DeviceObject = fdo;
pdx->DriverObject = DriverObject;
InitializeListHead(&pdx->registered);
InitializeListHead(&pdx->events);
KeInitializeSpinLock(&pdx->eventlock);
// Make a copy of the device name
pdx->devname.Buffer = (PWCHAR) ExAllocatePool(NonPagedPool,
devname.MaximumLength);
if (!pdx->devname.Buffer)
{ // can't allocate buffer
status = STATUS_INSUFFICIENT_RESOURCES;
KdPrint((DRIVERNAME " - Unable to allocate %d bytes for copy of
name\n", devname.MaximumLength));
break;;
} // can't allocate buffer
pdx->devname.MaximumLength = devname.MaximumLength;
RtlCopyUnicodeString(&pdx->devname, &devname);
// Not sure about this bit.
KeInitializeEvent(&pdx->RemoveLock.evRemove, NotificationEvent,
FALSE);
pdx->RemoveLock.usage = 1;
pdx->RemoveLock.removing = FALSE;
}
while (FALSE);
if(!NT_SUCCESS(status))
{
if (pdx->devname.Buffer)
RtlFreeUnicodeString(&pdx->devname);
IoDeleteDevice(fdo);
}
return status;
}
**** DispatchControl Function
NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp)
{
PAGED_CODE();
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
NTSTATUS status = STATUS_SUCCESS;
ULONG info = 0;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
KdPrint(("\n"DRIVERNAME " DispatchControl() - Irp=%08X IOCTL =
%08X\n",Irp,code));
switch(code)
{
case IOCTL_NETMON_STARTMON:
{
// Copy passed-in data to a unicode string.
// (This will be something like "\??\COM4").
UNICODE_STRING PortName;
WCHAR wPortName[32];
swprintf(wPortName,(WCHAR*)Irp->AssociatedIrp.SystemBuffer,cbin);
RtlInitUnicodeString(&PortName,wPortName);
PFILE_OBJECT FileObject = NULL; // Will be filled in with
pointer to a file object.
PDEVICE_OBJECT DeviceObject = NULL; // Will be filled in with
pointer to a device object.
status=IoGetDeviceObjectPointer(&PortName,
FILE_READ_DATA,
&FileObject,
&DeviceObject);
if(status!=STATUS_SUCCESS)
{
KdPrint((DRIVERNAME " DispatchControl() - Error=%08X\n",status));
break;
}
// "\??\COM4"
if(!FileObject)
break;
if(!DeviceObject)
break;
pdx->Pdo = DeviceObject; // The current device.
// Now attach our device to the device stack.
// Attach our object (which we created with IoCreateDevice() in the
// AddDevice() function and which has been passed to us as the "fdo"
// parameter) to the object we just obtained a pointer to.
// Save a pointer to the device beneath us so we can pass stuff on
to it.
// Attach OUR device object (fdo) to the curent device (ie for
COM4).
pdx->LowerDeviceObject =
IoAttachDeviceToDeviceStack(fdo,DeviceObject);
// Stuff from page 781 of Walt's book...
fdo->Flags |= pdx->LowerDeviceObject->Flags & (DO_DIRECT_IO |
DO_BUFFERED_IO | DO_POWER_PAGABLE);
if(!pdx->LowerDeviceObject)
{
KdPrint((DRIVERNAME " DispatchControl() - Failed to attach\n"));
ObDereferenceObject(FileObject);
break;
}
ObDereferenceObject(FileObject); // Close port again.
status = STATUS_SUCCESS;
info = 0;
KdPrint((DRIVERNAME " DispatchControl() - IOCTL_NETMON_STARTMON
(End)\n"));
break;
}
/***********/
/* Default */
/***********/
default:
KdPrint((DRIVERNAME " DispatchControl() - Default Start\n"));
static char* irpname[] =
{
"IRP_MJ_CREATE",
"IRP_MJ_CREATE_NAMED_PIPE",
"IRP_MJ_CLOSE",
"IRP_MJ_READ",
"IRP_MJ_WRITE",
"IRP_MJ_QUERY_INFORMATION",
"IRP_MJ_SET_INFORMATION",
"IRP_MJ_QUERY_EA",
"IRP_MJ_SET_EA",
"IRP_MJ_FLUSH_BUFFERS",
"IRP_MJ_QUERY_VOLUME_INFORMATION",
"IRP_MJ_SET_VOLUME_INFORMATION",
"IRP_MJ_DIRECTORY_CONTROL",
"IRP_MJ_FILE_SYSTEM_CONTROL",
"IRP_MJ_DEVICE_CONTROL",
"IRP_MJ_INTERNAL_DEVICE_CONTROL",
"IRP_MJ_SHUTDOWN",
"IRP_MJ_LOCK_CONTROL",
"IRP_MJ_CLEANUP",
"IRP_MJ_CREATE_MAILSLOT",
"IRP_MJ_QUERY_SECURITY",
"IRP_MJ_SET_SECURITY",
"IRP_MJ_POWER",
"IRP_MJ_SYSTEM_CONTROL",
"IRP_MJ_DEVICE_CHANGE",
"IRP_MJ_QUERY_QUOTA",
"IRP_MJ_SET_QUOTA",
"IRP_MJ_PNP",
};
UCHAR type = stack->MajorFunction;
if (type >= arraysize(irpname))
KdPrint((DRIVERNAME " Unknown IRP, major type %X\n", type));
else
KdPrint((DRIVERNAME " %s\n", irpname[type]));
// Pass request down without additional processing
NTSTATUS status;
KdPrint((DRIVERNAME " DispatchControl() Def - Calling
IoAcquireRemoveLock(%08X,%08X)\n",pdx->RemoveLock,Irp));
status = IoAcquireRemoveLock(&pdx->RemoveLock,Irp);
KdPrint((DRIVERNAME " DispatchControl() Def - IoAcquireRemoveLock()
acquired %08X and returns %08X\n",pdx->RemoveLock,status));
if (!NT_SUCCESS(status))
return CompleteRequest(Irp, status, 0);
// If there is no lower device object supplied.
if(pdx->LowerDeviceObject==NULL)
{
KdPrint((DRIVERNAME " DispatchControl() Def - No LDO so exit
now\n"));
status=STATUS_SUCCESS;
break;
}
IoSkipCurrentIrpStackLocation(Irp);
KdPrint((DRIVERNAME " DispatchControl() Def - Calling
IoCallDriver(%08X,%08X)\n",pdx->LowerDeviceObject,Irp));
status = IoCallDriver(pdx->LowerDeviceObject,Irp);
KdPrint((DRIVERNAME " DispatchControl() Def - IoCallDriver() returns
%08X\n",status));
if(Irp)
{
IoReleaseRemoveLock(&pdx->RemoveLock,Irp);
}
KdPrint((DRIVERNAME " DispatchControl() Def - End\n"));
break;
}
XXX Bugcheck DRIVER_PAGE_FAULT_IN_FREED_MEMORY_POOL when next
instruction is executed.
The Irp pointer is still the same so I guess the memory it points to
has been released.
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
} // DispatchControl