|
|
#include "iopack.h"
#include "kernel.h"
#pragma LOCKEDCODE
NTSTATUS onRequestComplete(PDEVICE_OBJECT pDO,IN PIRP Irp, IN PVOID context) { //DBG_PRINT(" ======= Request completion Irp %8.8lX, Packet %8.8lX\n",Irp,context);
CIoPacket* packet = (CIoPacket*) context; if(packet) { return packet->onRequestComplete(); } return STATUS_MORE_PROCESSING_REQUIRED; }
#pragma PAGEDCODE
CIoPacket::CIoPacket(UCHAR StackSize) { m_Status = STATUS_INSUFFICIENT_RESOURCES; systemIrp = FALSE; m_DoNotFreeIrp = FALSE; CompletionEvent = NULL; IoStatus.Status = STATUS_SUCCESS; IoStatus.Information = 0; SystemBuffer = NULL; m_Irp = NULL; m_TimeOut = 60000;// Default timeout 60 seconds for any kind of IORequest
__try { debug = kernel->createDebug(); memory = kernel->createMemory(); event = kernel->createEvent(); irp = kernel->createIrp();
if( !ALLOCATED_OK(memory) || !ALLOCATED_OK(event) || !ALLOCATED_OK(irp)) __leave;
SystemBuffer = memory->allocate(NonPagedPool,PAGE_SIZE); if(!SystemBuffer) __leave; m_Irp = irp->allocate(StackSize+1, FALSE); if (!m_Irp) __leave; irp->initialize(m_Irp,irp->sizeOfIrp(StackSize+1),StackSize+1); Stack = *(irp->getNextStackLocation(m_Irp)); irp->setCompletionRoutine(m_Irp,CALLBACK_FUNCTION(onRequestComplete),NULL,TRUE,TRUE,TRUE); m_Status = STATUS_SUCCESS; } __finally { if(!NT_SUCCESS(m_Status)) { // Remove all allocated objects...
// In this constructor we know that it is not system Irp...
TRACE("FAILED TO CREATE IoPacket object %x\n",m_Status); TRACE("SystemBuffer - %x\n",SystemBuffer); TRACE("debug - %x, memory - %x\n",debug,memory); TRACE("event - %x, irp - %x\n",event,irp);
if(ALLOCATED_OK(memory)) { if(SystemBuffer) memory->free(SystemBuffer); SystemBuffer = NULL; }
if(ALLOCATED_OK(irp)) { if(m_Irp) irp->free(m_Irp); m_Irp = NULL; } DISPOSE_OBJECT(irp); DISPOSE_OBJECT(event); DISPOSE_OBJECT(memory); DISPOSE_OBJECT(debug); } } };
CIoPacket::CIoPacket(PIRP Irp) { m_Status = STATUS_INSUFFICIENT_RESOURCES; systemIrp = TRUE; m_DoNotFreeIrp = FALSE; CompletionEvent = NULL; IoStatus.Status = STATUS_SUCCESS; IoStatus.Information = 0; SystemBuffer = NULL; m_TimeOut = 60000;// Default timeout 60 seconds for any kind of IORequest
m_Irp = NULL;
__try { if(!Irp) __leave;
debug = kernel->createDebug(); memory = kernel->createMemory(); event = kernel->createEvent(); irp = kernel->createIrp();
if( !ALLOCATED_OK(memory) || !ALLOCATED_OK(event) || !ALLOCATED_OK(irp)) __leave; m_Irp = Irp; Stack = *(irp->getNextStackLocation(m_Irp)); SystemBuffer = m_Irp->AssociatedIrp.SystemBuffer; // We do not care here if system buffers is NULL
// but we will not copy data if it will be not initialized (NULL)
m_Status = STATUS_SUCCESS; } __finally { if(!NT_SUCCESS(m_Status)) { TRACE("FAILED TO CREATE IoPacket object %x\n",m_Status); TRACE("SystemBuffer - %x, Irp - %x\n",SystemBuffer,Irp); TRACE("debug - %x, memory - %x\n",debug,memory); TRACE("event - %x, irp - %x\n",event,irp); // Remove all allocated objects...
DISPOSE_OBJECT(irp); DISPOSE_OBJECT(event); DISPOSE_OBJECT(memory); DISPOSE_OBJECT(debug); } } };
CIoPacket::~CIoPacket() { if(!systemIrp) { if(SystemBuffer) memory->free(SystemBuffer); SystemBuffer = NULL; }
DISPOSE_OBJECT(irp); DISPOSE_OBJECT(event); DISPOSE_OBJECT(memory); DISPOSE_OBJECT(debug); };
VOID CIoPacket::setMajorIOCtl(UCHAR controlCode) { Stack.MajorFunction = controlCode; };
UCHAR CIoPacket::getMajorIOCtl() { return Stack.MajorFunction; }; VOID CIoPacket::setMinorIOCtl(UCHAR controlCode) { Stack.MinorFunction = controlCode; };
NTSTATUS CIoPacket::buildStack(PDEVICE_OBJECT DeviceObject, ULONG Major, UCHAR Minor, ULONG IoCtl, PVOID Context) { // Create copy of the next stack
if(!m_Irp) return STATUS_INVALID_DEVICE_STATE;
Stack = *(irp->getNextStackLocation(m_Irp)); Stack.DeviceObject = DeviceObject; switch(Major) { case IRP_MJ_INTERNAL_DEVICE_CONTROL: { // Set stack parameters...
Stack.MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; Stack.Parameters.Others.Argument1 = Context; Stack.Parameters.DeviceIoControl.IoControlCode = IoCtl; } break; case IRP_MJ_PNP: { // Set stack parameters...
Stack.MajorFunction = IRP_MJ_PNP; Stack.MinorFunction = Minor; if(Minor==IRP_MN_QUERY_CAPABILITIES) { Stack.Parameters.DeviceCapabilities.Capabilities = (PDEVICE_CAPABILITIES) Context; } } break; default: // Copy current stack location to next...
if(systemIrp) Stack = *(irp->getCurrentStackLocation(m_Irp)); else { Stack.DeviceObject = DeviceObject; Stack.MajorFunction = (UCHAR)Major; Stack.MinorFunction = Minor; } } return STATUS_SUCCESS; };
VOID CIoPacket::copyStackToNext() { PIO_STACK_LOCATION nextStack; if(!m_Irp) return;
nextStack = irp->getNextStackLocation(m_Irp); if(nextStack) *nextStack = Stack; };
VOID CIoPacket::copyCurrentStackToNext() { if(!m_Irp) return; irp->copyCurrentStackLocationToNext(m_Irp); }
// Function will set completion routine for the Irp.
VOID CIoPacket::setCompletion(PIO_COMPLETION_ROUTINE CompletionFunction) { PIO_COMPLETION_ROUTINE Completion; if(!m_Irp) return; Completion = CompletionFunction==NULL ? CALLBACK_FUNCTION(onRequestComplete) : CompletionFunction; if(m_Irp) irp->setCompletionRoutine(m_Irp,Completion,this,TRUE,TRUE,TRUE); };
VOID CIoPacket::setDefaultCompletionFunction() { if(m_Irp) irp->setCompletionRoutine(m_Irp,CALLBACK_FUNCTION(onRequestComplete),this,TRUE,TRUE,TRUE); };
NTSTATUS CIoPacket::copyBuffer(PUCHAR pBuffer, ULONG BufferLength) { if(!pBuffer || !BufferLength || BufferLength>PAGE_SIZE) return STATUS_INVALID_PARAMETER; if(m_Irp) { if(!systemIrp) { if(!m_Irp->AssociatedIrp.SystemBuffer) { if(!SystemBuffer) { SystemBuffer = memory->allocate(NonPagedPool,PAGE_SIZE); if(!SystemBuffer) return STATUS_INSUFFICIENT_RESOURCES; } m_Irp->AssociatedIrp.SystemBuffer = SystemBuffer; } }
if(m_Irp->AssociatedIrp.SystemBuffer) memory->copy(m_Irp->AssociatedIrp.SystemBuffer,pBuffer,BufferLength); else { TRACE(" ***** AssociatedIrp SYSTEM BUFFER IS NULL!\nFailed to copy bus driver reply with len %x!\n",BufferLength); } return STATUS_SUCCESS; } else return STATUS_INSUFFICIENT_RESOURCES; };
PIO_STACK_LOCATION CIoPacket::getStack() { return &Stack; };
PVOID CIoPacket::getBuffer() { return SystemBuffer; };
ULONG CIoPacket::getReadLength() { return Stack.Parameters.Read.Length; };
VOID CIoPacket::setWriteLength(ULONG length) { Stack.Parameters.Write.Length = length; };
VOID CIoPacket::setReadLength(ULONG length) { Stack.Parameters.Read.Length = length; };
ULONG CIoPacket::getWriteLength() { return Stack.Parameters.Write.Length; };
VOID CIoPacket::setInformation(ULONG_PTR information) { if(m_Irp) m_Irp->IoStatus.Information = information; IoStatus.Information = information; };
ULONG_PTR CIoPacket::getInformation() { return IoStatus.Information; };
VOID CIoPacket::updateInformation() { if(m_Irp) IoStatus.Information = m_Irp->IoStatus.Information; };
NTSTATUS CIoPacket::getSystemReply(PUCHAR pReply,ULONG Length) { if(!pReply || !Length || Length> PAGE_SIZE) return STATUS_INVALID_PARAMETER; if(SystemBuffer) { memory->copy(pReply,SystemBuffer,Length); return STATUS_SUCCESS; } else return STATUS_INSUFFICIENT_RESOURCES; };
#pragma LOCKEDCODE
NTSTATUS CIoPacket::onRequestComplete() { // Callback to finish previously sended request
TRACE(" =======> IoPacket processes Completion()\n"); if(systemIrp) { if (m_Irp->PendingReturned) { TRACE(" Irp marked as pending...\n"); irp->markPending(m_Irp); } }
IoStatus.Status = m_Irp->IoStatus.Status; IoStatus.Information = m_Irp->IoStatus.Information; TRACE(" Irp completes with status %8.8lX , info %8.8lX\n",IoStatus.Status,IoStatus.Information); if(!systemIrp) { if(!m_DoNotFreeIrp) { PIRP Irp = m_Irp; m_Irp = NULL; if(Irp) irp->free(Irp); } } if(CompletionEvent) event->set(CompletionEvent,IO_NO_INCREMENT,FALSE); return STATUS_MORE_PROCESSING_REQUIRED; };
#pragma PAGEDCODE
VOID CIoPacket::setCompletionEvent(PKEVENT CompletionEvent) { if(CompletionEvent) { this->CompletionEvent = CompletionEvent; } }
VOID CIoPacket::setStatus(NTSTATUS status) { IoStatus.Status = status; }
NTSTATUS CIoPacket::getStatus() { return IoStatus.Status; }
VOID CIoPacket::setDefaultCompletionEvent() { event->initialize(&DefaultCompletionEvent,NotificationEvent, FALSE); setCompletionEvent(&DefaultCompletionEvent); }
NTSTATUS CIoPacket::waitForCompletion() { // Set current timeout
return waitForCompletion(getTimeout()); }
NTSTATUS CIoPacket::waitForCompletion(LONG TimeOut) { // Because we set Alertable parameter to FALSE,
// there are only two possible statuses from the function STATUS_SUCCESS and
// STATUS_TIMEOUT...
// We should not try to cancel system Irps!
if(systemIrp) { NTSTATUS status; status = event->waitForSingleObject(CompletionEvent, Executive,KernelMode, FALSE, NULL); if(!NT_SUCCESS(status)) { TRACE("waitForCompletion() reports error %x\n", status); setStatus(STATUS_IO_TIMEOUT); setInformation(0); } status = getStatus(); return status; } else { LARGE_INTEGER timeout; timeout.QuadPart = -TimeOut * 10000; if (event->waitForSingleObject(CompletionEvent, Executive, KernelMode, FALSE, &timeout) == STATUS_TIMEOUT) { KIRQL oldIrql; // Ok! We've got timeout..
// Completion function still can be called.
// First tell completion not to free our Irp
IoAcquireCancelSpinLock(&oldIrql); if(m_Irp) m_DoNotFreeIrp = TRUE; IoReleaseCancelSpinLock(oldIrql); DEBUG_START(); TRACE("######## waitForCompletion() reports TIMEOUT after %d msec ############\n",getTimeout()); if(m_Irp) { irp->cancel(m_Irp); // okay in this context
// Wait for the cancel callback to be called
event->waitForSingleObject(CompletionEvent, Executive, KernelMode, FALSE, NULL); TRACE("######## Current Irp cancelled!!! ############\n"); // Now we can safely free our Irp
if(m_DoNotFreeIrp) { if(m_Irp) irp->free(m_Irp); m_Irp = NULL; m_DoNotFreeIrp = FALSE; } // Report Irp timeout
setStatus(STATUS_IO_TIMEOUT); setInformation(0); } } return getStatus(); } }
VOID CIoPacket::setStackDefaults() { setDefaultCompletionEvent(); copyStackToNext(); setDefaultCompletionFunction(); }
// Normally IoPacket will be created on the next stack location.
// The function allows to take current stack location.
// It is useful if we want to forward system IRP down the stack.
VOID CIoPacket::setCurrentStack() { if(m_Irp) Stack = *(irp->getCurrentStackLocation(m_Irp)); }
VOID CIoPacket::setTimeout(LONG TimeOut) { m_TimeOut = TimeOut; };
ULONG CIoPacket::getTimeout() { return m_TimeOut; };
|