windows-nt/Source/XPSP1/NT/net/tcpip/driver/ipv4/ipmcast.h
2020-09-26 16:20:57 +08:00

563 lines
13 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
tcpip\ip\ipmcast.h
Abstract:
Defines and internal structures for IP Multicasting
Author:
Amritansh Raghav
Revision History:
AmritanR Created
Notes:
--*/
#ifndef __IPMCAST_H__
#define __IPMCAST_H__
typedef unsigned long DWORD, *PDWORD;
typedef unsigned char BYTE, *PBYTE;
#include "iproute.h"
#include "iprtdef.h"
#include "debug.h"
#include "ipmlock.h"
#include "ddipmcst.h"
#define is ==
#define isnot !=
#define or ||
#define and &&
//
// Symbolic link into DOS space
//
#define WIN32_IPMCAST_SYMBOLIC_LINK L"\\DosDevices\\IPMULTICAST"
//
// Nifty macro for printing IP Addresses
//
#define PRINT_IPADDR(x) \
((x)&0x000000FF),(((x)&0x0000FF00)>>8),(((x)&0x00FF0000)>>16),(((x)&0xFF000000)>>24)
//
// We use lookaside lists for a lot of stuff. The following #defines are for
// the depths of the lists
//
#define GROUP_LOOKASIDE_DEPTH 16
#define SOURCE_LOOKASIDE_DEPTH 64
#define OIF_LOOKASIDE_DEPTH 128
#define MSG_LOOKASIDE_DEPTH 8
//
// The number of packets pending per (S,G) entry when queuing is being done
//
#define MAX_PENDING 4
//
// The multicast state
// MCAST_STARTED is again defined in iproute.c and MUST be kept in synch with
// this #define
//
#define MCAST_STOPPED 0
#define MCAST_STARTED 1
//
// The groups are kept in a hash tableof size GROUP_TABLE_SIZE
// GROUP_HASH is the hash function
//
//
// TODO: Need to refine the hash function
//
#define GROUP_TABLE_SIZE 127
#define GROUP_HASH(addr) (addr % GROUP_TABLE_SIZE)
//
// The number of seconds of inactivity after which an SOURCE is deleted
//
#define INACTIVITY_PERIOD (10 * 60)
//
// The default timeout when a MFE is created
//
#define DEFAULT_LIFETIME (1 * 60)
//
// Number of seconds before which another wrong i/f upcall can be generated
//
#define UPCALL_PERIOD (3 * 60)
//
// Some #defines for time/timeticks conversions
//
#define TIMER_IN_MILLISECS (60 * 1000)
#define SYS_UNITS_IN_ONE_MILLISEC (1000 * 10)
#define MILLISECS_TO_TICKS(ms) \
((LONGLONG)(ms) * SYS_UNITS_IN_ONE_MILLISEC / KeQueryTimeIncrement())
#define SECS_TO_TICKS(s) \
((LONGLONG)MILLISECS_TO_TICKS((s) * 1000))
//
// We walk only BUCKETS_PER_QUANTUM number of buckets each time the Timer DPC
// fires. This way we do not hog up too much CPU. So currently we walk enough
// so that we need to fire 5 times every INACTIVITY_PERIOD
//
#define BUCKETS_PER_QUANTUM ((GROUP_TABLE_SIZE/5) + 1)
//
// All IOCTLs are handled by functions with the prototype below. This allows
// us to build a table of pointers and call out to them instead of doing
// a switch
//
typedef
NTSTATUS
(*PFN_IOCTL_HNDLR)(
PIRP pIrp,
ULONG ulInLength,
ULONG ulOutLength
);
//
// If an IRP is not available, the forwarder queues the notification message
// onto a list. Then next time an IRP is posted, a message is pulled of the
// list, copied to the IRP and the IRP is then completed.
//
typedef struct _NOTIFICATION_MSG
{
LIST_ENTRY leMsgLink;
IPMCAST_NOTIFICATION inMessage;
}NOTIFICATION_MSG, *PNOTIFICATION_MSG;
//
// The information for the GROUP entry
//
typedef struct _GROUP
{
//
// Link to the hash bucket
//
LIST_ENTRY leHashLink;
//
// Class D IP Address of the Group
//
DWORD dwGroup;
//
// The number of sources on this group. Not really used for anything
// right now.
//
ULONG ulNumSources;
//
// Linked list of sources active on the group. We should make this
// a singly linked list.
//
LIST_ENTRY leSrcHead;
}GROUP, *PGROUP;
typedef struct _OUT_IF OUT_IF, *POUT_IF;
//
// The information for each outgoing interface
//
struct _OUT_IF
{
//
// Link to the list of OIFs hanging off a source
//
POUT_IF pNextOutIf;
//
// Pointer to IP's Interface structure for the correspongind interface
// If DemandDial, then it points to DummyInterface, when disconnected
//
Interface *pIpIf;
//
// The Interface Index.
//
DWORD dwIfIndex;
//
// The NextHopAddr is either the IP Address of the receiver, for RAS client
// and NBMA type interfaces, or the Group Address.
//
DWORD dwNextHopAddr;
//
// The context to dial out with in case of Demand Dial interfaces
//
DWORD dwDialContext;
//
// The following fields are statistics kept for the OIF
//
ULONG ulTtlTooLow;
ULONG ulFragNeeded;
ULONG ulOutPackets;
ULONG ulOutDiscards;
};
typedef struct _EXCEPT_IF EXCEPT_IF, *PEXCEPT_IF;
struct _EXCEPT_IF
{
//
// Link to the list of i/fs that are exceptions to the wrong i/f bit
//
PEXCEPT_IF pNextExceptIf;
//
// We just store the index - it makes a lot of pnp issues go away
//
DWORD dwIfIndex;
};
//
// Information about an active source
//
typedef struct _SOURCE
{
//
// Link on the list of sources hanging off a group
//
LIST_ENTRY leGroupLink;
//
// IP Address of the source
//
DWORD dwSource;
//
// Mask associated with the source. Not used. Must be 0xFFFFFFFF
//
DWORD dwSrcMask;
//
// The index of the correct incoming interface
//
DWORD dwInIfIndex;
//
// The lock for the structure
//
RT_LOCK mlLock;
//
// Pointer to the IP Interface corresponding to the incoming interface
//
Interface *pInIpIf;
//
// The number of outgoing interfaces
//
ULONG ulNumOutIf;
//
// Singly linked list of OIFs
//
POUT_IF pFirstOutIf;
//
// Singly linked list of wrong i/f exception interfaces
//
PEXCEPT_IF pFirstExceptIf;
//
// Number of packets queued
//
ULONG ulNumPending;
//
// The list of queued packets
//
FWQ fwqPending;
//
// Used to refcount the structure
//
LONG lRefCount;
//
// Some stats pertaining to this source
//
ULONG ulInPkts;
ULONG ulInOctets;
ULONG ulPktsDifferentIf;
ULONG ulQueueOverflow;
ULONG ulUninitMfe;
ULONG ulNegativeMfe;
ULONG ulInDiscards;
ULONG ulInHdrErrors;
ULONG ulTotalOutPackets;
//
// The KeQueryTickCount() value the last time this structure was used
//
LONGLONG llLastActivity;
//
// User supplied timeout. If 0, then the source is timed out on the basis
// of inactivity after INACTIVITY_PERIOD
//
LONGLONG llTimeOut;
//
// The time the structure was created
//
LONGLONG llCreateTime;
//
// The state of the source
//
BYTE byState;
}SOURCE, *PSOURCE;
#define UpdateActivityTime(pSource) \
KeQueryTickCount((PLARGE_INTEGER)&(((pSource)->llLastActivity)))
//
// The states of the MFE
//
#define MFE_UNINIT 0x0
#define MFE_NEGATIVE 0x1
#define MFE_QUEUE 0x2
#define MFE_INIT 0x3
//
// The structure of a hash bucket
//
typedef struct _GROUP_ENTRY
{
//
// List of Groups that fall in the bucket
//
LIST_ENTRY leHashHead;
#if DBG
//
// Current number of groups
//
ULONG ulGroupCount;
ULONG ulCacheHits;
ULONG ulCacheMisses;
#endif
//
// One deep cache
//
PGROUP pGroup;
RW_LOCK rwlLock;
}GROUP_ENTRY, *PGROUP_ENTRY;
//
// The LIST_ENTRY macros from ntrtl.h modified to work on FWQ
//
#define InsertTailFwq(ListHead, Entry) \
{ \
FWQ *_EX_Blink; \
FWQ *_EX_ListHead; \
_EX_ListHead = (ListHead); \
_EX_Blink = _EX_ListHead->fq_prev; \
(Entry)->fq_next = _EX_ListHead; \
(Entry)->fq_prev = _EX_Blink; \
_EX_Blink->fq_next = (Entry); \
_EX_ListHead->fq_prev = (Entry); \
}
#define RemoveEntryFwq(Entry) \
{ \
FWQ *_EX_Blink; \
FWQ *_EX_Flink; \
_EX_Flink = (Entry)->fq_next; \
_EX_Blink = (Entry)->fq_prev; \
_EX_Blink->fq_next = _EX_Flink; \
_EX_Flink->fq_prev = _EX_Blink; \
}
#define RemoveHeadFwq(ListHead) \
(ListHead)->fq_next; \
{RemoveEntryFwq((ListHead)->fq_next)}
#define IsFwqEmpty(ListHead) \
((ListHead)->fq_next == (ListHead))
#define InitializeFwq(ListHead) \
{ \
(ListHead)->fq_next = (ListHead)->fq_prev = (ListHead); \
}
#define CopyFwq(Dest, Source) \
{ \
*(Dest) = *(Source); \
(Source)->fq_next->fq_prev = (Dest); \
(Source)->fq_prev->fq_next = (Dest); \
}
//
// The ref count for a SOURCE is set to 2, once because a pointer is saved in
// the group list and once because the function that creates the SOURCE will
// deref it once
//
#define InitRefCount(pSource) \
(pSource)->lRefCount = 2
#define ReferenceSource(pSource) \
InterlockedIncrement(&((pSource)->lRefCount))
#define DereferenceSource(pSource) \
{ \
if(InterlockedDecrement(&((pSource)->lRefCount)) == 0) \
{ \
DeleteSource((pSource)); \
} \
}
//
// #defines to keep track of number of threads of execution in our code
// This is needed for us to stop cleanly
//
//
// EnterDriver returns if the driver is stopping
//
#define EnterDriver() EnterDriverWithStatus(NOTHING)
#define EnterDriverWithStatus(_Status) \
{ \
RtAcquireSpinLockAtDpcLevel(&g_rlStateLock); \
if(g_dwMcastState is MCAST_STOPPED) \
{ \
RtReleaseSpinLockFromDpcLevel(&g_rlStateLock); \
return _Status; \
} \
g_dwNumThreads++; \
RtReleaseSpinLockFromDpcLevel(&g_rlStateLock); \
}
#define ExitDriver() \
{ \
RtAcquireSpinLockAtDpcLevel(&g_rlStateLock); \
g_dwNumThreads--; \
if((g_dwMcastState is MCAST_STOPPED) and \
(g_dwNumThreads is 0)) \
{ \
KeSetEvent(&g_keStateEvent, \
0, \
FALSE); \
} \
RtReleaseSpinLockFromDpcLevel(&g_rlStateLock); \
}
#if MCAST_REF
#define RefMIF(p) \
{ \
InterlockedIncrement(&((p)->if_mfecount)); \
(p)->if_refcount++; \
}
#define DerefMIF(p) \
{ \
InterlockedDecrement(&((p)->if_mfecount)); \
DerefIF((p)); \
}
#else
#define RefMIF(p) \
{ \
(p)->if_refcount++; \
}
#define DerefMIF(p) \
{ \
DerefIF((p)); \
}
#endif // MCAST_REF
#endif // __IPMCAST_H__