//=============================================================================
// Copyright (c) 1998 Microsoft Corporation
// Module Name: main.c
// Abstract:
//
// Author: K.S.Lokesh (lokeshs@)   1-1-98
//=============================================================================

//
// forward declarations
//

struct _DVMRP_IF_TABLE;
struct _ASYNC_SOCKET_DATA;


//-----------------------------------------------------------------------------
// globals structure
//-----------------------------------------------------------------------------

typedef struct _GLOBALS1 {
    ULONG               RunningStatus;
    ULONG               InitFlags;
    CRITICAL_SECTION    WorkItemCS;
    HANDLE              Heap;
    LOCKED_LIST         RtmQueue;    
    
} GLOBALS1;


typedef struct _GLOBALS {
    HANDLE              LogHandle;          //logging handle
    DWORD               TraceId;            //tracing handle
    
    DWORD               ActivityCount;      //count of pending work items
    HANDLE              ActivityEvent;      //signal it to notify 0 work items

    HANDLE              RtmNotifyEvent;     //signal it to notify Rtm

    DYNAMIC_LOCKS_STORE DynamicCSStore;     //global store for dynamic CS
    DYNAMIC_LOCKS_STORE DynamicRWLStore;    //global store for dynamic RWL

    struct _DVMRP_IF_TABLE    *pIfTable;           //interface table

    LARGE_INTEGER       CurrentTime;        //keeps current 64 bit tick time
    HANDLE              MgmDvmrpHandle;     //handle returned by MGM

    
} GLOBALS;


typedef DVMRP_GLOBAL_CONFIG  GLOBAL_CONFIG;
typedef PDVMRP_GLOBAL_CONFIG PGLOBAL_CONFIG;

typedef DVMRP_IF_CONFIG      IF_CONFIG;
typedef PDVMRP_IF_CONFIG     PIF_CONFIG;


//-----------------------------------------------------------------------------
// DVMRP_IF_TABLE
//-----------------------------------------------------------------------------

typedef struct _DVMRP_IF_TABLE {

    LIST_ENTRY          IfList;         // in order of increasing index
    CRITICAL_SECTION    IfList_CS;      // CS protecting IfList

    DWORD               NumInterfaces;

    PLIST_ENTRY         IfHashTable;
    PDYNAMIC_RW_LOCK   *aIfDRWL;

    CRITICAL_SECTION    PeerLists_CS;   // common lock for add/remove peers

    DWORD               NumActiveIfs;
    
} DVMRP_IF_TABLE, *PDVMRP_IF_TABLE;

#define IF_HASHTABLE_SIZE 50


//-----------------------------------------------------------------------------
// IF_TABLE_ENTRY
//-----------------------------------------------------------------------------

typedef struct _IF_TABLE_ENTRY {

    LIST_ENTRY          Link;
    LIST_ENTRY          HTLink;

    DWORD               IfIndex;
    IPADDR              IpAddr;

    DWORD               Status;
    DWORD               CreationFlags;
    DWORD               RefCount;
    
    PIF_CONFIG          pConfig;
    DWORD               NumAddrBound;
    PDVMRP_ADDR_MASK    pBinding;
    struct _IF_INFO     *pInfo;

    DWORD               NumPeers;           // peers in PeerList
    LIST_ENTRY          PeerList;           // list of peers being created
    LIST_ENTRY          DeletedPeerList;    // list of peers being deleted

    SOCKET              Socket;
    struct _ASYNC_SOCKET_DATA  *pSocketData;

    RTM_ENTITY_HANDLE   RtmHandle;          // register with Rtm
    
} IF_TABLE_ENTRY, *PIF_TABLE_ENTRY;



#define IF_CREATED_FLAG     0x00000001
#define IF_BOUND_FLAG       0x00000002
#define IF_ENABLED_FLAG     0x00000004
#define IF_ACTIVATED_FLAG   0x00000008
#define IF_DELETED_FLAG     0x80000000


#define IS_IF_BOUND(pite) \
        ((pite)->Status&IF_BOUND_FLAG)

#define IS_IF_ENABLED_BY_RTRMGR(pite) \
        ((pite)->Status&IF_ENABLED_FLAG)

#define IS_IF_ENABLED_IN_CONFIG(pite) \
        (IS_DVMRP_IF_ENABLED_FLAG_SET((pite)->pConfig->Flags))

#define IS_IF_ENABLED(pite) \
        ( IS_IF_ENABLED_BY_RTRMGR(pite) && IS_IF_ENABLED_IN_CONFIG(pite) )

#define IS_IF_ENABLED_BOUND(pite) \
        (IS_IF_ENABLED(pite)&&IS_IF_BOUND(pite))
        
#define IS_IF_DELETED(pite) \
        ((pite)->Status&IF_DELETED_FLAG)

#define IS_IF_ACTIVATED(pite) \
        ( !((pite)->Status&IF_DELETED_FLAG) \
            && ((pite)->Status & IF_ACTIVATED_FLAG) )


#define IF_FLAGS_SOCKETS_CREATED            0x00000001
#define IF_FLAGS_PROTO_REGISTERED_WITH_MGM  0x00000002
#define IF_FLAGS_IF_REGISTERED_WITH_MGM     0x00000004


//-----------------------------------------------------------------------------
// IF_INFO
//-----------------------------------------------------------------------------

typedef struct _IF_INFO {

    LONGLONG        TimeWhenActivated;
    
} IF_INFO, *PIF_INFO;



//-----------------------------------------------------------------------------
// type definitions for event message queue
//-----------------------------------------------------------------------------

typedef struct _EVENT_QUEUE_ENTRY {

    ROUTING_PROTOCOL_EVENTS EventType;
    MESSAGE                 Msg;

    LIST_ENTRY              Link;

} EVENT_QUEUE_ENTRY, *PEVENT_QUEUE_ENTRY;


//
// extern variables
//

extern GLOBALS          Globals;
extern GLOBALS1         Globals1;
extern GLOBAL_CONFIG    GlobalConfig;
#define G_pIfTable      (Globals.pIfTable)



//
// defines
//

//-----------------------------------------------------------------------------
// #defines for global structure
//-----------------------------------------------------------------------------

//
// various codes describing states of dvmrp
//

typedef enum {
    DVMRP_STATUS_STARTING   = 100,
    DVMRP_STATUS_RUNNING    = 101,
    DVMRP_STATUS_STOPPING   = 102,
    DVMRP_STATUS_STOPPED    = 103
} DVMRP_STATUS_CODE;

//
// WorkItemCS lock macros
//

#define ACQUIRE_WORKITEM_LOCK(proc) EnterCriticalSection(&Globals1.WorkItemCS)
#define RELEASE_WORKITEM_LOCK(proc) LeaveCriticalSection(&Globals1.WorkItemCS)


//-----------------------------------------------------------------------------
// #defines for global config
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// macros for IfTable
//-----------------------------------------------------------------------------

#define IF_HASH_VALUE(_index) ((_index) % IF_HASHTABLE_SIZE)


#define GET_IF_HASH_BUCKET(Index) \
    &G_pIfTable->IfHashTable[IF_HASH_VALUE(IfIndex)];


// macros for If DRW lock

#define ACQUIRE_IF_LOCK_EXCLUSIVE(_IfIndex, _proc) \
        AcquireDynamicRWLock( \
            &G_pIfTable->aIfDRWL[IF_HASH_VALUE(_IfIndex)], \
            LOCK_MODE_WRITE, &Globals.DynamicRWLStore)
            
#define RELEASE_IF_LOCK_EXCLUSIVE(_IfIndex, _proc) \
        ReleaseDynamicRWLock( \
            &G_pIfTable->aIfDRWL[IF_HASH_VALUE(_IfIndex)],\
            LOCK_MODE_WRITE, &Globals.DynamicRWLStore)

#define ACQUIRE_IF_LOCK_SHARED(_IfIndex, _proc) \
        AcquireDynamicRWLock( \
            &G_pIfTable->aIfDRWL[IF_HASH_VALUE(_IfIndex)],\
            LOCK_MODE_READ, &Globals.DynamicRWLStore)
            
#define RELEASE_IF_LOCK_SHARED(_IfIndex, _proc) \
        ReleaseDynamicRWLock( \
            &G_pIfTable->aIfDRWL[IF_HASH_VALUE(_IfIndex)], \
            LOCK_MODE_READ, &Globals.DynamicRWLStore)



// macros for IfList_CS lock

#define ACQUIRE_IF_LIST_LOCK(_proc) \
        ENTER_CRITICAL_SECTION(&G_pIfTable->IfList_CS, "G_IfListCS", _proc);

#define RELEASE_IF_LIST_LOCK(_proc) \
        LEAVE_CRITICAL_SECTION(&G_pIfTable->IfList_CS, "G_IfListCS", _proc);



// macros for PeerLists_CS lock (see in peer.h)


//
// local prototypes
//

DWORD
WINAPI
StartProtocol(
    IN HANDLE               hRtmNotifyEvent,
    IN PSUPPORT_FUNCTIONS   pSupportFunctions,
    IN PVOID                pGlobalConfig,
    IN ULONG                ulStructureVersion,
    IN ULONG                ulStructureSize,
    IN ULONG                ulStructureCount
    );

DWORD
APIENTRY
StartComplete(
    VOID
    );

DWORD
APIENTRY
StopProtocol(
    VOID
    );

DWORD
WINAPI
GetGlobalInfo(
    IN OUT PVOID    pvConfig,
    IN OUT PDWORD   pdwSize,
    IN OUT PULONG   pulStructureVersion,
    IN OUT PULONG   pulStructureSize,
    IN OUT PULONG   pulStructureCount
    );

DWORD
WINAPI
SetGlobalInfo(
    IN PVOID pvConfig,
    IN ULONG ulStructureVersion,
    IN ULONG ulStructureSize,
    IN ULONG ulStructureCount
    );

DWORD
APIENTRY
GetEventMessage(
    OUT ROUTING_PROTOCOL_EVENTS *pEventType,
    OUT PMESSAGE                pMessage
    );





DWORD
EnqueueEvent(
    PLOCKED_LIST pQueue,
    ROUTING_PROTOCOL_EVENTS EventType,
    MESSAGE Msg
    );

DWORD
DequeueEvent(
    PLOCKED_LIST pQueue,
    ROUTING_PROTOCOL_EVENTS *pEventType,
    PMESSAGE pResult
    );

BOOL
DllStartup(
    );

BOOL
DllCleanup(
    );

VOID
ProtocolCleanup(
    );
    
DWORD
ValidateGlobalConfig(
    PDVMRP_GLOBAL_CONFIG pGlobalConfig,
    DWORD StructureSize
    );