//--------------------------------------------------------------------------- // // Module: ins.cpp // // Description: // // KS Instance base class definitions // //@@BEGIN_MSINTERNAL // Development Team: // Mike McLaughlin // // History: Date Author Comment // // To Do: Date Author Comment // //@@END_MSINTERNAL // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR // PURPOSE. // // Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved. // //--------------------------------------------------------------------------- #include "common.h" //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- DEFINE_KSDISPATCH_TABLE( DispatchTable, CInstance::DispatchForwardIrp, // Ioctl DispatchInvalidDeviceRequest, // Read DispatchInvalidDeviceRequest, // Write DispatchInvalidDeviceRequest, // Flush CInstance::DispatchClose, // Close DispatchInvalidDeviceRequest, // QuerySecurity DispatchInvalidDeviceRequest, // SetSeturity DispatchFastIoDeviceControlFailure, // FastDeviceIoControl DispatchFastReadFailure, // FastRead DispatchFastWriteFailure // FastWrite ); //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- CInstance::CInstance( IN PPARENT_INSTANCE pParentInstance ) { Assert(pParentInstance); this->pObjectHeader = NULL; this->pParentInstance = pParentInstance; AddList(&pParentInstance->lstChildInstance); } CInstance::~CInstance( ) { Assert(this); RemoveList(); // IMPORTANT : Caller must acquire gmutex. // // "RemoveRef" from file object if(pNextFileObject != NULL) { ObDereferenceObject(pNextFileObject); pNextFileObject = NULL; } if(pObjectHeader != NULL) { KsFreeObjectHeader(pObjectHeader); } // "RemoveRef" from parent file object if(pParentFileObject != NULL) { ObDereferenceObject(pParentFileObject); } // Clean up pin mutex if(pMutex != NULL) { ExFreePool(pMutex); } } NTSTATUS CInstance::DispatchCreate( IN PIRP pIrp, IN UTIL_PFN pfnDispatchCreate, IN OUT PVOID pReference, IN ULONG cCreateItems, IN PKSOBJECT_CREATE_ITEM pCreateItems OPTIONAL, IN const KSDISPATCH_TABLE *pDispatchTable OPTIONAL ) { PIO_STACK_LOCATION pIrpStack; NTSTATUS Status; Assert(this); pIrpStack = IoGetCurrentIrpStackLocation(pIrp); pParentFileObject = pIrpStack->FileObject->RelatedFileObject; ObReferenceObject(pParentFileObject); pMutex = (KMUTEX *)ExAllocatePoolWithTag( NonPagedPool, sizeof(KMUTEX), POOLTAG_SYSA); if(pMutex == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } KeInitializeMutex(pMutex, 0); Status = KsAllocateObjectHeader( &pObjectHeader, cCreateItems, pCreateItems, pIrp, pDispatchTable); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } Status = pfnDispatchCreate(this, pReference); if(!NT_SUCCESS(Status)) { goto exit; } pNextDeviceObject = IoGetRelatedDeviceObject(pNextFileObject); // // ISSUE: 05/10/02 ALPERS // Windows does not support dynamically adjusting StackSizes on the fly. // The only place we are supposed to change this is in AddDevice. // This must be fixed later. // // // Never make the StackSize smaller. It can cause unexpected problems // if there are devices with deeper stacks. // if (pIrpStack->DeviceObject->StackSize < pNextDeviceObject->StackSize) { pIrpStack->DeviceObject->StackSize = pNextDeviceObject->StackSize; } pIrpStack->FileObject->FsContext = this; exit: return(Status); } VOID CInstance::Invalidate( ) { Assert(this); GrabInstanceMutex(); DPF1(50, "CInstance::Invalidate %08x", this); // "RemoveRef" from file object if(pNextFileObject != NULL) { ObDereferenceObject(pNextFileObject); } pNextFileObject = NULL; ReleaseInstanceMutex(); } VOID CParentInstance::Invalidate( ) { PINSTANCE pInstance; Assert(this); FOR_EACH_LIST_ITEM_DELETE(&lstChildInstance, pInstance) { pInstance->Invalidate(); } END_EACH_LIST_ITEM } NTSTATUS CInstance::DispatchClose( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { PIO_STACK_LOCATION pIrpStack; PINSTANCE pInstance; // // ISSUE: 02/26/02 ALPERS // Why do we need the global mutex here. Can't we do it with // instance mutex? // ::GrabMutex(); pIrpStack = IoGetCurrentIrpStackLocation( pIrp ); pInstance = (PINSTANCE)pIrpStack->FileObject->FsContext; Assert(pInstance); pIrpStack->FileObject->FsContext = NULL; delete pInstance; ::ReleaseMutex(); pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return(STATUS_SUCCESS); } #pragma LOCKED_CODE #pragma LOCKED_DATA NTSTATUS CInstance::DispatchForwardIrp( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { PIO_STACK_LOCATION pIrpStack; PFILE_OBJECT pNextFileObject; PINSTANCE pInstance; NTSTATUS Status = STATUS_SUCCESS; #ifdef DEBUG DumpIoctl(pIrp, "ForwardIrp", DBG_IOCTL_LOG); #endif pIrpStack = IoGetCurrentIrpStackLocation(pIrp); pInstance = (PINSTANCE)pIrpStack->FileObject->FsContext; // Use gMutex instead of instance mutex. The instance mutex // is not used in any of the dispatch handlers, therefore will // not synchronize DispatchForwardIrp with other DispatchHandlers in // CPinInstance. // Grab mutex for a very short time to check the validity of CInstance. // If it is valid, IoCallDriver is called. This does not need // synchronization // ::GrabMutex(); Assert(pInstance); pNextFileObject = pInstance->pNextFileObject; if(pNextFileObject == NULL) { DPF(60, "DispatchIoControl: pNextFileObject == NULL"); Status = pIrp->IoStatus.Status = STATUS_NO_SUCH_DEVICE; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } ::ReleaseMutex(); // // ISSUE: 02/21/02 ALPERS // This is totally wrong. How would sysaudio know that the pNextDeviceObject // and sysaudio has the same DeviceStack. // Sysaudio should allocate a new IRP and send the new IRP down to // pNextDeviceObject. // // This code path is executed for IOCTL_KS_READ_STREAM, // IOCTL_KS_WRITE_STREAM and IOCTL_KS_RESET_STATE requests. // // In order to solve the problem mentioned above sysaudio has to // create new irps, pend/queue original irp and complete irps // asynchronously. // There is no infrastructure to do it in sysaudio. And this is // not directly related to security. // if (NT_SUCCESS(Status)) { pIrpStack->FileObject = pNextFileObject; IoSkipCurrentIrpStackLocation(pIrp); AssertFileObject(pIrpStack->FileObject); Status = IoCallDriver(pInstance->pNextDeviceObject, pIrp); } return(Status); }