/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    Init.c

Abstract:

    This module implements the DRIVER_INITIALIZATION routine for the PROXY mini rdr.

Author:

    Balan Sethu Raman [SethuR]    7-Mar-1995

Revision History:


--*/

#include "precomp.h"
#pragma hdrstop
#include "ntverp.h"
#include "netevent.h"
#include "nvisible.h"

#define RDBSS_DRIVER_LOAD_STRING L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Rdbss"
NTSYSAPI
NTSTATUS
NTAPI
ZwLoadDriver(
    IN PUNICODE_STRING DriverServiceName
    );

//
// Global data declarations .   CODE.IMPROVEMENT why are these placed here!!
//

PEPROCESS MRxProxySystemProcess;

FAST_MUTEX   MRxProxySerializationMutex;
KIRQL           MRxProxyGlobalSpinLockSavedIrql;
KSPIN_LOCK      MRxProxyGlobalSpinLock;
BOOLEAN         MRxProxyGlobalSpinLockAcquired;

#ifdef EXPLODE_POOLTAGS
ULONG         MRxProxyExplodePoolTags = 1;
#else
ULONG         MRxProxyExplodePoolTags = 0;
#endif

NTSTATUS
MRxProxyInitializeTables(
          void
    );

NTSTATUS
ProxyCeGetConfigurationInformation (
          void
    );

VOID
MRxProxyUnload(
    IN PDRIVER_OBJECT DriverObject
    );

NTSTATUS
MRxProxyGetUlongRegistryParameter(
    HANDLE ParametersHandle,
    PWCHAR ParameterName,
    PULONG ParamUlong,
    BOOLEAN LogFailure
    );

//
// Mini Redirector global variables.
//

struct _MINIRDR_DISPATCH  MRxProxyDispatch;

PMRXPROXY_DEVICE_OBJECT MRxProxyDeviceObject;

ULONG MRxProxyBuildNumber = VER_PRODUCTBUILD;
#ifdef RX_PRIVATE_BUILD
ULONG MRxProxyPrivateBuild = 1;
#else
ULONG MRxProxyPrivateBuild = 0;
#endif


//declare the shadow debugtrace controlpoints

RXDT_DefineCategory(CREATE);
RXDT_DefineCategory(CLEANUP);
RXDT_DefineCategory(CLOSE);
RXDT_DefineCategory(READ);
RXDT_DefineCategory(WRITE);
RXDT_DefineCategory(LOCKCTRL);
RXDT_DefineCategory(FLUSH);
RXDT_DefineCategory(PREFIX);
RXDT_DefineCategory(FCBSTRUCTS);
RXDT_DefineCategory(DISPATCH);
RXDT_DefineCategory(EA);
RXDT_DefineCategory(DEVFCB);


typedef enum _MRXPROXY_INIT_STATES {
    MRXPROXYINIT_ALL_INITIALIZATION_COMPLETED,
    MRXPROXYINIT_MINIRDR_REGISTERED,
    MRXPROXYINIT_START
} MRXPROXY_INIT_STATES;

VOID
MRxProxyInitUnwind(
    IN PDRIVER_OBJECT DriverObject,
    IN MRXPROXY_INIT_STATES MRxProxyInitState
    );


NTSTATUS
MRxProxyFsdDispatch (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
/*++

Routine Description:

    This is the initialization routine for the PROXY mini redirector

Arguments:

    DriverObject - Pointer to driver object created by the system.

Return Value:

    RXSTATUS - The function value is the final status from the initialization
        operation.

--*/
{
    NTSTATUS       Status;
    //UNICODE_STRING MRxProxyRdbssDriverLoadString;
    MRXPROXY_INIT_STATES MRxProxyInitState = 0;
    UNICODE_STRING ProxyMiniRedirectorName;


#ifdef MONOLITHIC_MINIRDR
    DbgPrint("InitWrapper\n");
    Status =  RxDriverEntry(DriverObject, RegistryPath);
    DbgPrint("BackFromInitWrapper %08lx\n",Status);
    if (Status != STATUS_SUCCESS) {
        DbgPrint("Wrapper failed to initialize. Status = %08lx\n",Status);
        return(Status);
    }
#endif

    MRxProxySystemProcess = RxGetRDBSSProcess();

    MRxProxyInitializeLoudStrings();

    ExInitializeFastMutex(&MRxProxySerializationMutex);
    KeInitializeSpinLock(&MRxProxyGlobalSpinLock );
    MRxProxyGlobalSpinLockAcquired = FALSE;

    try {

        MRxProxyInitState = MRXPROXYINIT_START;

        RtlInitUnicodeString(&ProxyMiniRedirectorName,MRXPROXY_DEVICE_NAME_U);
        RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("MRxProxyDriverEntry: DriverObject =%08lx\n", DriverObject ));

        Status = RxRegisterMinirdr((PRDBSS_DEVICE_OBJECT *)(&MRxProxyDeviceObject),
                                    DriverObject,
                                    &MRxProxyDispatch,
                                    FALSE,FALSE,     //don't register with unc and for mailslots
                                    &ProxyMiniRedirectorName,
                                    sizeof(MRXPROXY_DEVICE_OBJECT) - sizeof(RDBSS_DEVICE_OBJECT), //IN  ULONG DeviceExtensionSize,
                                    0 //IN  ULONG DeviceCharacteristics
                                    );
        if (Status!=STATUS_SUCCESS) {
            RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("MRxProxyDriverEntry failed: %08lx\n", Status ));
            try_return(Status);
        }
        MRxProxyInitState = MRXPROXYINIT_MINIRDR_REGISTERED;
        MRxProxyDeviceObject->SectorSize = 512;  //BUGBUG go find out
        RtlInitUnicodeString(&MRxProxyDeviceObject->InnerPrefixForOpens,
                             MRXPROXY_INNERPREFIX_FOR_OPENS
                            );
        RtlInitUnicodeString(&MRxProxyDeviceObject->PrefixForRename,
                              MRXPROXY_INNERPREFIX_FOR_OPENS
                              //MRXPROXY_PREFIX_FOR_RENAME
                            );

        //for all this stuff, there's no undo.....so no extra state

        Status = MRxProxyInitializeTables();
        if (!NT_SUCCESS( Status )) {
            try_return(Status);
        }

        Status = ProxyCeGetConfigurationInformation();
        if (!NT_SUCCESS( Status )) {
            try_return(Status);
        }


  try_exit: NOTHING;
    } finally {
        if (Status != STATUS_SUCCESS) {
            MRxProxyInitUnwind(DriverObject,MRxProxyInitState);
        }
    }
    if (Status != STATUS_SUCCESS) {
        DbgPrint("MRxProxy failed to start with %08lx %08lx\n",Status,MRxProxyInitState);
        return(Status);
    }


    //  Setup Unload Routine
    DriverObject->DriverUnload = MRxProxyUnload;

    //setup the driverdispatch for people who come in here directly....like the browser
    //CODE.IMPROVEMENT we should change this code so that the things that aren't examined
    //    in MRxProxyFsdDispatch are routed directly, i.e. reads and writes
    {ULONG i;
    for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
        DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)MRxProxyFsdDispatch;
    }}

    //and get out
    return  STATUS_SUCCESS;
}

VOID
MRxProxyInitUnwind(
    IN PDRIVER_OBJECT DriverObject,
    IN MRXPROXY_INIT_STATES MRxProxyInitState
    )
/*++

Routine Description:

     This routine does the common uninit work for unwinding from a bad driver entry or for unloading.

Arguments:

     RxInitState - tells how far we got into the intialization

Return Value:

     None

--*/

{
    PAGED_CODE();

    switch (MRxProxyInitState) {
    case MRXPROXYINIT_ALL_INITIALIZATION_COMPLETED:
        //Nothing extra to do...this is just so that the constant in RxUnload doesn't change.......
        //lack of break intentional


    case MRXPROXYINIT_MINIRDR_REGISTERED:
        RxUnregisterMinirdr(&MRxProxyDeviceObject->RxDeviceObject);
        //lack of break intentional

    case MRXPROXYINIT_START:
        break;
    }

}


VOID
MRxProxyUnload(
    IN PDRIVER_OBJECT DriverObject
    )
/*++

Routine Description:

     This is the unload routine for the PROXY mini redirector.

Arguments:

     DriverObject - pointer to the driver object for the MRxProxy

Return Value:

     None

--*/

{
    PAGED_CODE();
    RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("MRxProxyUnload: DriverObject =%08lx\n", DriverObject) );
    //ASSERT(!"Starting to unload!");
    //RxUnregisterMinirdr(MRxProxyDeviceObject);
    MRxProxyInitUnwind(DriverObject,MRXPROXYINIT_ALL_INITIALIZATION_COMPLETED);

#ifdef MONOLITHIC_MINIRDR
    RxUnload(DriverObject);
#endif

    RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("MRxProxyUnload exit: DriverObject =%08lx\n", DriverObject) );
}



NTSTATUS
MRxProxyInitializeTables(
          void
    )
/*++

Routine Description:

     This routine sets up the mini redirector dispatch vector and also calls to initialize any other tables needed.

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    // Ensure that the PROXY mini redirector context satisfies the size constraints
    ASSERT(sizeof(MRXPROXY_RX_CONTEXT) <= MRX_CONTEXT_SIZE);

    //local minirdr dispatch table init
    ZeroAndInitializeNodeType( &MRxProxyDispatch, RDBSS_NTC_MINIRDR_DISPATCH, sizeof(MINIRDR_DISPATCH));

    // PROXY mini redirector extension sizes and allocation policies.
    // CODE.IMPROVEMENT -- currently we do not allocate the NET_ROOT and SRV_CALL extensions
    // in the wrapper. Except for V_NET_ROOT wherein it is shared across multiple instances in
    // the wrapper all the other data structure management should be left to the wrappers

    MRxProxyDispatch.MRxFlags = (RDBSS_MANAGE_FCB_EXTENSION |
                               RDBSS_MANAGE_SRV_OPEN_EXTENSION |
                               RDBSS_MANAGE_FOBX_EXTENSION);

    MRxProxyDispatch.MRxSrvCallSize  = 0;
    MRxProxyDispatch.MRxNetRootSize  = 0;
    MRxProxyDispatch.MRxVNetRootSize = 0;
    MRxProxyDispatch.MRxFcbSize      = sizeof(MRX_PROXY_FCB);
    MRxProxyDispatch.MRxSrvOpenSize  = sizeof(MRX_PROXY_SRV_OPEN);
    MRxProxyDispatch.MRxFobxSize     = sizeof(MRX_PROXY_FOBX);

//    // Transport update handler
//    MRxProxyDispatch.MRxTransportUpdateHandler = MRxProxyTransportUpdateHandler;

    // Mini redirector cancel routine ..
    MRxProxyDispatch.MRxCancel = NULL;

    // Mini redirector Start/Stop
    MRxProxyDispatch.MRxStart          = MRxProxyStart;
    MRxProxyDispatch.MRxStop           = MRxProxyStop;
    //MRxProxyDispatch.MRxMinirdrControl = MRxProxyMinirdrControl;    //now we have no way to readch this BUGBUG
    MRxProxyDispatch.MRxDevFcbXXXControlFile = MRxProxyDevFcbXXXControlFile;

    // Mini redirector name resolution
    MRxProxyDispatch.MRxCreateSrvCall = MRxProxyCreateSrvCall;
    MRxProxyDispatch.MRxSrvCallWinnerNotify = MRxProxySrvCallWinnerNotify;
    MRxProxyDispatch.MRxCreateVNetRoot = MRxProxyCreateVNetRoot;
    MRxProxyDispatch.MRxUpdateNetRootState = MRxProxyUpdateNetRootState;
    MRxProxyDispatch.MRxExtractNetRootName = MRxProxyExtractNetRootName;
    MRxProxyDispatch.MRxFinalizeSrvCall = MRxProxyFinalizeSrvCall;
    MRxProxyDispatch.MRxFinalizeNetRoot = MRxProxyFinalizeNetRoot;
    MRxProxyDispatch.MRxFinalizeVNetRoot = MRxProxyFinalizeVNetRoot;

    // File System Object Creation/Deletion.
    MRxProxyDispatch.MRxCreate            = MRxProxyCreate;
    MRxProxyDispatch.MRxCollapseOpen      = MRxProxyCollapseOpen;
    MRxProxyDispatch.MRxShouldTryToCollapseThisOpen      = MRxProxyShouldTryToCollapseThisOpen;
    MRxProxyDispatch.MRxExtendForCache    = MRxProxyExtendForCache;
    MRxProxyDispatch.MRxExtendForNonCache = MRxProxyExtendForNonCache;
    MRxProxyDispatch.MRxTruncate          = MRxProxyTruncate;
    MRxProxyDispatch.MRxCleanupFobx       = MRxProxyCleanupFobx;
    MRxProxyDispatch.MRxCloseSrvOpen      = MRxProxyCloseSrvOpen;
    MRxProxyDispatch.MRxFlush             = MRxProxyFlush;
    MRxProxyDispatch.MRxForceClosed       = MRxProxyForcedClose;
    MRxProxyDispatch.MRxDeallocateForFcb  = MRxProxyDeallocateForFcb;
    MRxProxyDispatch.MRxDeallocateForFobx = MRxProxyDeallocateForFobx;
    MRxProxyDispatch.MRxIsLockRealizable  = MRxProxyIsLockRealizable;

    // File System Objects query/Set
    MRxProxyDispatch.MRxQueryDirectory  = MRxProxyQueryDirectory;
    MRxProxyDispatch.MRxQueryVolumeInfo = MRxProxyQueryVolumeInformation;
    MRxProxyDispatch.MRxQueryEaInfo     = MRxProxyQueryEaInformation;
    MRxProxyDispatch.MRxSetEaInfo       = MRxProxySetEaInformation;
    MRxProxyDispatch.MRxQuerySdInfo     = MRxProxyQuerySecurityInformation;
    MRxProxyDispatch.MRxSetSdInfo       = MRxProxySetSecurityInformation;
    MRxProxyDispatch.MRxQueryFileInfo   = MRxProxyQueryFileInformation;
    MRxProxyDispatch.MRxSetFileInfo     = MRxProxySetFileInformation;
    MRxProxyDispatch.MRxSetFileInfoAtCleanup
                                      = MRxProxySetFileInformationAtCleanup;


    // Buffering state change
    MRxProxyDispatch.MRxComputeNewBufferingState = MRxProxyComputeNewBufferingState;

    // File System Object I/O
    MRxProxyDispatch.MRxLowIOSubmit[LOWIO_OP_READ]            = MRxProxyRead;
    MRxProxyDispatch.MRxLowIOSubmit[LOWIO_OP_WRITE]           = MRxProxyWrite;
    MRxProxyDispatch.MRxLowIOSubmit[LOWIO_OP_SHAREDLOCK]      = MRxProxyLocks;
    MRxProxyDispatch.MRxLowIOSubmit[LOWIO_OP_EXCLUSIVELOCK]   = MRxProxyLocks;
    MRxProxyDispatch.MRxLowIOSubmit[LOWIO_OP_UNLOCK]          = MRxProxyLocks;
    MRxProxyDispatch.MRxLowIOSubmit[LOWIO_OP_UNLOCK_MULTIPLE] = MRxProxyLocks;
    MRxProxyDispatch.MRxLowIOSubmit[LOWIO_OP_FSCTL]           = MRxProxyFsCtl;
    MRxProxyDispatch.MRxLowIOSubmit[LOWIO_OP_IOCTL]           = MRxProxyIoCtl;
    //CODE.IMPROVEMENT  shouldn't flush come thru lowio???
    MRxProxyDispatch.MRxLowIOSubmit[LOWIO_OP_NOTIFY_CHANGE_DIRECTORY] = MRxProxyNotifyChangeDirectory;

    //no longer a field MRxProxyDispatch.MRxUnlockRoutine   = MRxProxyUnlockRoutine;


    // Miscellanous
    MRxProxyDispatch.MRxCompleteBufferingStateChangeRequest = MRxProxyCompleteBufferingStateChangeRequest;

    return(STATUS_SUCCESS);
}

NTSTATUS
MRxProxyStart(
    PRX_CONTEXT RxContext,
    IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject
    )
/*++

Routine Description:

     This routine completes the initialization of the mini redirector fromn the
     RDBSS perspective. Note that this is different from the initialization done
     in DriverEntry. Any initialization that depends on RDBSS should be done as
     part of this routine while the initialization that is independent of RDBSS
     should be done in the DriverEntry routine.

Arguments:

    RxContext - Supplies the Irp that was used to startup the rdbss

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status;

    Status = STATUS_SUCCESS;
    return Status;
}


NTSTATUS
MRxProxyStop(
    PRX_CONTEXT RxContext,
    IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject
    )
/*++

Routine Description:

    This routine is used to activate the mini redirector from the RDBSS perspective

Arguments:

    RxContext - the context that was used to start the mini redirector

    pContext  - the PROXY mini rdr context passed in at registration time.

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    //NTSTATUS Status;

    // Deallocate the configuration strings ....
#if 0
    if (ProxyCeContext.Transports.Buffer != NULL) {

        // the transports buffer is at the end of a larger buffer (by 12 bytes)
        // allocated to read the value from the registry. recover the original buffer
        // pointer in orer to free.

        PKEY_VALUE_PARTIAL_INFORMATION TransportsValueFromRegistry;
        TransportsValueFromRegistry = CONTAINING_RECORD(
                                         ProxyCeContext.Transports.Buffer,
                                         KEY_VALUE_PARTIAL_INFORMATION,
                                         Data[0]
                                      );
        //DbgPrint("b1 %08lx b2 %08lx\n", TransportsValueFromRegistry,ProxyCeContext.Transports.Buffer);
        RxFreePool(TransportsValueFromRegistry);
    }
#endif //0

    return(STATUS_SUCCESS);
}

#if 0
#define PROXYMRX_CONFIG_COMPUTER_NAME \
    L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName"

#define COMPUTERNAME L"ComputerName"

#define PROXYMRX_CONFIG_TRANSPORTS \
    L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Linkage"

#define TRANSPORT_BINDINGS L"Bind"

#define PROXYMRX_MINIRDR_PARAMETERS \
    L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\MRxProxy\\Parameters"

VOID
MRxProxyReadMiscellaneousRegistryParameters()
{
    NTSTATUS Status;
    //ULONG BytesRead;
    OBJECT_ATTRIBUTES ObjectAttributes;
    UNICODE_STRING ParametersRegistryKeyName;
    HANDLE ParametersHandle;
    ULONG Temp;

    RtlInitUnicodeString(&ParametersRegistryKeyName, PROXYMRX_MINIRDR_PARAMETERS);

    InitializeObjectAttributes(
        &ObjectAttributes,
        &ParametersRegistryKeyName,
        OBJ_CASE_INSENSITIVE,
        NULL,
        NULL
        );


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

    if (!NT_SUCCESS(Status)) {
        RxLogFailure(
            MRxProxyDeviceObject,
            NULL,
            EVENT_RDR_CANT_READ_REGISTRY,
            Status);

        return;
    }

    if (0) {
        MRxProxyGetUlongRegistryParameter(ParametersHandle,
                                  L"NoPreciousServerSetup",
                                  (PULONG)&Temp,
                                  FALSE
                                  );
    }


    Status = MRxProxyGetUlongRegistryParameter(ParametersHandle,
                              L"DeferredOpensEnabled",
                              (PULONG)&Temp,
                              FALSE
                              );
    if (NT_SUCCESS(Status)) MRxProxyDeferredOpensEnabled = (BOOLEAN)Temp;


    Status = MRxProxyGetUlongRegistryParameter(ParametersHandle,
                              L"OplocksDisabled",
                              (PULONG)&Temp,
                              FALSE
                              );
    if (NT_SUCCESS(Status)) MRxProxyOplocksDisabled = (BOOLEAN)Temp;

    ZwClose(ParametersHandle);

}
#endif

NTSTATUS
ProxyCeGetConfigurationInformation()
{
   ULONG            Storage[256];
   //UNICODE_STRING   UnicodeString;
   //HANDLE           hRegistryKey;
   //HANDLE           hProxyMrxConfiguration;
   //HANDLE           ParametersHandle;
   NTSTATUS         Status;
   //ULONG            BytesRead;

   //OBJECT_ATTRIBUTES ObjectAttributes;
   PKEY_VALUE_FULL_INFORMATION Value = (PKEY_VALUE_FULL_INFORMATION)Storage;
   //KEY_VALUE_PARTIAL_INFORMATION InitialPartialInformationValue;
   //ULONG AllocationLength;

   PAGED_CODE();

   //MRxProxyReadMiscellaneousRegistryParameters();

#if 0
   // Obtain the list of transports associated with PROXY redirector. This is stored
   // as a multivalued string and is used subsequently to weed out the
   // appropriate transports. This is a two step process; first we try to find out
   // how much space we need; then we allocate; then we read in. unfortunately, the kind of
   // structure that we have to use to get the value has a header on it, so we have to offset the
   // returned pointer both here and in the free routine.

   //CODE.IMPROVEMENT we should perhaps get a subroutine going that does all this
   //also, there are no log entries.
   //also, we should be doing partial_infos instead of full

   RtlInitUnicodeString(&ProxyCeContext.Transports, NULL);
   RtlInitUnicodeString(&UnicodeString, PROXYMRX_CONFIG_TRANSPORTS);

   InitializeObjectAttributes(
       &ObjectAttributes,
       &UnicodeString,             // name
       OBJ_CASE_INSENSITIVE,       // attributes
       NULL,                       // root
       NULL);                      // security descriptor

   Status = ZwOpenKey (&hRegistryKey, KEY_READ, &ObjectAttributes);
   if (!NT_SUCCESS(Status)) {
       return Status;
   }

   RtlInitUnicodeString(&UnicodeString, TRANSPORT_BINDINGS);
   Status = ZwQueryValueKey(
               hRegistryKey,
               &UnicodeString,
               KeyValuePartialInformation,
               &InitialPartialInformationValue,
               sizeof(InitialPartialInformationValue),
               &BytesRead);
   if (Status== STATUS_BUFFER_OVERFLOW) {
       Status = STATUS_SUCCESS;
   }
   if (!NT_SUCCESS(Status)) {
       return Status;
   }

   AllocationLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION)
                                  + InitialPartialInformationValue.DataLength;
   if (0) {
       DbgPrint("SizeofBindingInfo=%08lx %08lx\n",
                      AllocationLength,
                      InitialPartialInformationValue.DataLength);
   }

   //RtlInitUnicodeString(&UnicodeString, TRANSPORT_BINDINGS);
   {
   PKEY_VALUE_PARTIAL_INFORMATION TransportsValueFromRegistry;

   (PBYTE)TransportsValueFromRegistry = RxAllocatePoolWithTag(
                                             PagedPool,
                                             AllocationLength,
                                             MRXPROXY_MISC_POOLTAG);
   if (TransportsValueFromRegistry == NULL) {
       return(STATUS_INSUFFICIENT_RESOURCES);
   }

   Status = ZwQueryValueKey(
               hRegistryKey,
               &UnicodeString,
               KeyValuePartialInformation,
               TransportsValueFromRegistry,
               AllocationLength,
               &BytesRead);

   if (NT_SUCCESS(Status) &&
       (TransportsValueFromRegistry->DataLength > 0) &&
       (TransportsValueFromRegistry->Type == REG_MULTI_SZ)) {
      ProxyCeContext.Transports.MaximumLength =
          ProxyCeContext.Transports.Length = (USHORT)TransportsValueFromRegistry->DataLength;
      ProxyCeContext.Transports.Buffer = (PWCHAR)(&TransportsValueFromRegistry->Data[0]);
      //DbgPrint("b1 %08lx b2 %08lx\n", TransportsValueFromRegistry,ProxyCeContext.Transports.Buffer);
   } else {
      RxLog(("Invalid Transport Binding string... using all transports"));
      RxFreePool(TransportsValueFromRegistry);
   }
   }

   ZwClose(hRegistryKey);
#endif //0

   Status = STATUS_SUCCESS;
   return Status;
}


NTSTATUS
MRxProxyFsdDispatch (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine implements the FSD dispatch for the proxymini DRIVER object.

Arguments:

    DeviceObject - Supplies the device object for the packet being processed.

    Irp - Supplies the Irp being processed

Return Value:

    RXSTATUS - The Fsd status for the Irp

--*/
{
    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );  //ok4ioget
    UCHAR MajorFunctionCode = IrpSp->MajorFunction;

    ASSERT(DeviceObject==(PDEVICE_OBJECT)MRxProxyDeviceObject);
    if (DeviceObject!=(PDEVICE_OBJECT)MRxProxyDeviceObject) {
        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
        Irp->IoStatus.Information = 0;
        IoCompleteRequest(Irp, IO_NO_INCREMENT );
        return (STATUS_INVALID_DEVICE_REQUEST);
    }
    return RxFsdDispatch((PRDBSS_DEVICE_OBJECT)MRxProxyDeviceObject,Irp);
}

NTSTATUS
MRxProxyDeallocateForFcb (
    IN OUT PMRX_FCB pFcb
    )
/*++

Routine Description:

    This routine is called when the wrapper is about to deallocate a FCB.

Arguments:

    pFcb - the Fcb being deallocated.

Return Value:

    RXSTATUS - STATUS_SUCCESS

--*/
{
    //DbgPrint("Bob's opportunity to get rid of his fcb storage......\n");
    return(STATUS_SUCCESS);
}

NTSTATUS
MRxProxyDeallocateForFobx (
    IN OUT PMRX_FOBX pFobx
    )
/*++

Routine Description:

    This routine is called when the wrapper is about to deallocate a FOBX.

Arguments:

    pFobx - the Fobx being deallocated.

Return Value:

    RXSTATUS - STATUS_SUCCESS

--*/
{
    PMRX_PROXY_FOBX proxyFobx = MRxProxyGetFileObjectExtension(pFobx);
    PMRX_SRV_OPEN SrvOpen = pFobx->pSrvOpen;
    PMRX_FCB Fcb = SrvOpen->pFcb;

    IF_DEBUG {
        if (proxyFobx && FlagOn(proxyFobx->Enumeration.Flags,PROXYFOBX_ENUMFLAG_LOUD_FINALIZE)) {
            DbgPrint("Finalizobx side buffer %08lx %08lx %08lx %08lx %08lxon %wZ\n",
                     0, 0, //sidebuffer,count
                     proxyFobx,pFobx,&Fcb->AlreadyPrefixedName
                     );
        }
    }

    return(STATUS_SUCCESS);
}


NTSTATUS
MRxProxyGetUlongRegistryParameter(
    HANDLE ParametersHandle,
    PWCHAR ParameterName,
    PULONG ParamUlong,
    BOOLEAN LogFailure
    )
/*++

Routine Description:

    This routine is called to read a ULONG param from t he registry.

Arguments:

    ParametersHandle - the handle of the containing registry "folder"
    ParameterName    - name of the parameter to be read
    ParamUlong       - where to store the value, if successful
    LogFailure       - if TRUE and the registry stuff fails, log an error

Return Value:

    RXSTATUS - STATUS_SUCCESS

--*/
{
    ULONG Storage[16];
    PKEY_VALUE_PARTIAL_INFORMATION Value;
    ULONG ValueSize;
    UNICODE_STRING UnicodeString;
    NTSTATUS Status;
    ULONG BytesRead;

    PAGED_CODE(); //INIT

    Value = (PKEY_VALUE_PARTIAL_INFORMATION)Storage;
    ValueSize = sizeof(Storage);

    RtlInitUnicodeString(&UnicodeString, ParameterName);

    Status = ZwQueryValueKey(ParametersHandle,
                        &UnicodeString,
                        KeyValuePartialInformation,
                        Value,
                        ValueSize,
                        &BytesRead);


    if (NT_SUCCESS(Status)) {
        if (Value->Type == REG_DWORD) {
            PULONG ConfigValue = (PULONG)&Value->Data[0];
            *ParamUlong = *((PULONG)ConfigValue);
            DbgPrint("readRegistryvalue %wZ = %08lx\n",&UnicodeString,*ParamUlong);
            return(STATUS_SUCCESS);
        } else {
            Status = STATUS_INVALID_PARAMETER;
        }
     }

     if (!LogFailure) { return Status; }

     RxLogFailureWithBuffer(
         MRxProxyDeviceObject,
         NULL,
         EVENT_RDR_CANT_READ_REGISTRY,
         Status,
         ParameterName,
         (USHORT)(wcslen(ParameterName)*sizeof(WCHAR))
         );

     return Status;
}

