/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    nb.h

Abstract:

    Private include file for the NB (NetBIOS) component of the NTOS project.

Author:

    Colin Watson (ColinW) 13-Mar-1991

Revision History:

--*/

#ifndef _NB_
#define _NB_

#include <ntifs.h>

//#include <ntos.h>
#include <windef.h>
#include <status.h>
#include <tdikrnl.h>                       // Transport Driver Interface.
#include <nb30.h>
#include <nb30p.h>
#include <netpnp.h>

#include "nbconst.h"                    // private NETBEUI constants.
#include "nbtypes.h"                    // private NETBEUI types.
#include "nbdebug.h"                    // private NETBEUI debug defines.
#include "nbprocs.h"                    // private NETBEUI function prototypes.

#ifdef MEMPRINT
#include "memprint.h"                   // drt's memory debug print
#endif

extern PEPROCESS    NbFspProcess;


extern ULONG                g_ulMaxLana;

extern LANA_ENUM            g_leLanaEnum;

extern PUNICODE_STRING      g_pusActiveDeviceList;

extern HANDLE               g_hBindHandle;

extern UNICODE_STRING       g_usRegistryPath;

extern LIST_ENTRY           g_leFCBList;

extern ERESOURCE            g_erGlobalLock;



#if DBG
#define PAGED_DBG 1
#endif
#ifdef PAGED_DBG
#undef PAGED_CODE
#define PAGED_CODE() \
    struct { ULONG bogus; } ThisCodeCantBePaged; \
    ThisCodeCantBePaged; \
    if (KeGetCurrentIrql() > APC_LEVEL) { \
        KdPrint(( "NETBIOS: Pageable code called at IRQL %d.  File %s, Line %d\n", KeGetCurrentIrql(), __FILE__, __LINE__ )); \
        ASSERT(FALSE); \
        }
#define PAGED_CODE_CHECK() if (ThisCodeCantBePaged) ;
extern ULONG ThisCodeCantBePaged;
#else
#define PAGED_CODE_CHECK()
#endif


#if PAGED_DBG
#define ACQUIRE_SPIN_LOCK(a, b) {               \
    PAGED_CODE_CHECK();                         \
    KeAcquireSpinLock(a, b);                    \
    }
#define RELEASE_SPIN_LOCK(a, b) {               \
    PAGED_CODE_CHECK();                         \
    KeReleaseSpinLock(a, b);                    \
    }

#else
#define ACQUIRE_SPIN_LOCK(a, b) KeAcquireSpinLock(a, b)
#define RELEASE_SPIN_LOCK(a, b) KeReleaseSpinLock(a, b)
#endif



//
//  Macro for filling in the status for an NCB.
//

#define NCB_COMPLETE( _pdncb, _code ) {                                 \
    UCHAR _internal_copy = _code;                                       \
    IF_NBDBG (NB_DEBUG_COMPLETE) {                                      \
        NbPrint (("%s %d NCB_COMPLETE: %lx, %lx\n" ,                    \
         __FILE__, __LINE__, _pdncb, _internal_copy ));                 \
    }                                                                   \
    if (((PDNCB)_pdncb)->ncb_retcode  == NRC_PENDING) {                 \
        ((PDNCB)_pdncb)->ncb_retcode  = _internal_copy;                 \
    } else {                                                            \
        IF_NBDBG (NB_DEBUG_NCBS) {                                      \
            NbPrint((" Status already set!!!!!!!!\n"));                 \
            IF_NBDBG (NB_DEBUG_NCBSBRK) {                               \
                DbgBreakPoint();                                        \
            }                                                           \
        }                                                               \
    }                                                                   \
    IF_NBDBG (NB_DEBUG_NCBS) {                                          \
        NbDisplayNcb( (PDNCB)_pdncb );                                  \
    }                                                                   \
    IF_NBDBG (NB_DEBUG_COMPLETE)                                        \
    {                                                                   \
        if ( ( (_code) == NRC_BRIDGE ) ||                               \
             ( (_code) == NRC_ENVNOTDEF ) )                             \
        {                                                               \
            DbgPrint("\n[NETBIOS]: NCB_COMPLETE : File %s,"             \
                     " line %d\n", __FILE__, __LINE__);                 \
            DbgPrint("LANA %x, Command %x ",                            \
                     ((PDNCB)_pdncb)->ncb_lana_num,                     \
                     ((PDNCB)_pdncb)->ncb_command );                    \
            DbgPrint("Return %x, Cmplt %x\n",                           \
                      ((PDNCB)_pdncb)->ncb_retcode,                     \
                      ((PDNCB)_pdncb)->ncb_cmd_cplt );                  \
            NbFormattedDump( ((PDNCB)_pdncb)->ncb_name, 16 );           \
            NbFormattedDump( ((PDNCB)_pdncb)->ncb_callname, 16 );       \
        }                                                               \
        else if ( ( ( (_code) == NRC_DUPNAME ) ||                       \
                    ( (_code) == NRC_INUSE ) ) &&                       \
                  ( ((PDNCB)_pdncb)-> ncb_command != NCBADDGRNAME ) )   \
        {                                                               \
            DbgPrint("\n[NETBIOS]: NCB_COMPLETE : DUPNAME : File %s,"   \
                     "line %d\n", __FILE__, __LINE__);                  \
            DbgPrint("LANA %x, Command %x ",                            \
                     ((PDNCB)_pdncb)->ncb_lana_num,                     \
                     ((PDNCB)_pdncb)->ncb_command );                    \
            DbgPrint("Return %x, Cmplt %x\n",                           \
                     ((PDNCB)_pdncb)->ncb_retcode,                      \
                     ((PDNCB)_pdncb)->ncb_cmd_cplt );                   \
            NbFormattedDump( ((PDNCB)_pdncb)->ncb_name, 16 );           \
            if ( ((PDNCB)_pdncb)->ncb_name[15] == 0x3)                  \
            {                                                           \
                DbgPrint("Messenger Name, dup ok\n");                   \
            }                                                           \
            else                                                        \
            {                                                           \
                IF_NBDBG(NB_DEBUG_NCBSBRK) DbgBreakPoint();             \
            }                                                           \
        }                                                               \
    }                                                                   \
}


//++
//
//  VOID
//  NbCompleteRequest (
//      IN PIRP Irp,
//      IN NTSTATUS Status
//      );
//
//  Routine Description:
//
//      This routine is used to complete an IRP with the indicated
//      status.  It does the necessary raise and lower of IRQL.
//
//  Arguments:
//
//      Irp - Supplies a pointer to the Irp to complete
//
//      Status - Supplies the completion status for the Irp
//
//  Return Value:
//
//      None.
//
//--
#define NbCompleteRequest(IRP,STATUS) {                 \
    (IRP)->IoStatus.Status = (STATUS);                  \
    IoCompleteRequest( (IRP), IO_NETWORK_INCREMENT );   \
}


#if defined(_WIN64)
#define NbCheckAndCompleteIrp32(Irp)                    \
{                                                       \
    if (IoIs32bitProcess(Irp) == TRUE)                  \
    {                                                   \
        NbCompleteIrp32(Irp);                           \
    }                                                   \
}
#else
#define NbCheckAndCompleteIrp32(Irp)
#endif                
//
//  Normally the driver wants to prohibit other threads making
//  requests (using a resource) and also prevent indication routines
//  being called (using a spinlock).
//
//  To do this LOCK and UNLOCK are used. IO system calls cannot
//  be called with a spinlock held so sometimes the ordering becomes
//  LOCK, UNLOCK_SPINLOCK <do IO calls> UNLOCK_RESOURCE.
//

#define LOCK(PFCB, OLDIRQL)   {                                 \
    IF_NBDBG (NB_DEBUG_LOCKS) {                                 \
        NbPrint (("%s %d LOCK: %lx %lx %lx\n" ,                 \
         __FILE__, __LINE__, (PFCB) ));                         \
    }                                                           \
    KeEnterCriticalRegion();                                    \
    ExAcquireResourceExclusiveLite( &(PFCB)->Resource, TRUE);   \
    ACQUIRE_SPIN_LOCK( &(PFCB)->SpinLock, &(OLDIRQL));          \
}

#define LOCK_RESOURCE(PFCB)   {                                 \
    IF_NBDBG (NB_DEBUG_LOCKS) {                                 \
        NbPrint(("%s %d LOCK_RESOURCE: %lx, %lx %lx\n" ,        \
         __FILE__, __LINE__, (PFCB)));                          \
    }                                                           \
    KeEnterCriticalRegion();                                    \
    ExAcquireResourceExclusiveLite( &(PFCB)->Resource, TRUE);   \
}

#define LOCK_GLOBAL()   {                                       \
    IF_NBDBG (NB_DEBUG_LOCKS) {                                 \
        NbPrint(("%s %d LOCK_GLOBAL: %lx, %lx\n" ,              \
         __FILE__, __LINE__));                                  \
    }                                                           \
    KeEnterCriticalRegion();                                    \
    ExAcquireResourceExclusiveLite( &g_erGlobalLock, TRUE);     \
}

#define LOCK_STOP()   {                                         \
    IF_NBDBG (NB_DEBUG_LOCKS) {                                 \
        NbPrint(("%s %d LOCK_STOP: %lx, %lx\n" ,                \
         __FILE__, __LINE__));                                  \
    }                                                           \
    KeEnterCriticalRegion();                                    \
    ExAcquireResourceExclusiveLite( &g_erStopLock, TRUE);       \
}


#define LOCK_SPINLOCK(PFCB, OLDIRQL)   {                        \
    IF_NBDBG (NB_DEBUG_LOCKS) {                                 \
        NbPrint( ("%s %d LOCK_SPINLOCK: %lx %lx %lx\n" ,        \
         __FILE__, __LINE__, (PFCB)));                          \
    }                                                           \
    ACQUIRE_SPIN_LOCK( &(PFCB)->SpinLock, &(OLDIRQL));          \
}

#define UNLOCK(PFCB, OLDIRQL) {                                 \
    UNLOCK_SPINLOCK( PFCB, OLDIRQL );                           \
    UNLOCK_RESOURCE( PFCB );                                    \
}

#define UNLOCK_GLOBAL()   {                                     \
    IF_NBDBG (NB_DEBUG_LOCKS) {                                 \
        NbPrint(("%s %d UNLOCK_GLOBAL: %lx, %lx\n" ,            \
         __FILE__, __LINE__));                                  \
    }                                                           \
    ExReleaseResourceLite( &g_erGlobalLock );                   \
    KeLeaveCriticalRegion();                                    \
}


#define UNLOCK_STOP()   {                                       \
    IF_NBDBG (NB_DEBUG_LOCKS) {                                 \
        NbPrint(("%s %d UNLOCK_STOP: %lx, %lx\n" ,              \
         __FILE__, __LINE__));                                  \
    }                                                           \
    ExReleaseResourceLite( &g_erStopLock );                     \
    KeLeaveCriticalRegion();                                    \
}

#define UNLOCK_RESOURCE(PFCB) {                                 \
    IF_NBDBG (NB_DEBUG_LOCKS) {                                 \
        NbPrint( ("%s %d RESOURCE: %lx, %lx %lx\n" ,            \
         __FILE__, __LINE__, (PFCB) ));                         \
    }                                                           \
    ExReleaseResourceLite( &(PFCB)->Resource );                 \
    KeLeaveCriticalRegion();                                    \
}

#define UNLOCK_SPINLOCK(PFCB, OLDIRQL) {                        \
    IF_NBDBG (NB_DEBUG_LOCKS) {                                 \
        NbPrint( ("%s %d SPINLOCK: %lx, %lx %lx %lx\n" ,        \
         __FILE__, __LINE__, (PFCB), (OLDIRQL)));               \
    }                                                           \
    RELEASE_SPIN_LOCK( &(PFCB)->SpinLock, (OLDIRQL) );          \
}


//  Assume resource held when modifying CurrentUsers
#define REFERENCE_AB(PAB) {                                     \
    (PAB)->CurrentUsers++;                                      \
    IF_NBDBG (NB_DEBUG_ADDRESS) {                               \
        NbPrint( ("ReferenceAb %s %d: %lx, NewCount:%lx\n",     \
            __FILE__, __LINE__,                                 \
            PAB,                                                \
            (PAB)->CurrentUsers));                              \
        NbFormattedDump( (PUCHAR)&(PAB)->Name, sizeof(NAME) );  \
    }                                                           \
}

//  Resource must be held before dereferencing the address block

#define DEREFERENCE_AB(PPAB) {                                  \
    IF_NBDBG (NB_DEBUG_ADDRESS) {                               \
        NbPrint( ("DereferenceAb %s %d: %lx, OldCount:%lx\n",   \
            __FILE__, __LINE__, *PPAB, (*PPAB)->CurrentUsers)); \
        NbFormattedDump( (PUCHAR)&(*PPAB)->Name, sizeof(NAME) );\
    }                                                           \
    (*PPAB)->CurrentUsers--;                                    \
    if ( (*PPAB)->CurrentUsers == 0 ) {                         \
        if ( (*PPAB)->AddressHandle != NULL ) {                 \
            IF_NBDBG (NB_DEBUG_ADDRESS) {                       \
                NbPrint( ("DereferenceAb: Closing: %lx\n",      \
                    (*PPAB)->AddressHandle));                   \
            }                                                   \
            NbAddressClose( (*PPAB)->AddressHandle,             \
                                 (*PPAB)->AddressObject );      \
            (*PPAB)->AddressHandle = NULL;                      \
        }                                                       \
        (*PPAB)->pLana->AddressCount--;                         \
        ExFreePool( *PPAB );                                    \
        *PPAB = NULL;                                           \
    }                                                           \
}



//
//  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 NETBIOS_STOPPING    1
#define NETBIOS_RUNNING     2;


#endif // def _NB_