/*++

Copyright (c) 1992  Microsoft Corporation

Module Name:

    NwInit.c

Abstract:

    This module implements the DRIVER_INITIALIZATION routine for NetWare

Author:

    Colin Watson     [ColinW]    15-Dec-1992

Revision History:

--*/

#include "Procs.h"
#define Dbg                              (DEBUG_TRACE_LOAD)

//
// Private declaration because ZwQueryDefaultLocale isn't in any header.
//

NTSYSAPI
NTSTATUS
NTAPI
ZwQueryDefaultLocale(
    IN BOOLEAN UserProfile,
    OUT PLCID DefaultLocaleId
    );

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    );

VOID
UnloadDriver(
    IN PDRIVER_OBJECT DriverObject
    );

VOID
GetConfigurationInformation(
    PUNICODE_STRING RegistryPath
    );

VOID
ReadValue(
    HANDLE  ParametersHandle,
    PLONG   pVar,
    PWCHAR  Name
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, DriverEntry )
#pragma alloc_text( PAGE, GetConfigurationInformation )
#pragma alloc_text( PAGE, ReadValue )
#endif

#if 0  // Not pageable
UnloadDriver
#endif

static ULONG IrpStackSize;

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

Routine Description:

    This is the initialization routine for the Nw file system
    device driver.  This routine creates the device object for the FileSystem
    device and performs all other driver initialization.

Arguments:

    DriverObject - Pointer to driver object created by the system.

Return Value:

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

--*/

{
    NTSTATUS Status;
    UNICODE_STRING UnicodeString;
    PAGED_CODE();

    //DbgBreakPoint();

    InitializeAttach( );
    NwInitializeData();
    NwInitializePidTable();

    //
    // Create the device object.
    //

    RtlInitUnicodeString( &UnicodeString, DD_NWFS_DEVICE_NAME_U );
    Status = IoCreateDevice( DriverObject,
                             0,
                             &UnicodeString,
                             FILE_DEVICE_NETWORK_FILE_SYSTEM,
                             FILE_REMOTE_DEVICE,
                             FALSE,
                             &FileSystemDeviceObject );

    if (!NT_SUCCESS( Status )) {
        Error(EVENT_NWRDR_CANT_CREATE_DEVICE, Status, NULL, 0, 0);
        return Status;
    }

    //
    //  Initialize parameters to the defaults.
    //

    IrpStackSize = NWRDR_IO_STACKSIZE;

    //
    //  Attempt to read config information from the registry
    //

    GetConfigurationInformation( RegistryPath );

    //
    //  Set the stack size.
    //

    FileSystemDeviceObject->StackSize = (CCHAR)IrpStackSize;

    //
    // Initialize the driver object with this driver's entry points.
    //

    DriverObject->MajorFunction[IRP_MJ_CREATE]                   = (PDRIVER_DISPATCH)NwFsdCreate;
    DriverObject->MajorFunction[IRP_MJ_CLEANUP]                  = (PDRIVER_DISPATCH)NwFsdCleanup;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]                    = (PDRIVER_DISPATCH)NwFsdClose;
    DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL]      = (PDRIVER_DISPATCH)NwFsdFileSystemControl;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]           = (PDRIVER_DISPATCH)NwFsdDeviceIoControl;
    DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]        = (PDRIVER_DISPATCH)NwFsdQueryInformation;
    DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)NwFsdQueryVolumeInformation;
    DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION]   = (PDRIVER_DISPATCH)NwFsdSetVolumeInformation;
    DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL]        = (PDRIVER_DISPATCH)NwFsdDirectoryControl;
    DriverObject->MajorFunction[IRP_MJ_READ]                     = (PDRIVER_DISPATCH)NwFsdRead;
    DriverObject->MajorFunction[IRP_MJ_WRITE]                    = (PDRIVER_DISPATCH)NwFsdWrite;
    DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]          = (PDRIVER_DISPATCH)NwFsdSetInformation;
    DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL]             = (PDRIVER_DISPATCH)NwFsdLockControl;
    DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]            = (PDRIVER_DISPATCH)NwFsdFlushBuffers;
/*
    DriverObject->MajorFunction[IRP_MJ_QUERY_EA]                 = (PDRIVER_DISPATCH)NwFsdQueryEa;
    DriverObject->MajorFunction[IRP_MJ_SET_EA]                   = (PDRIVER_DISPATCH)NwFsdSetEa;
    DriverObject->MajorFunction[IRP_MJ_SHUTDOWN]                 = (PDRIVER_DISPATCH)NwFsdShutdown;
*/
    DriverObject->DriverUnload = UnloadDriver;

#if NWFASTIO
    DriverObject->FastIoDispatch = &NwFastIoDispatch;

    NwFastIoDispatch.SizeOfFastIoDispatch =    sizeof(FAST_IO_DISPATCH);
    NwFastIoDispatch.FastIoCheckIfPossible =   NULL;
    NwFastIoDispatch.FastIoRead =              NwFastRead;
    NwFastIoDispatch.FastIoWrite =             NwFastWrite;
    NwFastIoDispatch.FastIoQueryBasicInfo =    NwFastQueryBasicInfo;
    NwFastIoDispatch.FastIoQueryStandardInfo = NwFastQueryStandardInfo;
    NwFastIoDispatch.FastIoLock =              NULL;
    NwFastIoDispatch.FastIoUnlockSingle =      NULL;
    NwFastIoDispatch.FastIoUnlockAll =         NULL;
    NwFastIoDispatch.FastIoUnlockAllByKey =    NULL;
    NwFastIoDispatch.FastIoDeviceControl =     NULL;
#endif

    NwInitializeRcb( &NwRcb );

    InitializeIrpContext( );

    NwPermanentNpScb.State = SCB_STATE_DISCONNECTING;

    //
    //  Do a kludge here so that we get to the "real" global variables.
    //

    //NlsLeadByteInfo = *(PUSHORT *)NlsLeadByteInfo;
    //NlsMbCodePageTag = *(*(PBOOLEAN *)&NlsMbCodePageTag);

#ifndef IFS
    FsRtlLegalAnsiCharacterArray = *(PUCHAR *)FsRtlLegalAnsiCharacterArray;
#endif

    DebugTrace(0, Dbg, "NetWare redirector loaded\n", 0);

    //
    //  And return to our caller
    //

    return( STATUS_SUCCESS );
}

VOID
UnloadDriver(
    IN PDRIVER_OBJECT DriverObject
    )
/*++

Routine Description:

     This is the unload routine for the NetWare redirector filesystem.

Arguments:

     DriverObject - pointer to the driver object for the redirector

Return Value:

     None

--*/
{
    KIRQL OldIrql;

    PAGED_CODE();

    IpxClose();

    IPX_Close_Socket( &NwPermanentNpScb.Server );

    KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
    RemoveEntryList( &NwPermanentNpScb.ScbLinks );
    KeReleaseSpinLock( &ScbSpinLock, OldIrql );

    DestroyAllScb();

    UninitializeIrpContext();

    if (IpxTransportName.Buffer != NULL) {

        FREE_POOL(IpxTransportName.Buffer);

    }

    if ( NwProviderName.Buffer != NULL ) {
        FREE_POOL( NwProviderName.Buffer );
    }

    NwUninitializePidTable();

    ASSERT( IsListEmpty( &NwPagedPoolList ) );
    ASSERT( IsListEmpty( &NwNonpagedPoolList ) );

    ASSERT( MdlCount == 0 );
    ASSERT( IrpCount == 0 );

    NwDeleteRcb( &NwRcb );

#ifdef NWDBG
    ExDeleteResource( &NwDebugResource );
#endif

    ExDeleteResource( &NwOpenResource );
    ExDeleteResource( &NwUnlockableCodeResource );

    IoDeleteDevice(FileSystemDeviceObject);

    DebugTrace(0, Dbg, "NetWare redirector unloaded\n\n", 0);

}



VOID
GetConfigurationInformation(
    PUNICODE_STRING RegistryPath
    )
/*++

Routine Description:

    This routine read redirector configuration information from the registry.

Arguments:

    RegistryPath - A pointer the a path to the

Return Value:

    None

--*/
{
    UNICODE_STRING UnicodeString;
    HANDLE ConfigHandle;
    HANDLE ParametersHandle;
    NTSTATUS Status;
    OBJECT_ATTRIBUTES ObjectAttributes;
    ULONG TimeOutEventinMins = 0L;
    LCID lcid;

    PAGED_CODE();

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

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

    if (!NT_SUCCESS(Status)) {
        return;
    }

    RtlInitUnicodeString( &UnicodeString, L"Parameters" );

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

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

    if ( !NT_SUCCESS( Status ) ) {
        ZwClose( ConfigHandle );
        return;
    }

    ReadValue( ParametersHandle, &IrpStackSize, L"IrpStackSize" );

    ReadValue( ParametersHandle, &MaxSendDelay, L"MaxSendDelay" );
    ReadValue( ParametersHandle, &MaxReceiveDelay, L"MaxReceiveDelay" );

    ReadValue( ParametersHandle, &MinSendDelay, L"MinSendDelay" );
    ReadValue( ParametersHandle, &MinReceiveDelay, L"MinReceiveDelay" );

    ReadValue( ParametersHandle, &BurstSuccessCount, L"BurstSuccessCount" );
    ReadValue( ParametersHandle, &BurstSuccessCount2, L"BurstSuccessCount2" );
    ReadValue( ParametersHandle, &MaxReadTimeout, L"MaxReadTimeout" );
    ReadValue( ParametersHandle, &MaxWriteTimeout, L"MaxWriteTimeout" );
    ReadValue( ParametersHandle, &ReadTimeoutMultiplier, L"ReadTimeoutMultiplier" );
    ReadValue( ParametersHandle, &WriteTimeoutMultiplier, L"WriteTimeoutMultiplier" );
    ReadValue( ParametersHandle, &AllowGrowth, L"AllowGrowth" );
    ReadValue( ParametersHandle, &DontShrink, L"DontShrink" );
    ReadValue( ParametersHandle, &SendExtraNcp, L"SendExtraNcp" );
    ReadValue( ParametersHandle, &DefaultMaxPacketSize, L"DefaultMaxPacketSize" );
    ReadValue( ParametersHandle, &PacketThreshold, L"PacketThreshold" );
    ReadValue( ParametersHandle, &LargePacketAdjustment, L"LargePacketAdjustment" );
    ReadValue( ParametersHandle, &LipPacketAdjustment, L"LipPacketAdjustment" );
    ReadValue( ParametersHandle, &LipAccuracy, L"LipAccuracy" );

    ReadValue( ParametersHandle, &DisableReadCache, L"DisableReadCache" );
    ReadValue( ParametersHandle, &DisableWriteCache, L"DisableWriteCache" );
    ReadValue( ParametersHandle, &FavourLongNames, L"FavourLongNames" );

    ReadValue( ParametersHandle, &LockTimeoutThreshold, L"LockTimeout" );

    ReadValue( ParametersHandle, &TimeOutEventinMins, L"TimeOutEventinMins");

    ReadValue( ParametersHandle, &EnableMultipleConnects, L"EnableMultipleConnects");

    ReadValue( ParametersHandle, &ReadExecOnlyFiles, L"ReadExecOnlyFiles");

    if (!TimeOutEventinMins) {
        //
        //  If for some reason, the registry has set the TimeOutEventInterval
        //  to zero, reset to the default value to avoid divide-by-zero
        //

        TimeOutEventinMins =  DEFAULT_TIMEOUT_EVENT_INTERVAL;
    }

    TimeOutEventInterval.QuadPart = TimeOutEventinMins * 60 * SECONDS;

    ZwClose( ParametersHandle );
    ZwClose( ConfigHandle );

    Japan = FALSE;


    ZwQueryDefaultLocale( TRUE, &lcid );

    if (PRIMARYLANGID(lcid) == LANG_JAPANESE ||
        PRIMARYLANGID(lcid) == LANG_KOREAN ||
        PRIMARYLANGID(lcid) == LANG_CHINESE) {

            Japan = TRUE;
    }

}


VOID
ReadValue(
    HANDLE  ParametersHandle,
    PLONG   pVar,
    PWCHAR  Name
    )
/*++

Routine Description:

    This routine reads a single redirector configuration value from the registry.

Arguments:

    Parameters  -   Supplies where to look for values.

    pVar        -   Address of the variable to receive the new value if the name exists.

    Name        -   Name whose value is to be loaded.

Return Value:

    None

--*/
{
    WCHAR Storage[256];
    UNICODE_STRING UnicodeString;
    NTSTATUS Status;
    ULONG BytesRead;
    PKEY_VALUE_FULL_INFORMATION Value = (PKEY_VALUE_FULL_INFORMATION)Storage;

    PAGED_CODE();

    UnicodeString.Buffer = Storage;

    RtlInitUnicodeString(&UnicodeString, Name );

    Status = ZwQueryValueKey(
                 ParametersHandle,
                 &UnicodeString,
                 KeyValueFullInformation,
                 Value,
                 sizeof(Storage),
                 &BytesRead );

    if ( NT_SUCCESS( Status ) ) {

        if ( Value->DataLength >= sizeof(ULONG) ) {

            *pVar = *(LONG UNALIGNED *)( (PCHAR)Value + Value->DataOffset );

        }
    }
}