/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    DevCtrl.c

Abstract:

    This module implements the File System Device Control routines for Rx
    called by the dispatch driver.

Author:

Revision History:

   Balan Sethu Raman [19-July-95] -- Hook it up to the mini rdr call down.

--*/

#include "precomp.h"
#pragma hdrstop

#include "ntddmup.h"

//
//  The local debug trace level
//

#define Dbg                              (DEBUG_TRACE_DEVCTRL)

NTSTATUS
RxLowIoIoCtlShellCompletion( RXCOMMON_SIGNATURE );


#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RxCommonDeviceControl)
#pragma alloc_text(PAGE, RxLowIoIoCtlShellCompletion)
#endif


NTSTATUS
RxCommonDeviceControl ( RXCOMMON_SIGNATURE )

/*++

Routine Description:

    This is the common routine for doing Device control operations called
    by both the fsd and fsp threads

Arguments:

    Irp - Supplies the Irp to process

    InFsp - Indicates if this is the fsp thread or someother thread

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status;
    RxCaptureRequestPacket;
    //RxCaptureFcb;
    //RxCaptureFobx;
    RxCaptureParamBlock;
    //RxCaptureFileObject;

    //NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);

    BOOLEAN SubmitLowIoRequest = TRUE;
    ULONG IoControlCode = capPARAMS->Parameters.DeviceIoControl.IoControlCode;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("RxCommonDeviceControl\n", 0));
    RxDbgTrace( 0, Dbg, ("Irp           = %08lx\n", capReqPacket));
    RxDbgTrace( 0, Dbg, ("MinorFunction = %08lx\n", capPARAMS->MinorFunction));

    //
    //

    if (IoControlCode == IOCTL_REDIR_QUERY_PATH) {
        Status = (STATUS_INVALID_DEVICE_REQUEST);
        SubmitLowIoRequest = FALSE;
    }

    if (SubmitLowIoRequest) {
        RxInitializeLowIoContext(&RxContext->LowIoContext,LOWIO_OP_IOCTL);
        Status = RxLowIoSubmit(RxContext,RxLowIoIoCtlShellCompletion);
    }

    RxDbgTrace(-1, Dbg, ("RxCommonDeviceControl -> %08lx\n", Status));
    return Status;
}

NTSTATUS
RxLowIoIoCtlShellCompletion( RXCOMMON_SIGNATURE )
/*++

Routine Description:

    This is the completion routine for IoCtl requests passed down to the mini rdr

Arguments:

    Irp - Supplies the Irp being processed

Return Value:

    RXSTATUS - The return status for the operation

--*/

{
    RxCaptureRequestPacket;
    //RxCaptureFcb;
    //RxCaptureFobx;
    //RxCaptureParamBlock;
    //RxCaptureFileObject;

    NTSTATUS       Status        = STATUS_SUCCESS;
    //NODE_TYPE_CODE TypeOfOpen    = NodeType(capFcb);
    PLOWIO_CONTEXT pLowIoContext  = &RxContext->LowIoContext;
    //ULONG          FsControlCode = capPARAMS->Parameters.FileSystemControl.FsControlCode;

    PAGED_CODE();

    Status = RxContext->StoredStatus;
    RxDbgTrace(+1, Dbg, ("RxLowIoIoCtlShellCompletion  entry  Status = %08lx\n", Status));

    switch (Status) {   //maybe success vs warning vs error
    case STATUS_SUCCESS:
    case STATUS_BUFFER_OVERFLOW:
       //capReqPacket->IoStatus.Information = pLowIoContext->ParamsFor.IoCtl.OutputBufferLength;
       capReqPacket->IoStatus.Information = RxContext->InformationToReturn;
       break;
    //case STATUS(CONNECTION_INVALID:
    default:
       break;
    }

    capReqPacket->IoStatus.Status = Status;
    RxDbgTrace(-1, Dbg, ("RxLowIoIoCtlShellCompletion  exit  Status = %08lx\n", Status));
    return Status;
}

#if 0


THIS CODE IS NOT USED CURRENTLY....IT'S BEING SAVED HERE TO MAP OVER TO HAVING RDBSS LOAD/UNLOAD EACH MINIRDR UNDER IOCTL

NTSTATUS
RxLoadMiniRdrs(
    IN PUNICODE_STRING RegistryPath
    );
VOID
RxUnloadMiniRdrs(
    void
    );

NTSYSAPI
NTSTATUS
NTAPI
ZwLoadDriver(
    IN PUNICODE_STRING DriverServiceName
    );
NTSYSAPI
NTSTATUS
NTAPI
ZwUnloadDriver(
    IN PUNICODE_STRING DriverServiceName
    );
PWCHAR RxMiniRdrInfo = NULL;
ULONG RxMiniRdrsLoaded = 0;

//CODE.IMPROVEMENT this should be allocated dynamically
#define MAXIMUM_NUMBER_OF_MINIRDRS 16
UNICODE_STRING RxLoadedDrivers[MAXIMUM_NUMBER_OF_MINIRDRS];
PWCHAR RxLoadedDriversNameBuffer = NULL;
ULONG RxNextDriverLoaded = 0;


NTSTATUS
RxFabricateRegistryStringZZ(
    IN OUT PUNICODE_STRING RegistryNameString,
    IN     PUNICODE_STRING DriverName,
    IN OUT PVOID           Buffer,
    IN     ULONG           BufferLength
    )
{
    UNICODE_STRING RegistryServicePrefix;
    NTSTATUS Status;

    RegistryNameString->Buffer = (PWCHAR)Buffer;
    RegistryNameString->MaximumLength = (USHORT)BufferLength;

    RtlInitUnicodeString(&RegistryServicePrefix, SERVICE_REGISTRY_KEY);

    RtlCopyUnicodeString(RegistryNameString,&RegistryServicePrefix);

    Status = RtlAppendUnicodeStringToString(RegistryNameString,DriverName);
    return(Status);
}

NTSTATUS
RxLoadMiniRdrs(
    IN PUNICODE_STRING RegistryPath
    )
/*++

Routine Description:

     This routine does an enumeration from the registry to load the minirdrs. It saves what it finds so it
     can unload them later. It also initializes the structures that are used to scan over minirdrs.......

Arguments:

     None.

Return Value:

     STATUS_SUCCESS if at least one minirdr was loaded
     STATUS_INSUFFICIENT_RESOURCES if the buffer to save the names could not be allocated
     STATUS_UNSUCCESSFUL if no minirdrs were loaded

--*/
{
    ULONG Storage[256];
    WCHAR ServiceNameRegistryStringBuffer[256]; //bugbug allocate this!
    UNICODE_STRING UnicodeString;
    PCHAR NextNameBufferPosition;
    HANDLE RdbssHandle = INVALID_HANDLE_VALUE;
    HANDLE MiniRdrsHandle = INVALID_HANDLE_VALUE;
    NTSTATUS Status;
    KEY_FULL_INFORMATION KeyInformation;
    PKEY_VALUE_BASIC_INFORMATION ValueInformation;
    ULONG DummyLength,Index;
    //ULONG BytesRead;
    OBJECT_ATTRIBUTES ObjectAttributes;
    //PKEY_VALUE_FULL_INFORMATION Value = (PKEY_VALUE_FULL_INFORMATION)Storage;

    DbgPrint("here we go\n");
    InitializeObjectAttributes(
        &ObjectAttributes,
        RegistryPath,               // name
        OBJ_CASE_INSENSITIVE,       // attributes
        NULL,                       // root
        NULL                        // security descriptor
        );

    Status = ZwOpenKey (&RdbssHandle, KEY_READ, &ObjectAttributes);

    if (!NT_SUCCESS(Status)) {
        DbgPrint("FirstOpenFailed: %08lx %wZ\n",Status,RegistryPath);
        RxLogFailure (
            RxFileSystemDeviceObject,
            NULL,
            EVENT_RDR_CANT_READ_REGISTRY,
            Status);

        goto FINALLY;
    }

    RtlInitUnicodeString(&UnicodeString, L"MiniRdrs");

    InitializeObjectAttributes(
        &ObjectAttributes,
        &UnicodeString,
        OBJ_CASE_INSENSITIVE,
        RdbssHandle,
        NULL
        );


    Status = ZwOpenKey (&MiniRdrsHandle, KEY_READ, &ObjectAttributes);

    if (!NT_SUCCESS(Status)) {
        DbgPrint("2ndOpenFailed: %08lx %wZ\n",Status,&UnicodeString);
        RxLogFailure (
            RxFileSystemDeviceObject,
            NULL,
            EVENT_RDR_CANT_READ_REGISTRY,
            Status);

        goto FINALLY;
    }

    Status = ZwQueryKey (MiniRdrsHandle, KeyFullInformation, &KeyInformation,sizeof(KeyInformation),&DummyLength);
    if (!NT_SUCCESS(Status)) {
        DbgPrint("QueryFailed: %08lx %wZ\n",Status,&UnicodeString);
        RxLogFailure (
            RxFileSystemDeviceObject,
            NULL,
            EVENT_RDR_CANT_READ_REGISTRY,
            Status);

        goto FINALLY;
    }

    DbgPrint("HandleInfo %08lx %08lx %08lx\n",
               KeyInformation.Values,
               KeyInformation.MaxValueNameLen,
               KeyInformation.MaxValueDataLen);

    RxLoadedDriversNameBuffer = RxAllocatePoolWithTag(PagedPool,
                                              KeyInformation.Values*KeyInformation.MaxValueNameLen,
                                              'xMxR');
    if (RxLoadedDriversNameBuffer==NULL) {
        DbgPrint("NameBufferAllocFailed: %08lx %wZ\n",Status,&UnicodeString);
        RxLogFailure (
            RxFileSystemDeviceObject,
            NULL,
            EVENT_RDR_CANT_READ_REGISTRY,
            Status);

        goto FINALLY;
    }

    NextNameBufferPosition = (PCHAR)RxLoadedDriversNameBuffer;
    ValueInformation = (PKEY_VALUE_BASIC_INFORMATION)(&Storage[0]); //this restricts the name length..we'll just skip long ones
    for (Index=0;Index<KeyInformation.Values;Index++) {
        UNICODE_STRING DriverName,RegistryNameString;
        NTSTATUS LoadStatus;
        ULONG ThisDriver;

        LoadStatus = ZwEnumerateValueKey(MiniRdrsHandle,
                                     Index,
                                     KeyValueBasicInformation,
                                     ValueInformation,
                                     sizeof(Storage),
                                     &DummyLength);
        if (!NT_SUCCESS(LoadStatus)) {
            continue;
        }

        DriverName.Length = DriverName.MaximumLength = (USHORT)(ValueInformation->NameLength);
        DriverName.Buffer = &(ValueInformation->Name[0]);

        LoadStatus = RxFabricateRegistryStringZZ(&RegistryNameString,
                                               &DriverName,
                                               &ServiceNameRegistryStringBuffer[0],
                                               sizeof(ServiceNameRegistryStringBuffer));
        if (!NT_SUCCESS(LoadStatus)) {
            continue;
        }

        DbgPrint(">>LOADING %wZ:%wZ\n",&DriverName,&RegistryNameString);
        LoadStatus = ZwLoadDriver(&RegistryNameString);
        if (!NT_SUCCESS(LoadStatus)) {
            continue;
        }

        ThisDriver = RxNextDriverLoaded;
        RxNextDriverLoaded++;
        RxLoadedDrivers[ThisDriver].Buffer = (PWCHAR)NextNameBufferPosition;
        RxLoadedDrivers[ThisDriver].Length = DriverName.MaximumLength;
        RxLoadedDrivers[ThisDriver].MaximumLength = DriverName.MaximumLength;
        RtlCopyMemory(NextNameBufferPosition,DriverName.Buffer,DriverName.MaximumLength);
        NextNameBufferPosition+=DriverName.MaximumLength;
        DbgPrint(">>SAVEDNAME %wZ:%wZ\n",&DriverName,&RxLoadedDrivers[ThisDriver]);

    }

FINALLY:
    if (MiniRdrsHandle!=INVALID_HANDLE_VALUE) ZwClose(MiniRdrsHandle);
    if (MiniRdrsHandle!=INVALID_HANDLE_VALUE) ZwClose(RdbssHandle);
    if (!NT_SUCCESS(Status)) {
        RxUnloadMiniRdrs();
    }
    return Status;
}



VOID
RxUnloadMiniRdrs(
    void
    )
{
    ULONG ThisDriver;
    WCHAR ServiceNameRegistryStringBuffer[256]; //bugbug allocate this!

    PAGED_CODE(); //not actually in use

    DbgPrint("here we ungo, drivertounload=%08lx\n",RxNextDriverLoaded);

    for (ThisDriver=0;ThisDriver<RxNextDriverLoaded;ThisDriver++) {
        NTSTATUS LoadStatus;
        UNICODE_STRING RegistryNameString;
        DbgPrint(">>Unloading %wZ\n",&RxLoadedDrivers[ThisDriver]);
        LoadStatus = RxFabricateRegistryStringZZ(&RegistryNameString,
                                               &RxLoadedDrivers[ThisDriver],
                                               &ServiceNameRegistryStringBuffer[0],
                                               sizeof(ServiceNameRegistryStringBuffer));
        LoadStatus = ZwUnloadDriver(&RegistryNameString);
        DbgPrint(">>Unloaded %wZ, status =%08lx\n",&RxLoadedDrivers[ThisDriver],LoadStatus);
        //no status check.....can't do anything anyway!
    }

    if (RxLoadedDriversNameBuffer!=NULL) RxFreePool(RxLoadedDriversNameBuffer);

    return;
}




#endif