Exemplo n.º 1
0
BOOL
NTAPI
DbgGdiHTIntegrityCheck()
{
	ULONG i, nDeleted = 0, nFree = 0, nUsed = 0;
	PGDI_TABLE_ENTRY pEntry;
	BOOL r = 1;

	KeEnterCriticalRegion();

	/* FIXME: Check reserved entries */

	/* Now go through the deleted objects */
	i = gulFirstFree & 0xffff;
	while (i)
	{
		pEntry = &GdiHandleTable->Entries[i];
		if (i >= GDI_HANDLE_COUNT)
		{
		    DPRINT1("nDeleted=%lu\n", nDeleted);
		    ASSERT(FALSE);
		}

        nDeleted++;

        /* Check the entry */
        if ((pEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
        {
            r = 0;
            DPRINT1("Deleted Entry has a type != 0\n");
        }
        if ((ULONG_PTR)pEntry->KernelData >= GDI_HANDLE_COUNT)
        {
            r = 0;
            DPRINT1("Deleted entries KernelPointer too big\n");
        }
        if (pEntry->UserData != NULL)
        {
            r = 0;
            DPRINT1("Deleted entry has UserData != 0\n");
        }
        if (pEntry->ProcessId != 0)
        {
            r = 0;
            DPRINT1("Deleted entry has ProcessId != 0\n");
        }

        i = (ULONG_PTR)pEntry->KernelData & 0xffff;
	};

	for (i = gulFirstUnused;
	     i < GDI_HANDLE_COUNT;
	     i++)
	{
		pEntry = &GdiHandleTable->Entries[i];

		if ((pEntry->Type) != 0)
		{
			r = 0;
			DPRINT1("Free Entry has a type != 0\n");
		}
		if ((ULONG_PTR)pEntry->KernelData != 0)
		{
			r = 0;
			DPRINT1("Free entries KernelPointer != 0\n");
		}
		if (pEntry->UserData != NULL)
		{
			r = 0;
			DPRINT1("Free entry has UserData != 0\n");
		}
		if (pEntry->ProcessId != 0)
		{
			r = 0;
			DPRINT1("Free entry has ProcessId != 0\n");
		}
		nFree++;
	}

	for (i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++)
	{
		HGDIOBJ Handle;
		ULONG Type;

		pEntry = &GdiHandleTable->Entries[i];
		Type = pEntry->Type;
		Handle = (HGDIOBJ)((Type << GDI_ENTRY_UPPER_SHIFT) + i);

		if (Type & GDI_ENTRY_BASETYPE_MASK)
		{
			if (pEntry->KernelData == NULL)
			{
				r = 0;
				DPRINT1("Used entry has KernelData == 0\n");
			}
			else if (pEntry->KernelData <= MmHighestUserAddress)
			{
				r = 0;
				DPRINT1("Used entry invalid KernelData\n");
			}
			else if (((POBJ)(pEntry->KernelData))->hHmgr != Handle)
			{
				r = 0;
				DPRINT1("Used entry %lu, has invalid hHmg %p (expected: %p)\n",
				        i, ((POBJ)(pEntry->KernelData))->hHmgr, Handle);
			}
			nUsed++;
		}
	}

	if (RESERVE_ENTRIES_COUNT + nDeleted + nFree + nUsed != GDI_HANDLE_COUNT)
	{
		r = 0;
		DPRINT1("Number of all entries incorrect: RESERVE_ENTRIES_COUNT = %lu, nDeleted = %lu, nFree = %lu, nUsed = %lu\n",
		        RESERVE_ENTRIES_COUNT, nDeleted, nFree, nUsed);
	}

	KeLeaveCriticalRegion();

	return r;
}
Exemplo n.º 2
0
NTSTATUS DriverEntry(
    IN OUT PDRIVER_OBJECT   pDriverObject,
    IN PUNICODE_STRING      pRegistryPath
    )
{
	NDIS_PROTOCOL_DRIVER_CHARACTERISTICS   protocolChar;
	NTSTATUS                        status = STATUS_SUCCESS;
	NDIS_STRING                     protoName = NDIS_STRING_CONST("WIFICAPTURE");     
	UNICODE_STRING                  ntDeviceName;
	UNICODE_STRING                  win32DeviceName;
	BOOLEAN                         fSymbolicLink = FALSE;
	PDEVICE_OBJECT                  deviceObject = NULL;
	NDIS_HANDLE  ProtocolDriverContext={0};

	UNREFERENCED_PARAMETER(pRegistryPath);

	DEBUGP(DL_LOUD, ("DriverEntry\n"));

	Globals.pDriverObject = pDriverObject;
	Globals.EthType = NPROT_ETH_TYPE;
	NPROT_INIT_EVENT(&Globals.BindsComplete);

	do
	{

		//
		// Create our device object using which an application can
		// access NDIS devices.
		//
		RtlInitUnicodeString(&ntDeviceName, NT_DEVICE_NAME);

		status = IoCreateDevice (pDriverObject,
			0,
			&ntDeviceName,
			FILE_DEVICE_NETWORK,
			FILE_DEVICE_SECURE_OPEN,
			FALSE,
			&deviceObject);


		if (!NT_SUCCESS (status))
		{
			//
			// Either not enough memory to create a deviceobject or another
			// deviceobject with the same name exits. This could happen
			// if you install another instance of this device.
			//
			break;
		}

		RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME);

		status = IoCreateSymbolicLink(&win32DeviceName, &ntDeviceName);

		if (!NT_SUCCESS(status))
		{
			break;
		}

		fSymbolicLink = TRUE;

		deviceObject->Flags |= DO_DIRECT_IO;
		Globals.ControlDeviceObject = deviceObject;

		NPROT_INIT_LIST_HEAD(&Globals.OpenList);
		NPROT_INIT_LOCK(&Globals.GlobalLock);

		//
		// Initialize the protocol characterstic structure
		//

		NdisZeroMemory(&protocolChar,sizeof(NDIS_PROTOCOL_DRIVER_CHARACTERISTICS));


		protocolChar.Header.Type                = NDIS_OBJECT_TYPE_PROTOCOL_DRIVER_CHARACTERISTICS,
		protocolChar.Header.Size                = sizeof(NDIS_PROTOCOL_DRIVER_CHARACTERISTICS);
		protocolChar.Header.Revision            = NDIS_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_1;

		protocolChar.MajorNdisVersion            = 6;
		protocolChar.MinorNdisVersion            = 0;
		protocolChar.Name                        = protoName;
		protocolChar.SetOptionsHandler           = NULL;
		protocolChar.OpenAdapterCompleteHandlerEx  = NdisprotOpenAdapterComplete;
		protocolChar.CloseAdapterCompleteHandlerEx = NdisprotCloseAdapterComplete;
		protocolChar.SendNetBufferListsCompleteHandler = NdisprotSendComplete;
		protocolChar.OidRequestCompleteHandler   = NdisprotRequestComplete;
		protocolChar.StatusHandlerEx             = NdisprotStatus;
		protocolChar.UninstallHandler            = NULL;
		protocolChar.ReceiveNetBufferListsHandler = NdisprotReceiveNetBufferLists;
		protocolChar.NetPnPEventHandler          = NdisprotPnPEventHandler;
		protocolChar.BindAdapterHandlerEx        = NdisprotBindAdapter;
		protocolChar.UnbindAdapterHandlerEx      = NdisprotUnbindAdapter;

		//
		// Register as a protocol driver
		//

		status = NdisRegisterProtocolDriver(ProtocolDriverContext,           // driver context
			&protocolChar,
			&Globals.NdisProtocolHandle);

		if (status != NDIS_STATUS_SUCCESS)
		{
			DEBUGP(DL_WARN, ("Failed to register protocol with NDIS\n"));
			status = STATUS_UNSUCCESSFUL;
			break;
		}

		Globals.PartialCancelId = NdisGeneratePartialCancelId();
		Globals.PartialCancelId <<= ((sizeof(PVOID) - 1) * 8);
		DEBUGP(DL_LOUD, ("DriverEntry: CancelId %lx\n", Globals.PartialCancelId));

		//
		// Now set only the dispatch points we would like to handle.
		//

		pDriverObject->MajorFunction[IRP_MJ_CREATE] = NdisprotOpen;

		pDriverObject->MajorFunction[IRP_MJ_CLOSE]  = NdisprotClose;

		pDriverObject->MajorFunction[IRP_MJ_READ]   = NdisprotRead;

		pDriverObject->MajorFunction[IRP_MJ_WRITE]  = NdisprotWrite;

		pDriverObject->MajorFunction[IRP_MJ_CLEANUP]  = NdisprotCleanup;

		pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = NdisprotIoControl;


		pDriverObject->DriverUnload = NdisprotUnload;

		status = STATUS_SUCCESS;


	}
	while (FALSE);


	if (!NT_SUCCESS(status))
	{
		if (deviceObject)
		{
			KeEnterCriticalRegion();
			#pragma prefast(suppress:28107, "The deviceObject is held within the critical section")
			IoDeleteDevice(deviceObject);
			KeLeaveCriticalRegion();
			Globals.ControlDeviceObject = NULL;
		}

		if (fSymbolicLink)
		{
			IoDeleteSymbolicLink(&win32DeviceName);
			fSymbolicLink = FALSE;
		}

		if (Globals.NdisProtocolHandle)
		{
			NdisDeregisterProtocolDriver(Globals.NdisProtocolHandle);
			Globals.NdisProtocolHandle = NULL;
		}


	}

	return status;
}
Exemplo n.º 3
0
BOOLEAN
NTAPI
ExCompareExchangeCallBack(IN OUT PEX_CALLBACK CallBack,
                          IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock,
                          IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock)
{
    EX_FAST_REF OldValue;
    PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock;
    ULONG Count;

    /* Check that we have a new block */
    if (NewBlock)
    {
        /* Acquire rundown */
        if (!ExfAcquireRundownProtectionEx(&NewBlock->RundownProtect,
                                           MAX_FAST_REFS + 1))
        {
            /* This should never happen */
            ASSERTMSG("Callback block is already undergoing rundown", FALSE);
            return FALSE;
        }
    }

    /* Do the swap */
    OldValue = ExCompareSwapFastReference(&CallBack->RoutineBlock,
                                          NewBlock,
                                          OldBlock);

    /* Get the routine block */
    CallbackBlock = ExGetObjectFastReference(OldValue);
    Count = ExGetCountFastReference(OldValue);

    /* Make sure the swap worked */
    if (CallbackBlock == OldBlock)
    {
        /* Make sure we replaced a valid pointer */
        if (CallbackBlock)
        {
            /* Acquire the flush lock and immediately release it */
            KeEnterCriticalRegion();
            ExWaitOnPushLock(&ExpCallBackFlush);

            /* Release rundown protection */
            KeLeaveCriticalRegion();
            ExfReleaseRundownProtectionEx(&CallbackBlock->RundownProtect,
                                          Count + 1);
        }

        /* Compare worked */
        return TRUE;
    }
    else
    {
        /* It failed, check if we had a block */
        if (NewBlock)
        {
            /* We did, remove the refernces that we had added */
            ExfReleaseRundownProtectionEx(&NewBlock->RundownProtect,
                                          MAX_FAST_REFS + 1);
        }

        /* Return failure */
        return FALSE;
    }
}
Exemplo n.º 4
0
NTSTATUS
DokanEventRelease(
	__in PDEVICE_OBJECT DeviceObject)
{
	PDokanDCB	dcb;
	PDokanVCB	vcb;
	PDokanFCB	fcb;
	PDokanCCB	ccb;
	PLIST_ENTRY	fcbEntry, fcbNext, fcbHead;
	PLIST_ENTRY	ccbEntry, ccbNext, ccbHead;
	NTSTATUS	status = STATUS_SUCCESS;

	vcb = DeviceObject->DeviceExtension;
	if (GetIdentifierType(vcb) != VCB) {
		return STATUS_INVALID_PARAMETER;
	}
	dcb = vcb->Dcb;

	//ExAcquireResourceExclusiveLite(&dcb->Resource, TRUE);
	dcb->Mounted = 0;
	//ExReleaseResourceLite(&dcb->Resource);

	// search CCB list to complete not completed Directory Notification 

	KeEnterCriticalRegion();
	ExAcquireResourceExclusiveLite(&vcb->Resource, TRUE);

	fcbHead = &vcb->NextFCB;

    for (fcbEntry = fcbHead->Flink; fcbEntry != fcbHead; fcbEntry = fcbNext) {

		fcbNext = fcbEntry->Flink;
		fcb = CONTAINING_RECORD(fcbEntry, DokanFCB, NextFCB);

		ExAcquireResourceExclusiveLite(&fcb->Resource, TRUE);

		ccbHead = &fcb->NextCCB;

		for (ccbEntry = ccbHead->Flink; ccbEntry != ccbHead; ccbEntry = ccbNext) {
			ccbNext = ccbEntry->Flink;
			ccb = CONTAINING_RECORD(ccbEntry, DokanCCB, NextCCB);

			DDbgPrint("  NotifyCleanup ccb:%X, context:%X, filename:%wZ\n",
					ccb, (ULONG)ccb->UserContext, &fcb->FileName);
			FsRtlNotifyCleanup(vcb->NotifySync, &vcb->DirNotifyList, ccb);
		}
		ExReleaseResourceLite(&fcb->Resource);
	}

	ExReleaseResourceLite(&vcb->Resource);
	KeLeaveCriticalRegion();

	ReleasePendingIrp(&dcb->PendingIrp);
	ReleasePendingIrp(&dcb->PendingEvent);
	DokanStopCheckThread(dcb);
	DokanStopEventNotificationThread(dcb);

	DokanDeleteDeviceObject(dcb);

	return status;
}
Exemplo n.º 5
0
//
// configure bus numbers [checked]
//
VOID PciConfigureBusNumbers(__in PPCI_FDO_EXTENSION FdoExt)
{
	PAGED_CODE();

	PPCI_PDO_EXTENSION PdoExt							= 0;
	if(FdoExt != FdoExt->BusRootFdoExtension)
		PdoExt											= static_cast<PPCI_PDO_EXTENSION>(FdoExt->PhysicalDeviceObject->DeviceExtension);

	KeEnterCriticalRegion();
	KeWaitForSingleObject(&FdoExt->ChildListLock,Executive,KernelMode,FALSE,0);

	PPCI_PDO_EXTENSION BridgeExt						= FdoExt->ChildBridgePdoList;
	ULONG BridgeCount									= 0;
	ULONG ConfiguredBridgeCount							= 0;
	while(BridgeExt)
	{
		if(BridgeExt->NotPresent)
		{
			PciDebugPrintf(0x100000,"Skipping not present bridge PDOX @ %p\n",BridgeExt);
		}
		else
		{
			BridgeCount									+= 1;

			if((!PdoExt || !PdoExt->Dependent.type1.WeChangedBusNumbers || BridgeExt->Common.DeviceState != PciNotStarted) && PciAreBusNumbersConfigured(BridgeExt))
				ConfiguredBridgeCount					+= 1;
			else
				PciDisableBridge(BridgeExt);

		}

		BridgeExt										= BridgeExt->NextBridge;
	}

	KeSetEvent(&FdoExt->ChildListLock,IO_NO_INCREMENT,FALSE);
	KeLeaveCriticalRegion();

	if(!BridgeCount)
	{
		PciDebugPrintf(0x100000,"PCI - No bridges found on bus 0x%x\n",FdoExt->BaseBus);
		return;
	}

	if(BridgeCount == ConfiguredBridgeCount)
	{
		PciDebugPrintf(0x100000,"PCI - 0x%x bridges found on bus 0x%x - all already configured\n",BridgeCount,FdoExt->BaseBus);
		return;
	}

	if(!ConfiguredBridgeCount)
	{
		PciDebugPrintf(0x100000,"PCI - 0x%x bridges found on bus 0x%x - all need configuration\n",BridgeCount,FdoExt->BaseBus);

		return PciSpreadBridges(FdoExt,BridgeCount);
	}

	ASSERT(ConfiguredBridgeCount < BridgeCount);

	PciDebugPrintf(0x100000,"PCI - 0x%x bridges found on bus 0x%x - 0x%x need configuration\n",BridgeCount,FdoExt->BaseBus,BridgeCount - ConfiguredBridgeCount);

	BridgeExt											= FdoExt->ChildBridgePdoList;
	while(BridgeExt)
	{
		if(BridgeExt->NotPresent)
		{
			PciDebugPrintf(0x100000,"Skipping not present bridge PDOX @ %p\n",BridgeExt);
		}
		else
		{
			if((PdoExt && PdoExt->Dependent.type1.WeChangedBusNumbers && BridgeExt->Common.DeviceState == PciNotStarted) || !PciAreBusNumbersConfigured(BridgeExt))
			{
				ASSERT(!BridgeExt->Dependent.type1.PrimaryBus && !BridgeExt->Dependent.type1.SecondaryBus && !BridgeExt->Dependent.type1.SubordinateBus);

				PciFitBridge(FdoExt,PdoExt);
			}
		}

		BridgeExt										= BridgeExt->NextBridge;
	}
}
Exemplo n.º 6
0
VOID
DokanCompleteCreate(
	 __in PIRP_ENTRY			IrpEntry,
	 __in PEVENT_INFORMATION	EventInfo
	 )
{
	PIRP				irp;
	PIO_STACK_LOCATION	irpSp;
	NTSTATUS			status;
	ULONG				info;
	PDokanCCB			ccb;
	PDokanFCB			fcb;

	irp   = IrpEntry->Irp;
	irpSp = IrpEntry->IrpSp;	

	DDbgPrint("==> DokanCompleteCreate\n");

	ccb	= IrpEntry->FileObject->FsContext2;
	ASSERT(ccb != NULL);
	
	fcb = ccb->Fcb;
	ASSERT(fcb != NULL);

	DDbgPrint("  FileName:%wZ\n", &fcb->FileName);

	ccb->UserContext = EventInfo->Context;
	//DDbgPrint("   set Context %X\n", (ULONG)ccb->UserContext);

	status = EventInfo->Status;

	info = EventInfo->Operation.Create.Information;

	switch (info) {
	case FILE_OPENED:
		DDbgPrint("  FILE_OPENED\n");
		break;
	case FILE_CREATED:
		DDbgPrint("  FILE_CREATED\n");
		break;
	case FILE_OVERWRITTEN:
		DDbgPrint("  FILE_OVERWRITTEN\n");
		break;
	case FILE_DOES_NOT_EXIST:
		DDbgPrint("  FILE_DOES_NOT_EXIST\n");
		break;
	case FILE_EXISTS:
		DDbgPrint("  FILE_EXISTS\n");
		break;
	case FILE_SUPERSEDED:
		DDbgPrint("  FILE_SUPERSEDED\n");
		break;
	default:
		DDbgPrint("  info = %d\n", info);
		break;
	}

    KeEnterCriticalRegion();
	ExAcquireResourceExclusiveLite(&fcb->Resource, TRUE);
	if (NT_SUCCESS(status) &&
		(irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE ||
		EventInfo->Operation.Create.Flags & DOKAN_FILE_DIRECTORY)) {
		if (irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE) {
			DDbgPrint("  FILE_DIRECTORY_FILE %p\n", fcb);
		} else {
			DDbgPrint("  DOKAN_FILE_DIRECTORY %p\n", fcb);
		}
		fcb->Flags |= DOKAN_FILE_DIRECTORY;
	}
	ExReleaseResourceLite(&fcb->Resource);
    KeLeaveCriticalRegion();

    KeEnterCriticalRegion();
	ExAcquireResourceExclusiveLite(&ccb->Resource, TRUE);
	if (NT_SUCCESS(status)) {
		ccb->Flags |= DOKAN_FILE_OPENED;
	}
	ExReleaseResourceLite(&ccb->Resource);
    KeLeaveCriticalRegion();

	if (NT_SUCCESS(status)) {
		if (info == FILE_CREATED) {
			if (fcb->Flags & DOKAN_FILE_DIRECTORY) {
				DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_ADDED);
			} else {
				DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED);
			}
		}
	} else {
		DDbgPrint("   IRP_MJ_CREATE failed. Free CCB:%p\n", ccb);
		DokanFreeCCB(ccb);
		DokanFreeFCB(fcb);
	}
	
	irp->IoStatus.Status = status;
	irp->IoStatus.Information = info;
	IoCompleteRequest(irp, IO_NO_INCREMENT);

	DokanPrintNTStatus(status);
	DDbgPrint("<== DokanCompleteCreate\n");
}
Exemplo n.º 7
0
PDokanFCB
DokanGetFCB(
	__in PDokanVCB	Vcb,
	__in PWCHAR		FileName,
	__in ULONG		FileNameLength)
{
	PLIST_ENTRY		thisEntry, nextEntry, listHead;
	PDokanFCB		fcb = NULL;
	ULONG			pos;

	KeEnterCriticalRegion();
	ExAcquireResourceExclusiveLite(&Vcb->Resource, TRUE);

	// search the FCB which is already allocated
	// (being used now)
	listHead = &Vcb->NextFCB;

    for (thisEntry = listHead->Flink;
			thisEntry != listHead;
			thisEntry = nextEntry) {

		nextEntry = thisEntry->Flink;

        fcb = CONTAINING_RECORD(thisEntry, DokanFCB, NextFCB);

		if (fcb->FileName.Length == FileNameLength) {
			// FileNameLength in bytes
			for (pos = 0; pos < FileNameLength/sizeof(WCHAR); ++pos) {
				if (fcb->FileName.Buffer[pos] != FileName[pos])
					break;
			}
			// we have the FCB which is already allocated and used
			if (pos == FileNameLength/sizeof(WCHAR))
				break;
		}

		fcb = NULL;
	}

	// we don't have FCB
	if (fcb == NULL) {
		DDbgPrint("  Allocate FCB\n");
		
		fcb = DokanAllocateFCB(Vcb);
		
		// no memory?
		if (fcb == NULL) {
			ExFreePool(FileName);
			ExReleaseResourceLite(&Vcb->Resource);
			KeLeaveCriticalRegion();
			return NULL;
		}

		ASSERT(fcb != NULL);

		fcb->FileName.Buffer = FileName;
		fcb->FileName.Length = (USHORT)FileNameLength;
		fcb->FileName.MaximumLength = (USHORT)FileNameLength;

	// we already have FCB
	} else {
		// FileName (argument) is never used and must be freed
		ExFreePool(FileName);
	}

	InterlockedIncrement(&fcb->FileCount);

	ExReleaseResourceLite(&Vcb->Resource);
	KeLeaveCriticalRegion();

	return fcb;
}
Exemplo n.º 8
0
/*
 *  ISSUE: REMOVE this old function implementation as soon as the
 *                  boottime pagefile problems with the new one (below)
 *                  are resolved.
 */
NTSTATUS
ClasspEjectionControl(
    IN PDEVICE_OBJECT Fdo,
    IN PIRP Irp,
    IN MEDIA_LOCK_TYPE LockType,
    IN BOOLEAN Lock
    )
{
    PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = Fdo->DeviceExtension;
    PCOMMON_DEVICE_EXTENSION commonExtension =
        (PCOMMON_DEVICE_EXTENSION) FdoExtension;

    PFILE_OBJECT_EXTENSION fsContext = NULL;
    NTSTATUS status;
    PSCSI_REQUEST_BLOCK srb = NULL;
    BOOLEAN countChanged = FALSE;

    PAGED_CODE();

    /*
     *  Ensure that the user thread is not suspended while we are holding EjectSynchronizationEvent.
     */
    KeEnterCriticalRegion();

    status = KeWaitForSingleObject(
                &(FdoExtension->EjectSynchronizationEvent),
                UserRequest,
                KernelMode,
                FALSE,
                NULL);

    NT_ASSERT(status == STATUS_SUCCESS);

    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
                "ClasspEjectionControl: "
                "Received request for %s lock type\n",
                LockTypeStrings[LockType]
                ));

    try {
        PCDB cdb = NULL;

        //
        // Determine if this is a "secured" request.
        //

        if (LockType == SecureMediaLock) {

            PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
            PFILE_OBJECT fileObject = irpStack->FileObject;

            //
            // Make sure that the file object we are supplied has a
            // proper FsContext before we try doing a secured lock.
            //

            if (fileObject != NULL) {
                fsContext = ClassGetFsContext(commonExtension, fileObject);
            }

            if (fsContext == NULL) {

                //
                // This handle isn't setup correctly.  We can't let the
                // operation go.
                //

                status = STATUS_INVALID_PARAMETER;
                leave;
            }
        }

        if (Lock) {

            //
            // This is a lock command.  Reissue the command in case bus or
            // device was reset and the lock was cleared.
            // note: may need to decrement count if actual lock operation
            //       failed....
            //

            switch (LockType) {

                case SimpleMediaLock: {
                    FdoExtension->LockCount++;
                    countChanged = TRUE;
                    break;
                }

                case SecureMediaLock: {
                    fsContext->LockCount++;
                    FdoExtension->ProtectedLockCount++;
                    countChanged = TRUE;
                    break;
                }

                case InternalMediaLock: {
                    FdoExtension->InternalLockCount++;
                    countChanged = TRUE;
                    break;
                }
            }

        } else {

            //
            // This is an unlock command.  If it's a secured one then make sure
            // the caller has a lock outstanding or return an error.
            // note: may need to re-increment the count if actual unlock
            //       operation fails....
            //

            switch (LockType) {

                case SimpleMediaLock: {
                    if(FdoExtension->LockCount != 0) {
                        FdoExtension->LockCount--;
                        countChanged = TRUE;
                    }
                    break;
                }

                case SecureMediaLock: {
                    if(fsContext->LockCount == 0) {
                        status = STATUS_INVALID_DEVICE_STATE;
                        leave;
                    }
                    fsContext->LockCount--;
                    FdoExtension->ProtectedLockCount--;
                    countChanged = TRUE;
                    break;
                }

                case InternalMediaLock: {
                    NT_ASSERT(FdoExtension->InternalLockCount != 0);
                    FdoExtension->InternalLockCount--;
                    countChanged = TRUE;
                    break;
                }
            }

            //
            // We only send an unlock command to the drive if both the
            // secured and unsecured lock counts have dropped to zero.
            //

            if ((FdoExtension->ProtectedLockCount != 0) ||
                (FdoExtension->InternalLockCount != 0) ||
                (FdoExtension->LockCount != 0)) {

                status = STATUS_SUCCESS;
                leave;
            }
        }

        status = STATUS_SUCCESS;
        if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {

            srb = (PSCSI_REQUEST_BLOCK)ClasspAllocateSrb(FdoExtension);

            if (srb == NULL) {
                status = STATUS_INSUFFICIENT_RESOURCES;
                leave;
            }

            if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {

                //
                // NOTE - this is based on size used in ClasspAllocateSrb
                //

                status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srb,
                                                       STORAGE_ADDRESS_TYPE_BTL8,
                                                       CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE,
                                                       1,
                                                       SrbExDataTypeScsiCdb16);
                if (!NT_SUCCESS(status)) {
                    NT_ASSERT(FALSE);
                    leave;
                }

            } else {
                RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
            }

            SrbSetCdbLength(srb, 6);
            cdb = SrbGetCdb(srb);
            NT_ASSERT(cdb != NULL);

            cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;

            //
            // TRUE - prevent media removal.
            // FALSE - allow media removal.
            //

            cdb->MEDIA_REMOVAL.Prevent = Lock;

            //
            // Set timeout value.
            //

            SrbSetTimeOutValue(srb, FdoExtension->TimeOutValue);

            //
            // The actual lock operation on the device isn't so important
            // as the internal lock counts.  Ignore failures.
            //

            status = ClassSendSrbSynchronous(FdoExtension->DeviceObject,
                                             srb,
                                             NULL,
                                             0,
                                             FALSE);
        }

    } finally {

        if (!NT_SUCCESS(status)) {
            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
                        "ClasspEjectionControl: FAILED status %x -- "
                        "reverting lock counts\n", status));

            if (countChanged) {

                //
                // have to revert to previous counts if the
                // lock/unlock operation actually failed.
                //

                if (Lock) {

                    switch (LockType) {

                        case SimpleMediaLock: {
                            FdoExtension->LockCount--;
                            break;
                        }

                        case SecureMediaLock: {
                            fsContext->LockCount--;
                            FdoExtension->ProtectedLockCount--;
                            break;
                        }

                        case InternalMediaLock: {
                            FdoExtension->InternalLockCount--;
                            break;
                        }
                    }

                } else {

                    switch (LockType) {

                        case SimpleMediaLock: {
                            FdoExtension->LockCount++;
                            break;
                        }

                        case SecureMediaLock: {
                            fsContext->LockCount++;
                            FdoExtension->ProtectedLockCount++;
                            break;
                        }

                        case InternalMediaLock: {
                            FdoExtension->InternalLockCount++;
                            break;
                        }
                    }
                }

            }

        } else {

            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
                        "ClasspEjectionControl: Succeeded\n"));

        }

        TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
                    "ClasspEjectionControl: "
                    "Current Counts: Internal: %x  Secure: %x  Simple: %x\n",
                    FdoExtension->InternalLockCount,
                    FdoExtension->ProtectedLockCount,
                    FdoExtension->LockCount
                    ));

        KeSetEvent(&(FdoExtension->EjectSynchronizationEvent),
                   IO_NO_INCREMENT,
                   FALSE);
        KeLeaveCriticalRegion();

        if (srb) {
            ClassFreeOrReuseSrb(FdoExtension, srb);
        }

    }
    return status;
}
Exemplo n.º 9
0
VOID
DokanCompleteSetInformation(
	__in PIRP_ENTRY		IrpEntry,
	__in PEVENT_INFORMATION EventInfo
	)
{
	PIRP				irp;
	PIO_STACK_LOCATION	irpSp;
	NTSTATUS			status;
	ULONG				info	 = 0;
	PDokanCCB			ccb;
	PDokanFCB			fcb;
	UNICODE_STRING		oldFileName;

	FILE_INFORMATION_CLASS infoClass;
    irp = IrpEntry->Irp;
    status = EventInfo->Status;

	__try {

		DDbgPrint("==> DokanCompleteSetInformation\n");

		irpSp = IrpEntry->IrpSp;

		ccb = IrpEntry->FileObject->FsContext2;
		ASSERT(ccb != NULL);

        KeEnterCriticalRegion();
		ExAcquireResourceExclusiveLite(&ccb->Resource, TRUE);

		fcb = ccb->Fcb;
		ASSERT(fcb != NULL);

		ccb->UserContext = EventInfo->Context;

		info = EventInfo->BufferLength;

		infoClass = irpSp->Parameters.SetFile.FileInformationClass;

		RtlZeroMemory(&oldFileName, sizeof(UNICODE_STRING));

		if (NT_SUCCESS(status)) {
			
			if (infoClass == FileDispositionInformation) {

				if (EventInfo->Operation.Delete.DeleteOnClose) {

					if (!MmFlushImageSection(
						&fcb->SectionObjectPointers,
						MmFlushForDelete)) {
						DDbgPrint("  Cannot delete user mapped image\n");
						status = STATUS_CANNOT_DELETE;
					} else {
						ccb->Flags |= DOKAN_DELETE_ON_CLOSE;
						fcb->Flags |= DOKAN_DELETE_ON_CLOSE;
						DDbgPrint("   FileObject->DeletePending = TRUE\n");
						IrpEntry->FileObject->DeletePending = TRUE;
					}

				} else {
					ccb->Flags &= ~DOKAN_DELETE_ON_CLOSE;
					fcb->Flags &= ~DOKAN_DELETE_ON_CLOSE;
					DDbgPrint("   FileObject->DeletePending = FALSE\n");
					IrpEntry->FileObject->DeletePending = FALSE;
				}
			}

			// if rename is executed, reassign the file name
			if(infoClass == FileRenameInformation) {
				PVOID buffer = NULL;

				ExAcquireResourceExclusiveLite(&fcb->Resource, TRUE);

				// this is used to inform rename in the bellow switch case
				oldFileName.Buffer = fcb->FileName.Buffer;
				oldFileName.Length = (USHORT)fcb->FileName.Length;
				oldFileName.MaximumLength = (USHORT)fcb->FileName.Length;

				// copy new file name
				buffer = ExAllocatePool(EventInfo->BufferLength+sizeof(WCHAR));

				if (buffer == NULL) {
					status = STATUS_INSUFFICIENT_RESOURCES;
					ExReleaseResourceLite(&fcb->Resource);
					ExReleaseResourceLite(&ccb->Resource);
                    KeLeaveCriticalRegion();
					__leave;
				}

				fcb->FileName.Buffer = buffer;

				ASSERT(fcb->FileName.Buffer != NULL);

				RtlZeroMemory(fcb->FileName.Buffer, EventInfo->BufferLength+sizeof(WCHAR));
				RtlCopyMemory(fcb->FileName.Buffer, EventInfo->Buffer, EventInfo->BufferLength);

				fcb->FileName.Length = (USHORT)EventInfo->BufferLength;
				fcb->FileName.MaximumLength = (USHORT)EventInfo->BufferLength;

				ExReleaseResourceLite(&fcb->Resource);
			}
		}

		ExReleaseResourceLite(&ccb->Resource);
        KeLeaveCriticalRegion();

		if (NT_SUCCESS(status)) {
			switch (irpSp->Parameters.SetFile.FileInformationClass) {
			case FileAllocationInformation:
				DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
				break;
			case FileBasicInformation:
				DokanNotifyReportChange(fcb,
					FILE_NOTIFY_CHANGE_ATTRIBUTES |
					FILE_NOTIFY_CHANGE_LAST_WRITE |
					FILE_NOTIFY_CHANGE_LAST_ACCESS |
					FILE_NOTIFY_CHANGE_CREATION,
					FILE_ACTION_MODIFIED);
				break;
			case FileDispositionInformation:
				if (IrpEntry->FileObject->DeletePending) {
					if (fcb->Flags & DOKAN_FILE_DIRECTORY) {
						DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_REMOVED);
					} else {
						DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED);
					}
				}
				break;
			case FileEndOfFileInformation:
				DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
				break;
			case FileLinkInformation:
				// TODO: should check whether this is a directory
				// TODO: should notify new link name
				//DokanNotifyReportChange(vcb, ccb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED);
				break;
			case FilePositionInformation:
				// this is never used
				break;
			case FileRenameInformation:
				{
					DokanNotifyReportChange0(fcb, &oldFileName,
						FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_RENAMED_OLD_NAME);
					
					// free old file name
					ExFreePool(oldFileName.Buffer);

					DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_RENAMED_NEW_NAME);
				}
				break;
			case FileValidDataLengthInformation:
				DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
				break;
			default:
				DDbgPrint("  unknown type:%d\n", irpSp->Parameters.SetFile.FileInformationClass);
				break;
			}
		}

	} __finally {

        DokanCompleteIrpRequest(irp, status, info);

		DDbgPrint("<== DokanCompleteSetInformation\n");
	}
}
Exemplo n.º 10
0
NTSTATUS
Bus_IoCtl (
    IN  PDEVICE_OBJECT  DeviceObject,
    IN  PIRP            Irp
    )
/*++
Routine Description:

    Handle user mode PlugIn, UnPlug and device Eject requests.

Arguments:

   DeviceObject - pointer to a device object.

   Irp - pointer to an I/O Request Packet.

Return Value:

   NT status code

--*/
{
    PIO_STACK_LOCATION      irpStack;
    NTSTATUS                status;
    ULONG                   inlen, outlen;
    PFDO_DEVICE_DATA        fdoData;
    PVOID                   buffer;

    PAGED_CODE ();

	//
	// It is not safe to call IOCTL in raised IRQL.
	//

	ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
    
    fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension;

    //
    // We only take Device Control requests for the FDO.
    // That is the bus itself.
    //

    if (!fdoData->IsFDO) {
    
        //
        // These commands are only allowed to go to the FDO.
        //   
        status = STATUS_INVALID_DEVICE_REQUEST;
        Irp->IoStatus.Status = status;
        IoCompleteRequest (Irp, IO_NO_INCREMENT);
        return status;

    }

    //
    // Check to see whether the bus is removed
    //
    
    if (fdoData->DevicePnPState == Deleted) {
        Irp->IoStatus.Status = status = STATUS_NO_SUCH_DEVICE;
        IoCompleteRequest (Irp, IO_NO_INCREMENT);
        return status;
    }

    Bus_IncIoCount (fdoData);
    
    irpStack = IoGetCurrentIrpStackLocation (Irp);

    buffer			= Irp->AssociatedIrp.SystemBuffer;  
    inlen			= irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outlen			= irpStack->Parameters.DeviceIoControl.OutputBufferLength;

    status = STATUS_INVALID_PARAMETER;

	Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("%d called\n", irpStack->Parameters.DeviceIoControl.IoControlCode));
    switch (irpStack->Parameters.DeviceIoControl.IoControlCode) 
	{

	case IOCTL_NDASBUS_ADD_TARGET:
	{
		PPDO_DEVICE_DATA	pdoData;

		Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA)));

		if ((inlen == outlen) &&
			(sizeof(NDASBUS_ADD_TARGET_DATA) <= inlen)) 
		{
			ULONG						ulSize;
			PNDASBUS_ADD_TARGET_DATA	addTargetData = buffer;
			BOOLEAN						accepted;
			
			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_ADD_TARGET called\n"));
			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET Target Type %d\n", addTargetData->ucTargetType));

			status = STATUS_SUCCESS;
			
			//
			// Check structure size
			//
			if(VerifySizeOfAddTargetData(addTargetData, &ulSize) == 0) {
				status = STATUS_INVALID_PARAMETER;
				break;
			}
			if(ulSize != inlen) 
			{
				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: Size mismatch. Req %d, in %d\n", ulSize, inlen));
				status = STATUS_UNSUCCESSFUL;
				break;
			}

			//
			//	Check to see if acceptable structure.
			//

			accepted = TRUE;
			switch(addTargetData->ucTargetType) 
			{
			case NDASSCSI_TYPE_DISK_NORMAL: 
			case NDASSCSI_TYPE_DVD: 
			case NDASSCSI_TYPE_VDVD: 
			case NDASSCSI_TYPE_MO:

				if(addTargetData->ulNumberOfUnitDiskList != 1)
					accepted = FALSE;
				break;

			case NDASSCSI_TYPE_DISK_MIRROR:

				if(2 != addTargetData->ulNumberOfUnitDiskList)
					accepted = FALSE;

				break;

			case NDASSCSI_TYPE_DISK_AGGREGATION:

				if (addTargetData->ulNumberOfUnitDiskList < 2 || 
					addTargetData->ulNumberOfUnitDiskList > MAX_NR_UNITDISK_FOR_AGGR)
					accepted = FALSE;
				break;

			case NDASSCSI_TYPE_DISK_RAID0:
				switch(addTargetData->ulNumberOfUnitDiskList)
				{
				case 2:
				case 4:
				case 8:
					break;
				default: // do not accept
					accepted = FALSE;
					break;
				}
				break;
			case NDASSCSI_TYPE_DISK_RAID1R3:
				{
					ULONG						ulDiskCount;
					ulDiskCount = addTargetData->ulNumberOfUnitDiskList - 
						addTargetData->RAID_Info.nSpareDisk;
					if (2 != ulDiskCount) 
						accepted = FALSE;
				}
				break;
			case NDASSCSI_TYPE_DISK_RAID4R3:
			case NDASSCSI_TYPE_DISK_RAID5:
				{
					ULONG						ulDiskCount;
					ulDiskCount = addTargetData->ulNumberOfUnitDiskList - 
						addTargetData->RAID_Info.nSpareDisk;
					switch(ulDiskCount)
				{
				case 3: // 2 + 1
				case 5: // 4 + 1
				case 9: // 8 + 1
					break;
				default: // do not accept
					accepted = FALSE;
					break;
				}
				break;
				}				
			default:
				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: Bad Disk Type.\n"));
				accepted = FALSE;
				break;
			}
			if(accepted == FALSE) {
				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: Invaild type.\n"));
				status = STATUS_UNSUCCESSFUL;
				break;
			}
						
#if DBG
			NDBusIoctlLogError(	fdoData->Self,
				NDASBUS_IO_TRY_TO_ADDTARGET,
				IOCTL_NDASBUS_ADD_TARGET,
				addTargetData->ulSlotNo);
#endif
			// Find Pdo Data...
			pdoData = LookupPdoData(fdoData, addTargetData->ulSlotNo);
			if(pdoData == NULL) 
			{
				Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
					("no pdo\n"));
				status = STATUS_UNSUCCESSFUL;
				NDBusIoctlLogError(	fdoData->Self,
									NDASBUS_IO_PDO_NOT_FOUND,
									IOCTL_NDASBUS_ADD_TARGET,
									addTargetData->ulSlotNo);
				break;
			}

			//
			// Save the add target information to the PDO extension
			//

			pdoData->LanscsiAdapterPDO.AddDevInfo = ExAllocatePoolWithTag(NonPagedPool, inlen, BUSENUM_POOL_TAG);
			
			if(pdoData->LanscsiAdapterPDO.AddDevInfo == NULL) 
			{
				Irp->IoStatus.Information = 0;
				status = STATUS_INSUFFICIENT_RESOURCES;
				break;
			}
			else 
			{
				RtlCopyMemory(pdoData->LanscsiAdapterPDO.AddDevInfo, addTargetData, inlen);
				status = STATUS_SUCCESS;
			}

			pdoData->LanscsiAdapterPDO.AddDevInfoLength = inlen;

			//
			// Init PDO status
			//

			pdoData->LanscsiAdapterPDO.LastAdapterStatus = NDASSCSI_ADAPTER_STATUS_INIT;
			pdoData->LanscsiAdapterPDO.DeviceMode = addTargetData->DeviceMode;

			//
			//	Notify to NDASSCSI
			//
			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET SetEvent AddTargetEvent!\n"));
			KeSetEvent(&pdoData->LanscsiAdapterPDO.AddTargetEvent, IO_NO_INCREMENT, FALSE);

			//
			//	Register Target
			//
			if(pdoData->Persistent) {
				status = LSBus_RegisterTarget(fdoData, addTargetData);
				if(!NT_SUCCESS(status)) {
					ExFreePoolWithTag(pdoData->LanscsiAdapterPDO.AddDevInfo, BUSENUM_POOL_TAG);
					pdoData->LanscsiAdapterPDO.AddDevInfo = NULL;
					Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: LSBus_RegisterTarget() failed. STATUS=%08lx\n", status));
					status = STATUS_INTERNAL_DB_ERROR;
					NDBusIoctlLogError(	fdoData->Self,
										NDASBUS_IO_REGISTER_TARGET_FAIL,
										IOCTL_NDASBUS_ADD_TARGET,
										addTargetData->ulSlotNo);
				} else {
					Bus_KdPrint(fdoData, BUS_DBG_IOCTL_INFO, ("ADD_TARGET: Successfully registered.\n"));
				}
			}

			ObDereferenceObject(pdoData->Self);

			Irp->IoStatus.Information = outlen;
		}        
		else
		{
			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR,
								("IOCTL_NDASBUS_ADD_TARGET length mismatch!!!"
								" inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n",
								inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA)));
		}

	}
		break;

	case IOCTL_NDASBUS_REMOVE_TARGET:
	{
	    PPDO_DEVICE_DATA	pdoData;
		PNDASBUS_REMOVE_TARGET_DATA	removeTarget;

        Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_REMOVE_TARGET called\n"));

        if (sizeof (NDASBUS_REMOVE_TARGET_DATA) != inlen)
			break;

		removeTarget = (PNDASBUS_REMOVE_TARGET_DATA)buffer;
		pdoData = LookupPdoData(fdoData, removeTarget->ulSlotNo);
		if(pdoData == NULL) {
			Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
						("no pdo\n"));
			status = STATUS_UNSUCCESSFUL;
			NDBusIoctlLogError(	fdoData->Self,
				NDASBUS_IO_PDO_NOT_FOUND,
				IOCTL_NDASBUS_REMOVE_TARGET,
				removeTarget->ulSlotNo);
			break;
		}

		//
		//	redirect to the NDAS SCSI Device
		//
		status = LSBus_IoctlToNdasScsiDevice(
				pdoData,
				NDASSCSI_IOCTL_REMOVE_DEVICE,
				NULL,
				0,
				NULL,
				0
			);

		if(NT_SUCCESS(status) && pdoData->Persistent) {

			status = LSBus_UnregisterTarget(fdoData, removeTarget->ulSlotNo, removeTarget->ulTargetId);
			if(!NT_SUCCESS(status)) {
				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_INFO, (	"REMOVE_TARGET: Removed  Target instance,"
															" but LSBus_UnregisterTarget() failed.\n"));
				status = STATUS_INTERNAL_DB_ERROR;
				NDBusIoctlLogError(	fdoData->Self,
					NDASBUS_IO_UNREGISTER_TARGET_FAIL,
					IOCTL_NDASBUS_REMOVE_TARGET,
					removeTarget->ulSlotNo);
			}
#if DBG
			else {
				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_INFO, ("REMOVE_TARGET: LSBus_UnregisterTarget() succeeded.\n"));
			}
#endif
		}

		ObDereferenceObject(pdoData->Self);

        Irp->IoStatus.Information = 0;
		break;
	}

	case IOCTL_NDASBUS_STARTSTOP_REGISTRARENUM:{
		PULONG	onOff = (PULONG)buffer;

		Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, (
			"STARTSTOP_REGISTRARENUM: inlen %d, outlen %d OnOff %u\n", inlen, outlen, *onOff));

		KeEnterCriticalRegion();
		ExAcquireFastMutexUnsafe(&fdoData->RegMutex);

		if(*onOff != 0) {

			//
			//	Save old state.
			//	Activate the registrar's enumeration
			//

			*onOff = fdoData->StartStopRegistrarEnum;
			fdoData->StartStopRegistrarEnum = TRUE;
		} else {

			//
			//	Save old state.
			//	Deactivate the registrar's enumeration
			//

			*onOff = fdoData->StartStopRegistrarEnum;
			fdoData->StartStopRegistrarEnum = FALSE;
		}

		//
		//	Clean up non-enumerated entries.
		//
		LSBus_CleanupNDASDeviceRegistryUnsafe(fdoData);

		ExReleaseFastMutexUnsafe(&fdoData->RegMutex);
		KeLeaveCriticalRegion();

		Irp->IoStatus.Information = sizeof(ULONG);
		status = STATUS_SUCCESS;

		break;
	}

	case IOCTL_NDASBUS_REGISTER_DEVICE:
	{

		Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, (
							"REGISTER_DEVICE: inlen %d, outlen %d,"
							" sizeof(NDASBUS_PLUGIN_HARDWARE_EX2) %d\n",
							inlen, outlen, sizeof(NDASBUS_PLUGIN_HARDWARE_EX2)));
		if ((inlen == outlen)) {

			PNDASBUS_PLUGIN_HARDWARE_EX2	PlugIn = buffer;

			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("REGISTER_DEVICE: entered\n"));

			status = LSBus_RegisterDevice(fdoData, PlugIn);

			Irp->IoStatus.Information = 0;
		}
		else
			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR,
									("REGISTER_DEVICE: length mismatch!!!"
									" inlen %d, outlen %d, sizeof(NDASBUS_PLUGIN_HARDWARE_EX2) %d\n",
									inlen, outlen, sizeof(NDASBUS_PLUGIN_HARDWARE_EX2)));

	}
		break;
	case IOCTL_NDASBUS_REGISTER_TARGET:
	{

		Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, (
									"REGISTER_TARGET: inlen %d, outlen %d,"
									" sizeof(NDASBUS_ADD_TARGET_DATA) %d\n",
									inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA)));
		if ((inlen == outlen)) {

			PNDASBUS_ADD_TARGET_DATA	AddTargetData = buffer;

			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("REGISTER_TARGET: entered\n"));

			status = LSBus_RegisterTarget(fdoData, AddTargetData);

			Irp->IoStatus.Information = 0;
		}
		else {
			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, (
									"REGISTER_TARGET: length mismatch!!!"
									" inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n",
									inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA)));
		}

	}
		break;
	case IOCTL_NDASBUS_UNREGISTER_DEVICE:
	{
		Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, (
									"UNREGISTER_DEVICE: inlen %d, outlen %d,"
									" sizeof(NDASBUS_UNREGISTER_NDASDEV) %d\n",
									inlen, outlen, sizeof(NDASBUS_UNREGISTER_NDASDEV)));
		if ((inlen == outlen)) {

			PNDASBUS_UNREGISTER_NDASDEV	UnregDev = buffer;

			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UNREGISTER_DEVICE: entered\n"));

			status = LSBus_UnregisterDevice(fdoData, UnregDev->SlotNo);

			Irp->IoStatus.Information = 0;
		}
		else {
			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, (
									"UNREGISTER_DEVICE: length mismatch!!!"
									" inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n",
									inlen, outlen, sizeof(NDASBUS_UNREGISTER_NDASDEV)));
		}
	}
	break;
	case IOCTL_NDASBUS_UNREGISTER_TARGET:
	{
		Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, (
									"UNREGISTER_TARGET: inlen %d, outlen %d,"
									" sizeof(NDASBUS_UNREGISTER_TARGET) %d\n",
									inlen, outlen, sizeof(NDASBUS_UNREGISTER_TARGET)));
		if ((inlen == outlen)) {

			PNDASBUS_UNREGISTER_TARGET	UnregTarget = buffer;

			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UNREGISTER_TARGET: entered\n"));

			status = LSBus_UnregisterTarget(fdoData, UnregTarget->SlotNo, UnregTarget->TargetId);

			Irp->IoStatus.Information = 0;
		}
		else {
			Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, (
									"UNREGISTER_TARGET: length mismatch!!!"
									" inlen %d, outlen %d, sizeof(NDASBUS_UNREGISTER_TARGET) %d\n",
									inlen, outlen, sizeof(NDASBUS_UNREGISTER_TARGET)));
		}
	}
	break;
	case IOCTL_NDASBUS_SETPDOINFO:
		{
	    PPDO_DEVICE_DATA	pdoData;
		PNDASBUS_SETPDOINFO	SetPdoInfo;
		KIRQL				oldIrql;
		PVOID				sectionHandle;
		BOOLEAN				acceptStatus;

        Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_SETPDOINFO called\n"));

        if (sizeof (NDASBUS_SETPDOINFO) != inlen)
			break;

		acceptStatus = TRUE;
		SetPdoInfo = (PNDASBUS_SETPDOINFO)buffer;
		pdoData = LookupPdoData(fdoData, SetPdoInfo->SlotNo);
		if(pdoData == NULL) {
			Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
						("no pdo\n"));
			status = STATUS_UNSUCCESSFUL;
			NDBusIoctlLogError(	fdoData->Self,
				NDASBUS_IO_PDO_NOT_FOUND,
				IOCTL_NDASBUS_SETPDOINFO,
				SetPdoInfo->SlotNo);
			break;
		}

		//
		//	lock the code section of this function to acquire spinlock in raised IRQL.
		//
	    sectionHandle = MmLockPagableCodeSection(Bus_IoCtl);

		KeAcquireSpinLock(&pdoData->LanscsiAdapterPDO.LSDevDataSpinLock, &oldIrql);

		Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("!!!!!!!!!!!!!!!!!!  SETPDOINFO: PDO %p: %08lx %08lx %08lx\n",
										pdoData->Self, SetPdoInfo->AdapterStatus,
										SetPdoInfo->SupportedFeatures,
										SetPdoInfo->EnabledFeatures));


		//
		// Deny the status change if the current status is STATUS_STOPPED except for RESETSTATUS flag.
		//

		if(ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.LastAdapterStatus, NDASSCSI_ADAPTER_STATUS_STOPPED)) {

				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: 'An event occured after 'Stopped' event\n"));

				if(ADAPTERINFO_ISSTATUSFLAG(SetPdoInfo->AdapterStatus, NDASSCSI_ADAPTER_STATUSFLAG_RESETSTATUS)) {
					Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: Reset-status event accepted.\n"));
				} else {
					acceptStatus = FALSE;
				}
		} else {
			if(pdoData->LanscsiAdapterPDO.AddDevInfo == NULL) {
				acceptStatus = FALSE;
				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("!!!!!!!!!!!!!!!!!! SETPDOINFO: AddTarget is not occured. Too early to set status.\n"));
			}
		}

		//
		// Mask off RESETSTATUS.
		// NDAS service does not need to know it.
		//

		SetPdoInfo->AdapterStatus &= ~NDASSCSI_ADAPTER_STATUSFLAG_RESETSTATUS;

		//
		// Set status values to the corresponding physical device object.
		// Save to the extension
		//

		if(acceptStatus) {
			PNDASBUS_PDOEVENT_ENTRY	pdoEventEntry;

			pdoEventEntry = NdasBusCreatePdoStatusItem(SetPdoInfo->AdapterStatus);
			if(pdoEventEntry) {
				NdasBusQueuePdoStatusItem(&pdoData->LanscsiAdapterPDO, pdoEventEntry);
			}
#if DBG
			else {
				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: Could not allocate PDO status entry.\n"));
			}
#endif

			pdoData->LanscsiAdapterPDO.LastAdapterStatus = SetPdoInfo->AdapterStatus;
			pdoData->LanscsiAdapterPDO.SupportedFeatures = SetPdoInfo->SupportedFeatures;
			pdoData->LanscsiAdapterPDO.EnabledFeatures = SetPdoInfo->EnabledFeatures;

			//
			//	Queue plugout worker if the NDAS SCSI stop abnormally.
			// Notify the NDAS service of abnormal termination
			//
			if(ADAPTERINFO_ISSTATUS(SetPdoInfo->AdapterStatus, NDASSCSI_ADAPTER_STATUS_STOPPED) &&
				ADAPTERINFO_ISSTATUSFLAG(SetPdoInfo->AdapterStatus, NDASSCSI_ADAPTER_STATUSFLAG_ABNORMAL_TERMINAT)) {

				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: Queueing Unplug worker!!!!!!!!\n"));

				status = QueueUnplugWorker(fdoData, SetPdoInfo->SlotNo);

				//
				// Set disconnection event
				//

				KeSetEvent(pdoData->LanscsiAdapterPDO.DisconEventToService, IO_DISK_INCREMENT, FALSE);
			} else {
				//
				// Notify the adapter status change
				//
				KeSetEvent(pdoData->LanscsiAdapterPDO.AlarmEventToService, IO_DISK_INCREMENT, FALSE);
			}
		}

		KeReleaseSpinLock(&pdoData->LanscsiAdapterPDO.LSDevDataSpinLock, oldIrql);


		//
		//	Release the code section.
		//

	    MmUnlockPagableImageSection(sectionHandle);

		status = STATUS_SUCCESS;
		ObDereferenceObject(pdoData->Self);

        Irp->IoStatus.Information = outlen;
	}
		break;

	case IOCTL_NDASBUS_QUERY_NODE_ALIVE: 
		{

		PPDO_DEVICE_DATA		pdoData;
		BOOLEAN					bAlive;
		PNDASBUS_NODE_ALIVE_IN	pNodeAliveIn;
		NDASBUS_NODE_ALIVE_OUT	nodeAliveOut;

		// Check Parameter.
		if(inlen != sizeof(NDASBUS_NODE_ALIVE_IN) || 
			outlen != sizeof(NDASBUS_NODE_ALIVE_OUT)) {
			status = STATUS_UNKNOWN_REVISION;
			break;
		}
		
		pNodeAliveIn = (PNDASBUS_NODE_ALIVE_IN)Irp->AssociatedIrp.SystemBuffer;  
		
		Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_NOISE,
			("FDO: IOCTL_NDASBUS_QUERY_NODE_ALIVE SlotNumber = %d\n",
			pNodeAliveIn->SlotNo));
		
		pdoData = LookupPdoData(fdoData, pNodeAliveIn->SlotNo);

		if(pdoData == NULL) {
//			Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_TRACE,
//				("[LanScsiBus]Bus_IoCtl: IOCTL_NDASBUS_QUERY_NODE_ALIVE No pdo\n"));
			
			bAlive = FALSE;
		} else {
			//
			// Check this PDO would be removed...
			//
			if(pdoData->Present == TRUE) 
				bAlive = TRUE;
			else
				bAlive = FALSE;
		}

		// For Result...
		nodeAliveOut.SlotNo = pNodeAliveIn->SlotNo;
		nodeAliveOut.bAlive = bAlive;
		// Get Adapter Status.
		if(bAlive == TRUE)
		{
			if(	ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.LastAdapterStatus, NDASSCSI_ADAPTER_STATUS_STOPPING)) {

				nodeAliveOut.bHasError = TRUE;
				Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
					("IOCTL_NDASBUS_QUERY_NODE_ALIVE Adapter has Error 0x%x\n", nodeAliveOut.bHasError));
			} else {
				nodeAliveOut.bHasError = FALSE;
			}

		}

		if(pdoData)
			ObDereferenceObject(pdoData->Self);

		RtlCopyMemory(
			Irp->AssociatedIrp.SystemBuffer,
			&nodeAliveOut,
			sizeof(NDASBUS_NODE_ALIVE_OUT)
			);
		
		Irp->IoStatus.Information = sizeof(NDASBUS_NODE_ALIVE_OUT);
		status = STATUS_SUCCESS;
		}
		break;

	//
	//	added by hootch 01172004
	//
	case IOCTL_NDASBUS_UPGRADETOWRITE:
		{
		PPDO_DEVICE_DATA				pdoData;

		Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_UPGRADETOWRITE called\n"));
		// Check Parameter.
		if(inlen != sizeof(NDASBUS_UPGRADE_TO_WRITE)) {
			Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
				("IOCTL_NDASBUS_UPGRADETOWRITE: Invalid input buffer length\n"));
			status = STATUS_UNKNOWN_REVISION;
			break;
		}

		pdoData = LookupPdoData(fdoData, ((PNDASBUS_UPGRADE_TO_WRITE)buffer)->SlotNo);
		if(pdoData == NULL) {
			Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
				("IOCTL_NDASBUS_UPGRADETOWRITE: No pdo for Slotno:%d\n", ((PNDASBUS_UPGRADE_TO_WRITE)buffer)->SlotNo));
			status = STATUS_NO_SUCH_DEVICE;
			NDBusIoctlLogError(	fdoData->Self,
				NDASBUS_IO_PDO_NOT_FOUND,
				IOCTL_NDASBUS_UPGRADETOWRITE,
				((PNDASBUS_UPGRADE_TO_WRITE)buffer)->SlotNo);
		} else {
			//
			//	redirect to the NDASSCSI Device
			//
			status = LSBus_IoctlToNdasScsiDevice(
					pdoData,
					NDASSCSI_IOCTL_UPGRADETOWRITE,
					buffer,
					inlen,
					buffer,
					outlen
				);

			ObDereferenceObject(pdoData->Self);
		}
		Irp->IoStatus.Information = 0;
	}
		break;

	case IOCTL_NDASBUS_REDIRECT_NDASSCSI:
		{
		PPDO_DEVICE_DATA				pdoData;
		PNDASBUS_REDIRECT_NDASSCSI		redirectIoctl;

		Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_REDIRECT_NDASSCSI called\n"));
		// Check Parameter.
		if(inlen < sizeof(NDASBUS_REDIRECT_NDASSCSI)) {
			Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
				("IOCTL_NDASBUS_REDIRECT_NDASSCSI: Invalid input buffer length\n"));
			status = STATUS_UNKNOWN_REVISION;
			break;
		}

		redirectIoctl = (PNDASBUS_REDIRECT_NDASSCSI)buffer;

		pdoData = LookupPdoData(fdoData, redirectIoctl->SlotNo);
		if(pdoData == NULL) {
			Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
				("IOCTL_NDASBUS_REDIRECT_NDASSCSI: No pdo for Slotno:%d\n", redirectIoctl->SlotNo));
			status = STATUS_NO_SUCH_DEVICE;
		} else {
			//
			//	redirect to the NDASSCSI Device
			//
			status = LSBus_IoctlToNdasScsiDevice(
					pdoData,
					redirectIoctl->IoctlCode,
					redirectIoctl->IoctlData,
					redirectIoctl->IoctlDataSize,
					redirectIoctl->IoctlData,
					redirectIoctl->IoctlDataSize
				);

			ObDereferenceObject(pdoData->Self);
		}
		Irp->IoStatus.Information = 0;
	}
		break;

	case IOCTL_NDASBUS_QUERY_NDASSCSIINFO:
		{
		PPDO_DEVICE_DATA				pdoData;

		Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_QUERY_NDASSCSIINFO called\n"));
		// Check Parameter.
		if(inlen < FIELD_OFFSET(NDASSCSI_QUERY_INFO_DATA, QueryData) ) {
			Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
				("IOCTL_NDASBUS_QUERY_NDASSCSIINFO: Invalid input buffer length too small.\n"));
			status = STATUS_UNKNOWN_REVISION;
			break;
		}
		pdoData = LookupPdoData(fdoData, ((PNDASSCSI_QUERY_INFO_DATA)buffer)->NdasScsiAddress.SlotNo);

		if(pdoData == NULL) {
			Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
				("IOCTL_NDASBUS_QUERY_NDASSCSIINFO No pdo\n"));
			status = STATUS_NO_SUCH_DEVICE;
			NDBusIoctlLogError(	fdoData->Self,
				NDASBUS_IO_PDO_NOT_FOUND,
				IOCTL_NDASBUS_QUERY_NDASSCSIINFO,
				((PNDASSCSI_QUERY_INFO_DATA)buffer)->NdasScsiAddress.SlotNo);
		} else {
			//
			//	redirect to the NDASSCSI Device
			//
			status = LSBus_IoctlToNdasScsiDevice(
					pdoData,
					NDASSCSI_IOCTL_QUERYINFO_EX,
					buffer,
					inlen,
					buffer,
					outlen
				);

			ObDereferenceObject(pdoData->Self);
		}
        Irp->IoStatus.Information = outlen;
		}
		break;

	case IOCTL_NDASBUS_QUERY_INFORMATION:
		{

//		PPDO_DEVICE_DATA				pdoData;
		NDASBUS_QUERY_INFORMATION		Query;
		PNDASBUS_INFORMATION			Information;
		LONG							BufferLenNeeded;

		// Check Parameter.
		if(	inlen < sizeof(NDASBUS_QUERY_INFORMATION) /*|| 
			outlen < sizeof(NDASBUS_INFORMATION) */) {
			status = STATUS_UNKNOWN_REVISION;
			break;
		}

		RtlCopyMemory(&Query, buffer, sizeof(NDASBUS_QUERY_INFORMATION));
		Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_TRACE,
			("FDO: IOCTL_NDASBUS_QUERY_INFORMATION QueryType : %d  SlotNumber = %d\n",
			Query.InfoClass, Query.SlotNo));

		Information = (PNDASBUS_INFORMATION)buffer;
		ASSERT(Information);
		Information->InfoClass = Query.InfoClass;
		status = LSBus_QueryInformation(fdoData, IoIs32bitProcess(Irp), &Query, Information, outlen, &BufferLenNeeded);
		if(NT_SUCCESS(status)) {
			Information->Size = BufferLenNeeded;
			Irp->IoStatus.Information = BufferLenNeeded;
		} else {
			Irp->IoStatus.Information = BufferLenNeeded;
		}
		}
		break;

	case IOCTL_NDASBUS_PLUGIN_HARDWARE_EX2:
		{
			ULONG	structLen;		// Without variable length field
			ULONG	wholeStructLen; // With variable length field
			ULONG	inputWholeStructLen;

			//
			// Check 32 bit thunking request
            //
			if(IoIs32bitProcess(Irp)) {
				structLen = FIELD_OFFSET(NDASBUS_PLUGIN_HARDWARE_EX2_32, HardwareIDs);
				wholeStructLen = sizeof(NDASBUS_PLUGIN_HARDWARE_EX2_32);
				inputWholeStructLen = ((PNDASBUS_PLUGIN_HARDWARE_EX2_32) buffer)->Size;
			} else {
				structLen = FIELD_OFFSET(NDASBUS_PLUGIN_HARDWARE_EX2, HardwareIDs);
				wholeStructLen = sizeof(NDASBUS_PLUGIN_HARDWARE_EX2);
				inputWholeStructLen = ((PNDASBUS_PLUGIN_HARDWARE_EX2) buffer)->Size;
			}

			if ((inlen == outlen) &&
				//
				// Make sure it has at least two nulls and the size 
				// field is set to the declared size of the struct
				//
				((structLen + sizeof(UNICODE_NULL) * 2) <=
				inlen) &&

				//
				// The size field should be set to the sizeof the struct as declared
				// and *not* the size of the struct plus the multi_sz
				//
				(wholeStructLen == inputWholeStructLen)) {

				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("PlugIn called\n"));

				status= Bus_PlugInDeviceEx2((PNDASBUS_PLUGIN_HARDWARE_EX2)buffer,
											inlen,
											fdoData,
											IoIs32bitProcess(Irp),
											Irp->RequestorMode, FALSE);

				Irp->IoStatus.Information = outlen;

			}
		}
        break;

	case IOCTL_NDASBUS_GETVERSION:
		{
			if (outlen >= sizeof(NDASBUS_GET_VERSION)) {
				PNDASBUS_GET_VERSION version = (PNDASBUS_GET_VERSION)buffer;

				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_GETVERSION: called\n"));

			try {
				version->VersionMajor = VER_FILEMAJORVERSION;
				version->VersionMinor = VER_FILEMINORVERSION;
				version->VersionBuild = VER_FILEBUILD;
				version->VersionPrivate = VER_FILEBUILD_QFE;

					Irp->IoStatus.Information = sizeof(NDASBUS_GET_VERSION);
					status = STATUS_SUCCESS;

				} except (EXCEPTION_EXECUTE_HANDLER) {

					status = GetExceptionCode();
					Irp->IoStatus.Information = 0;
				}

			}
		}			
		break;

    case IOCTL_NDASBUS_UNPLUG_HARDWARE:
		{
			if ((sizeof (NDASBUS_UNPLUG_HARDWARE) == inlen) &&
				(inlen == outlen) &&
				(((PNDASBUS_UNPLUG_HARDWARE)buffer)->Size == inlen)) {

				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UnPlug called\n"));

				status= Bus_UnPlugDevice(
						(PNDASBUS_UNPLUG_HARDWARE)buffer, fdoData);
				Irp->IoStatus.Information = outlen;

			}
		}
        break;

    case IOCTL_NDASBUS_EJECT_HARDWARE:
		{
			if ((sizeof (NDASBUS_EJECT_HARDWARE) == inlen) &&
				(inlen == outlen) &&
				(((PNDASBUS_EJECT_HARDWARE)buffer)->Size == inlen)) {

				Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("Eject called\n"));

				status= Bus_EjectDevice((PNDASBUS_EJECT_HARDWARE)buffer, fdoData);

				Irp->IoStatus.Information = outlen;
			}
		}
		break;

	case IOCTL_NDASBUS_DVD_GET_STATUS:
		{
			PPDO_DEVICE_DATA		pdoData;
			PNDASBUS_DVD_STATUS		pDvdStatusData;


			// Check Parameter.
			if((inlen != outlen)
				|| (sizeof(NDASBUS_DVD_STATUS) >  inlen))
			{
				status = STATUS_UNSUCCESSFUL ;
				break;
			}
			
			pDvdStatusData = (PNDASBUS_DVD_STATUS)Irp->AssociatedIrp.SystemBuffer;  
			
			Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
				("FDO: IOCTL_NDASBUS_DVD_GET_STATUS SlotNumber = %d\n",
				pDvdStatusData->SlotNo));	

			pdoData = LookupPdoData(fdoData, pDvdStatusData->SlotNo);
			
			if(pdoData == NULL) {
				Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
					("IOCTL_NDASBUS_DVD_GET_STATUS No pdo\n"));
				status = STATUS_UNSUCCESSFUL;
				NDBusIoctlLogError(	fdoData->Self,
					NDASBUS_IO_PDO_NOT_FOUND,
					IOCTL_NDASBUS_DVD_GET_STATUS,
					pDvdStatusData->SlotNo);
				break;	
			} else {

				if(pdoData->LanscsiAdapterPDO.Flags & LSDEVDATA_FLAG_LURDESC) {
					//
					//	A LUR descriptor is set.
					//
					if(((PLURELATION_DESC)pdoData->LanscsiAdapterPDO.AddDevInfo)->DevType != NDASSCSI_TYPE_DVD)
				{
					Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
						("IOCTL_NDASBUS_DVD_GET_STATUS  No DVD Device\n"));
					status = STATUS_UNSUCCESSFUL;
					break;
				}
				} else {
					//
					//	ADD_TARGET_DATA is set.
					//
					if(((PNDASBUS_ADD_TARGET_DATA)pdoData->LanscsiAdapterPDO.AddDevInfo)->ucTargetType != NDASSCSI_TYPE_DVD)
					{
						Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR,
							("IOCTL_NDASBUS_DVD_GET_STATUS  No DVD Device\n"));
						status = STATUS_UNSUCCESSFUL;
						break;
					}
				}
				//
				//	redirect to the NDASSCSI Device
				//
				status = LSBus_IoctlToNdasScsiDevice(
						pdoData,
						NDASSCSI_IOCTL_GET_DVD_STATUS,
						buffer,
						inlen,
						buffer,
						outlen
					);

				ObDereferenceObject(pdoData->Self);
				status = STATUS_SUCCESS;
				Irp->IoStatus.Information = outlen;
			}					
		}
		break;
    default:
        break; // default status is STATUS_INVALID_PARAMETER
    }
Exemplo n.º 11
0
VOID
ClasspCleanupProtectedLocks(
    IN PFILE_OBJECT_EXTENSION FsContext
    )
{
    PCOMMON_DEVICE_EXTENSION commonExtension =
        FsContext->DeviceObject->DeviceExtension;

    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
        commonExtension->PartitionZeroExtension;

    ULONG newDeviceLockCount = 1;

    PAGED_CODE();

    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
                "ClasspCleanupProtectedLocks called for %p\n",
                FsContext->DeviceObject));
    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
                "ClasspCleanupProtectedLocks - FsContext %p is locked "
                "%d times\n", FsContext, FsContext->LockCount));

    NT_ASSERT(BreakOnClose == FALSE);

    //
    // Synchronize with ejection and ejection control requests.
    //

    KeEnterCriticalRegion();
    (VOID)KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent),
                                UserRequest,
                                KernelMode,
                                FALSE,
                          NULL);

    //
    // For each secure lock on this handle decrement the secured lock count
    // for the FDO.  Keep track of the new value.
    //

    if (FsContext->LockCount != 0) {

        do {

            InterlockedDecrement((volatile LONG *)&FsContext->LockCount);

            newDeviceLockCount =
                InterlockedDecrement(&fdoExtension->ProtectedLockCount);

        } while (FsContext->LockCount > 0);

        //
        // If the new lock count has been dropped to zero then issue a lock
        // command to the device.
        //

        TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
                    "ClasspCleanupProtectedLocks: FDO secured lock count = %d "
                    "lock count = %d\n",
                    fdoExtension->ProtectedLockCount,
                    fdoExtension->LockCount));

        if ((newDeviceLockCount == 0) && (fdoExtension->LockCount == 0)) {

            SCSI_REQUEST_BLOCK srb = {0};
            UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0};
            PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer;
            PCDB cdb = NULL;
            NTSTATUS status;
            PSCSI_REQUEST_BLOCK srbPtr;

            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
                        "ClasspCleanupProtectedLocks: FDO lock count dropped "
                        "to zero\n"));

            if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
                #pragma prefast(suppress:26015, "InitializeStorageRequestBlock ensures buffer access is bounded")
                status = InitializeStorageRequestBlock(srbEx,
                                                       STORAGE_ADDRESS_TYPE_BTL8,
                                                       sizeof(srbExBuffer),
                                                       1,
                                                       SrbExDataTypeScsiCdb16);
                if (NT_SUCCESS(status)) {
                    srbEx->TimeOutValue = fdoExtension->TimeOutValue;
                    SrbSetCdbLength(srbEx, 6);
                    cdb = SrbGetCdb(srbEx);
                    srbPtr = (PSCSI_REQUEST_BLOCK)srbEx;
                } else {
                    //
                    // Should not happen. Revert to legacy SRB.
                    //
                    NT_ASSERT(FALSE);
                    srb.TimeOutValue = fdoExtension->TimeOutValue;
                    srb.CdbLength = 6;
                    cdb = (PCDB) &(srb.Cdb);
                    srbPtr = &srb;
                }

            } else {

                srb.TimeOutValue = fdoExtension->TimeOutValue;
                srb.CdbLength = 6;
                cdb = (PCDB) &(srb.Cdb);
                srbPtr = &srb;

            }

            cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;

            //
            // TRUE - prevent media removal.
            // FALSE - allow media removal.
            //

            cdb->MEDIA_REMOVAL.Prevent = FALSE;

            status = ClassSendSrbSynchronous(fdoExtension->DeviceObject,
                                             srbPtr,
                                             NULL,
                                             0,
                                             FALSE);

            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
                        "ClasspCleanupProtectedLocks: unlock request to drive "
                        "returned status %lx\n", status));
        }
    }

    KeSetEvent(&fdoExtension->EjectSynchronizationEvent,
               IO_NO_INCREMENT,
               FALSE);
    KeLeaveCriticalRegion();
    return;
}
Exemplo n.º 12
0
VOID
ApphelpCacheReleaseLock(VOID)
{
    ExReleaseResourceLite(&ApphelpCacheLock);
    KeLeaveCriticalRegion();
}
Exemplo n.º 13
0
BOOLEAN
KspSynchronizedEventRoutine(
    IN KSEVENTS_LOCKTYPE EventsFlags,
    IN PVOID EventsLock,
    IN PKSEVENT_SYNCHRONIZED_ROUTINE SynchronizedRoutine,
    IN PKSEVENT_CTX Ctx)
{
    BOOLEAN Result = FALSE;
    KIRQL OldLevel;

    if (EventsFlags == KSEVENTS_NONE)
    {
        /* no synchronization required */
        Result = SynchronizedRoutine(Ctx);
    }
    else if (EventsFlags == KSEVENTS_SPINLOCK)
    {
        /* use spin lock */
        KeAcquireSpinLock((PKSPIN_LOCK)EventsLock, &OldLevel);
        Result = SynchronizedRoutine(Ctx);
        KeReleaseSpinLock((PKSPIN_LOCK)EventsLock, OldLevel);
    }
    else if (EventsFlags == KSEVENTS_MUTEX)
    {
        /* use a mutex */
        KeWaitForSingleObject(EventsLock, Executive, KernelMode, FALSE, NULL);
        Result = SynchronizedRoutine(Ctx);
        KeReleaseMutex((PRKMUTEX)EventsLock, FALSE);
    }
    else if (EventsFlags == KSEVENTS_FMUTEX)
    {
        /* use a fast mutex */
        ExAcquireFastMutex((PFAST_MUTEX)EventsLock);
        Result = SynchronizedRoutine(Ctx);
        ExReleaseFastMutex((PFAST_MUTEX)EventsLock);
    }
    else if (EventsFlags == KSEVENTS_FMUTEXUNSAFE)
    {
        /* acquire fast mutex unsafe */
        KeEnterCriticalRegion();
        ExAcquireFastMutexUnsafe((PFAST_MUTEX)EventsLock);
        Result = SynchronizedRoutine(Ctx);
        ExReleaseFastMutexUnsafe((PFAST_MUTEX)EventsLock);
        KeLeaveCriticalRegion();
    }
    else if (EventsFlags == KSEVENTS_INTERRUPT)
    {
        /* use interrupt for locking */
        Result = KeSynchronizeExecution((PKINTERRUPT)EventsLock, (PKSYNCHRONIZE_ROUTINE)SynchronizedRoutine, (PVOID)Ctx);
    }
    else if (EventsFlags == KSEVENTS_ERESOURCE)
    {
        /* use an eresource */
        KeEnterCriticalRegion();
        ExAcquireResourceExclusiveLite((PERESOURCE)EventsLock, TRUE);
        Result = SynchronizedRoutine(Ctx);
        ExReleaseResourceLite((PERESOURCE)EventsLock);
        KeLeaveCriticalRegion();
    }

    return Result;
}
Exemplo n.º 14
0
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT   pDriverObject,
    IN PUNICODE_STRING  pRegistryPath
    )
/*++

Routine Description:

    Called on loading. We create a device object to handle user-mode requests
    on, and register ourselves as a protocol with NDIS.

Arguments:

    pDriverObject - Pointer to driver object created by system.

    pRegistryPath - Pointer to the Unicode name of the registry path
        for this driver.

Return Value:

    NT Status code
    
--*/
{
    NDIS_PROTOCOL_DRIVER_CHARACTERISTICS   protocolChar = {0};
    NTSTATUS                        status = STATUS_SUCCESS;
    NDIS_STRING                     protoName = NDIS_STRING_CONST("NDISPROT");     
    UNICODE_STRING                  ntDeviceName;
    UNICODE_STRING                  win32DeviceName;
    BOOLEAN                         fSymbolicLink = FALSE;
    PDEVICE_OBJECT                  deviceObject = NULL;
    NDIS_HANDLE  ProtocolDriverContext={0};

    UNREFERENCED_PARAMETER(pRegistryPath);
	
    DEBUGP(DL_LOUD, ("DriverEntry\n"));

    Globals.pDriverObject = pDriverObject;
    Globals.EthType = NPROT_ETH_TYPE;
    NPROT_INIT_EVENT(&Globals.BindsComplete);

    do
    {
        //
        // Create our device object using which an application can
        // access NDIS devices.
        //
        RtlInitUnicodeString(&ntDeviceName, NT_DEVICE_NAME);

        status = IoCreateDevice (pDriverObject,
                                 0,
                                 &ntDeviceName,
                                 FILE_DEVICE_NETWORK,
                                 FILE_DEVICE_SECURE_OPEN,
                                 FALSE,
                                 &deviceObject);
    
        if (!NT_SUCCESS (status))
        {
            //
            // Either not enough memory to create a deviceobject or another
            // deviceobject with the same name exits. This could happen
            // if you install another instance of this device.
            //
            break;
        }

        RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME);

        status = IoCreateSymbolicLink(&win32DeviceName, &ntDeviceName);

        if (!NT_SUCCESS(status))
        {
            break;
        }

        fSymbolicLink = TRUE;
    
        deviceObject->Flags |= DO_DIRECT_IO;
        Globals.ControlDeviceObject = deviceObject;

        NPROT_INIT_LIST_HEAD(&Globals.OpenList);
        NPROT_INIT_LOCK(&Globals.GlobalLock);

        //
        // Initialize the protocol characterstic structure
        //     
#if (NDIS_SUPPORT_NDIS630)
        {C_ASSERT(sizeof(protocolChar) >= NDIS_SIZEOF_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_2);}
        protocolChar.Header.Type        = NDIS_OBJECT_TYPE_PROTOCOL_DRIVER_CHARACTERISTICS,
        protocolChar.Header.Size        = NDIS_SIZEOF_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_2;
        protocolChar.Header.Revision    = NDIS_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_2;
#elif (NDIS_SUPPORT_NDIS6)
        {C_ASSERT(sizeof(protocolChar) >= NDIS_SIZEOF_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_1);}
        protocolChar.Header.Type        = NDIS_OBJECT_TYPE_PROTOCOL_DRIVER_CHARACTERISTICS,
        protocolChar.Header.Size        = NDIS_SIZEOF_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_1;
        protocolChar.Header.Revision    = NDIS_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_1;
#endif // NDIS MINIPORT VERSION

        protocolChar.MajorNdisVersion            = NDIS_PROT_MAJOR_VERSION;
        protocolChar.MinorNdisVersion            = NDIS_PROT_MINOR_VERSION;
        protocolChar.MajorDriverVersion          = MAJOR_DRIVER_VERSION;
        protocolChar.MinorDriverVersion          = MINOR_DRIVER_VERISON;
        protocolChar.Name                        = protoName;
        protocolChar.SetOptionsHandler           = NULL;
        protocolChar.OpenAdapterCompleteHandlerEx  = NdisprotOpenAdapterComplete;
        protocolChar.CloseAdapterCompleteHandlerEx = NdisprotCloseAdapterComplete;
        protocolChar.SendNetBufferListsCompleteHandler = NdisprotSendComplete;
        protocolChar.OidRequestCompleteHandler   = NdisprotRequestComplete;
        protocolChar.StatusHandlerEx             = NdisprotStatus;
        protocolChar.UninstallHandler            = NULL;
        protocolChar.ReceiveNetBufferListsHandler = NdisprotReceiveNetBufferLists;
        protocolChar.NetPnPEventHandler          = NdisprotPnPEventHandler;
        protocolChar.BindAdapterHandlerEx        = NdisprotBindAdapter;
        protocolChar.UnbindAdapterHandlerEx      = NdisprotUnbindAdapter;

        //
        // Register as a protocol driver
        //
    
        status = NdisRegisterProtocolDriver(ProtocolDriverContext,           // driver context
                                            &protocolChar,
                                            &Globals.NdisProtocolHandle);

        if (status != NDIS_STATUS_SUCCESS)
        {
            DEBUGP(DL_WARN, ("Failed to register protocol with NDIS\n"));
            status = STATUS_UNSUCCESSFUL;
            break;
        }

        Globals.PartialCancelId = NdisGeneratePartialCancelId();
        Globals.PartialCancelId <<= ((sizeof(PVOID) - 1) * 8);
        DEBUGP(DL_LOUD, ("DriverEntry: CancelId %lx\n", Globals.PartialCancelId));

        //
        // Now set only the dispatch points we would like to handle.
        //

        pDriverObject->MajorFunction[IRP_MJ_CREATE] = NdisprotOpen;

        pDriverObject->MajorFunction[IRP_MJ_CLOSE]  = NdisprotClose;

        pDriverObject->MajorFunction[IRP_MJ_READ]   = NdisprotRead;

        pDriverObject->MajorFunction[IRP_MJ_WRITE]  = NdisprotWrite;

        pDriverObject->MajorFunction[IRP_MJ_CLEANUP]  = NdisprotCleanup;

        pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = NdisprotIoControl;
        

        pDriverObject->DriverUnload = NdisprotUnload;

        status = STATUS_SUCCESS;

        
    }
    while (FALSE);
       

    if (!NT_SUCCESS(status))
    {
        if (deviceObject)
        {
            KeEnterCriticalRegion();
            IoDeleteDevice(deviceObject);
            KeLeaveCriticalRegion();
            Globals.ControlDeviceObject = NULL;
        }

        if (fSymbolicLink)
        {
            IoDeleteSymbolicLink(&win32DeviceName);
            fSymbolicLink = FALSE;
        }
        
        if (Globals.NdisProtocolHandle)
        {
            NdisDeregisterProtocolDriver(Globals.NdisProtocolHandle);
            Globals.NdisProtocolHandle = NULL;
        }        
    }
    
    return status;
}
Exemplo n.º 15
0
/*
 * @implemented
 */
LONG
NTAPI
KeReleaseMutant(IN PKMUTANT Mutant,
                IN KPRIORITY Increment,
                IN BOOLEAN Abandon,
                IN BOOLEAN Wait)
{
    KIRQL OldIrql;
    LONG PreviousState;
    PKTHREAD CurrentThread = KeGetCurrentThread();
    BOOLEAN EnableApc = FALSE;
    ASSERT_MUTANT(Mutant);
    ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);

    /* Lock the Dispatcher Database */
    OldIrql = KiAcquireDispatcherLock();

    /* Save the Previous State */
    PreviousState = Mutant->Header.SignalState;

    /* Check if it is to be abandonned */
    if (Abandon == FALSE)
    {
        /* Make sure that the Owner Thread is the current Thread */
        if (Mutant->OwnerThread != CurrentThread)
        {
            /* Release the lock */
            KiReleaseDispatcherLock(OldIrql);

            /* Raise an exception */
            ExRaiseStatus(Mutant->Abandoned ? STATUS_ABANDONED :
                                              STATUS_MUTANT_NOT_OWNED);
        }

        /* If the thread owns it, then increase the signal state */
        Mutant->Header.SignalState++;
    }
    else
    {
        /* It's going to be abandonned */
        Mutant->Header.SignalState = 1;
        Mutant->Abandoned = TRUE;
    }

    /* Check if the signal state is only single */
    if (Mutant->Header.SignalState == 1)
    {
        /* Check if it's below 0 now */
        if (PreviousState <= 0)
        {
            /* Remove the mutant from the list */
            RemoveEntryList(&Mutant->MutantListEntry);

            /* Save if we need to re-enable APCs */
            EnableApc = Mutant->ApcDisable;
        }

        /* Remove the Owning Thread and wake it */
        Mutant->OwnerThread = NULL;

        /* Check if the Wait List isn't empty */
        if (!IsListEmpty(&Mutant->Header.WaitListHead))
        {
            /* Wake the Mutant */
            KiWaitTest(&Mutant->Header, Increment);
        }
    }

    /* Check if the caller wants to wait after this release */
    if (Wait == FALSE)
    {
        /* Release the Lock */
        KiReleaseDispatcherLock(OldIrql);
    }
    else
    {
        /* Set a wait */
        CurrentThread->WaitNext = TRUE;
        CurrentThread->WaitIrql = OldIrql;
    }

    /* Check if we need to re-enable APCs */
    if (EnableApc) KeLeaveCriticalRegion();

    /* Return the previous state */
    return PreviousState;
}
Exemplo n.º 16
0
NTSTATUS
NTAPI
PspCreateThread(OUT PHANDLE ThreadHandle,
                IN ACCESS_MASK DesiredAccess,
                IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
                IN HANDLE ProcessHandle,
                IN PEPROCESS TargetProcess,
                OUT PCLIENT_ID ClientId,
                IN PCONTEXT ThreadContext,
                IN PINITIAL_TEB InitialTeb,
                IN BOOLEAN CreateSuspended,
                IN PKSTART_ROUTINE StartRoutine OPTIONAL,
                IN PVOID StartContext OPTIONAL)
{
    HANDLE hThread;
    PEPROCESS Process;
    PETHREAD Thread;
    PTEB TebBase = NULL;
    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
    NTSTATUS Status, AccessStatus;
    HANDLE_TABLE_ENTRY CidEntry;
    ACCESS_STATE LocalAccessState;
    PACCESS_STATE AccessState = &LocalAccessState;
    AUX_ACCESS_DATA AuxData;
    BOOLEAN Result, SdAllocated;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    SECURITY_SUBJECT_CONTEXT SubjectContext;
    PAGED_CODE();
    PSTRACE(PS_THREAD_DEBUG,
            "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n",
            ThreadContext, TargetProcess, ProcessHandle);

    /* If we were called from PsCreateSystemThread, then we're kernel mode */
    if (StartRoutine) PreviousMode = KernelMode;

    /* Reference the Process by handle or pointer, depending on what we got */
    if (ProcessHandle)
    {
        /* Normal thread or System Thread */
        Status = ObReferenceObjectByHandle(ProcessHandle,
                                           PROCESS_CREATE_THREAD,
                                           PsProcessType,
                                           PreviousMode,
                                           (PVOID*)&Process,
                                           NULL);
        PSREFTRACE(Process);
    }
    else
    {
        /* System thread inside System Process, or Normal Thread with a bug */
        if (StartRoutine)
        {
            /* Reference the Process by Pointer */
            ObReferenceObject(TargetProcess);
            Process = TargetProcess;
            Status = STATUS_SUCCESS;
        }
        else
        {
            /* Fake ObReference returning this */
            Status = STATUS_INVALID_HANDLE;
        }
    }

    /* Check for success */
    if (!NT_SUCCESS(Status)) return Status;

    /* Also make sure that User-Mode isn't trying to create a system thread */
    if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess))
    {
        /* Fail */
        ObDereferenceObject(Process);
        return STATUS_INVALID_HANDLE;
    }

    /* Create Thread Object */
    Status = ObCreateObject(PreviousMode,
                            PsThreadType,
                            ObjectAttributes,
                            PreviousMode,
                            NULL,
                            sizeof(ETHREAD),
                            0,
                            0,
                            (PVOID*)&Thread);
    if (!NT_SUCCESS(Status))
    {
        /* We failed; dereference the process and exit */
        ObDereferenceObject(Process);
        return Status;
    }

    /* Zero the Object entirely */
    RtlZeroMemory(Thread, sizeof(ETHREAD));

    /* Initialize rundown protection */
    ExInitializeRundownProtection(&Thread->RundownProtect);

    /* Initialize exit code */
    Thread->ExitStatus = STATUS_PENDING;

    /* Set the Process CID */
    Thread->ThreadsProcess = Process;
    Thread->Cid.UniqueProcess = Process->UniqueProcessId;

    /* Create Cid Handle */
    CidEntry.Object = Thread;
    CidEntry.GrantedAccess = 0;
    Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry);
    if (!Thread->Cid.UniqueThread)
    {
        /* We couldn't create the CID, dereference the thread and fail */
        ObDereferenceObject(Thread);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    /* Save the read cluster size */
    Thread->ReadClusterSize = MmReadClusterSize;

    /* Initialize the LPC Reply Semaphore */
    KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1);

    /* Initialize the list heads and locks */
    InitializeListHead(&Thread->LpcReplyChain);
    InitializeListHead(&Thread->IrpList);
    InitializeListHead(&Thread->PostBlockList);
    InitializeListHead(&Thread->ActiveTimerListHead);
    KeInitializeSpinLock(&Thread->ActiveTimerListLock);

    /* Acquire rundown protection */
    if (!ExAcquireRundownProtection (&Process->RundownProtect))
    {
        /* Fail */
        ObDereferenceObject(Thread);
        return STATUS_PROCESS_IS_TERMINATING;
    }

    /* Now let the kernel initialize the context */
    if (ThreadContext)
    {
        /* User-mode Thread, create Teb */
        Status = MmCreateTeb(Process, &Thread->Cid, InitialTeb, &TebBase);
        if (!NT_SUCCESS(Status))
        {
            /* Failed to create the TEB. Release rundown and dereference */
            ExReleaseRundownProtection(&Process->RundownProtect);
            ObDereferenceObject(Thread);
            return Status;
        }

        /* Set the Start Addresses */
        Thread->StartAddress = (PVOID)KeGetContextPc(ThreadContext);
        Thread->Win32StartAddress = (PVOID)KeGetContextReturnRegister(ThreadContext);

        /* Let the kernel intialize the Thread */
        Status = KeInitThread(&Thread->Tcb,
                              NULL,
                              PspUserThreadStartup,
                              NULL,
                              Thread->StartAddress,
                              ThreadContext,
                              TebBase,
                              &Process->Pcb);
    }
    else
    {
        /* System Thread */
        Thread->StartAddress = StartRoutine;
        PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);

        /* Let the kernel intialize the Thread */
        Status = KeInitThread(&Thread->Tcb,
                              NULL,
                              PspSystemThreadStartup,
                              StartRoutine,
                              StartContext,
                              NULL,
                              NULL,
                              &Process->Pcb);
    }

    /* Check if we failed */
    if (!NT_SUCCESS(Status))
    {
        /* Delete the TEB if we had done */
        if (TebBase) MmDeleteTeb(Process, TebBase);

        /* Release rundown and dereference */
        ExReleaseRundownProtection(&Process->RundownProtect);
        ObDereferenceObject(Thread);
        return Status;
    }

    /* Lock the process */
    KeEnterCriticalRegion();
    ExAcquirePushLockExclusive(&Process->ProcessLock);

    /* Make sure the proces didn't just die on us */
    if (Process->ProcessDelete) goto Quickie;

    /* Check if the thread was ours, terminated and it was user mode */
    if ((Thread->Terminated) &&
        (ThreadContext) &&
        (Thread->ThreadsProcess == Process))
    {
        /* Cleanup, we don't want to start it up and context switch */
        goto Quickie;
    }

    /*
     * Insert the Thread into the Process's Thread List
     * Note, this is the ETHREAD Thread List. It is removed in
     * ps/kill.c!PspExitThread.
     */
    InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
    Process->ActiveThreads++;

    /* Start the thread */
    KeStartThread(&Thread->Tcb);

    /* Release the process lock */
    ExReleasePushLockExclusive(&Process->ProcessLock);
    KeLeaveCriticalRegion();

    /* Release rundown */
    ExReleaseRundownProtection(&Process->RundownProtect);

    /* Notify WMI */
    //WmiTraceProcess(Process, TRUE);
    //WmiTraceThread(Thread, InitialTeb, TRUE);

    /* Notify Thread Creation */
    PspRunCreateThreadNotifyRoutines(Thread, TRUE);

    /* Reference ourselves as a keep-alive */
    ObReferenceObjectEx(Thread, 2);

    /* Suspend the Thread if we have to */
    if (CreateSuspended) KeSuspendThread(&Thread->Tcb);

    /* Check if we were already terminated */
    if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb);

    /* Create an access state */
    Status = SeCreateAccessStateEx(NULL,
                                   ThreadContext ?
                                   PsGetCurrentProcess() : Process,
                                   &LocalAccessState,
                                   &AuxData,
                                   DesiredAccess,
                                   &PsThreadType->TypeInfo.GenericMapping);
    if (!NT_SUCCESS(Status))
    {
        /* Access state failed, thread is dead */
        PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);

        /* If we were suspended, wake it up */
        if (CreateSuspended) KeResumeThread(&Thread->Tcb);

        /* Dispatch thread */
        KeReadyThread(&Thread->Tcb);

        /* Dereference completely to kill it */
        ObDereferenceObjectEx(Thread, 2);
        return Status;
    }

    /* Insert the Thread into the Object Manager */
    Status = ObInsertObject(Thread,
                            AccessState,
                            DesiredAccess,
                            0,
                            NULL,
                            &hThread);

    /* Delete the access state if we had one */
    if (AccessState) SeDeleteAccessState(AccessState);

    /* Check for success */
    if (NT_SUCCESS(Status))
    {
        /* Wrap in SEH to protect against bad user-mode pointers */
        _SEH2_TRY
        {
            /* Return Cid and Handle */
            if (ClientId) *ClientId = Thread->Cid;
            *ThreadHandle = hThread;
        }
        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
        {
            /* Thread insertion failed, thread is dead */
            PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);

            /* If we were suspended, wake it up */
            if (CreateSuspended) KeResumeThread(&Thread->Tcb);

            /* Dispatch thread */
            KeReadyThread(&Thread->Tcb);

            /* Dereference it, leaving only the keep-alive */
            ObDereferenceObject(Thread);

            /* Close its handle, killing it */
            ObCloseHandle(ThreadHandle, PreviousMode);

            /* Return the exception code */
            _SEH2_YIELD(return _SEH2_GetExceptionCode());
        }
        _SEH2_END;
    }
    else
    {