|
|
#include "gpcpre.h"
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
ioctl.c
Abstract:
Creates symbolic link to receive ioctls from user mode and contains the ioctl case statement.
Author:
Yoram Bernet (yoramb) May, 7th. 1997
Environment:
Kernel Mode
Revision History:
Ofer Bar (oferbar) Oct 1, 1997 - revision II
--*/
#pragma hdrstop
VOID IoctlCleanup( ULONG ShutdownMask );
NTSTATUS GPCIoctl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
VOID CancelPendingIrpCfInfo( IN PDEVICE_OBJECT Device, IN PIRP Irp );
VOID CancelPendingIrpNotify( IN PDEVICE_OBJECT Device, IN PIRP Irp );
NTSTATUS ProxyGpcRegisterClient( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength, PFILE_OBJECT FileObject );
NTSTATUS ProxyGpcDeregisterClient( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength );
NTSTATUS ProxyGpcAddCfInfo( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength, PIRP Irp );
NTSTATUS ProxyGpcModifyCfInfo( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength, PIRP Irp );
NTSTATUS ProxyGpcRemoveCfInfo( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength, PIRP Irp );
NTSTATUS ProxyGpcAddPattern( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength );
NTSTATUS ProxyGpcRemovePattern( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength );
NTSTATUS ProxyGpcEnumCfInfo( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength );
GPC_CLIENT_FUNC_LIST CallBackProxyList; PDEVICE_OBJECT GPCDeviceObject; LIST_ENTRY PendingIrpCfInfoList; LIST_ENTRY PendingIrpNotifyList; LIST_ENTRY QueuedNotificationList; LIST_ENTRY QueuedCompletionList;
/* End Forward */
#pragma NDIS_PAGEABLE_FUNCTION(GPCIoctl)
UNICODE_STRING GpcDriverName = {sizeof(DD_GPC_DEVICE_NAME)-2, sizeof(DD_GPC_DEVICE_NAME), DD_GPC_DEVICE_NAME}; NTSTATUS IoctlInitialize( PDRIVER_OBJECT DriverObject, PULONG InitShutdownMask )
/*++
Routine Description:
Perform initialization
Arguments:
DriverObject - pointer to DriverObject from DriverEntry InitShutdownMask - pointer to mask used to indicate which events have been successfully init'ed
Return Value:
STATUS_SUCCESS if everything worked ok
--*/
{ NTSTATUS Status; UINT FuncIndex;
InitializeListHead(&PendingIrpCfInfoList); InitializeListHead(&PendingIrpNotifyList); InitializeListHead(&QueuedNotificationList); InitializeListHead(&QueuedCompletionList);
//
// Initialize the driver object's entry points
//
DriverObject->FastIoDispatch = NULL;
for (FuncIndex = 0; FuncIndex <= IRP_MJ_MAXIMUM_FUNCTION; FuncIndex++) { DriverObject->MajorFunction[FuncIndex] = GPCIoctl; }
Status = IoCreateDevice(DriverObject, 0, &GpcDriverName, FILE_DEVICE_NETWORK, FILE_DEVICE_SECURE_OPEN, FALSE, &GPCDeviceObject);
if ( NT_SUCCESS( Status )) {
*InitShutdownMask |= SHUTDOWN_DELETE_DEVICE;
GPCDeviceObject->Flags |= DO_BUFFERED_IO;
/* yoramb - don't need a symbolic link for now...
Status = IoCreateSymbolicLink( &GPCSymbolicName, &GPCDriverName );
if ( NT_SUCCESS( Status )) {
*InitShutdownMask |= SHUTDOWN_DELETE_SYMLINK; } else { DBGPRINT(IOCTL, ("IoCreateSymbolicLink Failed (%08X): %ls -> %ls\n", Status, GPCSymbolicName.Buffer, PSDriverName.Buffer)); } */ } else { DbgPrint("IoCreateDevice failed. Status = %x\n", Status); GPCDeviceObject = NULL; }
//
// Initialize the callback functions. These are called by the
// kernel Gpc and turned into async notifications to the user.
// For now, the user does not get callbacks, so they are NULL.
//
CallBackProxyList.GpcVersion = GpcMajorVersion; CallBackProxyList.ClAddCfInfoCompleteHandler = NULL; CallBackProxyList.ClAddCfInfoNotifyHandler = NULL; CallBackProxyList.ClModifyCfInfoCompleteHandler = NULL; CallBackProxyList.ClModifyCfInfoNotifyHandler = NULL; CallBackProxyList.ClRemoveCfInfoCompleteHandler = NULL; CallBackProxyList.ClRemoveCfInfoNotifyHandler = NULL;
return Status; }
NTSTATUS GPCIoctl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description:
Process the IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object Irp - pointer to an I/O Request Packet
Return Value:
None
--*/
{ PIO_STACK_LOCATION irpStack; PVOID ioBuffer; ULONG inputBufferLength; ULONG outputBufferLength; ULONG ioControlCode; UCHAR saveControlFlags; NTSTATUS Status = STATUS_SUCCESS; #if DBG
KIRQL irql = KeGetCurrentIrql(); KIRQL irql2; HANDLE thrd = PsGetCurrentThreadId(); #endif
PAGED_CODE();
//
// Init to default settings- we only expect 1 type of
// IOCTL to roll through here, all others an error.
//
Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation(Irp);
//
// Get the pointer to the input/output buffer and it's length
//
ioBuffer = Irp->AssociatedIrp.SystemBuffer; inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength; outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; saveControlFlags = irpStack->Control;
TRACE(LOCKS, thrd, irql, "GPCIoctl");
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE: DBGPRINT(IOCTL, ("IRP Create\n")); break;
case IRP_MJ_READ: DBGPRINT(IOCTL, ("IRP Read\n")); break;
case IRP_MJ_CLOSE: DBGPRINT(IOCTL, ("IRP Close\n")); TRACE(IOCTL, irpStack->FileObject, 0, "IRP Close");
//
// make sure we clean all the objects for this particular
// file object, since it's closing right now.
//
CloseAllObjects(irpStack->FileObject, Irp);
break;
case IRP_MJ_CLEANUP: DBGPRINT(IOCTL, ("IRP Cleanup\n")); break;
case IRP_MJ_SHUTDOWN: DBGPRINT(IOCTL, ("IRP Shutdown\n")); break;
case IRP_MJ_DEVICE_CONTROL:
DBGPRINT(IOCTL, ("GPCIoctl: ioctl=0x%X, IRP=0x%X\n", ioControlCode, (ULONG_PTR)Irp));
TRACE(IOCTL, ioControlCode, Irp, "GPCIoctl.irp:");
//
// Mark the IRP as Pending BEFORE calling any dispatch routine.
// If Status is actually set to STATUS_PENDING, we assume the IRP
// is ready to be returned.
// It is possible the IoCompleteRequest has been called async for the
// IRP, but this should be taken care of by the IO subsystem.
//
IoMarkIrpPending(Irp);
switch (ioControlCode) {
case IOCTL_GPC_REGISTER_CLIENT:
Status = ProxyGpcRegisterClient(ioBuffer, inputBufferLength, &outputBufferLength, irpStack->FileObject);
break; case IOCTL_GPC_DEREGISTER_CLIENT:
Status = ProxyGpcDeregisterClient(ioBuffer, inputBufferLength, &outputBufferLength);
break; case IOCTL_GPC_ADD_CF_INFO: Status = ProxyGpcAddCfInfo(ioBuffer, inputBufferLength, &outputBufferLength, Irp );
break; case IOCTL_GPC_MODIFY_CF_INFO: Status = ProxyGpcModifyCfInfo(ioBuffer, inputBufferLength, &outputBufferLength, Irp ); break; case IOCTL_GPC_REMOVE_CF_INFO: Status = ProxyGpcRemoveCfInfo(ioBuffer, inputBufferLength, &outputBufferLength, Irp ); break; case IOCTL_GPC_ADD_PATTERN: Status = ProxyGpcAddPattern(ioBuffer, inputBufferLength, &outputBufferLength); break; case IOCTL_GPC_REMOVE_PATTERN: Status = ProxyGpcRemovePattern(ioBuffer, inputBufferLength, &outputBufferLength); break; case IOCTL_GPC_ENUM_CFINFO: Status = ProxyGpcEnumCfInfo(ioBuffer, inputBufferLength, &outputBufferLength); break; case IOCTL_GPC_NOTIFY_REQUEST: //
// request to pend an IRP
//
Status = CheckQueuedNotification(Irp, &outputBufferLength);
break;
case IOCTL_GPC_GET_ENTRIES:
#ifdef STANDALONE_DRIVER
//
// Return the exported calls in the buffer
//
if (outputBufferLength >= sizeof(glGpcExportedCalls)) { NdisMoveMemory(ioBuffer, &glGpcExportedCalls, sizeof(glGpcExportedCalls));
outputBufferLength = sizeof(glGpcExportedCalls);
} else { outputBufferLength = sizeof(glGpcExportedCalls); Status = GPC_STATUS_INSUFFICIENT_BUFFER; } #else
Status = STATUS_INVALID_PARAMETER; #endif
break;
default: DBGPRINT(IOCTL, ("GPCIoctl: Unknown IRP_MJ_DEVICE_CONTROL\n = %X\n", ioControlCode));
Status = STATUS_INVALID_PARAMETER; break; } // switch (ioControlCode)
break;
default: DBGPRINT(IOCTL, ("GPCIoctl: Unknown IRP major function = %08X\n", irpStack->MajorFunction));
Status = STATUS_UNSUCCESSFUL; break; }
DBGPRINT(IOCTL, ("GPCIoctl: Status=0x%X, IRP=0x%X, outSize=%d\n", Status, (ULONG_PTR)Irp, outputBufferLength)); TRACE(IOCTL, Irp, Status, "GPCIoctl.Complete:");
if (Status != STATUS_PENDING) {
//
// IRP completed and it's not Pending, we need to restore the Control flags,
// since it might have been marked as Pending before...
//
irpStack->Control = saveControlFlags; Irp->IoStatus.Status = Status; Irp->IoStatus.Information = outputBufferLength; IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); }
#if DBG
irql2 = KeGetCurrentIrql(); ASSERT(irql == irql2); #endif
TRACE(LOCKS, thrd, irql2, "GPCIoctl (end)");
return Status;
} // GPCIoctl
VOID IoctlCleanup( ULONG ShutdownMask )
/*++
Routine Description:
Cleanup code for Initialize
Arguments:
ShutdownMask - mask indicating which functions need to be cleaned up
Return Value:
None
--*/
{ /*
if ( ShutdownMask & SHUTDOWN_DELETE_SYMLINK ) {
IoDeleteSymbolicLink( &PSSymbolicName ); } */
if ( ShutdownMask & SHUTDOWN_DELETE_DEVICE ) {
IoDeleteDevice( GPCDeviceObject ); } }
NTSTATUS ProxyGpcRegisterClient( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength, PFILE_OBJECT FileObject ) { NTSTATUS Status; PCLIENT_BLOCK pClient; PGPC_REGISTER_CLIENT_REQ GpcReq; PGPC_REGISTER_CLIENT_RES GpcRes;
if (inputBufferLength < sizeof(GPC_REGISTER_CLIENT_REQ) || *outputBufferLength < sizeof(GPC_REGISTER_CLIENT_RES) ) { return STATUS_BUFFER_TOO_SMALL; }
GpcReq = (PGPC_REGISTER_CLIENT_REQ)ioBuffer; GpcRes = (PGPC_REGISTER_CLIENT_RES)ioBuffer;
Status = GpcRegisterClient(GpcReq->CfId, GpcReq->Flags | GPC_FLAGS_USERMODE_CLIENT, GpcReq->MaxPriorities, &CallBackProxyList, GpcReq->ClientContext, (PGPC_HANDLE)&pClient);
ASSERT(Status != GPC_STATUS_PENDING);
if (Status == STATUS_SUCCESS) {
ASSERT(pClient);
pClient->pFileObject = FileObject;
GpcRes->ClientHandle = AllocateHandle(&pClient->ClHandle, (PVOID)pClient); }
GpcRes->Status = Status;
*outputBufferLength = sizeof(GPC_REGISTER_CLIENT_RES);
return STATUS_SUCCESS; } NTSTATUS ProxyGpcDeregisterClient( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength ) { NTSTATUS Status; PGPC_DEREGISTER_CLIENT_REQ GpcReq; PGPC_DEREGISTER_CLIENT_RES GpcRes; GPC_HANDLE GpcClientHandle;
if (inputBufferLength < sizeof(GPC_DEREGISTER_CLIENT_REQ) || *outputBufferLength < sizeof(GPC_DEREGISTER_CLIENT_RES) ) { return STATUS_BUFFER_TOO_SMALL; }
GpcReq = (PGPC_DEREGISTER_CLIENT_REQ)ioBuffer; GpcRes = (PGPC_DEREGISTER_CLIENT_RES)ioBuffer;
GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle, GPC_ENUM_CLIENT_TYPE, 'PGDC');
if (GpcClientHandle) {
Status = GpcDeregisterClient(GpcClientHandle);
} else {
Status = STATUS_INVALID_HANDLE; } if (GpcClientHandle) {
REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGDC'); }
ASSERT(Status != GPC_STATUS_PENDING);
GpcRes->Status = Status; *outputBufferLength = sizeof(GPC_DEREGISTER_CLIENT_RES); return STATUS_SUCCESS; }
NTSTATUS ProxyGpcAddCfInfo( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength, PIRP Irp ) { NTSTATUS Status; GPC_HANDLE GpcClientHandle; PGPC_ADD_CF_INFO_REQ GpcReq; PGPC_ADD_CF_INFO_RES GpcRes; PBLOB_BLOCK pBlob = NULL; QUEUED_COMPLETION QItem; UNICODE_STRING CfInfoName; USHORT NameLen = 0;
if (inputBufferLength < sizeof(GPC_ADD_CF_INFO_REQ) || *outputBufferLength < sizeof(GPC_ADD_CF_INFO_RES) ) { return STATUS_BUFFER_TOO_SMALL; }
GpcReq = (PGPC_ADD_CF_INFO_REQ)ioBuffer; GpcRes = (PGPC_ADD_CF_INFO_RES)ioBuffer;
if (GpcReq->CfInfoSize > inputBufferLength - FIELD_OFFSET(GPC_ADD_CF_INFO_REQ, CfInfo)) {
return STATUS_INVALID_BUFFER_SIZE; }
GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle, GPC_ENUM_CLIENT_TYPE, 'PGAC'); if (GpcClientHandle) {
Status = GpcAddCfInfo(GpcClientHandle, GpcReq->CfInfoSize, &GpcReq->CfInfo, GpcReq->ClientCfInfoContext, (PGPC_HANDLE)&pBlob);
if (NT_SUCCESS(Status)) {
//
// including PENDING
//
if (Status == GPC_STATUS_PENDING) {
QItem.OpCode = OP_ADD_CFINFO; QItem.ClientHandle = GpcClientHandle; QItem.CfInfoHandle = (GPC_HANDLE)pBlob;
Status = CheckQueuedCompletion(&QItem, Irp);
}
if (Status == GPC_STATUS_SUCCESS) { GPC_STATUS st = GPC_STATUS_FAILURE; GPC_CLIENT_HANDLE NotifiedClientCtx = pBlob->NotifiedClientCtx; PCLIENT_BLOCK pNotifiedClient = pBlob->pNotifiedClient;
GpcRes->GpcCfInfoHandle = (GPC_HANDLE)AllocateHandle(&pBlob->ClHandle, (PVOID)pBlob);
// what if we cant allocate a handle? fail the add!
if (!GpcRes->GpcCfInfoHandle) { GpcRemoveCfInfo(GpcClientHandle, pBlob);
Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; }
if (pNotifiedClient) {
if (pNotifiedClient->FuncList.ClGetCfInfoName && NotifiedClientCtx) { st = pNotifiedClient->FuncList.ClGetCfInfoName( pNotifiedClient->ClientCtx, NotifiedClientCtx, &CfInfoName ); if (CfInfoName.Length >= MAX_STRING_LENGTH * sizeof(WCHAR)) CfInfoName.Length = (MAX_STRING_LENGTH-1) * sizeof(WCHAR); //
// RajeshSu claims this can never happen.
//
ASSERT(NT_SUCCESS(st));
} } if (NT_SUCCESS(st)) { //
// copy the instance name
//
GpcRes->InstanceNameLength = NameLen = CfInfoName.Length; RtlMoveMemory(GpcRes->InstanceName, CfInfoName.Buffer, CfInfoName.Length ); } else { //
// generate a default name
//
if (NotifiedClientCtx) swprintf(GpcRes->InstanceName, L"Flow %08X", NotifiedClientCtx); else swprintf(GpcRes->InstanceName, L"Flow <unkonwn name>"); GpcRes->InstanceNameLength = NameLen = wcslen(GpcRes->InstanceName)*sizeof(WCHAR); } GpcRes->InstanceName[GpcRes->InstanceNameLength/sizeof(WCHAR)] = L'\0'; } else {
pBlob = NULL; }
}
//
// release the ref count we got earlier
//
exit:
REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGAC');
} else {
ASSERT(pBlob == NULL); Status = GPC_STATUS_INVALID_HANDLE; }
GpcRes->InstanceNameLength = NameLen; GpcRes->Status = Status; *outputBufferLength = sizeof(GPC_ADD_CF_INFO_RES);
return (Status == GPC_STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS; }
NTSTATUS ProxyGpcAddPattern( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength ) { NTSTATUS Status; GPC_HANDLE GpcClientHandle; GPC_HANDLE GpcCfInfoHandle; CLASSIFICATION_HANDLE ClassificationHandle; PGPC_ADD_PATTERN_REQ GpcReq; PGPC_ADD_PATTERN_RES GpcRes; PVOID Pattern; PVOID Mask; PPATTERN_BLOCK pPattern;
if (inputBufferLength < sizeof(GPC_ADD_PATTERN_REQ) || *outputBufferLength < sizeof(GPC_ADD_PATTERN_RES) ) { return STATUS_BUFFER_TOO_SMALL; }
GpcReq = (PGPC_ADD_PATTERN_REQ)ioBuffer; GpcRes = (PGPC_ADD_PATTERN_RES)ioBuffer;
if (GpcReq->PatternSize > MAX_PATTERN_SIZE) { return STATUS_INVALID_PARAMETER; }
if (inputBufferLength - FIELD_OFFSET(GPC_ADD_PATTERN_REQ, PatternAndMask) < 2 * GpcReq->PatternSize) { return STATUS_BUFFER_TOO_SMALL; }
GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle, GPC_ENUM_CLIENT_TYPE, 'PGAP'); GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE, 'PGAP'); if (GpcClientHandle && GpcCfInfoHandle) { Pattern = (PVOID)&GpcReq->PatternAndMask; Mask = (PVOID)((PCHAR)(&GpcReq->PatternAndMask) + GpcReq->PatternSize);
Status = GpcAddPattern(GpcClientHandle, GpcReq->ProtocolTemplate, Pattern, Mask, GpcReq->Priority, GpcCfInfoHandle, (PGPC_HANDLE)&pPattern, &ClassificationHandle);
if (Status == GPC_STATUS_SUCCESS) { ASSERT(Pattern);
GpcRes->GpcPatternHandle = AllocateHandle(&pPattern->ClHandle, (PVOID)pPattern);
//
// In certain circs, alloc_HF_handle could return 0.
// check for that and clean up the mess.
//
if (!GpcRes->GpcPatternHandle) {
//
// remove the pattern that was just added.
//
Status = GpcRemovePattern(GpcClientHandle, pPattern);
//
// This was really the problem why we got a NULL handle
//
Status = STATUS_INSUFFICIENT_RESOURCES;
} }
} else {
//
// Something went wrong and we dont know WHAT!!
//
Status = STATUS_INVALID_HANDLE; }
if (GpcCfInfoHandle) {
REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGAP'); }
if (GpcClientHandle) {
//
// release the ref count we got earlier
//
REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGAP'); }
ASSERT(Status != GPC_STATUS_PENDING);
GpcRes->Status = Status; GpcRes->ClassificationHandle = ClassificationHandle; *outputBufferLength = sizeof(GPC_ADD_PATTERN_RES);
return STATUS_SUCCESS; }
NTSTATUS ProxyGpcModifyCfInfo( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength, PIRP Irp ) { NTSTATUS Status; GPC_HANDLE GpcClientHandle; GPC_HANDLE GpcCfInfoHandle; PGPC_MODIFY_CF_INFO_REQ GpcReq; PGPC_MODIFY_CF_INFO_RES GpcRes; QUEUED_COMPLETION QItem;
if (inputBufferLength < sizeof(GPC_MODIFY_CF_INFO_REQ) || *outputBufferLength < sizeof(GPC_MODIFY_CF_INFO_RES) ) { return STATUS_BUFFER_TOO_SMALL; }
GpcReq = (PGPC_MODIFY_CF_INFO_REQ)ioBuffer; GpcRes = (PGPC_MODIFY_CF_INFO_RES)ioBuffer;
if (GpcReq->CfInfoSize > inputBufferLength - FIELD_OFFSET(GPC_MODIFY_CF_INFO_REQ, CfInfo)) {
return STATUS_INVALID_BUFFER_SIZE; }
GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle, GPC_ENUM_CLIENT_TYPE, 'PGMP'); GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE, 'PGMP'); if (GpcClientHandle && GpcCfInfoHandle) {
Status = GpcModifyCfInfo(GpcClientHandle, GpcCfInfoHandle, GpcReq->CfInfoSize, &GpcReq->CfInfo );
if (Status == GPC_STATUS_PENDING) { QItem.OpCode = OP_MODIFY_CFINFO; QItem.ClientHandle = GpcClientHandle; QItem.CfInfoHandle = GpcCfInfoHandle; Status = CheckQueuedCompletion(&QItem, Irp); }
} else {
Status = STATUS_INVALID_HANDLE; } if (GpcCfInfoHandle) {
REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGMP'); }
if (GpcClientHandle) {
//
// release the ref count we got earlier
//
REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGMP'); }
GpcRes->Status = Status; *outputBufferLength = sizeof(GPC_MODIFY_CF_INFO_RES);
return (Status == GPC_STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS; }
NTSTATUS ProxyGpcRemoveCfInfo( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength, PIRP Irp ) { NTSTATUS Status; GPC_HANDLE GpcClientHandle; GPC_HANDLE GpcCfInfoHandle; PGPC_REMOVE_CF_INFO_REQ GpcReq; PGPC_REMOVE_CF_INFO_RES GpcRes; QUEUED_COMPLETION QItem;
if (inputBufferLength < sizeof(GPC_REMOVE_CF_INFO_REQ) || *outputBufferLength < sizeof(GPC_REMOVE_CF_INFO_RES) ) { return STATUS_BUFFER_TOO_SMALL; }
GpcReq = (PGPC_REMOVE_CF_INFO_REQ)ioBuffer; GpcRes = (PGPC_REMOVE_CF_INFO_RES)ioBuffer;
GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle, GPC_ENUM_CLIENT_TYPE, 'PGRC'); GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE, 'PGRC'); if (GpcClientHandle && GpcCfInfoHandle) { Status = privateGpcRemoveCfInfo(GpcClientHandle, GpcCfInfoHandle, GPC_FLAGS_USERMODE_CLIENT ); if (Status == GPC_STATUS_PENDING) { QItem.OpCode = OP_REMOVE_CFINFO; QItem.ClientHandle = GpcClientHandle; QItem.CfInfoHandle = GpcCfInfoHandle; Status = CheckQueuedCompletion(&QItem, Irp); }
} else {
Status = STATUS_INVALID_HANDLE; } if (GpcCfInfoHandle) { //
// release the ref count we got earlier
//
REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGRC'); }
if (GpcClientHandle) {
//
// release the ref count we got earlier
//
REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGRC'); }
GpcRes->Status = Status; *outputBufferLength = sizeof(GPC_REMOVE_CF_INFO_RES); return (Status == GPC_STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS; }
NTSTATUS ProxyGpcRemovePattern( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength ) { NTSTATUS Status; GPC_HANDLE GpcClientHandle; GPC_HANDLE GpcPatternHandle; PGPC_REMOVE_PATTERN_REQ GpcReq; PGPC_REMOVE_PATTERN_RES GpcRes;
if (inputBufferLength < sizeof(GPC_REMOVE_PATTERN_REQ) || *outputBufferLength < sizeof(GPC_REMOVE_PATTERN_RES) ) { return STATUS_BUFFER_TOO_SMALL; }
GpcReq = (PGPC_REMOVE_PATTERN_REQ)ioBuffer; GpcRes = (PGPC_REMOVE_PATTERN_RES)ioBuffer;
GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle, GPC_ENUM_CLIENT_TYPE, 'PGRP'); GpcPatternHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcPatternHandle, GPC_ENUM_PATTERN_TYPE, 'PGRP'); if (GpcClientHandle && GpcPatternHandle) {
Status = GpcRemovePattern(GpcClientHandle, GpcPatternHandle);
} else {
//
// Something is wrong. Set the status to invalid handle!
//
Status = STATUS_INVALID_HANDLE; }
if (GpcPatternHandle) { REFDEL(&((PPATTERN_BLOCK)GpcPatternHandle)->RefCount, 'PGRP'); }
if (GpcClientHandle) {
//
// release the ref count we got earlier
//
REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGRP'); }
ASSERT(Status != GPC_STATUS_PENDING);
GpcRes->Status = Status; *outputBufferLength = sizeof(GPC_REMOVE_PATTERN_RES); return STATUS_SUCCESS; }
NTSTATUS ProxyGpcEnumCfInfo( PVOID ioBuffer, ULONG inputBufferLength, ULONG *outputBufferLength ) { NTSTATUS Status; PGPC_ENUM_CFINFO_REQ GpcReq; PGPC_ENUM_CFINFO_RES GpcRes; ULONG Size; ULONG TotalCount; GPC_HANDLE GpcClientHandle; GPC_HANDLE GpcCfInfoHandle; GPC_HANDLE EnumHandle; PBLOB_BLOCK pBlob;
if (inputBufferLength < sizeof(GPC_ENUM_CFINFO_REQ) || *outputBufferLength < sizeof(GPC_ENUM_CFINFO_RES) ) { return STATUS_BUFFER_TOO_SMALL; }
GpcReq = (PGPC_ENUM_CFINFO_REQ)ioBuffer; GpcRes = (PGPC_ENUM_CFINFO_RES)ioBuffer; GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle, GPC_ENUM_CLIENT_TYPE, 'PGEC');
GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->EnumHandle, GPC_ENUM_CFINFO_TYPE, 'PGEC'); if (GpcReq->EnumHandle != NULL && GpcCfInfoHandle == NULL) {
//
// the flow has been deleted during enumeration
//
Status = STATUS_DATA_ERROR;
} else if (GpcClientHandle) {
TotalCount = GpcReq->CfInfoCount; EnumHandle = GpcReq->EnumHandle; Size = *outputBufferLength - FIELD_OFFSET(GPC_ENUM_CFINFO_RES, EnumBuffer);
//
// save the blob pointer with the one extra ref count
// since we called GetHandleObjectWithRef
//
pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
Status = GpcEnumCfInfo(GpcClientHandle, &GpcCfInfoHandle, &EnumHandle, &TotalCount, &Size, GpcRes->EnumBuffer );
if (pBlob) {
REFDEL(&pBlob->RefCount, 'PGEC');
}
if (Status == GPC_STATUS_SUCCESS) {
//
// fill in the results
//
GpcRes->TotalCfInfo = TotalCount; GpcRes->EnumHandle = EnumHandle; *outputBufferLength = Size + FIELD_OFFSET(GPC_ENUM_CFINFO_RES, EnumBuffer); }
} else {
if (GpcCfInfoHandle) { REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGEC'); }
Status = STATUS_INVALID_HANDLE; }
if (GpcClientHandle) {
//
// release the ref count we got earlier
//
REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGEC'); }
ASSERT(Status != GPC_STATUS_PENDING);
GpcRes->Status = Status; return STATUS_SUCCESS; }
VOID CancelPendingIrpCfInfo( IN PDEVICE_OBJECT Device, IN PIRP Irp )
/*++
Routine Description:
Cancels an outstanding IRP request for a CfInfo request.
Arguments:
Device - The device on which the request was issued. Irp - Pointer to I/O request packet to cancel.
Return Value:
None
Notes:
This function is called with cancel spinlock held. It must be released before the function returns.
The cfinfo block associated with this request cannot be freed until the request completes. The completion routine will free it.
--*/
{ PPENDING_IRP pPendingIrp = NULL; PPENDING_IRP pItem; PLIST_ENTRY pEntry; #if DBG
KIRQL irql = KeGetCurrentIrql(); HANDLE thrd = PsGetCurrentThreadId(); #endif
DBGPRINT(IOCTL, ("CancelPendingIrpCfInfo: Irp=0x%X\n", (ULONG_PTR)Irp));
TRACE(IOCTL, Irp, 0, "CancelPendingIrpCfInfo:"); TRACE(LOCKS, thrd, irql, "CancelPendingIrpCfInfo:");
for ( pEntry = PendingIrpCfInfoList.Flink; pEntry != &PendingIrpCfInfoList; pEntry = pEntry->Flink ) {
pItem = CONTAINING_RECORD(pEntry, PENDING_IRP, Linkage);
if (pItem->Irp == Irp) {
pPendingIrp = pItem; GpcRemoveEntryList(pEntry);
IoSetCancelRoutine(pPendingIrp->Irp, NULL);
break; } }
IoReleaseCancelSpinLock(Irp->CancelIrql);
if (pPendingIrp != NULL) {
DBGPRINT(IOCTL, ("CancelPendingIrpCfInfo: found PendingIrp=0x%X\n", (ULONG_PTR)pPendingIrp));
TRACE(IOCTL, Irp, pPendingIrp, "CancelPendingIrpCfInfo.PendingIrp:");
//
// Free the PENDING_IRP structure. The control block will be freed
// when the request completes.
//
GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
//
// Complete the IRP.
//
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
} else {
DBGPRINT(IOCTL, ("CancelPendingIrpCfInfo: PendingIrp not found\n")); TRACE(IOCTL, Irp, 0, "CancelPendingIrpCfInfo.NoPendingIrp:");
}
#if DBG
irql = KeGetCurrentIrql(); #endif
TRACE(LOCKS, thrd, irql, "CancelPendingIrpCfInfo (end)");
return; }
VOID CancelPendingIrpNotify( IN PDEVICE_OBJECT Device, IN PIRP Irp )
/*++
Routine Description:
Cancels an outstanding IRP request for a notification.
Arguments:
Device - The device on which the request was issued. Irp - Pointer to I/O request packet to cancel.
Return Value:
None
Notes:
This function is called with cancel spinlock held. It must be released before the function returns.
--*/
{ PPENDING_IRP pPendingIrp = NULL; PPENDING_IRP pItem; PLIST_ENTRY pEntry; #if DBG
KIRQL irql = KeGetCurrentIrql(); HANDLE thrd = PsGetCurrentThreadId(); #endif
DBGPRINT(IOCTL, ("CancelPendingIrpNotify: Irp=0x%X\n", (ULONG_PTR)Irp)); TRACE(IOCTL, Irp, 0, "CancelPendingIrpNotify:"); TRACE(LOCKS, thrd, irql, "CancelPendingIrpNotify:");
for ( pEntry = PendingIrpNotifyList.Flink; pEntry != &PendingIrpNotifyList; pEntry = pEntry->Flink ) {
pItem = CONTAINING_RECORD(pEntry, PENDING_IRP, Linkage);
if (pItem->Irp == Irp) {
pPendingIrp = pItem; GpcRemoveEntryList(pEntry);
IoSetCancelRoutine(pPendingIrp->Irp, NULL);
break; } }
IoReleaseCancelSpinLock(Irp->CancelIrql);
if (pPendingIrp != NULL) {
DBGPRINT(IOCTL, ("CancelPendingIrpNotify: Found a PendingIrp=0x%X\n", (ULONG_PTR)pPendingIrp)); TRACE(IOCTL, Irp, pPendingIrp, "CancelPendingIrpNotify.PendingIrp:");
//
// Free the PENDING_IRP structure.
//
GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
//
// Complete the IRP.
//
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
} else {
DBGPRINT(IOCTL, ("CancelPendingIrpNotify: PendingIrp not found\n")); TRACE(IOCTL, Irp, 0, "CancelPendingIrpNotify.NoPendingIrp:"); }
#if DBG
irql = KeGetCurrentIrql(); #endif
TRACE(LOCKS, thrd, irql, "CancelPendingIrpNotify (end)");
return; }
VOID UMClientRemoveCfInfoNotify( IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob )
/*++
Routine Description:
Notify user mode client that the CfInfo is deleted. This will dequeue a pending IRP and will complete it. If there is no pending IRP, a GPC_NOTIFY_REQUEST_RES buffer will be queued until we get an IRP down the stack.
Arguments:
pClient - the notified client pBlob - the deleted cfinfo
Return Value:
None
--*/
{ KIRQL oldIrql; PIRP pIrp; PPENDING_IRP pPendingIrp = NULL; PLIST_ENTRY pEntry; PQUEUED_NOTIFY pQItem; PGPC_NOTIFY_REQUEST_RES GpcRes;
ASSERT(pClient == pBlob->pOwnerClient);
DBGPRINT(IOCTL, ("UMClientRemoveCfInfoNotify: pClient=0x%X, pBlob=0x%X\n", (ULONG_PTR)pClient, (ULONG_PTR)pBlob)); TRACE(IOCTL, pClient, pBlob, "UMClientRemoveCfInfoNotify:");
//
// Find the request IRP on the pending list.
//
IoAcquireCancelSpinLock(&oldIrql);
for ( pEntry = PendingIrpNotifyList.Flink; pEntry != &PendingIrpNotifyList; pEntry = pEntry->Flink ) {
pPendingIrp = CONTAINING_RECORD( pEntry, PENDING_IRP, Linkage);
if (pPendingIrp->FileObject == pClient->pFileObject) {
//
// that's the pending request
//
pIrp = pPendingIrp->Irp; IoSetCancelRoutine(pIrp, NULL); GpcRemoveEntryList(pEntry); break;
} else { pPendingIrp = NULL; } }
if (pPendingIrp == NULL) {
//
// No IRP, we need to queue the notification block
//
DBGPRINT(IOCTL, ("UMClientRemoveCfInfoNotify: No pending IRP found\n" )); TRACE(IOCTL, pClient->ClientCtx, pBlob->arClientCtx[pClient->AssignedIndex], "UMClientRemoveCfInfoNotify.NoPendingIrp:");
GpcAllocFromLL(&pQItem, &QueuedNotificationLL, QueuedNotificationTag);
if (pQItem) {
pQItem->FileObject = pClient->pFileObject;
//
// fill the item
//
pQItem->NotifyRes.ClientCtx = pClient->ClientCtx; pQItem->NotifyRes.NotificationCtx = (ULONG_PTR)pBlob->arClientCtx[pClient->AssignedIndex]; pQItem->NotifyRes.SubCode = GPC_NOTIFY_CFINFO_CLOSED; pQItem->NotifyRes.Reason = 0; // for now...
pQItem->NotifyRes.Param1 = 0; // for now...
GpcInsertTailList(&QueuedNotificationList, &pQItem->Linkage);
}
}
IoReleaseCancelSpinLock(oldIrql);
if (pPendingIrp) {
//
// found an IRP, fill and complete
//
DBGPRINT(IOCTL, ("UMClientRemoveCfInfoNotify: Pending IRP found=0x%X\n", (ULONG_PTR)pIrp)); TRACE(IOCTL, pClient->ClientCtx, pBlob->arClientCtx[pClient->AssignedIndex], "UMClientRemoveCfInfoNotify.PendingIrp:");
GpcRes = (PGPC_NOTIFY_REQUEST_RES)pIrp->AssociatedIrp.SystemBuffer;
GpcRes->ClientCtx = pClient->ClientCtx; GpcRes->NotificationCtx = (ULONG_PTR)pBlob->arClientCtx[pClient->AssignedIndex]; GpcRes->SubCode = GPC_NOTIFY_CFINFO_CLOSED; GpcRes->Reason = 0; // for now...
GpcRes->Param1 = 0; // for now...
//
// complete the IRP
//
pIrp->IoStatus.Information = sizeof(GPC_NOTIFY_REQUEST_REQ); pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
//
// We can free the pending irp item
//
GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
}
//
// for now - complete the operation
// we should probably let the User Mode client do it,
// but this complicates things a little...
//
GpcRemoveCfInfoNotifyComplete((GPC_HANDLE)pClient, (GPC_HANDLE)pBlob, GPC_STATUS_SUCCESS ); return; }
VOID UMCfInfoComplete( IN GPC_COMPLETION_OP OpCode, IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob, IN GPC_STATUS Status )
/*++
Routine Description:
This is the completion routine for any pending CfInfo request. It will search the pending IRP CfInfo list for a matching CfInfo structure that has been stored while the Add, Modify or Remove request returned PENDING. The client must be the CfInfo owner, otherwise we would have never got here. If an IRP is not found, it means the operation completed *before* we got back the PENDING status, which is perfectly legal. In this case, we queue a completion item and return.
Arguments:
OpCode - the code of the completion (add, modify or remove) pClient - the notified client pBlob - the deleted cfinfo Status - the reported status
Return Value:
None
--*/
{ typedef union _GPC_CF_INFO_RES { GPC_ADD_CF_INFO_RES AddRes; GPC_MODIFY_CF_INFO_RES ModifyRes; GPC_REMOVE_CF_INFO_RES RemoveRes; } GPC_CF_INFO_RES; KIRQL oldIrql; PIRP pIrp; PIO_STACK_LOCATION pIrpSp; PPENDING_IRP pPendingIrp = NULL; PLIST_ENTRY pEntry; GPC_CF_INFO_RES *GpcRes; ULONG outputBuferLength; //PQUEUED_COMPLETION pQItem;
//ASSERT(pClient == pBlob->pOwnerClient);
DBGPRINT(IOCTL, ("UMCfInfoComplete: pClient=0x%X, pBlob=0x%X, Status=0x%X\n", (ULONG_PTR)pClient, (ULONG_PTR)pBlob, Status)); TRACE(IOCTL, OpCode, pClient, "UMCfInfoComplete:"); TRACE(IOCTL, pBlob, Status, "UMCfInfoComplete:"); //
// Find the request IRP on the pending list.
//
IoAcquireCancelSpinLock(&oldIrql);
for ( pEntry = PendingIrpCfInfoList.Flink; pEntry != &PendingIrpCfInfoList; pEntry = pEntry->Flink ) {
pPendingIrp = CONTAINING_RECORD( pEntry, PENDING_IRP, Linkage);
if (pPendingIrp->QComp.CfInfoHandle == (GPC_HANDLE)pBlob && pPendingIrp->QComp.OpCode == OpCode ) {
//
// that's the pending request
//
pIrp = pPendingIrp->Irp; ASSERT(pIrp); IoSetCancelRoutine(pIrp, NULL); GpcRemoveEntryList(pEntry); break;
} else {
pPendingIrp = NULL; } }
if (pPendingIrp == NULL) {
//
// No IRP, we need to queue a completion block
//
DBGPRINT(IOCTL, ("UMCfInfoComplete: No pending IRP found\n")); TRACE(IOCTL, pBlob, Status, "UMCfInfoComplete.NoPendingIrp:");
GpcAllocFromLL(&pPendingIrp, &PendingIrpLL, PendingIrpTag);
if (pPendingIrp) {
pPendingIrp->Irp = NULL; pPendingIrp->FileObject = pClient->pFileObject; pPendingIrp->QComp.OpCode = OpCode; pPendingIrp->QComp.ClientHandle = (GPC_HANDLE)pClient; pPendingIrp->QComp.CfInfoHandle = (GPC_HANDLE)pBlob; pPendingIrp->QComp.Status = Status;
GpcInsertTailList(&QueuedCompletionList, &pPendingIrp->Linkage);
}
IoReleaseCancelSpinLock(oldIrql);
return; }
IoReleaseCancelSpinLock(oldIrql);
ASSERT(pPendingIrp && pIrp);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
GpcRes = (GPC_CF_INFO_RES *)pIrp->AssociatedIrp.SystemBuffer;
DBGPRINT(IOCTL, ("UMCfInfoComplete: Pending IRP found=0x%X, Ioctl=0x%X\n", (ULONG_PTR)pIrp, pIrpSp->Parameters.DeviceIoControl.IoControlCode ));
TRACE(IOCTL, pIrp, pIrpSp->Parameters.DeviceIoControl.IoControlCode, "UMCfInfoComplete.PendingIrp:");
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_GPC_ADD_CF_INFO:
ASSERT(OpCode == OP_ADD_CFINFO); ASSERT(pBlob->State == GPC_STATE_ADD);
GpcRes->AddRes.Status = Status;
GpcRes->AddRes.ClientCtx = pClient->ClientCtx; GpcRes->AddRes.CfInfoCtx = pBlob->OwnerClientCtx; GpcRes->AddRes.GpcCfInfoHandle = pBlob->ClHandle; if (Status == GPC_STATUS_SUCCESS) { UNICODE_STRING CfInfoName; if (pBlob->pNotifiedClient) { GPC_STATUS st = GPC_STATUS_FAILURE;
if (pBlob->pNotifiedClient->FuncList.ClGetCfInfoName) {
ASSERT(pBlob->NotifiedClientCtx);
pBlob->pNotifiedClient->FuncList.ClGetCfInfoName( pBlob->pNotifiedClient->ClientCtx, pBlob->NotifiedClientCtx, &CfInfoName ); if (CfInfoName.Length >= MAX_STRING_LENGTH * sizeof(WCHAR)) CfInfoName.Length = (MAX_STRING_LENGTH-1) * sizeof(WCHAR); }
if (!NT_SUCCESS(st)) {
//
// generate a default name
//
swprintf(CfInfoName.Buffer, L"Flow %08X", pBlob->NotifiedClientCtx); CfInfoName.Length = wcslen(CfInfoName.Buffer)*sizeof(WCHAR);
}
//
// copy the instance name
//
GpcRes->AddRes.InstanceNameLength = CfInfoName.Length; NdisMoveMemory(GpcRes->AddRes.InstanceName, CfInfoName.Buffer, CfInfoName.Length ); } }
outputBuferLength = sizeof(GPC_ADD_CF_INFO_RES); break;
case IOCTL_GPC_MODIFY_CF_INFO:
ASSERT(OpCode == OP_MODIFY_CFINFO); ASSERT(pBlob->State == GPC_STATE_MODIFY);
GpcRes->ModifyRes.Status = Status; GpcRes->ModifyRes.ClientCtx = pClient->ClientCtx; GpcRes->ModifyRes.CfInfoCtx = pBlob->OwnerClientCtx;
outputBuferLength = sizeof(GPC_MODIFY_CF_INFO_RES); break;
case IOCTL_GPC_REMOVE_CF_INFO:
ASSERT(OpCode == OP_REMOVE_CFINFO); ASSERT(pBlob->State == GPC_STATE_REMOVE);
GpcRes->RemoveRes.Status = Status; GpcRes->RemoveRes.ClientCtx = pClient->ClientCtx; GpcRes->RemoveRes.CfInfoCtx = pBlob->OwnerClientCtx;
outputBuferLength = sizeof(GPC_REMOVE_CF_INFO_RES); break; default: ASSERT(0); } GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
//
// Complete the IRP.
//
pIrp->IoStatus.Information = outputBuferLength; pIrp->IoStatus.Status = STATUS_SUCCESS;
DBGPRINT(IOCTL, ("UMCfInfoComplete: Completing IRP =0x%X, Status=0x%X\n", (ULONG_PTR)pIrp, Status ));
TRACE(IOCTL, pIrp, Status, "UMCfInfoComplete.Completing:");
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return; }
NTSTATUS CheckQueuedNotification( IN PIRP Irp, IN OUT ULONG *outputBufferLength ) /*++
Routine Description:
This routine will check for a queued notification structrue, and it will fill the ioBuffer in the IRP if one has been found and return STATUS_SUCCESS. This should cover the case where the IRP was not available when the notification was generated. O/w the routine returns STATUS_PENDING.
Arguments:
Irp - the incoming IRP
Return Value:
STATUS_SUCCESS or STATUS_PENDING
--*/
{ KIRQL oldIrql; PIO_STACK_LOCATION pIrpSp; PQUEUED_NOTIFY pQItem = NULL; PLIST_ENTRY pEntry; NTSTATUS Status; PPENDING_IRP pPendingIrp;
DBGPRINT(IOCTL, ("CheckQueuedNotification: IRP =0x%X\n", (ULONG_PTR)Irp));
TRACE(IOCTL, Irp, 0, "CheckQueuedNotification:");
if (*outputBufferLength < sizeof(GPC_NOTIFY_REQUEST_RES)) {
return STATUS_BUFFER_TOO_SMALL; }
pIrpSp = IoGetCurrentIrpStackLocation(Irp);
IoAcquireCancelSpinLock(&oldIrql);
for ( pEntry = QueuedNotificationList.Flink; pEntry != &QueuedNotificationList; pEntry = pEntry->Flink ) {
pQItem = CONTAINING_RECORD( pEntry, QUEUED_NOTIFY, Linkage);
if (pQItem->FileObject == pIrpSp->FileObject) {
//
// the queued item if for this file object
//
GpcRemoveEntryList(pEntry); break;
} else {
pQItem = NULL; } }
if (pQItem) {
//
// We found something on the queue, copy it to the IRP
// and delete the item
//
DBGPRINT(IOCTL, ("CheckQueuedNotification: found QItem =0x%X\n", (ULONG_PTR)pQItem));
TRACE(IOCTL, pQItem, pQItem->NotifyRes.ClientCtx, "CheckQueuedNotification.QItem:");
ASSERT(*outputBufferLength >= sizeof(GPC_NOTIFY_REQUEST_RES));
NdisMoveMemory(Irp->AssociatedIrp.SystemBuffer, &pQItem->NotifyRes, sizeof(GPC_NOTIFY_REQUEST_RES) );
GpcFreeToLL(pQItem, &QueuedNotificationLL, QueuedNotificationTag);
*outputBufferLength = sizeof(GPC_NOTIFY_REQUEST_RES);
Status = STATUS_SUCCESS;
} else {
DBGPRINT(IOCTL, ("CheckQueuedNotification: QItem not found...PENDING\n" ));
TRACE(IOCTL, 0, 0, "CheckQueuedNotification.NoQItem:");
GpcAllocFromLL(&pPendingIrp, &PendingIrpLL, PendingIrpTag);
if (pPendingIrp != NULL) {
//
// add the IRP on the pending notification list
//
DBGPRINT(IOCTL, ("CheckQueuedNotification: adding IRP=0x%X to list=0x%X\n", (ULONG_PTR)Irp, (ULONG_PTR)pIrpSp )); TRACE(IOCTL, Irp, pIrpSp, "CheckQueuedNotification.Irp:");
pPendingIrp->Irp = Irp; pPendingIrp->FileObject = pIrpSp->FileObject;
if (!Irp->Cancel) { IoSetCancelRoutine(Irp, CancelPendingIrpNotify); GpcInsertTailList(&PendingIrpNotifyList, &(pPendingIrp->Linkage));
Status = STATUS_PENDING;
} else {
DBGPRINT(IOCTL, ("CheckQueuedNotification: Status Cacelled: IRP=0x%X\n", (ULONG_PTR)Irp ));
TRACE(IOCTL, Irp, pIrpSp, "CheckQueuedNotification.Cancelled:"); GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
Status = STATUS_CANCELLED; }
} else {
Status = STATUS_INSUFFICIENT_RESOURCES; }
*outputBufferLength = 0; }
IoReleaseCancelSpinLock(oldIrql);
return Status; }
NTSTATUS CheckQueuedCompletion( IN PQUEUED_COMPLETION pQItem, IN PIRP Irp ) /*++
Routine Description:
This routine will check for a queued completion structrue with the same CfInfoHandle, and it will return it if found. The original queued memory block is release here. If not found, the returned status is PENDING, o/w the queued status is returned.
Arguments:
pQItem - pass in the CfInfoHandle and ClientHandle
Return Value:
Queued status or STATUS_PENDING
--*/
{ KIRQL oldIrql; PLIST_ENTRY pEntry; NTSTATUS Status; PPENDING_IRP pPendingIrp = NULL; PIO_STACK_LOCATION irpStack;
DBGPRINT(IOCTL, ("CheckQueuedCompletion: pQItem=0x%X\n", (ULONG_PTR)pQItem));
TRACE(IOCTL, pQItem->OpCode, pQItem->ClientHandle, "CheckQueuedCompletion:"); TRACE(IOCTL, pQItem->CfInfoHandle, pQItem->Status, "CheckQueuedCompletion:");
IoAcquireCancelSpinLock(&oldIrql);
for ( pEntry = QueuedCompletionList.Flink; pEntry != &QueuedCompletionList; pEntry = pEntry->Flink ) {
pPendingIrp = CONTAINING_RECORD( pEntry, PENDING_IRP, Linkage);
if ((pQItem->OpCode == OP_ANY_CFINFO || pQItem->OpCode == pPendingIrp->QComp.OpCode) && pPendingIrp->QComp.ClientHandle == (PVOID)pQItem->ClientHandle && pPendingIrp->QComp.CfInfoHandle == (PVOID)pQItem->CfInfoHandle) {
//
// the queued item if for this file object
// and the OpCode match
// and it has the same CfInfo memory pointer
//
GpcRemoveEntryList(pEntry); break;
} else {
pPendingIrp = NULL; } }
if (pPendingIrp) {
//
// get the status and free the queued completion item
//
DBGPRINT(IOCTL, ("CheckQueuedCompletion: found pPendingIrp=0x%X, Status=0x%X\n", (ULONG_PTR)pPendingIrp, pPendingIrp->QComp.Status));
TRACE(IOCTL, pPendingIrp->QComp.OpCode, pPendingIrp->QComp.ClientHandle, "CheckQueuedCompletion.Q:"); TRACE(IOCTL, pPendingIrp->QComp.CfInfoHandle, pPendingIrp->QComp.Status, "CheckQueuedCompletion.Q:");
#if DBG
if (pQItem->OpCode != OP_ANY_CFINFO) {
ASSERT(pPendingIrp->QComp.OpCode == pQItem->OpCode); ASSERT(pPendingIrp->QComp.ClientHandle == pQItem->ClientHandle); } #endif
Status = pPendingIrp->QComp.Status;
GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
} else {
DBGPRINT(IOCTL, ("CheckQueuedCompletion: pPendingIrp not found...PENDING\n" ));
TRACE(IOCTL, 0, 0, "CheckQueuedCompletion.NopQ:");
GpcAllocFromLL(&pPendingIrp, &PendingIrpLL, PendingIrpTag);
if (pPendingIrp != NULL) {
//
// add the IRP on the pending CfInfo list
//
irpStack = IoGetCurrentIrpStackLocation(Irp);
DBGPRINT(IOCTL, ("CheckQueuedCompletion: adding IRP=0x%X\n", (ULONG_PTR)Irp )); TRACE(IOCTL, Irp, irpStack, "CheckQueuedCompletion.Irp:");
pPendingIrp->Irp = Irp; pPendingIrp->FileObject = irpStack->FileObject; pPendingIrp->QComp.OpCode = pQItem->OpCode; pPendingIrp->QComp.ClientHandle = pQItem->ClientHandle; pPendingIrp->QComp.CfInfoHandle = pQItem->CfInfoHandle; pPendingIrp->QComp.Status = pQItem->Status;
if (!Irp->Cancel) { IoSetCancelRoutine(Irp, CancelPendingIrpCfInfo); GpcInsertTailList(&PendingIrpCfInfoList, &(pPendingIrp->Linkage));
Status = STATUS_PENDING;
} else {
DBGPRINT(IOCTL, ("CheckQueuedCompletion: Status Cacelled: IRP=0x%X\n", (ULONG_PTR)Irp ));
TRACE(IOCTL, Irp, irpStack, "CheckQueuedCompletion.Cancelled:"); GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
Status = STATUS_CANCELLED; }
} else {
Status = STATUS_INSUFFICIENT_RESOURCES; } }
IoReleaseCancelSpinLock(oldIrql);
return Status; }
/* end ioctl.c */
|