📄 irp.c
字号:
return NULL;
}
/* Copy into the System Buffer */
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
InputBuffer,
InputBufferLength);
/* Write the flags */
Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
}
else
{
Irp->Flags = 0;
}
/* Check if we got an output buffer */
if (OutputBuffer)
{
/* Allocate the System Buffer */
Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
OutputBufferLength,
FALSE,
FALSE,
Irp);
if (!Irp->MdlAddress)
{
/* Free the IRP and fail */
IoFreeIrp(Irp);
return NULL;
}
/* Probe and Lock */
_SEH_TRY
{
/* Do the probe */
MmProbeAndLockPages(Irp->MdlAddress,
KernelMode,
IO_METHOD_FROM_CTL_CODE(IoControlCode) ==
METHOD_IN_DIRECT ?
IoReadAccess : IoWriteAccess);
}
_SEH_HANDLE
{
/* Free the MDL */
IoFreeMdl(Irp->MdlAddress);
/* Free the input buffer and IRP */
if (InputBuffer) ExFreePool(Irp->AssociatedIrp.SystemBuffer);
IoFreeIrp(Irp);
Irp = NULL;
}
_SEH_END;
/* This is how we know if probing failed */
if (!Irp) return NULL;
}
break;
case METHOD_NEITHER:
/* Just save the Buffer */
Irp->UserBuffer = OutputBuffer;
StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
}
/* Now write the Event and IoSB */
Irp->UserIosb = IoStatusBlock;
Irp->UserEvent = Event;
/* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
IoQueueThreadIrp(Irp);
/* Return the IRP */
IOTRACE(IO_IRP_DEBUG,
"%s - Built IRP %p with IOCTL, Buffers, DO %lx %p %p %p\n",
__FUNCTION__,
Irp,
IoControlCode,
InputBuffer,
OutputBuffer,
DeviceObject);
return Irp;
}
/*
* @implemented
*/
PIRP
NTAPI
IoBuildSynchronousFsdRequest(IN ULONG MajorFunction,
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER StartingOffset,
IN PKEVENT Event,
IN PIO_STATUS_BLOCK IoStatusBlock)
{
PIRP Irp;
/* Do the big work to set up the IRP */
Irp = IoBuildAsynchronousFsdRequest(MajorFunction,
DeviceObject,
Buffer,
Length,
StartingOffset,
IoStatusBlock );
if (!Irp) return NULL;
/* Set the Event which makes it Syncronous */
Irp->UserEvent = Event;
/* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
IoQueueThreadIrp(Irp);
return Irp;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
IoCancelIrp(IN PIRP Irp)
{
KIRQL OldIrql;
PDRIVER_CANCEL CancelRoutine;
IOTRACE(IO_IRP_DEBUG,
"%s - Canceling IRP %p\n",
__FUNCTION__,
Irp);
ASSERT(Irp->Type == IO_TYPE_IRP);
/* Acquire the cancel lock and cancel the IRP */
IoAcquireCancelSpinLock(&OldIrql);
Irp->Cancel = TRUE;
/* Clear the cancel routine and get the old one */
CancelRoutine = IoSetCancelRoutine(Irp, NULL);
if (CancelRoutine)
{
/* We had a routine, make sure the IRP isn't completed */
if (Irp->CurrentLocation > (Irp->StackCount + 1))
{
/* It is, bugcheck */
KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP,
(ULONG_PTR)Irp,
0,
0,
0);
}
/* Set the cancel IRQL And call the routine */
Irp->CancelIrql = OldIrql;
CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp);
return TRUE;
}
/* Otherwise, release the cancel lock and fail */
IoReleaseCancelSpinLock(OldIrql);
return FALSE;
}
/*
* @implemented
*/
VOID
NTAPI
IoCancelThreadIo(IN PETHREAD Thread)
{
KIRQL OldIrql;
ULONG Retries = 3000;
LARGE_INTEGER Interval;
PLIST_ENTRY ListHead, NextEntry;
PIRP Irp;
IOTRACE(IO_IRP_DEBUG,
"%s - Canceling IRPs for Thread %p\n",
__FUNCTION__,
Thread);
/* Raise to APC to protect the IrpList */
OldIrql = KfRaiseIrql(APC_LEVEL);
/* Start by cancelling all the IRPs in the current thread queue. */
ListHead = &Thread->IrpList;
NextEntry = ListHead->Flink;
while (ListHead != NextEntry)
{
/* Get the IRP */
Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
/* Cancel it */
IoCancelIrp(Irp);
/* Move to the next entry */
NextEntry = NextEntry->Flink;
}
/* Wait 100 milliseconds */
Interval.QuadPart = -1000000;
/* Wait till all the IRPs are completed or cancelled. */
while (!IsListEmpty(&Thread->IrpList))
{
/* Now we can lower */
KfLowerIrql(OldIrql);
/* Wait a short while and then look if all our IRPs were completed. */
KeDelayExecutionThread(KernelMode, FALSE, &Interval);
/*
* Don't stay here forever if some broken driver doesn't complete
* the IRP.
*/
if (!(Retries--)) IopRemoveThreadIrp();
/* Raise the IRQL Again */
OldIrql = KfRaiseIrql(APC_LEVEL);
}
/* We're done, lower the IRQL */
KfLowerIrql(OldIrql);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoCallDriver(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
/* Call fast call */
return IofCallDriver(DeviceObject, Irp);
}
/*
* @implemented
*/
VOID
NTAPI
IoCompleteRequest(IN PIRP Irp,
IN CCHAR PriorityBoost)
{
/* Call the fastcall */
IofCompleteRequest(Irp, PriorityBoost);
}
/*
* @implemented
*/
VOID
NTAPI
IoEnqueueIrp(IN PIRP Irp)
{
/* This is the same as calling IoQueueThreadIrp */
IoQueueThreadIrp(Irp);
}
/*
* @implemented
*/
NTSTATUS
FASTCALL
IofCallDriver(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDRIVER_OBJECT DriverObject;
PIO_STACK_LOCATION Param;
/* Get the Driver Object */
DriverObject = DeviceObject->DriverObject;
/* Decrease the current location and check if */
Irp->CurrentLocation--;
if (Irp->CurrentLocation <= 0)
{
/* This IRP ran out of stack, bugcheck */
KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR)Irp, 0, 0, 0);
}
/* Now update the stack location */
Param = IoGetNextIrpStackLocation(Irp);
Irp->Tail.Overlay.CurrentStackLocation = Param;
/* Get the Device Object */
Param->DeviceObject = DeviceObject;
/* Call it */
return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject,
Irp);
}
FORCEINLINE
VOID
IopClearStackLocation(IN PIO_STACK_LOCATION IoStackLocation)
{
IoStackLocation->MinorFunction = 0;
IoStackLocation->Flags = 0;
IoStackLocation->Control &= SL_ERROR_RETURNED;
IoStackLocation->Parameters.Others.Argument1 = 0;
IoStackLocation->Parameters.Others.Argument2 = 0;
IoStackLocation->Parameters.Others.Argument3 = 0;
IoStackLocation->FileObject = NULL;
}
/*
* @implemented
*/
VOID
FASTCALL
IofCompleteRequest(IN PIRP Irp,
IN CCHAR PriorityBoost)
{
PIO_STACK_LOCATION StackPtr, LastStackPtr;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
PETHREAD Thread;
NTSTATUS Status;
PMDL Mdl, NextMdl;
ULONG MasterCount;
PIRP MasterIrp;
ULONG Flags;
NTSTATUS ErrorCode = STATUS_SUCCESS;
IOTRACE(IO_IRP_DEBUG,
"%s - Completing IRP %p\n",
__FUNCTION__,
Irp);
/* Make sure this IRP isn't getting completed twice or is invalid */
if ((Irp->CurrentLocation) > (Irp->StackCount + 1))
{
/* Bugcheck */
KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR)Irp, 0, 0, 0);
}
/* Some sanity checks */
ASSERT(Irp->Type == IO_TYPE_IRP);
ASSERT(!Irp->CancelRoutine);
ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
ASSERT(Irp->IoStatus.Status != 0xFFFFFFFF);
/* Get the last stack */
LastStackPtr = (PIO_STACK_LOCATION)(Irp + 1);
if (LastStackPtr->Control & SL_ERROR_RETURNED)
{
/* Get the error code */
ErrorCode = (NTSTATUS)LastStackPtr->Parameters.Others.Argument4;
}
/* Get the Current Stack and skip it */
StackPtr = IoGetCurrentIrpStackLocation(Irp);
IoSkipCurrentIrpStackLocation(Irp);
/* Loop the Stacks and complete the IRPs */
do
{
/* Set Pending Returned */
Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED;
/* Check if we failed */
if (!NT_SUCCESS(Irp->IoStatus.Status))
{
/* Check if it was changed by a completion routine */
if (Irp->IoStatus.Status != ErrorCode)
{
/* Update the error for the current stack */
ErrorCode = Irp->IoStatus.Status;
StackPtr->Control |= SL_ERROR_RETURNED;
LastStackPtr->Parameters.Others.Argument4 = (PVOID)ErrorCode;
LastStackPtr->Control |= SL_ERROR_RETURNED;
}
}
/* Check if there is a Completion Routine to Call */
if ((NT_SUCCESS(Irp->IoStatus.Status) &&
(StackPtr->Control & SL_INVOKE_ON_SUCCESS)) ||
(!NT_SUCCESS(Irp->IoStatus.Status) &&
(StackPtr->Control & SL_INVOKE_ON_ERROR)) ||
(Irp->Cancel &&
(StackPtr->Control & SL_INVOKE_ON_CANCEL)))
{
/* Clear the stack location */
IopClearStackLocation(StackPtr);
/* Check for highest-level device completion routines */
if (Irp->CurrentLocation == (Irp->StackCount + 1))
{
/* Clear the DO, since the current stack location is invalid */
DeviceObject = NULL;
}
else
{
/* Otherwise, return the real one */
DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
}
/* Call the completion routine */
Status = StackPtr->CompletionRoutine(DeviceObject,
Irp,
StackPtr->Context);
/* Don't touch the Packet in this case, since it might be gone! */
if (Status == STATUS_MORE_PROCESSING_REQUIRED) return;
}
else
{
/* Otherwise, check if this is a completed IRP */
if ((Irp->CurrentLocation <= Irp->StackCount) &&
(Irp->PendingReturned))
{
/* Mark it as pending */
IoMarkIrpPending(Irp);
}
/* Clear the stack location */
IopClearStackLocation(StackPtr);
}
/* Move to next stack location and pointer */
IoSkipCurrentIrpStackLocation(Irp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -