/*++

Copyright (c) 1992  Microsoft Corporation

Module Name:

    Procs.h

Abstract:

    This module defines all of the globally used procedures in the NetWare
    redirector.

Author:

    Colin Watson    [ColinW]    15-Dec-1992

Revision History:

--*/

#ifndef _NWPROCS_
#define _NWPROCS_

#ifndef QFE_BUILD
#define IFS 1
#define NWFASTIO 1
#endif

#ifdef IFS

    #include <ntifs.h>
    #include <ntddmup.h>

#else

    #include <ntioapi.h>
    #include <zwapi.h>
    #include <FsRtl.h>

#endif
#include <string.h>
#include <Tdi.h>
#include <TdiKrnl.h>
#include <Status.h>
#include <nwstatus.h>

//  Netware and Netware redirector specific includes

#ifndef DBG
#define DBG 0
#endif

#if !DBG
#undef NWDBG
#endif

#if NWDBG
#define PAGED_DBG 1
#endif
#ifdef PAGED_DBG
#undef PAGED_CODE
#define PAGED_CODE() \
    struct { ULONG bogus; } ThisCodeCantBePaged; \
    ThisCodeCantBePaged; \
    if (KeGetCurrentIrql() > APC_LEVEL) { \
        KdPrint(( "EX: Pageable code called at IRQL %d\n", KeGetCurrentIrql() )); \
        ASSERT(FALSE); \
        }
#define PAGED_CODE_CHECK() if (ThisCodeCantBePaged) ;
extern ULONG ThisCodeCantBePaged;
#else
#define PAGED_CODE_CHECK()
#endif

#include <NtDDNwfs.h>
#include "Const.h"
#include "Nodetype.h"
#include "ncp.h"
#include "Struct.h"
#include "Data.h"
#include "Exchange.h"
#include <NwEvent.h>

//
// NDS Additions.
//

#include <nds.h>
#include "ndsprocs.h"

//  Attach.c

NTSTATUS
ConnectToServer(
    IN PIRP_CONTEXT pIrpContext,
    OUT PSCB *pScbCollision
);

NTSTATUS
ProcessFindNearest(
    IN struct _IRP_CONTEXT* pIrpContext,
    IN ULONG BytesAvailable,
    IN PUCHAR RspData
    );

NTSTATUS
CrackPath (
    IN PUNICODE_STRING BaseName,
    OUT PUNICODE_STRING DriveName,
    OUT PWCHAR DriveLetter,
    OUT PUNICODE_STRING ServerName,
    OUT PUNICODE_STRING VolumeName,
    OUT PUNICODE_STRING PathName,
    OUT PUNICODE_STRING FileName,
    OUT PUNICODE_STRING FullName OPTIONAL
    );

NTSTATUS
CheckScbSecurity(
    IN PIRP_CONTEXT pIrpContext,
    IN PSCB pScb,
    IN PUNICODE_STRING puUserName,
    IN PUNICODE_STRING puPassword,
    IN BOOLEAN fDeferLogon
);

NTSTATUS
ConnectScb(
    IN PSCB *Scb,
    IN PIRP_CONTEXT pIrpContext,
    IN PUNICODE_STRING Server,
    IN IPXaddress *pServerAddress,
    IN PUNICODE_STRING UserName,
    IN PUNICODE_STRING Password,
    IN BOOLEAN DeferLogon,
    IN BOOLEAN DeleteConnection,
    IN BOOLEAN ExistingScb
);

#define IS_ANONYMOUS_SCB( pScb ) \
        ( (pScb->UidServerName).Length == 0 )

NTSTATUS
CreateScb(
    OUT PSCB *Scb,
    IN PIRP_CONTEXT pIrpC,
    IN PUNICODE_STRING Server,
    IN IPXaddress *pServerAddress,
    IN PUNICODE_STRING UserName,
    IN PUNICODE_STRING Password,
    IN BOOLEAN DeferLogon,
    IN BOOLEAN DeleteConnection
    );

VOID
DestroyAllScb(
    VOID
    );

VOID
InitializeAttach (
    VOID
    );

NTSTATUS
OpenScbSockets(
    PIRP_CONTEXT pIrpC,
    PNONPAGED_SCB pNpScb
    );

PNONPAGED_SCB
SelectConnection(
    PNONPAGED_SCB NpScb
    );

VOID
NwLogoffAndDisconnect(
    PIRP_CONTEXT pIrpContext,
    PNONPAGED_SCB pNpScb
    );

VOID
NwLogoffAllServers(
    PIRP_CONTEXT pIrpContext,
    PLARGE_INTEGER Uid
    );

VOID
NwDeleteScb(
    PSCB pScb
    );

NTSTATUS
NegotiateBurstMode(
    PIRP_CONTEXT pIrpContext,
    PNONPAGED_SCB pNpScb,
    BOOLEAN *LIPNegotiated
    );

VOID
RenegotiateBurstMode(
    PIRP_CONTEXT pIrpContext,
    PNONPAGED_SCB pNpScb
    );

BOOLEAN
NwFindScb(
    OUT PSCB *ppScb,
    IN PIRP_CONTEXT pIrpContext,
    IN PUNICODE_STRING UidServerName,
    IN PUNICODE_STRING ServerName
    );

NTSTATUS
QueryServersAddress(
    PIRP_CONTEXT pIrpContext,
    PNONPAGED_SCB pNearestScb,
    PUNICODE_STRING pServerName,
    IPXaddress *pServerAddress
    );

VOID
TreeConnectScb(
    IN PSCB Scb
    );

NTSTATUS
TreeDisconnectScb(
    IN PIRP_CONTEXT IrpContext,
    IN PSCB Scb
    );

VOID
ReconnectScb(
    IN PIRP_CONTEXT IrpContext,
    IN PSCB pScb
    );

//  Cache.c

ULONG
CacheRead(
    IN PNONPAGED_FCB NpFcb,
    IN ULONG FileOffset,
    IN ULONG BytesToRead,
    IN PVOID UserBuffer
#if NWFASTIO
    , IN BOOLEAN WholeBufferOnly
#endif
    );

BOOLEAN
CacheWrite(
    IN PIRP_CONTEXT IrpContext,
    IN PNONPAGED_FCB NpFcb,
    IN ULONG FileOffset,
    IN ULONG BytesToWrite,
    IN PVOID UserBuffer
    );

ULONG
CalculateReadAheadSize(
    IN PIRP_CONTEXT IrpContext,
    IN PNONPAGED_FCB NpFcb,
    IN ULONG CacheReadSize,
    IN ULONG FileOffset,
    IN ULONG ByteCount
    );

NTSTATUS
FlushCache(
    PIRP_CONTEXT IrpContext,
    PNONPAGED_FCB NpFcb
    );

NTSTATUS
AcquireFcbAndFlushCache(
    PIRP_CONTEXT IrpContext,
    PNONPAGED_FCB NpFcb
    );

VOID
FlushAllBuffers(
    PIRP_CONTEXT pIrpContext
);

//  Callback.c


NTSTATUS
SynchronousResponseCallback (
    IN PIRP_CONTEXT pIrpContext,
    IN ULONG BytesAvailable,
    IN PUCHAR RspData
    );

NTSTATUS
AsynchResponseCallback (
    IN PIRP_CONTEXT pIrpContext,
    IN ULONG BytesAvailable,
    IN PUCHAR RspData
    );

NTSTATUS
NcpSearchFileCallback (
    IN PIRP_CONTEXT pIrpContext,
    IN ULONG BytesIndicated,
    IN ULONG BytesAvailable,
    OUT ULONG *BytesTaken,
    IN PUCHAR RspData
    );

// Cleanup.c

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

//  Close.c

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

//  Create.c

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

NTSTATUS
ReadAttachEas(
    IN PIRP Irp,
    OUT PUNICODE_STRING UserName,
    OUT PUNICODE_STRING Password,
    OUT PULONG ShareType,
    OUT PDWORD CredentialExtension
    );

//  Convert.c

NTSTATUS
pNwErrorToNtStatus(
    UCHAR Error
    );

NTSTATUS
NwBurstResultToNtStatus(
    ULONG Result
    );

#define NwErrorToNtStatus( STATUS ) \
    (STATUS == 0 )? STATUS_SUCCESS : pNwErrorToNtStatus(STATUS)

NTSTATUS
NwConnectionStatusToNtStatus(
    UCHAR NwStatus
    );

UCHAR
NtAttributesToNwAttributes(
    ULONG FileAttributes
    );

UCHAR
NtToNwShareFlags(
    ULONG DesiredAccess,
    ULONG NtShareFlags
    );

LARGE_INTEGER
NwDateTimeToNtTime(
    USHORT Date,
    USHORT Time
    );

NTSTATUS
NwNtTimeToNwDateTime (
    IN LARGE_INTEGER NtTime,
    IN PUSHORT NwDate,
    IN PUSHORT NwTime
    );

//  Data.c

VOID
NwInitializeData(
    VOID
    );

//  Debug.c

#ifdef NWDBG

ULONG
NwMemDbg (
    IN PCH Format,
    ...
    );

VOID
RealDebugTrace(
    IN LONG Indent,
    IN ULONG Level,
    IN PCH Message,
    IN PVOID Parameter
    );

VOID
dump(
    IN ULONG Level,
    IN PVOID far_p,
    IN ULONG  len
    );

VOID
dumpMdl(
    IN ULONG Level,
    IN PMDL Mdl
    );

VOID
DumpIcbs(
    VOID
    ) ;


PVOID
NwAllocatePool(
    ULONG Type,
    ULONG Size,
    BOOLEAN RaiseStatus
    );

VOID
NwFreePool(
    PVOID Buffer
    );

PIRP
NwAllocateIrp(
    CCHAR Size,
    BOOLEAN ChargeQuota
    );

VOID
NwFreeIrp(
    PIRP Irp
    );

PMDL
NwAllocateMdl(
    PVOID Va,
    ULONG Length,
    BOOLEAN Secondary,
    BOOLEAN ChargeQuota,
    PIRP Irp,
    PUCHAR FileName,
    int Line
    );

VOID
NwFreeMdl(
    PMDL Mdl
    );

#else
#define dump( level, pointer, length ) { NOTHING;}
#endif


//  Deviosup.c

VOID
NwMapUserBuffer (
    IN OUT PIRP Irp,
    IN KPROCESSOR_MODE AccessMode,
    OUT PVOID *UserBuffer
    );

VOID
NwLockUserBuffer (
    IN OUT PIRP Irp,
    IN LOCK_OPERATION Operation,
    IN ULONG BufferLength
    );

//  Dir.c

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

//  Encrypt.c

VOID
RespondToChallenge(
    IN PUCHAR achObjectId,
    IN POEM_STRING Password,
    IN PUCHAR pChallenge,
    OUT PUCHAR pResponse
    );

//  Exchange.c

BOOLEAN
AppendToScbQueue(
    IN PIRP_CONTEXT IrpContext,
    IN PNONPAGED_SCB NpScb
    );

VOID
PreparePacket(
    PIRP_CONTEXT pIrpContext,
    PIRP pOriginalIrp,
    PMDL pMdl
    );

NTSTATUS
PrepareAndSendPacket(
    PIRP_CONTEXT    pIrpContext
    );

NTSTATUS
SendPacket(
    PIRP_CONTEXT    pIrpContext,
    PNONPAGED_SCB   pNpScb
    );

VOID
SendNow(
    IN PIRP_CONTEXT IrpContext
    );

VOID
SetEvent(
    IN PIRP_CONTEXT IrpContext
    );

NTSTATUS
_cdecl
ExchangeWithWait(
    PIRP_CONTEXT    pIrpContext,
    PEX             pEx,
    char*           f,
    ...                         //  format specific parameters
    );

NTSTATUS
_cdecl
BuildRequestPacket(
    PIRP_CONTEXT    pIrpContext,
    PEX             pEx,
    char*           f,
    ...                       //  format specific parameters
    );

NTSTATUS
_cdecl
ParseResponse(
    PIRP_CONTEXT IrpContext,
    PUCHAR RequestHeader,
    ULONG RequestLength,
    char*  f,
    ...                       //  format specific parameters
    );

NTSTATUS
ParseNcpResponse(
    PIRP_CONTEXT IrpContext,
    PNCP_RESPONSE Response
    );

BOOLEAN
VerifyResponse(
    PIRP_CONTEXT pIrpContext,
    PVOID Response
    );

VOID
FreeReceiveIrp(
    PIRP_CONTEXT IrpContext
    );

NTSTATUS
NewRouteRetry(
    IN PIRP_CONTEXT pIrpContext
    );

NTSTATUS
NewRouteBurstRetry(
    IN PIRP_CONTEXT pIrpContext
    );

VOID
ReconnectRetry(
    PIRP_CONTEXT pIrpContext
    );

ULONG
MdlLength (
    register IN PMDL Mdl
    );

VOID
NwProcessSendBurstFailure(
    PNONPAGED_SCB NpScb,
    USHORT MissingFragmentCount
    );

VOID
NwProcessSendBurstSuccess(
    PNONPAGED_SCB NpScb
    );

VOID
NwProcessReceiveBurstFailure(
    PNONPAGED_SCB NpScb,
    USHORT MissingFragmentCount
    );

VOID
NwProcessReceiveBurstSuccess(
    PNONPAGED_SCB NpScb
    );

VOID
NwProcessPositiveAck(
    PNONPAGED_SCB NpScb
    );

//  Errorlog.c

VOID
_cdecl
Error(
    IN ULONG UniqueErrorCode,
    IN NTSTATUS NtStatusCode,
    IN PVOID ExtraInformationBuffer,
    IN USHORT ExtraInformationLength,
    IN USHORT NumberOfInsertionStrings,
    ...
    );

//  FileInfo.c

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

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

NTSTATUS
NwDeleteFile(
    IN PIRP_CONTEXT pIrpContext
    );

ULONG
OccurenceCount (
    IN PUNICODE_STRING String,
    IN WCHAR SearchChar
    );

#if NWFASTIO
BOOLEAN
NwFastQueryBasicInfo (
    IN PFILE_OBJECT FileObject,
    IN BOOLEAN Wait,
    IN OUT PFILE_BASIC_INFORMATION Buffer,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );

BOOLEAN
NwFastQueryStandardInfo (
    IN PFILE_OBJECT FileObject,
    IN BOOLEAN Wait,
    IN OUT PFILE_STANDARD_INFORMATION Buffer,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );
#endif

//  Filobsup.c

VOID
NwSetFileObject (
    IN PFILE_OBJECT FileObject OPTIONAL,
    IN PVOID FsContext,
    IN PVOID FsContext2
    );

NODE_TYPE_CODE
NwDecodeFileObject (
    IN PFILE_OBJECT FileObject,
    OUT PVOID *FsContext,
    OUT PVOID *FsContext2
    );

BOOLEAN
NwIsIrpTopLevel (
    IN PIRP Irp
    );

//  Fsctl.c

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

NTSTATUS
NwCommonFileSystemControl (
    IN PIRP_CONTEXT IrpContext
    );

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

#ifndef _PNP_POWER_

VOID
HandleTdiBindMessage(
    IN PUNICODE_STRING DeviceName
);

VOID
HandleTdiUnbindMessage(
    IN PUNICODE_STRING DeviceName
);

#endif

PLOGON
FindUser(
    IN PLARGE_INTEGER Uid,
    IN BOOLEAN ExactMatch
    );

LARGE_INTEGER
GetUid(
    IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
    );

PLOGON
FindUserByName(
    IN PUNICODE_STRING UserName
);

VOID
LazySetShareable(
    PIRP_CONTEXT IrpContext,
    PICB pIcb,
    PFCB pFcb
);

NTSTATUS
RegisterWithMup(
    VOID
    );

VOID
DeregisterWithMup(
    VOID
    );

//  FspDisp.c

VOID
NwFspDispatch (
    IN PVOID Context
    );

NTSTATUS
NwPostToFsp (
    IN PIRP_CONTEXT IrpContext,
    IN BOOLEAN MarkIrpPending
    );

// hack.c

NTSTATUS
_cdecl
BuildNcpResponse(
    PIRP_CONTEXT    pIrpC,
    char*           f,
    char            Error,
    char            Status,
    ...
    );

NTSTATUS
HackSendMessage(
    PIRP_CONTEXT    pIrpContext
    );

NTSTATUS
_cdecl
HackParseResponse(
    PUCHAR Response,
    char*  FormatString,
    ...                       //  format specific parameters
    );

//  Ipx.c

NTSTATUS
IpxOpenHandle(
    OUT PHANDLE pHandle,
    OUT PDEVICE_OBJECT* ppDeviceObject,
    OUT PFILE_OBJECT* pFileObject,
    IN PVOID EaBuffer OPTIONAL,
    IN ULONG EaLength
    );

NTSTATUS
IpxOpen(
    VOID
    );

VOID
IpxClose(
    VOID
    );

VOID
BuildIpxAddress(
    IN ULONG NetworkAddress,
    IN PUCHAR NodeAddress,
    IN USHORT Socket,
    OUT PTA_IPX_ADDRESS NetworkName
    );

VOID
BuildIpxAddressEa (
    IN ULONG NetworkAddress,
    IN PUCHAR NodeAddress,
    IN USHORT Socket,
    OUT PVOID NetworkName
    );

NTSTATUS
SetEventHandler (
    IN PIRP_CONTEXT pIrpC,
    IN PNW_TDI_STRUCT pTdiStruc,
    IN ULONG EventType,
    IN PVOID pEventHandler,
    IN PVOID pContext
    );

NTSTATUS
GetMaximumPacketSize(
    IN PIRP_CONTEXT pIrpContext,
    IN PNW_TDI_STRUCT pTdiStruct,
    OUT PULONG pMaximumPacketSize
    );

NTSTATUS
GetNewRoute(
    IN PIRP_CONTEXT pIrpContext
    );

NTSTATUS
GetTickCount(
    IN PIRP_CONTEXT pIrpContext,
    OUT PUSHORT HopCount
    );

#ifndef QFE_BUILD

NTSTATUS
SubmitLineChangeRequest(
    VOID
    );

#endif

VOID
FspProcessLineChange(
    IN PVOID Context
    );

//  Lock.c

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

VOID
NwFreeLocksForIcb(
    PIRP_CONTEXT pIrpContext,
    PICB Icb
    );

//  Lockcode.c

VOID
NwReferenceUnlockableCodeSection (
    VOID
    );

VOID
NwDereferenceUnlockableCodeSection (
    VOID
    );

BOOLEAN
NwUnlockCodeSections(
    BOOLEAN BlockIndefinitely
    );

//  Pid.c

BOOLEAN
NwInitializePidTable(
//    VOID
    IN PNONPAGED_SCB pNpScb
    );

NTSTATUS
NwMapPid(
    IN PNONPAGED_SCB pNpScb,
    IN ULONG_PTR Pid32,
    OUT PUCHAR Pid8
    );

VOID
NwSetEndOfJobRequired(
    IN PNONPAGED_SCB pNpScb,
    IN UCHAR Pid8
    );

VOID
NwUnmapPid(
    IN PNONPAGED_SCB pNpScb,
    IN UCHAR Pid8,
    IN PIRP_CONTEXT IrpContext OPTIONAL
    );

VOID
NwUninitializePidTable(
    IN PNONPAGED_SCB pNpScb
//    VOID
    );

//  Read.c

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

VOID
BurstReadTimeout(
    PIRP_CONTEXT IrpContext
    );

NTSTATUS
ResubmitBurstRead (
    IN PIRP_CONTEXT IrpContext
    );

#if NWFASTIO
BOOLEAN
NwFastRead (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER FileOffset,
    IN ULONG Length,
    IN BOOLEAN Wait,
    IN ULONG LockKey,
    OUT PVOID Buffer,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );
#endif

//  Scavenger.c

VOID
DisconnectTimedOutScbs(
    LARGE_INTEGER Now
    );

VOID
NwScavengerRoutine(
    IN PWORK_QUEUE_ITEM WorkItem
    );

BOOLEAN
NwAllocateExtraIrpContext(
    OUT PIRP_CONTEXT *ppIrpContext,
    IN PNONPAGED_SCB pScb
    );

VOID
NwFreeExtraIrpContext(
    IN PIRP_CONTEXT pIrpContext
    );

VOID
CleanupScbs(
    LARGE_INTEGER Now
    );

VOID
CleanupSupplementalCredentials(
    LARGE_INTEGER Now,
    BOOLEAN       bShuttingDown
);

//  Security.c

VOID
CreateAnsiUid(
    OUT PCHAR aUid,
    IN PLARGE_INTEGER Uid
    );

NTSTATUS
MakeUidServer(
    PUNICODE_STRING UidServer,
    PLARGE_INTEGER Uid,
    PUNICODE_STRING Server
    );

NTSTATUS
Logon(
    IN PIRP_CONTEXT IrpContext
    );

VOID
FreeLogon(
    IN PLOGON Logon
    );

NTSTATUS
Logoff(
    IN PIRP_CONTEXT IrpContext
    );


PVCB *
GetDriveMapTable (
    IN LARGE_INTEGER Uid
    );

NTSTATUS
UpdateUsersPassword(
    IN PUNICODE_STRING UserName,
    IN PUNICODE_STRING Password,
    OUT PLARGE_INTEGER Uid
    );

NTSTATUS
UpdateServerPassword(
    PIRP_CONTEXT IrpContext,
    IN PUNICODE_STRING ServerName,
    IN PUNICODE_STRING UserName,
    IN PUNICODE_STRING Password,
    IN PLARGE_INTEGER Uid
    );

//  String.c

NTSTATUS
DuplicateStringWithString (
    OUT PSTRING DestinationString,
    IN PSTRING SourceString,
    IN POOL_TYPE PoolType
    );


NTSTATUS
DuplicateUnicodeStringWithString (
    OUT PUNICODE_STRING DestinationString,
    IN PUNICODE_STRING SourceString,
    IN POOL_TYPE PoolType
    );

NTSTATUS
SetUnicodeString (
    IN PUNICODE_STRING Destination,
    IN ULONG Length,
    IN PWCHAR Source
    );

VOID
MergeStrings(
    IN PUNICODE_STRING Destination,
    IN PUNICODE_STRING S1,
    IN PUNICODE_STRING S2,
    IN ULONG Type
    );

//  Strucsup.c

VOID
NwInitializeRcb (
    IN PRCB Rcb
    );

VOID
NwDeleteRcb (
    IN PRCB Rcb
    );

PFCB
NwCreateFcb (
    IN PUNICODE_STRING FileName,
    IN PSCB Scb,
    IN PVCB Vcb
    );

PFCB
NwFindFcb (
    IN PSCB Scb,
    IN PVCB Vcb,
    IN PUNICODE_STRING FileName,
    IN PDCB Dcb OPTIONAL
    );

VOID
NwDereferenceFcb (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb
    );

PICB
NwCreateIcb (
    IN USHORT Type,
    IN PVOID Associate
    );

VOID
NwVerifyIcb (
    IN PICB Icb
    );

VOID
NwVerifyIcbSpecial(
    IN PICB Icb
    );

VOID
NwVerifyScb (
    IN PSCB Scb
    );

VOID
NwDeleteIcb (
    IN PIRP_CONTEXT IrpContext OPTIONAL,
    IN PICB Icb
    );

PVCB
NwFindVcb (
    IN PIRP_CONTEXT IrpContext,
    IN PUNICODE_STRING VolumeName,
    IN ULONG ShareType,
    IN WCHAR DriveLetter,
    IN BOOLEAN ExplicitConnection,
    IN BOOLEAN FindExisting
    );

PVCB
NwCreateVcb (
    IN PIRP_CONTEXT IrpContext,
    IN PSCB Scb,
    IN PUNICODE_STRING VolumeName,
    IN ULONG ShareType,
    IN WCHAR DriveLetter,
    IN BOOLEAN ExplicitConnection
    );

VOID
NwDereferenceVcb (
    IN PVCB Vcb,
    IN PIRP_CONTEXT IrpContext OPTIONAL,
    IN BOOLEAN OwnRcb
    );

VOID
NwCleanupVcb(
    IN PVCB pVcb,
    IN PIRP_CONTEXT pIrpContext
    );

VOID
NwCloseAllVcbs(
    PIRP_CONTEXT pIrpContext
    );

VOID
NwReopenVcbHandlesForScb (
    IN PIRP_CONTEXT IrpContext,
    IN PSCB Scb
    );

VOID
NwReopenVcbHandle(
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb
    );

ULONG
NwInvalidateAllHandles (
    PLARGE_INTEGER Uid,
    PIRP_CONTEXT IrpContext
    );

ULONG
NwInvalidateAllHandlesForScb (
    PSCB Scb
    );

BOOLEAN
IsFatNameValid (
    IN PUNICODE_STRING FileName
    );

VOID
NwFreeDirCacheForIcb(
    IN PICB Icb
    );

//  Timer.c

VOID
StartTimer(
    );

VOID
StopTimer(
    );

//  Util.c

VOID
CopyBufferToMdl(
    PMDL DestinationMdl,
    ULONG DataOffset,
    PVOID SourceData,
    ULONG SourceByteCount
    );

NTSTATUS
GetCredentialFromServerName(
    IN PUNICODE_STRING puServerName,
    OUT PUNICODE_STRING puCredentialName
);

NTSTATUS
BuildExCredentialServerName(
    IN PUNICODE_STRING puServerName,
    IN PUNICODE_STRING puUserName,
    OUT PUNICODE_STRING puExCredServerName
);

NTSTATUS
UnmungeCredentialName(
    IN PUNICODE_STRING puCredName,
    OUT PUNICODE_STRING puServerName
);

BOOLEAN
IsCredentialName(
    IN PUNICODE_STRING puObjectName
);

NTSTATUS
ExCreateReferenceCredentials(
    PIRP_CONTEXT pIrpContext,
    PUNICODE_STRING puResource
);

NTSTATUS
ExCreateDereferenceCredentials(
    PIRP_CONTEXT pIrpContext,
    PNDS_SECURITY_CONTEXT pNdsCredentials
);

//  VolInfo.c

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

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

//  WorkQue.c

PIRP_CONTEXT
AllocateIrpContext (
    PIRP pIrp
    );

VOID
FreeIrpContext (
    PIRP_CONTEXT IrpContext
    );

VOID
InitializeIrpContext (
    VOID
    );

VOID
UninitializeIrpContext (
    VOID
    );

VOID
NwCompleteRequest (
    PIRP_CONTEXT IrpContext,
    NTSTATUS Status
    );

VOID
NwAppendToQueueAndWait(
    PIRP_CONTEXT IrpContext
    );

VOID
NwDequeueIrpContext(
    IN PIRP_CONTEXT IrpContext,
    IN BOOLEAN OwnSpinLock
    );

VOID
NwCancelIrp (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

PIRP
NwAllocateSendIrp (
    PIRP_CONTEXT IrpContext
    );

PMINI_IRP_CONTEXT
AllocateMiniIrpContext (
    PIRP_CONTEXT IrpContext
    );

VOID
FreeMiniIrpContext (
    PMINI_IRP_CONTEXT MiniIrpContext
    );

PWORK_CONTEXT
AllocateWorkContext (
    VOID
    );

VOID
FreeWorkContext (
   PWORK_CONTEXT
   );

VOID
SpawnWorkerThread (
   VOID
   );

VOID
WorkerThread (
   VOID
    );

VOID
TerminateWorkerThread (
    VOID
    );


//  Write.c

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

NTSTATUS
DoWrite(
    PIRP_CONTEXT IrpContext,
    LARGE_INTEGER ByteOffset,
    ULONG BufferLength,
    PVOID WriteBuffer,
    PMDL WriteMdl
    );

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

NTSTATUS
ResubmitBurstWrite(
    PIRP_CONTEXT IrpContext
    );

#if NWFASTIO
BOOLEAN
NwFastWrite (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER FileOffset,
    IN ULONG Length,
    IN BOOLEAN Wait,
    IN ULONG LockKey,
    OUT PVOID Buffer,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );
#endif

#ifdef _PNP_POWER_

//
// NwPnP.C
//

NTSTATUS
StartRedirector(
    PIRP_CONTEXT IrpContext
);

NTSTATUS
StopRedirector(
    IN PIRP_CONTEXT IrpContext
);

NTSTATUS
RegisterTdiPnPEventHandlers(
    IN PIRP_CONTEXT IrpContext
);

NTSTATUS
PnPSetPower(
    PNET_PNP_EVENT pEvent,
    PTDI_PNP_CONTEXT pContext1,
    PTDI_PNP_CONTEXT pContext2
);

NTSTATUS
PnPQueryPower(
    PNET_PNP_EVENT pEvent,
    PTDI_PNP_CONTEXT pContext1,
    PTDI_PNP_CONTEXT pContext2
);
NTSTATUS
PnPQueryRemove(
    PNET_PNP_EVENT pEvent,
    PTDI_PNP_CONTEXT pContext1,
    PTDI_PNP_CONTEXT pContext2
);
NTSTATUS
PnPCancelRemove(
    PNET_PNP_EVENT pEvent,
    PTDI_PNP_CONTEXT pContext1,
    PTDI_PNP_CONTEXT pContext2
);

ULONG
PnPCountActiveHandles(
    VOID
);

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

NTSTATUS
PnpIrpCompletion(
    PDEVICE_OBJECT pDeviceObject,
    PIRP           pIrp,
    PVOID          pContext
);

NTSTATUS
NwCommonProcessPnpIrp (
    IN PIRP_CONTEXT IrpContext
);

#endif

//
//  A function that returns finished denotes if it was able to complete the
//  operation (TRUE) or could not complete the operation (FALSE) because the
//  wait value stored in the irp context was false and we would have had
//  to block for a resource or I/O
//

typedef BOOLEAN FINISHED;

//
//  Miscellaneous support routines
//

//
//  This macro returns TRUE if a flag in a set of flags is on and FALSE
//  otherwise.  It is followed by two macros for setting and clearing
//  flags
//

#ifndef BooleanFlagOn
#define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0)))
#endif

#ifndef SetFlag
#define SetFlag(Flags,SingleFlag) { \
    (Flags) |= (SingleFlag);        \
}
#endif


#ifndef ClearFlag
#define ClearFlag(Flags,SingleFlag) { \
    (Flags) &= ~(SingleFlag);         \
}
#endif

//
//  The following macro is used to determine if an FSD thread can block
//  for I/O or wait for a resource.  It returns TRUE if the thread can
//  block and FALSE otherwise.  This attribute can then be used to call
//  the FSD & FSP common work routine with the proper wait value.
//

#define CanFsdWait(IRP) IoIsOperationSynchronous(IRP)

//
//  This macro takes a pointer (or ulong) and returns its rounded up word
//  value
//

#define WordAlign(Ptr) (                \
    ((((ULONG)(Ptr)) + 1) & 0xfffffffe) \
    )

//
//  This macro takes a pointer (or ulong) and returns its rounded up longword
//  value
//

#define LongAlign(Ptr) (                \
    ((((ULONG)(Ptr)) + 3) & 0xfffffffc) \
    )

//
//  This macro takes a pointer (or ulong) and returns its rounded up quadword
//  value
//

#define QuadAlign(Ptr) (                \
    ((((ULONG)(Ptr)) + 7) & 0xfffffff8) \
    )

//
//  The following two macro are used by the Fsd/Fsp exception handlers to
//  process an exception.  The first macro is the exception filter used in the
//  Fsd/Fsp to decide if an exception should be handled at this level.
//  The second macro decides if the exception is to be finished off by
//  completing the IRP, and cleaning up the Irp Context, or if we should
//  bugcheck.  Exception values such as STATUS_FILE_INVALID (raised by
//  VerfySup.c) cause us to complete the Irp and cleanup, while exceptions
//  such as accvio cause us to bugcheck.
//
//  The basic structure for fsd/fsp exception handling is as follows:
//
//  NwFsdXxx(...)
//  {
//      try {
//
//          ...
//
//      } except(NwExceptionFilter( IrpContext, GetExceptionCode() )) {
//
//          Status = NwProcessException( IrpContext, Irp, GetExceptionCode() );
//      }
//
//      Return Status;
//  }
//
//  To explicitly raise an exception that we expect, such as
//  STATUS_FILE_INVALID, use the below macro NwRaiseStatus().  To raise a
//  status from an unknown origin (such as CcFlushCache()), use the macro
//  NwNormalizeAndRaiseStatus.  This will raise the status if it is expected,
//  or raise STATUS_UNEXPECTED_IO_ERROR if it is not.
//
//  Note that when using these two macros, the original status is placed in
//  IrpContext->ExceptionStatus, signaling NwExceptionFilter and
//  NwProcessException that the status we actually raise is by definition
//  expected.
//

LONG
NwExceptionFilter (
    IN PIRP Irp,
    IN PEXCEPTION_POINTERS ExceptionPointer
    );

NTSTATUS
NwProcessException (
    IN PIRP_CONTEXT IrpContext,
    IN NTSTATUS ExceptionCode
    );

//
//  VOID
//  NwRaiseStatus (
//      IN NT_STATUS Status
//  );
//
//

#define NwRaiseStatus(IRPCONTEXT,STATUS) {   \
    ExRaiseStatus( (STATUS) );                \
    KeBugCheck( NW_FILE_SYSTEM );            \
}

//
//  VOID
//  NwNormalAndRaiseStatus (
//      IN NT_STATUS Status
//  );
//

#define NwNormalizeAndRaiseStatus(IRPCONTEXT,STATUS) {                         \
    if ((STATUS) == STATUS_VERIFY_REQUIRED) { ExRaiseStatus((STATUS)); }        \
    ExRaiseStatus(FsRtlNormalizeNtstatus((STATUS),STATUS_UNEXPECTED_IO_ERROR)); \
    KeBugCheck( NW_FILE_SYSTEM );                                              \
}

//
//  The Following routine makes a popup
//

#define NwRaiseInformationalHardError(STATUS,NAME) {               \
    UNICODE_STRING Name;                                                       \
    if (NT_SUCCESS(RtlOemStringToCountedUnicodeString(&Name, (NAME), TRUE))) { \
        IoRaiseInformationalHardError(Status, &Name, (Irp == NULL ?\
             NULL : &(Irp->Tail.Overlay.Thread)->Tcb));            \
        RtlFreeUnicodeString(&Name);                                           \
    }                                                                          \
}


//
//  The following macros are used to establish the semantics needed
//  to do a return from within a try-finally clause.  As a rule every
//  try clause must end with a label call try_exit.  For example,
//
//      try {
//              :
//              :
//
//      try_exit: NOTHING;
//      } finally {
//
//              :
//              :
//      }
//
//  Every return statement executed inside of a try clause should use the
//  try_return macro.  If the compiler fully supports the try-finally construct
//  then the macro should be
//
//      #define try_return(S)  { return(S); }
//
//  If the compiler does not support the try-finally construct then the macro
//  should be
//
//      #define try_return(S)  { S; goto try_exit; }
//

#define try_return(S) { S; goto try_exit; }


#if NWDBG
#define InternalError(String) {                             \
    DbgPrint("Internal NetWare Redirector Error ");         \
    DbgPrint String;                                        \
    DbgPrint("\nFile %s, Line %d\n", __FILE__, __LINE__);   \
    ASSERT(FALSE);                                          \
}
#else
#define InternalError(String) {NOTHING;}
#endif

#define DbgPrintf DbgPrint

//
//  Reference and dereference Macros.
//

VOID
RefDbgTrace (
    PVOID Resource,
    DWORD Count,
    BOOLEAN Reference,
    PBYTE FileName,
    UINT Line
);

#ifdef NWDBG

VOID
ChkNwReferenceScb(
    PNONPAGED_SCB pNpScb,
    PBYTE FileName,
    UINT Line,
    BOOLEAN Silent
);

VOID
ChkNwDereferenceScb(
    PNONPAGED_SCB pNpScb,
    PBYTE FileName,
    UINT Line,
    BOOLEAN Silent
);

#define NwReferenceScb( pNpScb ) \
        ChkNwReferenceScb( pNpScb, __FILE__, __LINE__, FALSE )

#define NwQuietReferenceScb( pNpScb ) \
        ChkNwReferenceScb( pNpScb, __FILE__, __LINE__, TRUE )

#define NwDereferenceScb( pNpScb ) \
        ChkNwDereferenceScb( pNpScb, __FILE__, __LINE__, FALSE )

#define NwQuietDereferenceScb( pNpScb ) \
        ChkNwDereferenceScb( pNpScb, __FILE__, __LINE__, TRUE )

#else

#define NwReferenceScb( pNpScb ) \
        InterlockedIncrement( &(pNpScb)->Reference )

#define NwQuietReferenceScb( pNpScb ) \
        InterlockedIncrement( &(pNpScb)->Reference )

#define NwDereferenceScb( pNpScb ) \
        InterlockedDecrement( &(pNpScb)->Reference )

#define NwQuietDereferenceScb( pNpScb ) \
        InterlockedDecrement( &(pNpScb)->Reference )
#endif

//
// Irpcontext event macro.
//

#define NwSetIrpContextEvent( pIrpContext ) \
        DebugTrace( 0, DEBUG_TRACE_WORKQUE, "Set event for IrpC = %08lx\n", pIrpContext ); \
        DebugTrace( 0, DEBUG_TRACE_WORKQUE, "IrpC->pNpScb = %08lx\n", pIrpContext->pNpScb ); \
        KeSetEvent( &pIrpContext->Event, 0, FALSE )

//
//  VCB macros must be called with the RCB resource held.
//


#if NWDBG
VOID
NwReferenceVcb (
    IN PVCB Vcb
    );
#else
#define NwReferenceVcb( pVcb )      ++(pVcb)->Reference;
#endif

//
// Resource acquisition and release macros
//

#if NWDBG

VOID
NwAcquireExclusiveRcb(
    PRCB Rcb,
    BOOLEAN Wait
    );

VOID
NwAcquireSharedRcb(
    PRCB Rcb,
    BOOLEAN Wait
    );

VOID
NwReleaseRcb(
    PRCB Rcb
    );

VOID
NwAcquireExclusiveFcb(
    PNONPAGED_FCB pFcb,
    BOOLEAN Wait
    );

VOID
NwAcquireSharedFcb(
    PNONPAGED_FCB pFcb,
    BOOLEAN Wait
    );

VOID
NwReleaseFcb(
    PNONPAGED_FCB pFcb
    );

VOID
NwAcquireOpenLock(
    VOID
    );

VOID
NwReleaseOpenLock(
    VOID
    );

#else

#define NwAcquireExclusiveRcb( Rcb, Wait )  \
    ExAcquireResourceExclusiveLite( &((Rcb)->Resource), Wait )

#define NwAcquireSharedRcb( Rcb, Wait )  \
    ExAcquireResourceSharedLite( &((Rcb)->Resource), Wait )

#define NwReleaseRcb( Rcb ) \
    ExReleaseResourceLite( &((Rcb)->Resource) )

#define NwAcquireExclusiveFcb( pFcb, Wait )  \
    ExAcquireResourceExclusiveLite( &((pFcb)->Resource), Wait )

#define NwAcquireSharedFcb( pFcb, Wait )  \
    ExAcquireResourceSharedLite( &((pFcb)->Resource), Wait )

#define NwReleaseFcb( pFcb ) \
    ExReleaseResourceLite( &((pFcb)->Resource) )

#define NwAcquireOpenLock( ) \
    ExAcquireResourceExclusiveLite( &NwOpenResource, TRUE )

#define NwReleaseOpenLock( ) \
    ExReleaseResourceLite( &NwOpenResource )

#endif

#define NwReleaseFcbForThread( pFcb, pThread ) \
    ExReleaseResourceForThreadLite( &((pFcb)->Resource), pThread )

//
//  Memory allocation and deallocation macros
//

#ifdef NWDBG

#define ALLOCATE_POOL_EX( Type, Size )  NwAllocatePool( Type, Size, TRUE )
#define ALLOCATE_POOL( Type, Size )     NwAllocatePool( Type, Size, FALSE )
#define FREE_POOL( Buffer )             NwFreePool( Buffer )

#define ALLOCATE_IRP( Size, ChargeQuota ) \
                                        NwAllocateIrp( Size, ChargeQuota )
#define FREE_IRP( Irp )                 NwFreeIrp( Irp )

#define ALLOCATE_MDL( Va, Length, Secondary, ChargeQuota, Irp ) \
                    NwAllocateMdl(Va, Length, Secondary, ChargeQuota, Irp, __FILE__, __LINE__ )
#define FREE_MDL( Mdl )                 NwFreeMdl( Mdl )

#else

#define ALLOCATE_POOL_EX( Type, Size )  FsRtlAllocatePoolWithTag( Type, Size, 'scwn' )
#ifndef QFE_BUILD
#define ALLOCATE_POOL( Type, Size )     ExAllocatePoolWithTag( Type, Size, 'scwn' )
#else
#define ALLOCATE_POOL( Type, Size )     ExAllocatePool( Type, Size )
#endif
#define FREE_POOL( Buffer )             ExFreePool( Buffer )

#define ALLOCATE_IRP( Size, ChargeQuota ) \
                                        IoAllocateIrp( Size, ChargeQuota )
#define FREE_IRP( Irp )                 IoFreeIrp( Irp )

#define ALLOCATE_MDL( Va, Length, Secondary, ChargeQuota, Irp ) \
                    IoAllocateMdl(Va, Length, Secondary, ChargeQuota, Irp )
#define FREE_MDL( Mdl )                 IoFreeMdl( Mdl )
#endif

//
// Useful macros
//

#define MIN(a,b)     ((a)<(b) ? (a):(b))
#define MAX(a,b)     ((a)>(b) ? (a):(b))

#define DIFFERENT_PAGES( START, SIZE ) \
    (((ULONG)START & ~(4096-1)) != (((ULONG)START + SIZE) & ~(4096-1)))

#define UP_LEVEL_SERVER( Scb )  \
    ( ( Scb->MajorVersion >= 4 ) ||   \
      ( Scb->MajorVersion == 3 && Scb->MinorVersion >= 12 ) )

#define LFN_SUPPORTED( Scb )  \
    ( ( Scb->MajorVersion >= 4 ) ||   \
      ( Scb->MajorVersion == 3 && Scb->MinorVersion >= 11 ) )

#define LongByteSwap( l1, l2 )     \
{                                  \
    PUCHAR c1 = (PUCHAR)&l1;       \
    PUCHAR c2 = (PUCHAR)&l2;       \
    c1[0] = c2[3];                 \
    c1[1] = c2[2];                 \
    c1[2] = c2[1];                 \
    c1[3] = c2[0];                 \
}

#define ShortByteSwap( s1, s2 )    \
{                                  \
    PUCHAR c1 = (PUCHAR)&s1;       \
    PUCHAR c2 = (PUCHAR)&s2;       \
    c1[0] = c2[1];                 \
    c1[1] = c2[0];                 \
}



#define CanLogTimeOutEvent( LastTime, CurrentTime ) \
     ( ( CurrentTime.QuadPart ) - ( LastTime.QuadPart ) >= 0 )

#define UpdateNextEventTime( LastTime, CurrentTime, TimeOutEventInterval ) \
    ( LastTime.QuadPart ) = ( CurrentTime.QuadPart ) + \
                            ( TimeOutEventInterval.QuadPart )



//
//  Macros to isolate NT 3.1 and NT 3.5 differences.
//

#ifdef QFE_BUILD

#define NwGetTopLevelIrp()     (PIRP)(PsGetCurrentThread()->TopLevelIrp)
#define NwSetTopLevelIrp(Irp)  (PIRP)(PsGetCurrentThread())->TopLevelIrp = Irp;


#else

#define NwGetTopLevelIrp()     IoGetTopLevelIrp()
#define NwSetTopLevelIrp(Irp)  IoSetTopLevelIrp(Irp)

#endif

//
// David Goebel - pls figure out which file below should come from
//          io.h cannot be included successfully
//

NTKERNELAPI
VOID
IoRemoveShareAccess(
    IN PFILE_OBJECT FileObject,
    IN OUT PSHARE_ACCESS ShareAccess
    );

// now all SKUs have TerminalServer flag.  If App Server is enabled, SingleUserTS flag is cleared
#define IsTerminalServer() !(ExVerifySuite(SingleUserTS))

#endif // _NWPROCS_