//=============================================================================
// Copyright (c) 1997 Microsoft Corporation
//
// File: table.h
//
// Abstract:
//      This module contains declarations for interface and group table 
//      structures, related macros, and function prototypes.
//
// Author: K.S.Lokesh (lokeshs@)   11-1-97
//
// Revision History:
//=============================================================================

#ifndef _IGMP_TABLE_H_
#define _IGMP_TABLE_H_


//
// forward declarations
//
struct _IF_TABLE_ENTRY;
struct _GROUP_TABLE_ENTRY;
struct _GI_ENTRY;


//
// struct:   GLOBAL_CONFIG (same as mib structs in igmprm.h)   
//
typedef  IGMP_MIB_GLOBAL_CONFIG      GLOBAL_CONFIG;
typedef  PIGMP_MIB_GLOBAL_CONFIG     PGLOBAL_CONFIG; 




//---------------------------------------------------
// struct:    IGMP_GLOBAL_STATS
//---------------------------------------------------

typedef struct _GLOBAL_STATS {

    DWORD                CurrentGroupMemberships;
    DWORD                GroupMembershipsAdded;
    LARGE_INTEGER        TimeWhenRtrStarted;

} IGMP_GLOBAL_STATS, *PIGMP_GLOBAL_STATS;





//-------------------------------------------------
// static group structures(external)
//-------------------------------------------------

typedef struct _STATIC_GROUP_V3 {
    IGMP_STATIC_GROUP_V3;
    DWORD       Sources[0];
    
} STATIC_GROUP_V3, *PSTATIC_GROUP_V3;

typedef struct _MIB_GROUP_INFO_V3 {
    IGMP_MIB_GROUP_INFO_V3;
    IGMP_MIB_GROUP_SOURCE_INFO_V3      Sources[0];
    
} MIB_GROUP_INFO_V3, *PMIB_GROUP_INFO_V3;

typedef PIGMP_MIB_GROUP_INFO PMIB_GROUP_INFO;
typedef IGMP_MIB_GROUP_INFO MIB_GROUP_INFO;


#define GET_FIRST_STATIC_GROUP_V3(pConfig) \
                        ((PSTATIC_GROUP_V3)((PIGMP_MIB_IF_CONFIG)(pConfig)+1))

#define GET_NEXT_STATIC_GROUP_V3(pStaticGroupV3) \
    ((PSTATIC_GROUP_V3) ((PCHAR)pStaticGroupV3+sizeof(IGMP_STATIC_GROUP_V3) \
                            +sizeof(IPADDR)*pStaticGroupV3->NumSources))

//----------------------------------------------------------------------------
// struct:      IF_STATIC_GROUP
//----------------------------------------------------------------------------

typedef struct _IF_STATIC_GROUP {

    LIST_ENTRY              Link;
    STATIC_GROUP_V3;
    
} IF_STATIC_GROUP, *PIF_STATIC_GROUP;




//---------------------------------------------------------------
// struct:    IGMP_IF_CONFIG (same as mib structs in igmprm.h)
//
// if they are made different, then CopyMemory should not be used
//---------------------------------------------------------------

typedef struct _IGMP_IF_CONFIG {

    IGMP_MIB_IF_CONFIG;

    //v3: NonQuerier saves old values
    DWORD               RobustnessVariableOld;
    DWORD               GenQueryIntervalOld;
    DWORD               OtherQuerierPresentIntervalOld;
    DWORD               GroupMembershipTimeoutOld;

    DWORD       ExtSize;
    LIST_ENTRY  ListOfStaticGroups;

} IGMP_IF_CONFIG, *PIGMP_IF_CONFIG;



//---------------------------------------------------
// struct:     IF_INFO
//---------------------------------------------------
typedef struct _IF_INFO {

    UCHAR               QuerierState;       //if made DWORD, then change to interlocked operations
    DWORD               QuerierIpAddr;
    
    LONGLONG            QuerierPresentTimeout;    //when the last query was heard. only if I am not querier
    LONGLONG            LastQuerierChangeTime;       // when the last querier was changed
    LONGLONG            V1QuerierPresentTime; //when the last v1 query was heard
    LONGLONG            OtherVerPresentTimeWarn; //when the last warning was given
        
    DWORD               StartupQueryCountCurrent;

    DWORD               GroupQueriesSent;
    DWORD               GroupQueriesReceived;

    LONGLONG            TimeWhenActivated;
    DWORD               TotalIgmpPacketsReceived;
    DWORD               TotalIgmpPacketsForRouter;
    DWORD               GenQueriesSent;
    DWORD               GenQueriesReceived;
    DWORD               WrongVersionQueries;
    DWORD               JoinsReceived;
    DWORD               LeavesReceived;
    DWORD               CurrentGroupMemberships;
    DWORD               GroupMembershipsAdded;
    DWORD               WrongChecksumPackets;
    DWORD               ShortPacketsReceived;
    DWORD               LongPacketsReceived;
    DWORD               PacketsWithoutRtrAlert;
    DWORD               PacketSize;
    
} IF_INFO, *PIF_INFO;


//---------------------------------------------------
// struct      RAS_CLIENT_INFO
//---------------------------------------------------

typedef struct _RAS_CLIENT_INFO {

    DWORD               SendFailures;
    DWORD               TotalIgmpPacketsReceived;
    DWORD               TotalIgmpPacketsForRouter;
    DWORD               GenQueriesReceived;
    DWORD               JoinsReceived;
    DWORD               LeavesReceived;
    DWORD               CurrentGroupMemberships;
    DWORD               GroupMembershipsAdded;
    DWORD               GroupMembershipsRemoved;
    DWORD               WrongChecksumPackets;
    DWORD               ShortPacketsReceived;
    DWORD               LongPacketsReceived;
    DWORD               WrongVersionQueries;
    
} RAS_CLIENT_INFO, *PRAS_CLIENT_INFO;


//---------------------------------------------------
// struct:         RAS_TABLE_ENTRY
//---------------------------------------------------

typedef struct _RAS_TABLE_ENTRY {

    LIST_ENTRY              LinkByAddr;
    LIST_ENTRY              HTLinkByAddr;
    LIST_ENTRY              ListOfSameClientGroups;

    DWORD                   NHAddr;
    struct _IF_TABLE_ENTRY *IfTableEntry;
    
    DWORD                   Status;
    RAS_CLIENT_INFO         Info;

} RAS_TABLE_ENTRY, *PRAS_TABLE_ENTRY;



//---------------------------------------------------
// struct:        RAS_TABLE
//---------------------------------------------------

#define RAS_HASH_TABLE_SZ    256
typedef struct _RAS_TABLE {

    LIST_ENTRY              ListByAddr;                         //links ras clients
    LIST_ENTRY              HashTableByAddr[RAS_HASH_TABLE_SZ];
        
    struct _IF_TABLE_ENTRY  *pIfTable;          //ptr to interface table entry

    DWORD                   RefCount;
    DWORD                   Status;

} RAS_TABLE, *PRAS_TABLE;





//---------------------------------------------------
// struct:    SOCKET_EVENT_ENTRY
//---------------------------------------------------

typedef struct _SOCKET_EVENT_ENTRY {

    LIST_ENTRY          LinkBySocketEvents;

    LIST_ENTRY          ListOfInterfaces;
    DWORD               NumInterfaces;

    HANDLE              InputWaitEvent;
    HANDLE              InputEvent;
    
} SOCKET_EVENT_ENTRY, *PSOCKET_EVENT_ENTRY;    




//---------------------------------------------------
// struct:    SOCKET_ENTRY
//---------------------------------------------------

typedef struct _SOCKET_ENTRY {

    LIST_ENTRY              LinkByInterfaces;

    SOCKET                  Socket;
    PSOCKET_EVENT_ENTRY     pSocketEventsEntry;
    
} SOCKET_ENTRY, *PSOCKET_ENTRY;    
    




//------------------------------------------------------------------------------
// struct:      IF_TABLE_ENTRY
//
// IF-table:Table_RWL          protects LinkByAddr, LinkByIndex, HTLinkByIndex
//                                      IpAddr, Status, pBinding
// IF-table:IfTableBucketCS protects ListOfSameIfGroups
// Interlocked operations      protect  Info, Config
//------------------------------------------------------------------------------

typedef struct _IF_TABLE_ENTRY {

    LIST_ENTRY          LinkByAddr;             // sorted by Ipaddr.only activated interfaces
    LIST_ENTRY          LinkByIndex;            // sorted by Index. all interfaces
    LIST_ENTRY          HTLinkByIndex;          // not sorted within bucket

    LIST_ENTRY          ListOfSameIfGroups;     // sorted by GroupAddr. GI entries for IF (all GIs of Ras clients)
    LIST_ENTRY          ListOfSameIfGroupsNew;  // unmerged list. sorted by GroupAddr. GI entries same as above
    DWORD               NumGIEntriesInNewList;  // used to decide if lists should be merged


    UCHAR               IfType;                 // IGMP_IF_ (NOT_RAS,RAS_ROUTER,RAS_SERVER). for external calls, IGMP_IF_PROXY might be set
                                                // set when interface is created. cannot be changed again.
    DWORD               IfIndex;                
    IPADDR              IpAddr;                 // set when IF is bound. ==0 for un-numbered IFs.

    DWORD               Status;                 // IF_(CREATED/BOUND/ENABLED/ACTIVATED),
                                                // IF_DEACTIVATE_DELETE_FLAG, 
                                                // MGM_ENABLED_IGMPRTR_FLAG, IGMPRTR_MPROTOCOL_PRESENT_FLAG

    PRAS_TABLE          pRasTable;              // null if not IGMP_IF_RAS_SERVER. created in _AddIfEntry()
    PLIST_ENTRY         pProxyHashTable;        // g_pProxyHashTable: contains the proxy entries. They are also linked in
                                                // order using the LinkBySameIfGroups field accessed through pite.

    IGMP_IF_CONFIG      Config;
    PIGMP_IF_BINDING    pBinding;               // null if not bound or unNumbered interface.
    IF_INFO             Info;

    SOCKET_ENTRY        SocketEntry;            // used by igmpRouter for getting input, and binding to waitEvent
                                                // used by proxy to join the igmp groups as a host.
                                                
    IGMP_TIMER_ENTRY    QueryTimer;             // Querier mode: used for sending general query.

    IGMP_TIMER_ENTRY    NonQueryTimer;          // used when in NonQuerier mode: used for detecting other queriers

    HANDLE              pPrevIfGroupEnumPtr;    // points to the next GI entry to be enumerated.
    USHORT              PrevIfGroupEnumSignature;//used in enumerating interface GI list in order

    SOCKET              StaticGroupSocket;      // used only by igmp Router. created in _CreateIfSockets and 
                                                // closed in _DeleteIfSockets.
                                                // Static groups in proxy are joined on SocketEntry.
    DWORD               CreationFlags;          // see below.
    
} IF_TABLE_ENTRY, *PIF_TABLE_ENTRY;


//
// values for CreationFlags
//

#define REGISTERED_PROTOCOL_WITH_MGM        0x0001
#define TAKEN_INTERFACE_OWNERSHIP_WITH_MGM  0x0002
#define DONE_STAR_STAR_JOIN                 0x0004
#define SOCKETS_CREATED                     0x0008

// the above flags are cleared during deactivation, while below flags
// are retained across deactivations.
#define CREATION_FLAGS_DEACTIVATION_CLEAR   0x00FF


#define CREATED_PROXY_HASH_TABLE            0x0100





// expand the table if the number of interface is greater than 16        
#define IF_HASHTABLE_SZ1     256
#define IF_EXPAND_THRESHOLD1 256

#define IF_HASHTABLE_SZ2     512

//---------------------------------------------------
// struct:      IGMP_IF_TABLE
//---------------------------------------------------

typedef struct _IF_TABLE {

    LIST_ENTRY          ListByAddr;
    LIST_ENTRY          ListByIndex;

    DWORD               Status;
    DWORD               NumBuckets;
    DWORD               NumInterfaces;
    
    PLIST_ENTRY         HashTableByIndex;
    PDYNAMIC_CS_LOCK   *aIfBucketDCS;
    PDYNAMIC_RW_LOCK   *aIfBucketDRWL;

    CRITICAL_SECTION    IfLists_CS;    // CS protecting the 1st two lists

} IGMP_IF_TABLE, *PIGMP_IF_TABLE;


        

//---------------------------------------------------
// struct:     GI_INFO
//---------------------------------------------------

typedef struct _GROUP_INFO {

    DWORD               LastReporter;
    LONGLONG            GroupUpTime;
    LONGLONG            GroupExpiryTime;
    LONGLONG            V1HostPresentTimeLeft;

    // version 3 fields
    LONGLONG            V2HostPresentTimeLeft;
    
} GI_INFO, *PGROUP_INFO;




//---------------------------------------------------
// struct:      GI_ENTRY (group-Interface entry)
//---------------------------------------------------

typedef struct _GI_ENTRY {

    LIST_ENTRY          LinkByGI;
    LIST_ENTRY          LinkBySameIfGroups;
    LIST_ENTRY          LinkBySameClientGroups; //links all ras client groups

    DWORD               IfIndex;
    DWORD               Status;     //bound,enabled,deleted,activated
    BOOL                bRasClient; //rasclient or not
    BOOL                bStaticGroup;
    
    PIF_TABLE_ENTRY     pIfTableEntry;    
    struct _GROUP_TABLE_ENTRY    *pGroupTableEntry;

    //below two fields valid only for ras    
    DWORD               NHAddr;
    PRAS_TABLE_ENTRY    pRasTableEntry;


    IGMP_TIMER_ENTRY    GroupMembershipTimer;

    /*timerlock*///LastMemQueryCount left to be sent
    DWORD               LastMemQueryCount;
    IGMP_TIMER_ENTRY    LastMemQueryTimer;
        
    IGMP_TIMER_ENTRY    LastVer1ReportTimer;/*timelock*/
    BYTE                Version;    //ver1, ver2, ver3

    GI_INFO             Info;

    // igmpv3 fields. ignored for rest.
    IGMP_TIMER_ENTRY    LastVer2ReportTimer;/*timelock*/
    DWORD               FilterType;
    DWORD               NumSources;
    LIST_ENTRY          *V3InclusionList;
    LIST_ENTRY          V3InclusionListSorted;
    LIST_ENTRY          V3ExclusionList;

    //query sources
    LIST_ENTRY          V3SourcesQueryList;
    DWORD               V3SourcesQueryCount;
    BOOL                bV3SourcesQueryNow;
    IGMP_TIMER_ENTRY    V3SourcesQueryTimer;

    #if DEBUG_FLAGS_SIGNATURE
    DWORD               Signature;//0xfadfad02
    #endif
    
} GI_ENTRY, *PGI_ENTRY;

//kslksl1 10
#define SOURCES_BUCKET_SZ 1

//---------------------------------------------------
// struct:      GI_SOURCE_ENTRY
//---------------------------------------------------

typedef struct _GI_SOURCE_ENTRY {

    LIST_ENTRY          LinkSources;
    LIST_ENTRY          LinkSourcesInclListSorted;
    LIST_ENTRY          V3SourcesQueryList;
    PGI_ENTRY           pGIEntry;
    
    BOOL                bInclusionList;
    
    IPADDR              IpAddr;

    //how many more src queries left to be sent
    DWORD               V3SourcesQueryLeft;
    BOOL                bInV3SourcesQueryList;
    
    //timeout sources in inc list
    IGMP_TIMER_ENTRY    SourceExpTimer;
    LONGLONG            SourceInListTime;

    BOOL                bStaticSource;
    
} GI_SOURCE_ENTRY, *PGI_SOURCE_ENTRY;

#define GET_IF_CONFIG_FOR_SOURCE(pSourceEntry) \
    pSourceEntry->pGIEntry->pIfTableEntry->Config
    
#define GET_IF_ENTRY_FOR_SOURCE(pSourceEntry) \
    pSourceEntry->pGIEntry->pIfTableEntry
    
    
//---------------------------------------------------
// struct:      GROUP_TABLE_ENTRY
//---------------------------------------------------

typedef struct _GROUP_TABLE_ENTRY {

    LIST_ENTRY          HTLinkByGroup;
    LIST_ENTRY          LinkByGroup; //ordered list of groups
    LIST_ENTRY          ListOfGIs;
    
    DWORD               Group;
    DWORD               GroupLittleEndian;
    
    DWORD               NumVifs;
    
    DWORD               Status;
    
    LONGLONG            GroupUpTime;

    #if DEBUG_FLAGS_SIGNATURE
    DWORD               Signature; //0xfadfad01
    #endif

} GROUP_TABLE_ENTRY, *PGROUP_TABLE_ENTRY;




#define GROUP_HASH_TABLE_SZ     256
//---------------------------------------------------
// struct:      GROUP_TABLE
//---------------------------------------------------

typedef struct _GROUP_TABLE {
        
    LOCKED_LIST             ListByGroup;
    LIST_ENTRY              ListByGroupNew;
    DWORD                   NumGroupsInNewList;

    DWORD                   Status;

    LONG                    NumIfs;    //Interlocked Operations

    DYNAMIC_CS_LOCKED_LIST  HashTableByGroup[GROUP_HASH_TABLE_SZ];
    
} GROUP_TABLE, *PGROUP_TABLE;




//-------------------------------------------------
// Proxy group entry
//-------------------------------------------------
typedef struct _PROXY_GROUP_ENTRY {

    LIST_ENTRY          HT_Link;
    LIST_ENTRY          LinkBySameIfGroups;

    //v3
    LIST_ENTRY          ListSources;
    
    DWORD               Group;
    DWORD               GroupLittleEndian;
    DWORD               RefCount;
    LONGLONG            InitTime;
    BOOL                bStaticGroup;

    //v3
    DWORD               NumSources;
    DWORD               FilterType;
    
} PROXY_GROUP_ENTRY, *PPROXY_GROUP_ENTRY;

typedef struct _PROXY_SOURCE_ENTRY {
    LIST_ENTRY          LinkSources;
    IPADDR              IpAddr;
    DWORD               RefCount;
    BOOL                bStaticSource;
    DWORD               JoinMode;//ALLOW,BLOCK, NO_STATE
    DWORD               JoinModeIntended;
} PROXY_SOURCE_ENTRY, *PPROXY_SOURCE_ENTRY;



//-------------------------------------------------
// prototypes
//-------------------------------------------------

DWORD 
CreateIfSockets (
    PIF_TABLE_ENTRY    pite
    );

VOID
DeleteIfSockets (
    PIF_TABLE_ENTRY pite
    );

VOID
DeleteAllTimers (
    PLIST_ENTRY     pHead,
    DWORD           bEntryType //RAS_CLIENT, NOT_RAS_CLIENT
    );


DWORD
DeleteGIEntry (
    PGI_ENTRY   pgie,   //group interface entry
    BOOL        bUpdateStats,
    BOOL        bCallMgm
    );

VOID
DeleteAllGIEntries(
    PIF_TABLE_ENTRY pite
    );
    
VOID
DeleteGIEntryFromIf (
    PGI_ENTRY   pgie   //group interface entry
    );
    
VOID
MergeGroupLists(
    );

VOID
MergeIfGroupsLists(
    PIF_TABLE_ENTRY pite
    );

VOID
MergeProxyLists(
    PIF_TABLE_ENTRY pite
    );

DWORD
CopyinIfConfig (
    PIGMP_IF_CONFIG     pConfig,
    PIGMP_MIB_IF_CONFIG pConfigExt,
    DWORD               IfIndex
    );
    
DWORD
CopyinIfConfigAndUpdate (
    PIF_TABLE_ENTRY     pite,
    PIGMP_MIB_IF_CONFIG pConfigExt,
    ULONG               IfIndex
    );
    
VOID
CopyoutIfConfig (
    PIGMP_MIB_IF_CONFIG pConfigExt,
    PIF_TABLE_ENTRY     pite
    );
    
DWORD 
ValidateIfConfig (
    PIGMP_MIB_IF_CONFIG pConfigExt,
    DWORD               IfIndex,
    DWORD               IfType,
    ULONG               StructureVersion,
    ULONG               StructureSize
    );
    
DWORD    
InitializeIfTable (
    );

VOID    
DeInitializeIfTable (
    );

DWORD    
InitializeGroupTable (
    );

VOID    
DeInitializeGroupTable (
    );

DWORD
InitializeRasTable(
    DWORD               IfIndex,
    PIF_TABLE_ENTRY     pite
    );

VOID
DeInitializeRasTable (
    PIF_TABLE_ENTRY     pite,
    BOOL                bFullCleanup
    );


#endif // _IGMP_TABLE_H_