Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2903 lines
94 KiB

//=============================================================================
// Copyright (c) 1997 Microsoft Corporation
// File: table.c
//
// Abstract:
// This module implements some of the routines associated with creating,
// initializing, deleting timers, GI entries, table entries etc
//
// Author: K.S.Lokesh (lokeshs@) 11-1-97
//
// Revision History:
//=============================================================================
#include "pchigmp.h"
#pragma hdrstop
//------------------------------------------------------------------------------
// _CreateIfSockets
//
// Creates the sockets.
// for proxy: a raw IPPROTO_IP socket so that igmp host functionality will
// take over for all groups added on that interface.
// for router: a raw IPPROTO_IGMP socket so that it receives all igmp packets
// A router never does Add Memberships
//
// Called by: _ActivateInterface()
// Locks: assumes exclusive lock on the interface, and socketsList
//------------------------------------------------------------------------------
DWORD
CreateIfSockets (
PIF_TABLE_ENTRY pite
)
{
DWORD Error = NO_ERROR, dwRetval, SockType;
DWORD IpAddr = pite->IpAddr;
DWORD IfIndex = pite->IfIndex;
SOCKADDR_IN saLocalIf;
BOOL bProxy = IS_PROTOCOL_TYPE_PROXY(pite);
PSOCKET_ENTRY pse = &pite->SocketEntry;
BEGIN_BREAKOUT_BLOCK1 {
//
// for proxy, create a IPPROTO_IP socket so that igmp host functionality
// takes over.
// for igmp router, create a raw IPPROTO_IGMP socket
//
SockType = (bProxy)? IPPROTO_IP : IPPROTO_IGMP;
//
// create input socket
//
pse->Socket = WSASocket(AF_INET, SOCK_RAW, SockType, NULL, 0, 0);
if (pse->Socket == INVALID_SOCKET) {
Error = WSAGetLastError();
Trace3(IF,
"error %d creating socket for interface %0x (%d.%d.%d.%d)",
Error, IfIndex, PRINT_IPADDR(IpAddr));
Logerr1(CREATE_SOCKET_FAILED_2, "%I", IpAddr, Error);
GOTO_END_BLOCK1;
}
//
// bind socket to local interface. If I dont bind multicast may
// not work.
//
ZeroMemory(&saLocalIf, sizeof(saLocalIf));
saLocalIf.sin_family = PF_INET;
saLocalIf.sin_addr.s_addr = IpAddr;
saLocalIf.sin_port = 0; //port shouldnt matter
// bind the input socket
Error = bind(pse->Socket, (SOCKADDR FAR *)&saLocalIf, sizeof(SOCKADDR));
if (Error == SOCKET_ERROR) {
Error = WSAGetLastError();
Trace3(IF, "error %d binding on socket for interface %0x (%d.%d.%d.%d)",
Error, IfIndex, PRINT_IPADDR(IpAddr));
Logerr1(BIND_FAILED, "%I", IpAddr, Error);
GOTO_END_BLOCK1;
}
//
// A proxy never sends/receives any packets. It is just expected to enable
// igmp host functionality to take over for the groups on which it joins.
//
//------------------------------
// if proxy then done
//------------------------------
if (bProxy)
GOTO_END_BLOCK1;
//------------------------------
// NOT PROXY INTERFACE
//------------------------------
if (!bProxy) {
// set ttl to 1: not required as it is set to 1 by default.
McastSetTtl(pse->Socket, 1);
//
// disable multicast packets from being loopedback.
// This may not work due to promiscuous mode,
// so you still have to check the input packets
//
{
BOOL bLoopBack = FALSE;
dwRetval = setsockopt(pse->Socket, IPPROTO_IP, IP_MULTICAST_LOOP,
(char *)&bLoopBack, sizeof(BOOL));
if (dwRetval==SOCKET_ERROR) {
Trace2(ERR, "error %d disabling multicast loopBack on IfIndex %0x",
WSAGetLastError(), IfIndex);
IgmpAssertOnError(FALSE);
}
}
//
// if RasServerInterface, then activate hdrInclude option so that I can
// send GenQuery to all RAS clients
//
if (IS_RAS_SERVER_IF(pite->IfType)) {
INT iSetHdrIncl = 1;
Error = setsockopt( pse->Socket, IPPROTO_IP, IP_HDRINCL,
(char *) &iSetHdrIncl, sizeof(INT));
if (Error!=NO_ERROR) {
Error = WSAGetLastError();
Trace2(ERR, "error %d unable to set IP_HDRINCL option on interface %0x",
Error, IfIndex);
IgmpAssertOnError(FALSE);
Logerr1(SET_HDRINCL_FAILED, "%I", pite->IpAddr, Error);
GOTO_END_BLOCK1;
}
}
else {
//
// set the interface on which multicasts must be sent
// set only for non rasserver (not internal) interfaces
//
dwRetval = setsockopt(pse->Socket, IPPROTO_IP, IP_MULTICAST_IF,
(PBYTE)&saLocalIf.sin_addr, sizeof(IN_ADDR));
if (dwRetval == SOCKET_ERROR) {
Error = WSAGetLastError();
Trace3(IF, "error %d setting interface %0x (%d.%d.%d.%d) to send multicast",
Error, IfIndex, PRINT_IPADDR(pite->IpAddr));
Logerr1(SET_MCAST_IF_FAILED, "%I", pite->IpAddr, Error);
Error = SOCKET_ERROR;
GOTO_END_BLOCK1;
}
{
//
// set router alert option for packets sent. dont have to set it for
// RasServerInterface where I do hdrInclude.
//
u_char Router_alert[4] = {148, 4, 0, 0};
dwRetval = setsockopt(pse->Socket, IPPROTO_IP, IP_OPTIONS,
(void *)Router_alert, sizeof(Router_alert));
if (dwRetval!=0) {
dwRetval = WSAGetLastError();
Trace2(ERR,
"error %d unable to set router alert option on interface %0x",
dwRetval, IfIndex
);
IgmpAssertOnError(FALSE);
Logerr1(SET_ROUTER_ALERT_FAILED, "%I", pite->IpAddr, dwRetval);
Error = dwRetval;
GOTO_END_BLOCK1;
}
}
}
//
// set the interface in promiscuous igmp multicast mode.
//
{
DWORD dwEnable = 1;
DWORD dwNum;
dwRetval = WSAIoctl(pse->Socket, SIO_RCVALL_IGMPMCAST, (char *)&dwEnable,
sizeof(dwEnable), NULL , 0, &dwNum, NULL, NULL);
if (dwRetval !=0) {
dwRetval = WSAGetLastError();
Trace2(IF, "error %d setting interface %0x as promiscuous multicast",
dwRetval, IfIndex);
Logerr1(SET_ROUTER_ALERT_FAILED, "%I", pite->IpAddr, dwRetval);
Error = dwRetval;
GOTO_END_BLOCK1;
}
else {
Trace1(IF, "promiscuous igmp multicast enabled on If (%d)",
IfIndex);
}
}
//
// Router doesnt have to join any group as it is in promiscuous mode
//
//
// create entry in the SocketsEvents list
//
{
BOOLEAN bCreateNewEntry;
PLIST_ENTRY ple, pHead = &g_ListOfSocketEvents;
PSOCKET_EVENT_ENTRY psee;
bCreateNewEntry = TRUE;
//
// see if a new socket-event entry has to be created
//
if (g_pIfTable->NumInterfaces>NUM_SINGLE_SOCKET_EVENTS) {
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
psee = CONTAINING_RECORD(ple, SOCKET_EVENT_ENTRY,
LinkBySocketEvents);
if (psee->NumInterfaces < MAX_SOCKETS_PER_EVENT) {
bCreateNewEntry = FALSE;
break;
}
}
}
//
// create a new socket-event entry and insert in the list
// register the event entry with the wait thread
//
if (bCreateNewEntry) {
psee = IGMP_ALLOC(sizeof(SOCKET_EVENT_ENTRY),
0x80000,pite->IfIndex);
PROCESS_ALLOC_FAILURE2(psee,
"error %d allocating %d bytes for SocketEventEntry",
Error, sizeof(SOCKET_EVENT_ENTRY),
GOTO_END_BLOCK1);
InitializeListHead(&psee->ListOfInterfaces);
psee->NumInterfaces = 0;
InsertHeadList(pHead, &psee->LinkBySocketEvents);
psee->InputEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
if (psee->InputEvent == NULL) {
Error = GetLastError();
Trace1(ERR,
"error %d creating InputEvent in CreateIfSockets",
Error);
IgmpAssertOnError(FALSE);
Logerr0(CREATE_EVENT_FAILED, Error);
GOTO_END_BLOCK1;
}
if (! RegisterWaitForSingleObject(
&psee->InputWaitEvent,
psee->InputEvent,
WT_ProcessInputEvent, psee,
INFINITE,
(WT_EXECUTEINWAITTHREAD)|(WT_EXECUTEONLYONCE)
))
{
Error = GetLastError();
Trace1(ERR, "error %d RegisterWaitForSingleObject", Error);
IgmpAssertOnError(FALSE);
GOTO_END_BLOCK1;
}
}
//
// put the socketEntry in the list
//
InsertTailList(&psee->ListOfInterfaces, &pse->LinkByInterfaces);
pse->pSocketEventsEntry = psee;
//
// if the socket-event entry cannot take any more sockets,
// then put it at end of list
//
if (++psee->NumInterfaces==MAX_SOCKETS_PER_EVENT) {
RemoveEntryList(&psee->LinkBySocketEvents);
InsertTailList(pHead, &psee->LinkBySocketEvents);
}
} //end:create entry in the sockets list
//
// create socket for static joins.
//
{
pite->StaticGroupSocket =
WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, 0);
if (pite->StaticGroupSocket == INVALID_SOCKET) {
Error = WSAGetLastError();
Trace3(IF,
"error %d creating static group socket for interface "
"%d (%d.%d.%d.%d)",
Error, pite->IfIndex, PRINT_IPADDR(pite->IpAddr));
Logerr1(CREATE_SOCKET_FAILED_2, "%I", pite->IpAddr, Error);
GOTO_END_BLOCK1;
}
//
// bind socket to local interface. If I dont bind multicast may
// not work.
//
saLocalIf.sin_family = PF_INET;
saLocalIf.sin_addr.s_addr = pite->IpAddr;
saLocalIf.sin_port = 0; //port shouldnt matter
Error = bind(pite->StaticGroupSocket, (SOCKADDR FAR *)&saLocalIf,
sizeof(SOCKADDR));
}
} // end: not proxy interface
} END_BREAKOUT_BLOCK1;
if (Error!=NO_ERROR)
DeleteIfSockets(pite);
return Error;
} //end _CreateIfSockets
//------------------------------------------------------------------------------
// _DeleteIfSockets
//
// Called by: _DeActivateInterfaceComplete()
//------------------------------------------------------------------------------
VOID
DeleteIfSockets (
PIF_TABLE_ENTRY pite
)
{
PSOCKET_ENTRY pse = &pite->SocketEntry;
BOOL bProxy = IS_PROTOCOL_TYPE_PROXY(pite);
// close input socket
if (pse->Socket!=INVALID_SOCKET) {
if (closesocket(pse->Socket) == SOCKET_ERROR) {
Trace1(IF, "error %d closing socket", WSAGetLastError());
}
pse->Socket = INVALID_SOCKET;
}
//
// if router interface. delete socket from socketEventList
// and free the socketEventEntry only if they were initialized.
//
if ((!bProxy)&&(pse->pSocketEventsEntry!=NULL)) {
PSOCKET_EVENT_ENTRY psee = pse->pSocketEventsEntry;
RemoveEntryList(&pse->LinkByInterfaces);
if (--psee->NumInterfaces==0) {
if (psee->InputWaitEvent) {
HANDLE WaitHandle ;
WaitHandle = InterlockedExchangePointer(&psee->InputWaitEvent, NULL);
if (WaitHandle)
UnregisterWaitEx( WaitHandle, NULL ) ;
}
CloseHandle(psee->InputEvent);
RemoveEntryList(&psee->LinkBySocketEvents);
IGMP_FREE(psee);
}
if (pite->StaticGroupSocket!=INVALID_SOCKET) {
closesocket(pite->StaticGroupSocket);
pite->StaticGroupSocket = INVALID_SOCKET;
}
}
return;
}
//------------------------------------------------------------------------------
// _DeleteAllTimers
//
// Deletes all timers associated with a GI entry.
//
// Called by: _DeActivateInterfaceComplete()
// Locks: Assumes Timer lock and GroupBucket lock.
//------------------------------------------------------------------------------
VOID
DeleteAllTimers (
PLIST_ENTRY pHead,
DWORD bEntryType
)
{
PLIST_ENTRY ple;
PGI_ENTRY pgie;
Trace0(ENTER1, "entering _DeleteAllTimers()");
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pgie = (bEntryType==RAS_CLIENT)
? CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameClientGroups)
: CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups);
if (IS_TIMER_ACTIVE(pgie->GroupMembershipTimer))
RemoveTimer(&pgie->GroupMembershipTimer, DBG_N);
if (IS_TIMER_ACTIVE(pgie->LastMemQueryTimer))
RemoveTimer(&pgie->LastMemQueryTimer, DBG_N);
if (IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer))
RemoveTimer(&pgie->LastVer1ReportTimer, DBG_N);
if (IS_TIMER_ACTIVE(pgie->LastVer2ReportTimer))
RemoveTimer(&pgie->LastVer2ReportTimer, DBG_N);
if (IS_TIMER_ACTIVE(pgie->V3SourcesQueryTimer))
RemoveTimer(&pgie->V3SourcesQueryTimer, DBG_N);
// delete all sources timers
if (pgie->Version==3) {
PLIST_ENTRY pleSrc, pHeadSrc;
pHeadSrc = &pgie->V3InclusionListSorted;
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink){
PGI_SOURCE_ENTRY pSourceEntry;
pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSourcesInclListSorted);
if (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer))
RemoveTimer(&pSourceEntry->SourceExpTimer, DBG_Y);
}
pHeadSrc = &pgie->V3ExclusionList;
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink){
PGI_SOURCE_ENTRY pSourceEntry;
pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSources);
if (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer))
RemoveTimer(&pSourceEntry->SourceExpTimer, DBG_Y);
}
}
}
Trace0(LEAVE1, "Leaving _DeleteAllTimers()");
return;
}
//------------------------------------------------------------------------------
// _DeleteGIEntry
//
// Locks: Assumes lock on the group bucket. takes lock on IfGroup list.
// takes lock on groupList if group being deleted.
//------------------------------------------------------------------------------
DWORD
DeleteGIEntry (
PGI_ENTRY pgie, //group interface entry
BOOL bUpdateStats,
BOOL bCallMgm
)
{
PIF_TABLE_ENTRY pite = pgie->pIfTableEntry;
PRAS_TABLE_ENTRY prte = pgie->pRasTableEntry;
PGROUP_TABLE_ENTRY pge = pgie->pGroupTableEntry;
PGI_ENTRY pgieCur;
BOOL bRas = (prte!=NULL);
DWORD NHAddr;
DWORD dwRetval;
Trace0(ENTER1, "Entering _DeleteGIEntry()");
NHAddr = (bRas) ? prte->NHAddr : 0;
Trace4(GROUP, "Deleting group(%d.%d.%d.%d) on Interface(%0x)(%d.%d.%d.%d) "
"NHAddr(%d.%d.%d.%d)",
PRINT_IPADDR(pge->Group), pite->IfIndex,
PRINT_IPADDR(pite->IpAddr), PRINT_IPADDR(NHAddr));
bCallMgm = bCallMgm && (CAN_ADD_GROUPS_TO_MGM(pite));
//
// exclusion mode. remove all exclusion entries
// dont have to call MGM as it still has to be excluded
//
if (pgie->Version==3) {
PLIST_ENTRY pleSrc, pHeadSrc;
pHeadSrc = &pgie->V3InclusionListSorted;
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; ){
PGI_SOURCE_ENTRY pSourceEntry;
pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSources);
pleSrc=pleSrc->Flink;
DeleteSourceEntry(pSourceEntry, bCallMgm);
}
pHeadSrc = &pgie->V3ExclusionList;
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; ){
PGI_SOURCE_ENTRY pSourceEntry;
pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSources);
pleSrc=pleSrc->Flink;
DeleteSourceEntry(pSourceEntry, bCallMgm);
}
}
//
// call mgm to remove this group
//
if ( bCallMgm ) {
if ( (pgie->Version==3 && pgie->FilterType==EXCLUSION)
|| pgie->Version!=3)
{
MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(pite, NHAddr,
0, 0,
pge->Group, 0xffffffff, MGM_JOIN_STATE_FLAG);
}
}
//
// remove all timers
//
ACQUIRE_TIMER_LOCK("_DeleteGIEntry");
if (IS_TIMER_ACTIVE(pgie->GroupMembershipTimer))
RemoveTimer(&pgie->GroupMembershipTimer, DBG_N);
if (IS_TIMER_ACTIVE(pgie->LastMemQueryTimer))
RemoveTimer(&pgie->LastMemQueryTimer, DBG_N);
if (IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer))
RemoveTimer(&pgie->LastVer1ReportTimer, DBG_N);
if (IS_TIMER_ACTIVE(pgie->LastVer2ReportTimer))
RemoveTimer(&pgie->LastVer2ReportTimer, DBG_N);
if (IS_TIMER_ACTIVE(pgie->V3SourcesQueryTimer))
RemoveTimer(&pgie->V3SourcesQueryTimer, DBG_Y);
RELEASE_TIMER_LOCK("_DeleteGIEntry");
//
// Remove from IfGroupList. needs lock on IfGroupList
//
ACQUIRE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_DeleteGIEntry");
// if interface being deleted, then return from here
if (IS_IF_DELETED(pgie->pIfTableEntry)) {
RELEASE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_DeleteGIEntry");
return NO_ERROR;
}
// remove GI entry from group's GI list
RemoveEntryList(&pgie->LinkByGI);
//
// remove entry from interface list
//
RemoveEntryList(&pgie->LinkBySameIfGroups);
if (bRas)
RemoveEntryList(&pgie->LinkBySameClientGroups);
RELEASE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_DeleteGIEntry");
//
// decrement the number of virtual interfaces. I have to do
// interlocked decrement as I dont take group_list lock
//
InterlockedDecrement(&pge->NumVifs);
//
// if group has no more interfaces hanging from it, then delete it
// and update statistics
//
if (IsListEmpty(&pge->ListOfGIs)) {
// take groupList lock before deleting it from the group list
ACQUIRE_GROUP_LIST_LOCK("_DeleteGIEntry");
RemoveEntryList(&pge->LinkByGroup);
RELEASE_GROUP_LIST_LOCK("_DeleteGIEntry");
// remove group entry from the group hash table
RemoveEntryList(&pge->HTLinkByGroup);
IGMP_FREE(pge);
pge = NULL;
//global stats (has to be updated even if bUpdateStats==FALSE)
InterlockedDecrement(&g_Info.CurrentGroupMemberships);
#if DBG
DebugPrintGroupsList(1);
#endif
}
//
// update statistics
//
if (bUpdateStats) {
//
// ras interface statistics (decrement only if last GI for ras)
//
if (bRas) {
// see if GI entry exists for that ras client. very inefficient
if (pge!=NULL) {
PLIST_ENTRY pHead, ple;
pHead = &pge->ListOfGIs;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pgieCur = CONTAINING_RECORD(ple, GI_ENTRY, LinkByGI);
if (pgieCur->IfIndex>=pite->IfIndex)
break;
}
if ( (ple==pHead)||(pgieCur->IfIndex!=pite->IfIndex) ) {
InterlockedDecrement(&pite->Info.CurrentGroupMemberships);
}
}
// last GI entry
else {
InterlockedDecrement(&pite->Info.CurrentGroupMemberships);
}
// update ras client stats
if (g_Config.RasClientStats) {
InterlockedDecrement(&prte->Info.CurrentGroupMemberships);
}
}
// not ras interace
else {
InterlockedDecrement(&pite->Info.CurrentGroupMemberships);
}
}
IGMP_FREE_NOT_NULL(pgie->V3InclusionList);
IGMP_FREE(pgie);
Trace0(LEAVE1, "Leaving _DeleteGIEntry");
return NO_ERROR;
}//end _DeleteGIEntry
//------------------------------------------------------------------------------
// _DeleteAllGIEntries
//
// Repeatedly calls _DeleteGIEntryFromIf() to delete each GI entry from the list.
// If there are a lot of GI entries, optimizes on the GroupBucket locks
// by grouping all GI entries hashing to the same bucket and then acquiring
// GroupBucket locks to delete them.
//
// Locks: interface_group_list lock not req. exclusive interface lock not req.
// as the interface has been removed from external lists.
// Calls: Repeatedly calls _DeleteGIEntryFromIf() to remove each GI entry
// Called by: _DeActivateInterfaceComplete()
//------------------------------------------------------------------------------
VOID
DeleteAllGIEntries(
PIF_TABLE_ENTRY pite
)
{
PLIST_ENTRY pHead, ple, pleOld;
PGI_ENTRY pgie;
DWORD dwGroup;
//
// concatenate ListOfSameIfGroupsNew at the end of ListOfSameIfGroups so
// that I have to delete only one list
//
CONCATENATE_LISTS(pite->ListOfSameIfGroups, pite->ListOfSameIfGroupsNew);
// if ras interface then return as list will be deleted through RAS clients
if (IS_RAS_SERVER_IF(pite->IfType))
return;
pHead = &pite->ListOfSameIfGroups;
if (IsListEmpty(pHead))
return;
//--------------------------------------------------------
// do optimization only if there are lots of GI entries
//--------------------------------------------------------
if (pite->Info.CurrentGroupMemberships > GROUP_HASH_TABLE_SZ*2) {
DWORD i;
LIST_ENTRY TmpGroupTable[GROUP_HASH_TABLE_SZ];
// initialize the temp group table
for (i=0; i<GROUP_HASH_TABLE_SZ; i++) {
InitializeListHead(&TmpGroupTable[i]);
}
// move the GI entries to the temp group table using LinkBySameIfGroups
// LinkBySameIfGroups is not used anymore
pHead = &pite->ListOfSameIfGroups;
for (ple=pHead->Flink; ple!=pHead; ) {
// remove from old list
pleOld = ple;
ple = ple->Flink;
RemoveEntryList(pleOld);
pgie = CONTAINING_RECORD(pleOld, GI_ENTRY, LinkBySameIfGroups);
dwGroup = pgie->pGroupTableEntry->Group;
// put in appropriate bucket
InsertHeadList(&TmpGroupTable[GROUP_HASH_VALUE(dwGroup)],
&pgie->LinkBySameIfGroups);
}
//
// now delete GI entries going by all groups which hash to same bucket
//
for (i=0; i<GROUP_HASH_TABLE_SZ; i++) {
if (IsListEmpty(&TmpGroupTable[i]))
continue;
//
// LOCK GROUP BUCKET (done use ACQUIRE_GROUP_LOCK macros)
//
ACQUIRE_GROUP_LOCK(i, "_DeleteAllGIEntries");
pHead = &TmpGroupTable[i];
// delete all GI entries that hash to that bucket
for (ple=pHead->Flink; ple!=pHead; ) {
pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups);
ple=ple->Flink;
//
// remove the entry from the group's GI list and update
// statistics. If group's GI list becomes empty, removes group
//
DeleteGIEntryFromIf(pgie);
}
RELEASE_GROUP_LOCK(i, "_DeleteAllGIEntries");
}
InitializeListHead(&pite->ListOfSameIfGroups);
return;
}
//-----------------------------------------------------------
// NO OPTIMIZATION
//-----------------------------------------------------------
pHead = &pite->ListOfSameIfGroups;
//
// delete all GI entries hanging from that interface.
//
for (ple=pHead->Flink; ple!=pHead; ) {
pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups);
ple=ple->Flink;
dwGroup = pgie->pGroupTableEntry->Group;
// LOCK GROUP BUCKET
ACQUIRE_GROUP_LOCK(dwGroup,
"_DeActivateInterfaceComplete");
DeleteGIEntryFromIf(pgie);
RELEASE_GROUP_LOCK(dwGroup, "_DeActivateInterfaceComplete");
}
InitializeListHead(&pite->ListOfSameIfGroups);
return;
}
//------------------------------------------------------------------------------
// _DeleteGIEntryFromIf
//
// Called to delete a GI entry when an interface/RAS client is being deleted.
// The GI entries cannot be accessed from anywhere except through enumeration of
// group list.
//
// Locks: Assumes lock on the group bucket. lock on IfGroup list not req.
// Called by: _DeleteAllGIEntries() which in turn called by
// _DeActivateInterfaceComplete().
//------------------------------------------------------------------------------
VOID
DeleteGIEntryFromIf (
PGI_ENTRY pgie //group interface entry
)
{
PIF_TABLE_ENTRY pite = pgie->pIfTableEntry;
PGROUP_TABLE_ENTRY pge = pgie->pGroupTableEntry;
PLIST_ENTRY pHead, ple;
DWORD IfIndex = pite->IfIndex;
Trace1(ENTER1, "Entering _DeleteGIEntryFromIf(): IfIndex(%0x)", IfIndex);
//
// delete sources
//
if (pgie->Version==3) {
PLIST_ENTRY pleSrc, pHeadSrc;
pHeadSrc = &pgie->V3InclusionListSorted;
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; ){
PGI_SOURCE_ENTRY pSourceEntry;
pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSourcesInclListSorted);
pleSrc=pleSrc->Flink;
IGMP_FREE(pSourceEntry);
}
pHeadSrc = &pgie->V3ExclusionList;
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; ){
PGI_SOURCE_ENTRY pSourceEntry;
pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSources);
pleSrc=pleSrc->Flink;
IGMP_FREE(pSourceEntry);
}
}
//
// Remove pgie from gi list. Dont have to remove from ListBySameIfGroups
//
RemoveEntryList(&pgie->LinkByGI);
InterlockedDecrement(&pge->NumVifs);
//
// if group has no more interfaces hanging from it, then delete it
// and update statistics
//
if (IsListEmpty(&pge->ListOfGIs)) {
// have to lock the group-list before deleting any group
ACQUIRE_GROUP_LIST_LOCK("_DeleteGIEntryFromIf");
RemoveEntryList(&pge->LinkByGroup);
RELEASE_GROUP_LIST_LOCK("_DeleteGIEntryFromIf");
RemoveEntryList(&pge->HTLinkByGroup);
IGMP_FREE(pge);
InterlockedDecrement(&g_Info.CurrentGroupMemberships);
}
IGMP_FREE_NOT_NULL(pgie->V3InclusionList);
IGMP_FREE(pgie);
Trace1(LEAVE1, "Leaving _DeleteGIEntryFromIf(%0x)", IfIndex);
return;
}//end _DeleteGIEntryFromIf
//------------------------------------------------------------------------------
// DebugPrintIfConfig
//------------------------------------------------------------------------------
VOID
DebugPrintIfConfig (
PIGMP_MIB_IF_CONFIG pConfigExt,
DWORD IfIndex
)
{
DWORD i;
PCHAR StaticGroupStr[5];
BOOL bVersion3 = IS_CONFIG_IGMP_V3(pConfigExt);
Trace1(CONFIG, "Printing Config Info for interface(%0x)", IfIndex);
Trace1(CONFIG, "Version: 0x%0x", pConfigExt->Version);
Trace1(CONFIG, "IfType: %d", pConfigExt->IfType);
{
CHAR str[150];
strcpy(str, "");
if (pConfigExt->Flags&IGMP_INTERFACE_ENABLED_IN_CONFIG)
strcat(str, "IF_ENABLED ");
else
strcat(str, "IF_DISABLED ");
if (pConfigExt->Flags&IGMP_ACCEPT_RTRALERT_PACKETS_ONLY)
strcat(str, "RTRALERT_PACKETS_ONLY ");
Trace1(CONFIG, "Flags: %s", str);
}
Trace1(CONFIG, "IgmpProtocolType: %d", pConfigExt->IgmpProtocolType);
Trace1(CONFIG, "RobustnessVariable: %d", pConfigExt->RobustnessVariable);
Trace1(CONFIG, "StartupQueryInterval: %d",
pConfigExt->StartupQueryInterval);
Trace1(CONFIG, "StartupQueryCount : %d",
pConfigExt->StartupQueryCount);
Trace1(CONFIG, "GenQueryInterval: %d", pConfigExt->GenQueryInterval);
Trace1(CONFIG, "GenQueryMaxResponseTime: %d",
pConfigExt->GenQueryMaxResponseTime);
Trace1(CONFIG, "LastMemQueryInterval: %d (ms)",
pConfigExt->LastMemQueryInterval);
Trace1(CONFIG, "LastMemQueryCount: %d", pConfigExt->LastMemQueryCount);
Trace1(CONFIG, "OtherQuerierPresentInterval:%d",
pConfigExt->OtherQuerierPresentInterval);
Trace1(CONFIG, "GroupMembershipTimeout: %d",
pConfigExt->GroupMembershipTimeout);
if (pConfigExt->NumStaticGroups>0) {
PIGMP_STATIC_GROUP pStaticGroup;
PSTATIC_GROUP_V3 pStaticGroupV3;
Trace1(CONFIG, "NumStaticGroups: %d",
pConfigExt->NumStaticGroups);
pStaticGroup = GET_FIRST_IGMP_STATIC_GROUP(pConfigExt);
if (bVersion3) {
pStaticGroupV3 = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
Trace0(CONFIG, " Group Mode(Host/MGM) Filter(In/Ex) "
"NumSources");
}
else
Trace0(CONFIG, " Group Mode(Host/MGM)");
for (i=0; i<pConfigExt->NumStaticGroups; i++){
if (bVersion3) {
DWORD j;
Trace5(CONFIG, "%d. %15s %d %d %d",
i+1, INET_NTOA(pStaticGroupV3->GroupAddr),
pStaticGroupV3->Mode, pStaticGroupV3->FilterType,
pStaticGroupV3->NumSources
);
for (j=0; j<pStaticGroupV3->NumSources; j++) {
Trace1(CONFIG, " %d.%d.%d.%d",
PRINT_IPADDR(pStaticGroupV3->Sources[j]));
}
pStaticGroupV3 = (PSTATIC_GROUP_V3)
GET_NEXT_STATIC_GROUP_V3(pStaticGroupV3);
}
else {
Trace3(CONFIG, "%d. %15s Mode:%d",
i+1, INET_NTOA(pStaticGroup->GroupAddr),
pStaticGroup->Mode
);
pStaticGroup++;
}
}
}
Trace0(CONFIG, "");
return;
}
//------------------------------------------------------------------------------
// CopyinIfConfigAndUpdate
//
// Copies the if config struct passed by mib to igmp and update the timers
// and does static joins if req.
// Called when the interface is activated
//------------------------------------------------------------------------------
DWORD
CopyinIfConfigAndUpdate (
PIF_TABLE_ENTRY pite,
PIGMP_MIB_IF_CONFIG pConfigExt,
ULONG IfIndex
)
{
PIGMP_IF_CONFIG pConfig = &pite->Config;
BOOL bGroupMembershipTimer=FALSE, bLastMemQueryTimer=FALSE;
ULONG NewStartupQueryInterval, NewGenQueryInterval,
NewGenQueryMaxResponseTime, NewLastMemQueryInterval,
NewOtherQuerierPresentInterval, NewGroupMembershipTimeout;
BOOL bFound;
DWORD Error=NO_ERROR;
DWORD bVer3=IS_CONFIG_IGMP_V3(pConfigExt);
NewStartupQueryInterval
= CONFIG_TO_INTERNAL_TIME(pConfigExt->StartupQueryInterval);
NewGenQueryInterval
= CONFIG_TO_INTERNAL_TIME(pConfigExt->GenQueryInterval);
NewGenQueryMaxResponseTime
= CONFIG_TO_INTERNAL_TIME(pConfigExt->GenQueryMaxResponseTime);
NewOtherQuerierPresentInterval
= CONFIG_TO_INTERNAL_TIME(pConfigExt->OtherQuerierPresentInterval);
NewLastMemQueryInterval = pConfigExt->LastMemQueryInterval; //already in ms
NewGroupMembershipTimeout
= CONFIG_TO_INTERNAL_TIME(pConfigExt->GroupMembershipTimeout);
//
// used only in ver3
//
pConfig->RobustnessVariableOld = pConfigExt->RobustnessVariable;
pConfig->GenQueryIntervalOld = NewGenQueryInterval;
pConfig->OtherQuerierPresentIntervalOld
= NewOtherQuerierPresentInterval;
pConfig->GroupMembershipTimeoutOld = NewGroupMembershipTimeout;
//
// update values only if it is ver1,ver2 or ver3&&Querier
//
if (!IS_IF_VER3(pite) || (IS_IF_VER3(pite) && IS_QUERIER(pite)) ){
ACQUIRE_TIMER_LOCK("_CopyinIfConfigAndUpdate");
//
// change Info.StartupQueryCountCurrent if it was set to some very high value.
// During startup, Info.StartupQueryCountCurrent is used, and not the Config value.
//
if (pConfigExt->StartupQueryCount < pite->Info.StartupQueryCountCurrent)
InterlockedExchange(&pite->Info.StartupQueryCountCurrent,
pConfigExt->StartupQueryCount);
// in startup mode. StartupQueryInterval active and to be reduced
if (pite->Info.StartupQueryCountCurrent>0) {
if ( (NewStartupQueryInterval < pConfig->StartupQueryInterval)
&& (IS_TIMER_ACTIVE(pite->QueryTimer)) )
{
UpdateLocalTimer(&pite->QueryTimer, NewStartupQueryInterval, DBG_Y);
}
}
// in querier mode. GenQueryInterval is active and to be updated
else {
if ( (NewGenQueryInterval < pConfig->GenQueryInterval)
&& (IS_TIMER_ACTIVE(pite->QueryTimer)) )
{
UpdateLocalTimer(&pite->QueryTimer, NewGenQueryInterval, DBG_Y);
}
}
// OtherQuerierPresentInterval active and to be updated
if ( (NewOtherQuerierPresentInterval<pConfig->OtherQuerierPresentInterval)
&& (IS_TIMER_ACTIVE(pite->NonQueryTimer)) )
{
UpdateLocalTimer(&pite->NonQueryTimer, NewOtherQuerierPresentInterval, DBG_Y);
}
// NewLastMemQueryInterval is to be processed only if in ver-2 mode and not
// server
if ( (pConfigExt->IgmpProtocolType==IGMP_ROUTER_V2)
&& (pite->IfType!=IGMP_IF_RAS_SERVER) )
{
if (NewLastMemQueryInterval < pConfig->LastMemQueryInterval)
bLastMemQueryTimer = TRUE;
}
// check if GroupMembership timeout is reduced
if (NewGroupMembershipTimeout < pConfig->GroupMembershipTimeout)
bGroupMembershipTimer = TRUE;
//
// Go through the GI list for that interface (all ras clients) and update
// their timers if they are higher
//
if ( ((bLastMemQueryTimer||bGroupMembershipTimer)&&(!IS_RAS_SERVER_IF(pite->IfType)))
|| ((bGroupMembershipTimer)&&(IS_RAS_SERVER_IF(pite->IfType))) )
{
PLIST_ENTRY pHead, ple;
PGI_ENTRY pgie;
LONGLONG llNewLastMemQueryInterval, llNewGroupMembershipTimeout;
LONGLONG llMaxTime, llCurTime = GetCurrentIgmpTime();
//
// get the absolute timeout values
//
llNewLastMemQueryInterval = llCurTime
+ CONFIG_TO_SYSTEM_TIME(NewLastMemQueryInterval);
llNewGroupMembershipTimeout = llCurTime
+ CONFIG_TO_SYSTEM_TIME(NewGroupMembershipTimeout);
// if not ras interface, then go through the list from interface
if ( !IS_RAS_SERVER_IF(pite->IfType)) {
// merge the IfGroup lists
MergeIfGroupsLists(pite);
pHead = &pite->ListOfSameIfGroups;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups);
// update LastMemQueryTimer/V3SourcesQueryTimer if it is active and has a higher value
if (bLastMemQueryTimer && IS_TIMER_ACTIVE(pgie->LastMemQueryTimer)
&& (llNewLastMemQueryInterval<pgie->LastMemQueryTimer.Timeout))
{
UpdateLocalTimer(&pgie->LastMemQueryTimer,
NewLastMemQueryInterval, DBG_Y);
}
if (bLastMemQueryTimer)
pgie->LastMemQueryTimer.Timeout = llNewLastMemQueryInterval;
if (bLastMemQueryTimer && IS_TIMER_ACTIVE(pgie->V3SourcesQueryTimer)
&& (llNewLastMemQueryInterval<pgie->V3SourcesQueryTimer.Timeout))
{
UpdateLocalTimer(&pgie->V3SourcesQueryTimer,
NewLastMemQueryInterval, DBG_Y);
}
if (bLastMemQueryTimer)
pgie->V3SourcesQueryTimer.Timeout = llNewLastMemQueryInterval;
// update GroupMembershipTimeout if it is active and has a higher value
if (bGroupMembershipTimer
&& IS_TIMER_ACTIVE(pgie->GroupMembershipTimer)
&& (llNewGroupMembershipTimeout<pgie->GroupMembershipTimer.Timeout))
{
UpdateLocalTimer(&pgie->GroupMembershipTimer,
NewGroupMembershipTimeout, DBG_Y);
}
if (bGroupMembershipTimer)
{
pgie->GroupMembershipTimer.Timeout = llNewGroupMembershipTimeout;
pgie->LastVer1ReportTimer.Timeout = llNewGroupMembershipTimeout;
pgie->LastVer2ReportTimer.Timeout = llNewGroupMembershipTimeout;
}
// update LastVer1ReportTimer/LastVer2ReportTimer if it is active and has a higher value
// LastVer1ReportTimeout is set to GroupMembershipTimeout
if (bGroupMembershipTimer
&& IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer)
&& (llNewGroupMembershipTimeout<pgie->LastVer1ReportTimer.Timeout))
{
UpdateLocalTimer(&pgie->LastVer1ReportTimer,
NewGroupMembershipTimeout, DBG_Y);
}
if (bGroupMembershipTimer
&& IS_TIMER_ACTIVE(pgie->LastVer2ReportTimer)
&& (llNewGroupMembershipTimeout<pgie->LastVer2ReportTimer.Timeout))
{
UpdateLocalTimer(&pgie->LastVer2ReportTimer,
NewGroupMembershipTimeout, DBG_Y);
}
}
}
// IS_RAS_SERVER_IF: process for all clients. have to process
// GroupMembershipTimeout only
else {
PLIST_ENTRY pHeadClient, pleClient;
PRAS_TABLE_ENTRY prte;
PRAS_TABLE prt = pite->pRasTable;
//
// process GI list of each ras client
//
pHeadClient = &pite->pRasTable->ListByAddr;
for (pleClient=pHeadClient->Flink; pleClient!=pHeadClient;
pleClient=pleClient->Flink)
{
prte = CONTAINING_RECORD(pleClient, RAS_TABLE_ENTRY, LinkByAddr);
pHead = &prte->ListOfSameClientGroups;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameClientGroups);
if (IS_TIMER_ACTIVE(pgie->GroupMembershipTimer)
&& (llNewGroupMembershipTimeout
<pgie->GroupMembershipTimer.Timeout))
{
UpdateLocalTimer(&pgie->GroupMembershipTimer,
NewGroupMembershipTimeout, DBG_Y);
}
pgie->GroupMembershipTimer.Timeout = llNewGroupMembershipTimeout;
}
}
}
}
RELEASE_TIMER_LOCK("_CopyinIfConfigAndUpdate");
//
// finally copy the new values
//
CopyMemory(pConfig, pConfigExt, sizeof(IGMP_MIB_IF_CONFIG));
pConfig->StartupQueryInterval = NewStartupQueryInterval;
pConfig->GenQueryInterval = NewGenQueryInterval;
pConfig->GenQueryMaxResponseTime = NewGenQueryMaxResponseTime;
pConfig->LastMemQueryInterval = NewLastMemQueryInterval;
pConfig->OtherQuerierPresentInterval = NewOtherQuerierPresentInterval;
pConfig->GroupMembershipTimeout = NewGroupMembershipTimeout;
pConfig->IfIndex = IfIndex;
}
pConfig->NumStaticGroups = 0;
return Error;
#if 0
{
PSTATIC_GROUP_V3 pStaticGroupExt;
PIF_STATIC_GROUP pStaticGroup;
PLIST_ENTRY ple, pHead;
DWORD i, GroupAddr;
SOCKADDR_IN saLocalIf;
//
// delete all static groups which are different in the old config
//
pHead = &pite->Config.ListOfStaticGroups;
for (ple=pHead->Flink; ple!=pHead; ) {
pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
GroupAddr = pStaticGroup->GroupAddr;
ple = ple->Flink;
bFound = FALSE;
pStaticGroupExt = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
for (i=0; i<pConfigExt->NumStaticGroups; i++) {
if ( (GroupAddr == pStaticGroupExt->GroupAddr)
&& (pStaticGroup->Mode == pStaticGroupExt->Mode) )
{
bFound = TRUE;
break;
}
pStaticGroupExt = GET_NEXT_STATIC_GROUP_V3(pStaticGroupExt);
}
//
// group exists in old and new config. check for changes in sources.
//
if (bFound && bVer3) {
if (pStaticGroupExt->NumSources==0) {
//delete all static sources
}
if (pStaticGroupExt->NumSources==0 &&
pStaticGroupExt->FilterType!=EXCLUSION) {
// delete the static group
}
// check for differences in sources
}
// if old static group not found in new list, delete it
// Router
if (IS_CONFIG_IGMPRTR(pConfig)) {
if (pStaticGroup->Mode==IGMP_HOST_JOIN) {
LeaveMulticastGroup(pite->StaticGroupSocket, GroupAddr,
pite->IfIndex, pite->IpAddr, 0 );
}
else {
PGROUP_TABLE_ENTRY pge;
PGI_ENTRY pgie;
ACQUIRE_GROUP_LOCK(GroupAddr, "_CopyinIfConfigAndUpdate");
pge = GetGroupFromGroupTable(GroupAddr, NULL, 0);
pgie = GetGIFromGIList(pge, pite, 0, STATIC_GROUP, NULL, 0);
pgie->bStaticGroup = 0;
if (bVer3) {
PLIST_ENTRY pHead, ple;
PGI_SOURCE_ENTRY pSourceEntry;
//
// delete all static source entries
//
pHead = &pgie->V3ExclusionList;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSources);
// delete source entry (forward the packets)
if (pSourceEntry->bStaticSource) {
DeleteSourceEntry(pSourceEntry, MGM_YES);
}
}
pHead = &pgie->V3InclusionListSorted;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSourcesInclListSorted);
if (pSourceEntry->bStaticSource) {
pSourceEntry->bStaticSource = FALSE;
if (!IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer))
DeleteSourceEntry(pSourceEntry, MGM_YES);
}
}
}
else {
if (!(pgie->GroupMembershipTimer.Status&TIMER_STATUS_ACTIVE))
DeleteGIEntry(pgie, TRUE, TRUE);
}
RELEASE_GROUP_LOCK(GroupAddr, "_CopyinIfConfigAndUpdate");
}
}
// Proxy Interface
else {
if (bVer3){
for (i=0; i<pStaticGroup->NumSources; i++){
ProcessProxyGroupChange(pStaticGroup->Sources[i],
GroupAddr, DELETE_FLAG, STATIC_GROUP);
}
}
if (!bVer3 || pStaticGroup->NumSources==0)
ProcessProxyGroupChange(0,GroupAddr, DELETE_FLAG, STATIC_GROUP);
}
RemoveEntryList(&pStaticGroup->Link);
IGMP_FREE(pStaticGroup);
}
//
// for all new static groups, if not in old list, create it
//
pStaticGroupExt = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
for (i=0; i<pConfigExt->NumStaticGroups; i++,pStaticGroupExt++) {
pHead = &pite->Config.ListOfStaticGroups;
bFound = FALSE;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
if (pStaticGroup->GroupAddr==pStaticGroupExt->GroupAddr) {
bFound = TRUE;
break;
}
}
// not found: create the new static group
if (!bFound) {
pStaticGroup = IGMP_ALLOC(
IGMP_MIB_STATIC_GROUP_SIZE(pConfigExt,
pStaticGroupExt), 0x100000,IfIndex);
PROCESS_ALLOC_FAILURE3(pStaticGroup,
"error %d allocating %d bytes for static group for IF:%0x",
Error, sizeof(IF_STATIC_GROUP), pite->IfIndex,
return Error);
memcpy(pStaticGroup, pStaticGroupExt,
IGMP_MIB_STATIC_GROUP_SIZE(pConfigExt, pStaticGroupExt));
InsertHeadList(&pConfig->ListOfStaticGroups, &pStaticGroup->Link);
if (IS_IF_ACTIVATED(pite)) {
// if proxy
if (IS_CONFIG_IGMPPROXY(pConfig)) {
if (pStaticGroup->NumSources==0)
ProcessProxyGroupChange(0, pStaticGroup->GroupAddr,
ADD_FLAG, STATIC_GROUP);
else {
for (i=0; i<pStaticGroup->NumSources; i++) {
ProcessProxyGroupChange(pStaticGroup->Sources[i],
pStaticGroup->GroupAddr,
ADD_FLAG, STATIC_GROUP);
}
}
}
// Add static group to Router
else {
if (pStaticGroup->Mode==IGMP_HOST_JOIN) {
if (!bVer3) {
JoinMulticastGroup(pite->StaticGroupSocket,
pStaticGroup->GroupAddr,
pite->IfIndex,
pite->IpAddr,
0
);
}
else {
// include filter
if (pStaticGroup->FilterType==INCLUSION) {
if (pStaticGroup->NumSources==0) {
JoinMulticastGroup(pite->StaticGroupSocket,
pStaticGroup->GroupAddr,
pite->IfIndex,
pite->IpAddr,
0
);
}
for (i=0; i<pStaticGroup->NumSources; i++) {
JoinMulticastGroup(pite->StaticGroupSocket,
pStaticGroup->GroupAddr,
pite->IfIndex,
pite->IpAddr,
pStaticGroup->Sources[i]
);
}
}
// exclude filter
else {
if (pStaticGroup->NumSources==0) {
JoinMulticastGroup(pite->StaticGroupSocket,
pStaticGroup->GroupAddr,
pite->IfIndex,
pite->IpAddr,
0
);
}
for (i=0; i<pStaticGroup->NumSources; i++) {
BlockSource(pite->StaticGroupSocket,
pStaticGroup->GroupAddr,
pite->IfIndex,
pite->IpAddr,
pStaticGroup->Sources[i]
);
}
}
}
}
// IGMPRTR_MGM_ONLY
else {
PGROUP_TABLE_ENTRY pge;
PGI_ENTRY pgie;
BOOL bCreate;
PGI_SOURCE_ENTRY pSourceEntry;
GroupAddr = pStaticGroup->GroupAddr;
ACQUIRE_GROUP_LOCK(GroupAddr,
"_CopyinIfConfigAndUpdate");
bCreate = TRUE;
pge = GetGroupFromGroupTable(GroupAddr, &bCreate, 0);
bCreate = TRUE;
pgie = GetGIFromGIList(pge, pite, 0,
(pStaticGroup->NumSources==0)
?STATIC_GROUP:NOT_STATIC_GROUP,
&bCreate, 0);
for (i=0; i<pStaticGroup->NumSources; i++) {
if (pStaticGroup->FilterType!=pgie->FilterType) {
pSourceEntry = GetSourceEntry(pgie,
pStaticGroup->Sources[i],
pStaticGroup->FilterType ^ 1,
NULL, 0, 0);
if (pSourceEntry) {
pSourceEntry->bStaticSource = TRUE;
ChangeSourceFilterMode(pgie,
pSourceEntry);
continue;
}
}
bCreate = TRUE;
pSourceEntry = GetSourceEntry(pgie,
pStaticGroup->Sources[i],
pStaticGroup->FilterType,
&bCreate, STATIC, MGM_YES);
}
RELEASE_GROUP_LOCK(GroupAddr,
"_CopyinIfConfigAndUpdate");
}
}
}
}
}
}
return Error;
#endif
} //end _CopyinIfConfigAndUpdate
//------------------------------------------------------------------------------
// _CopyinIfConfig
// Copies the if config struct passed by mib to igmp.
// called after the interface is in disabled state
//------------------------------------------------------------------------------
DWORD
CopyinIfConfig (
PIGMP_IF_CONFIG pConfig,
PIGMP_MIB_IF_CONFIG pConfigExt,
ULONG IfIndex
)
{
DWORD Error=NO_ERROR;
CopyMemory(pConfig, pConfigExt, sizeof(IGMP_MIB_IF_CONFIG));
CONV_CONFIG_TO_INTERNAL_TIME(pConfig->StartupQueryInterval);
CONV_CONFIG_TO_INTERNAL_TIME(pConfig->GenQueryInterval);
CONV_CONFIG_TO_INTERNAL_TIME(pConfig->GenQueryMaxResponseTime);
// already in ms
//CONV_CONFIG_TO_INTERNAL_TIME(pConfig->LastMemQueryInterval);
CONV_CONFIG_TO_INTERNAL_TIME(pConfig->OtherQuerierPresentInterval);
CONV_CONFIG_TO_INTERNAL_TIME(pConfig->GroupMembershipTimeout);
pConfig->RobustnessVariableOld = pConfig->RobustnessVariable;
pConfig->GenQueryIntervalOld = pConfig->GenQueryInterval;
pConfig->OtherQuerierPresentIntervalOld
= pConfig->OtherQuerierPresentInterval;
pConfig->GroupMembershipTimeoutOld = pConfig->GroupMembershipTimeout;
pConfig->ExtSize = IgmpMibIfConfigSize(pConfigExt);
pConfig->IfIndex = IfIndex ;
pConfig->NumStaticGroups = 0;
return Error;
#if 0
{
PIGMP_STATIC_GROUP pStaticGroupExt;
PSTATIC_GROUP_V3 pStaticGroupExtV3;
PIF_STATIC_GROUP pStaticGroup;
DWORD i;
PLIST_ENTRY ple;
BOOL bVersion3=IS_CONFIG_IGMP_V3(pConfigExt);
// delete all old static groups
for (ple=pConfig->ListOfStaticGroups.Flink;
ple!=&pConfig->ListOfStaticGroups; )
{
pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
ple = ple->Flink;
IGMP_FREE(pStaticGroup);
}
// copy all static groups
InitializeListHead(&pConfig->ListOfStaticGroups);
if (bVersion3)
pStaticGroupExtV3 = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
else
pStaticGroupExt = GET_FIRST_IGMP_STATIC_GROUP(pConfigExt);
for (i=0; i<pConfig->NumStaticGroups; i++) {
DWORD Size = IGMP_MIB_STATIC_GROUP_SIZE(pConfigExt, pStaticGroupExtV3);
pStaticGroup = IGMP_ALLOC(Size, 0x200000,IfIndex);
PROCESS_ALLOC_FAILURE2(pStaticGroup,
"error %d allocating %d bytes for static group for IF:%0x",
Error, Size,return Error);
if (!bVersion3) {
pStaticGroup->GroupAddr = pStaticGroupExt->GroupAddr;
pStaticGroup->Mode = pStaticGroupExt->Mode;
pStaticGroupExt++;
}
else {
memcpy(pStaticGroup, pStaticGroupExtV3, Size);
pStaticGroupExtV3 = (PSTATIC_GROUP_V3)
((PCHAR)pStaticGroupExtV3 + Size);
}
InsertHeadList(&pConfig->ListOfStaticGroups, &pStaticGroup->Link);
}
}
#endif
}
//------------------------------------------------------------------------------
// _CopyoutIfConfig
//------------------------------------------------------------------------------
VOID
CopyoutIfConfig (
PIGMP_MIB_IF_CONFIG pConfigMib,
PIF_TABLE_ENTRY pite
)
{
PIGMP_IF_CONFIG pConfig = &pite->Config;
BOOL bVersion3 = IS_CONFIG_IGMP_V3(pConfig);
//
// the initial IGMP_MIB_IF_CONFIG size of struct is common
//
CopyMemory(pConfigMib, pConfig, sizeof(IGMP_MIB_IF_CONFIG));
CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->StartupQueryInterval);
CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->GenQueryInterval);
CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->GenQueryMaxResponseTime);
// keep in ms
//CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->LastMemQueryInterval);
CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->OtherQuerierPresentInterval);
CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->GroupMembershipTimeout);
pConfigMib->IfIndex = pite->IfIndex;
pConfigMib->IpAddr = pite->IpAddr;
// have to convert the Iftype to external type
pConfigMib->IfType = GET_EXTERNAL_IF_TYPE(pite);
{
PLIST_ENTRY pHead, ple;
PIGMP_STATIC_GROUP pStaticGroupExt;
PSTATIC_GROUP_V3 pStaticGroupExtV3;
PIF_STATIC_GROUP pStaticGroup;
if (bVersion3)
pStaticGroupExtV3 = GET_FIRST_STATIC_GROUP_V3(pConfigMib);
else
pStaticGroupExt = GET_FIRST_IGMP_STATIC_GROUP(pConfigMib);
pHead = &pConfig->ListOfStaticGroups;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
if (bVersion3) {
memcpy(pStaticGroupExtV3,
(PCHAR)pStaticGroup+FIELD_OFFSET(IF_STATIC_GROUP,GroupAddr),
sizeof(STATIC_GROUP_V3)+pStaticGroup->NumSources*sizeof(IPADDR)
);
pStaticGroupExtV3 = GET_NEXT_STATIC_GROUP_V3(pStaticGroupExtV3);
}
else {
pStaticGroupExt->GroupAddr = pStaticGroup->GroupAddr;
pStaticGroupExt->Mode = pStaticGroup->Mode;
pStaticGroupExt++;
}
}
}
return;
}
//------------------------------------------------------------------------------
// _ValidateIfConfig
//
// Corrects some values, and returns error for some others.
// Return: ERROR_INVALID_DATA, NO_ERROR
//------------------------------------------------------------------------------
DWORD
ValidateIfConfig (
PIGMP_MIB_IF_CONFIG pConfigExt,
DWORD IfIndex,
DWORD IfType,
ULONG ulStructureVersion,
ULONG ulStructureSize
)
{
DWORD Error = NO_ERROR, i, Size;
BOOL bVersion3;
//
// verify config size
//
/*kslksl
if (ulStructureSize<sizeof(IGMP_MIB_IF_CONFIG)) {
Trace2(ERR, "IGMP config size %d very small. Expected:%d", ulStructureSize,
sizeof(IGMP_MIB_IF_CONFIG));
return ERROR_INVALID_DATA;
}
*/
bVersion3 = IS_IGMP_VERSION_3(pConfigExt->Version);
{
if (!bVersion3) {
Size = sizeof(IGMP_MIB_IF_CONFIG)
+ pConfigExt->NumStaticGroups*sizeof(IGMP_STATIC_GROUP);
}
else {
PSTATIC_GROUP_V3 pStaticGroupV3 = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
Size = sizeof(IGMP_MIB_IF_CONFIG)
+sizeof(STATIC_GROUP_V3)*pConfigExt->NumStaticGroups;
for (i=0; i<pConfigExt->NumStaticGroups; i++) {
Size += pStaticGroupV3->NumSources*sizeof(IPADDR);
if (ulStructureSize<Size)
break;
pStaticGroupV3 = GET_NEXT_STATIC_GROUP_V3(pStaticGroupV3);
}
}
/*kslksl
if (ulStructureSize!=Size) {
Trace0(ERR, "Invalid IGMP structure size");
return ERROR_INVALID_DATA;
}
*/
}
// DebugPrintIfConfig
DebugPrintIfConfig(pConfigExt, IfIndex);
// check version
if (pConfigExt->Version >= IGMP_VERSION_3_5) {
Trace1(ERR, "Invalid version in interface config.\n"
"Create the Igmp configuration again", pConfigExt->Version);
IgmpAssertOnError(FALSE);
Logerr0(INVALID_VERSION, ERROR_INVALID_DATA);
return ERROR_INVALID_DATA;
}
//
// check the proxy/router common fields, and then check the router fields
//
//
// check the protocolType
//
switch (pConfigExt->IgmpProtocolType) {
case IGMP_ROUTER_V1 :
case IGMP_ROUTER_V2 :
{
if ( (pConfigExt->Version<IGMP_VERSION_1_2)
||(pConfigExt->Version>=IGMP_VERSION_1_2_5) )
{
Trace1(ERR, "IGMP v1/v2 should have version %0x", IGMP_VERSION_1_2);
IgmpAssertOnError(FALSE);
return ERROR_INVALID_DATA;
}
break;
}
case IGMP_ROUTER_V3:
{
if (pConfigExt->Version<IGMP_VERSION_3 || pConfigExt->Version>=IGMP_VERSION_3_5) {
Trace1(ERR, "IGMP v3 should have version %0x", IGMP_VERSION_3);
IgmpAssertOnError(FALSE);
return ERROR_INVALID_DATA;
}
break;
}
case IGMP_PROXY :
case IGMP_PROXY_V3 :
break;
// if none of above, then return error
default : {
Trace2(ERR,
"Error: IGMP protocol type(%d) for interface(%0x) invalid",
pConfigExt->IgmpProtocolType, IfIndex);
IgmpAssertOnError(FALSE);
Logerr2(INVALID_PROTOTYPE, "%d%d", pConfigExt->IgmpProtocolType,
IfIndex, ERROR_INVALID_DATA);
return ERROR_INVALID_DATA;
}
}
// cannot configure a proxy on a ras server interface
if (IS_RAS_SERVER_IF(IfType) && IS_CONFIG_IGMPPROXY(pConfigExt)) {
Trace1(ERR,
"Error: Cannot configure Proxy on RAS server interface:%0x",
IfIndex);
IgmpAssertOnError(FALSE);
Logerr1(PROXY_ON_RAS_SERVER, "%d",IfIndex, ERROR_INVALID_DATA);
return ERROR_INVALID_DATA;
}
//
// check for static joins
//
if (pConfigExt->NumStaticGroups>0) {
PIGMP_STATIC_GROUP pStaticGroup = GET_FIRST_IGMP_STATIC_GROUP(pConfigExt);
PSTATIC_GROUP_V3 pStaticGroupV3
= GET_FIRST_STATIC_GROUP_V3(pConfigExt);
for (i=0; i<pConfigExt->NumStaticGroups; i++) {
//
// make sure that the static group is a multicast address
//
if (!IS_MCAST_ADDR(pStaticGroup->GroupAddr)) {
Trace2(ERR,
"Error: Static group:%d.%d.%d.%d on IF:%0x not a multicast address",
PRINT_IPADDR(pStaticGroup->GroupAddr), IfIndex);
IgmpAssertOnError(FALSE);
Logerr2(INVALID_STATIC_GROUP, "%I%d", pStaticGroup->GroupAddr,
IfIndex, ERROR_INVALID_DATA);
return ERROR_INVALID_DATA;
}
//
// make sure that the mode of the static group is correct
//
if ( (pStaticGroup->Mode!=IGMP_HOST_JOIN
&& pStaticGroup->Mode!=IGMPRTR_JOIN_MGM_ONLY)
||(IS_CONFIG_IGMPPROXY(pConfigExt)
&& pStaticGroup->Mode!=IGMP_HOST_JOIN) )
{
Trace2(ERR,
"Error: Invalid mode for static group:%d.%d.%d.%d on IF:%0x",
PRINT_IPADDR(pStaticGroup->GroupAddr), IfIndex);
IgmpAssertOnError(FALSE);
Logerr2(INVALID_STATIC_MODE, "%I%d", pStaticGroup->GroupAddr,
IfIndex, ERROR_INVALID_DATA);
return ERROR_INVALID_DATA;
}
if (bVersion3) {
DWORD EntrySize = sizeof(STATIC_GROUP_V3)
+ pStaticGroupV3->NumSources*sizeof(IPADDR);
// check filter mode
if ( (pStaticGroupV3->FilterType!=INCLUSION)
&& (pStaticGroupV3->FilterType!=EXCLUSION))
{
Trace2(ERR,
"Error: Invalid filter type for static group:%d.%d.%d.%d on IF:%0x",
PRINT_IPADDR(pStaticGroup->GroupAddr), IfIndex);
IgmpAssertOnError(FALSE);
Logerr2(INVALID_STATIC_FILTER, "%I%d", pStaticGroup->GroupAddr,
IfIndex, ERROR_INVALID_DATA);
return ERROR_INVALID_DATA;
}
// not checking source addresses
pStaticGroupV3 = (PSTATIC_GROUP_V3)
((PCHAR)pStaticGroupV3 + EntrySize);
pStaticGroup = (PIGMP_STATIC_GROUP)pStaticGroupV3;
}
else {
pStaticGroup ++;
}
}
}
//
// if it is a proxy interface, then none of the config variables other than
// static group is used. I return no_error
//
if (IS_CONFIG_IGMPPROXY(pConfigExt))
return NO_ERROR;
// robustness variable must be greater than 0
if (pConfigExt->RobustnessVariable<=0) {
Trace1(ERR, "Error RobustnessVariable for Interface(%0x) cannot be 0.",
IfIndex);
Logerr2(INVALID_ROBUSTNESS, "%d%d", pConfigExt->RobustnessVariable,
IfIndex, ERROR_INVALID_DATA);
return ERROR_INVALID_DATA;
}
// if robustness variable == 1, then log a warning
if (pConfigExt->RobustnessVariable==1) {
Trace1(ERR,
"Warning: Robustness variable for interface (%d) being set to 1",
IfIndex);
Logwarn0(ROBUSTNESS_VARIABLE_EQUAL_1, NO_ERROR);
}
// if robustness variable > 7, then I correct it to 7 and log a warning
if (pConfigExt->RobustnessVariable>7) {
Trace2(ERR, "RobustnessVariable for Interface(%0x) too high(%d)."
"Being set to 7", IfIndex, pConfigExt->RobustnessVariable);
Logwarn2(INVALID_ROBUSTNESS, "%d%d", pConfigExt->RobustnessVariable,
IfIndex, NO_ERROR);
pConfigExt->RobustnessVariable = 7;
}
// default value of GenQueryInterval is 125 sec. I force a minimum
// value of 10 secs to prevent trashing the network.
// max of 31744 as possible by exp value
if (pConfigExt->GenQueryInterval<10) {
Trace2(ERR, "GetQueryInterval for Interface(%0x) too low(%d)."
"Being set to 10", IfIndex, pConfigExt->GenQueryInterval);
pConfigExt->GenQueryInterval = 10;
}
if (pConfigExt->GenQueryInterval>31744) {
Trace2(ERR, "GetQueryInterval for Interface(%0x) too high(%d)."
"Being set to 31744", IfIndex, pConfigExt->GenQueryInterval);
pConfigExt->GenQueryInterval = 31744;
}
//
// StartupQueryInterval: default is 1/4 of GenQueryInterval
// I enforce a minimum of 1 sec and a max of GenQueryInterval
//
if (pConfigExt->StartupQueryInterval<1) {
Trace2(ERR, "StartupQueryInterval for Interface(%0x) too low(%d)."
"Being set to 1 sec", IfIndex, pConfigExt->StartupQueryInterval);
pConfigExt->StartupQueryInterval = 1;
}
if (pConfigExt->StartupQueryInterval>pConfigExt->GenQueryInterval) {
Trace3(ERR, "StartupQueryInterval(%d) for Interface(%0x) "
"higher than GenQueryInterval(%d). StartupQueryInterval set "
"to GenQueryInterval", pConfigExt->StartupQueryInterval, IfIndex,
pConfigExt->GenQueryInterval
);
pConfigExt->StartupQueryInterval = pConfigExt->GenQueryInterval;
}
//
// StartupQueryCount: default is Robustness variable
// I enforce a max of 7. (I am allowing someone to set it to 0??)
//
if (pConfigExt->StartupQueryCount>7) {
Trace2(ERR, "StartupQueryCount for IF(%0x) too high(%d). "
"Being set to 7.", IfIndex, pConfigExt->StartupQueryCount);
Logerr2(INVALID_STARTUPQUERYCOUNT, "%d%d",
pConfigExt->StartupQueryCount, IfIndex, ERROR_INVALID_DATA);
pConfigExt->StartupQueryCount = 7;
}
if ((int)pConfigExt->StartupQueryCount<0) {
Trace2(ERR,
"Error: StartupQueryCount(%d) for IF(%0x) cannot be < than 0.",
pConfigExt->StartupQueryCount, IfIndex);
Logerr2(INVALID_STARTUPQUERYCOUNT, "%d%d",
pConfigExt->StartupQueryCount, IfIndex, ERROR_INVALID_DATA);
return ERROR_INVALID_DATA;
}
//
// GenQueryMaxResponseTime: default is 10.
// Absurd if value is greater than GenQueryInterval.
// I correct the values, if required
//
if (pConfigExt->GenQueryMaxResponseTime > pConfigExt->GenQueryInterval) {
Trace3(ERR, "GenQueryMaxResponseTime(%d) for IF(%0x) "
"higher than GenQueryInterval(%d). GenQueryMaxResponseTime "
"set to GenQueryInterval", pConfigExt->GenQueryMaxResponseTime,
IfIndex, pConfigExt->GenQueryInterval);
pConfigExt->GenQueryMaxResponseTime = pConfigExt->GenQueryInterval;
}
if (pConfigExt->GenQueryMaxResponseTime > 3174) {
Trace2(ERR, "GenQueryMaxResponseTime(%d) for IF(%0x) "
"higher than 3174 "
"set to 1sec", pConfigExt->GenQueryMaxResponseTime,
IfIndex);
pConfigExt->GenQueryMaxResponseTime = 1;
}
if (pConfigExt->GenQueryMaxResponseTime <= 0) {
Trace2(ERR, "Error. GenQueryMaxResponseTime(%d) for Interface(%0x) "
"should be greater than 0.", pConfigExt->GenQueryMaxResponseTime,
IfIndex);
return ERROR_INVALID_DATA;
}
//
// check LastMemQueryCount and LastMemQueryInterval only if
// protocol type is not IGMP-Router-ver1 and it is not a ras server interface
//
if ( (pConfigExt->IgmpProtocolType!=IGMP_ROUTER_V1) && (!IS_RAS_SERVER_IF(IfType)) ) {
// LastMemQueryCount can be 0
// set max LastMemQueryCount to 7
if (pConfigExt->LastMemQueryCount>7) {
Trace2(ERR, "Warning. LastMemQueryCount(%d) for IF(%0x) "
"is too high. Resetting it to 10.", pConfigExt->LastMemQueryCount,
IfIndex);
pConfigExt->LastMemQueryCount = 10;
}
// limit LastMemQueryInterval(in ms) to GroupMembershipTimeout(in sec)
if (pConfigExt->LastMemQueryInterval>pConfigExt->GroupMembershipTimeout*1000) {
Trace3(ERR,
"Warning. LastMemberQueryInterval(%d) for IF(%0x) "
"is too high. Resetting it to GroupMembershipTimeout(%d ms).",
pConfigExt->LastMemQueryCount, IfIndex,
pConfigExt->GroupMembershipTimeout*1000
);
pConfigExt->LastMemQueryInterval = pConfigExt->GroupMembershipTimeout*1000;
}
// limit LastMemQueryInterval(in ms) to 3174(in sec)
if (pConfigExt->LastMemQueryInterval>3174*1000) {
Trace2(ERR,
"Warning. LastMemberQueryInterval(%d) for IF(%0x) "
"is too high. Resetting it to 1000ms).",
pConfigExt->LastMemQueryCount, IfIndex
);
pConfigExt->LastMemQueryInterval = 1000;
}
}
// check the value of OtherQuerierPresentInterval
if (pConfigExt->OtherQuerierPresentInterval !=
pConfigExt->RobustnessVariable*pConfigExt->GenQueryInterval
+ (pConfigExt->GenQueryMaxResponseTime)/2
)
{
pConfigExt->OtherQuerierPresentInterval =
pConfigExt->RobustnessVariable*pConfigExt->GenQueryInterval
+ (pConfigExt->GenQueryMaxResponseTime)/2;
Trace0(ERR, "Warning: OtherQuerierPresentInterval's value should be "
"RobustnessVariable*GenQueryInterval + (GenQueryMaxResponseTime)/2");
}
// check the value of GroupMembershipTimeout
if (pConfigExt->GroupMembershipTimeout !=
(pConfigExt->RobustnessVariable*pConfigExt->GenQueryInterval
+ pConfigExt->GenQueryMaxResponseTime) )
{
pConfigExt->GroupMembershipTimeout =
pConfigExt->RobustnessVariable*pConfigExt->GenQueryInterval
+ pConfigExt->GenQueryMaxResponseTime;
Trace0(ERR, "Warning: GroupMembershipTimeout's value should be "
"RobustnessVariable*GenQueryInterval + GenQueryMaxResponseTime");
}
return Error;
} // _ValidateIfConfig
//------------------------------------------------------------------------------
// InitializeIfTable
// Creates the Interface table. The interface table size is dynamic
//------------------------------------------------------------------------------
DWORD
InitializeIfTable(
)
{
DWORD Error = NO_ERROR;
PIGMP_IF_TABLE pTable;
DWORD NumBuckets, i;
BEGIN_BREAKOUT_BLOCK1 {
// set the initial size of the interface table to IF_HASHTABLE_SZ1
NumBuckets = IF_HASHTABLE_SZ1;
//
// allocate memory for the interface table
//
g_pIfTable = IGMP_ALLOC(sizeof(IGMP_IF_TABLE), 0x400000,0);
PROCESS_ALLOC_FAILURE2(g_pIfTable,
"error %d allocating %d bytes for interface table",
Error, sizeof(IGMP_IF_TABLE),
GOTO_END_BLOCK1);
pTable = g_pIfTable;
// initialize NumBuckets and NumInterfaces
pTable->NumBuckets = NumBuckets;
pTable->NumInterfaces = 0;
//
// Initialize the IfTable lists
//
InitializeListHead(&pTable->ListByIndex);
InitializeListHead(&pTable->ListByAddr);
//
// Initialize the list CS and proxyAlertCS
//
try {
InitializeCriticalSection(&pTable->IfLists_CS);
InitializeCriticalSection(&g_ProxyAlertCS);
}
except (EXCEPTION_EXECUTE_HANDLER) {
Error = GetExceptionCode();
Trace1(ANY,
"exception %d initializing critical section in InitIfTable",
Error);
Logerr0(INIT_CRITSEC_FAILED, Error);
GOTO_END_BLOCK1;
}
//
// allocate memory for the different buckets
//
pTable->HashTableByIndex = IGMP_ALLOC(sizeof(LIST_ENTRY)*NumBuckets,
0x800000,0);
PROCESS_ALLOC_FAILURE2(pTable->HashTableByIndex,
"error %d allocating %d bytes for interface table",
Error, sizeof(LIST_ENTRY)*NumBuckets,
GOTO_END_BLOCK1);
//
// allocate memory for the array of pointers to dynamic RWLs
//
pTable->aIfBucketDRWL
= IGMP_ALLOC(sizeof(PDYNAMIC_RW_LOCK)*NumBuckets, 0x800001,0);
PROCESS_ALLOC_FAILURE2(pTable->aIfBucketDRWL,
"error %d allocating %d bytes for interface table",
Error, sizeof(PDYNAMIC_RW_LOCK)*NumBuckets,
GOTO_END_BLOCK1);
//
// allocate memory for the array of pointers to dynamic CSs
//
pTable->aIfBucketDCS
= IGMP_ALLOC(sizeof(PDYNAMIC_CS_LOCK)*NumBuckets, 0x800002,0);
PROCESS_ALLOC_FAILURE2(pTable->aIfBucketDCS,
"error %d allocating %d bytes for interface table",
Error, sizeof(PDYNAMIC_CS_LOCK)*NumBuckets,
GOTO_END_BLOCK1);
//
// init locks to NULL, implying that the dynamic locks have not been
// allocated. and initialize the list heads.
//
for (i=0; i<NumBuckets; i++) {
InitializeListHead(&pTable->HashTableByIndex[i]);
pTable->aIfBucketDRWL[i] = NULL;
pTable->aIfBucketDCS[i] = NULL;
}
pTable->Status = 0;
} END_BREAKOUT_BLOCK1;
return Error;
} //end _InitializeIfTable
//------------------------------------------------------------------------------
// _DeInitializeIfTable
//------------------------------------------------------------------------------
VOID
DeInitializeIfTable(
)
{
PIGMP_IF_TABLE pTable = g_pIfTable;
PLIST_ENTRY pHead, ple;
PIF_TABLE_ENTRY pite;
DWORD i, dwRetval;
if (pTable==NULL)
return;
//
// for each active interface call deregister MGM.
//
// go through the list of active interfaces ordered by IpAddr
pHead = &g_pIfTable->ListByAddr;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, LinkByAddr);
// if not activated then continue
if (!IS_IF_ACTIVATED(pite))
continue;
// deregister all interfaces, ras clients and proxy protocol from mgm
DeActivationDeregisterFromMgm(pite);
}
// delete the IfLists CS
DeleteCriticalSection(&pTable->IfLists_CS);
IGMP_FREE_NOT_NULL(pTable->aIfBucketDCS);
IGMP_FREE_NOT_NULL(pTable->aIfBucketDRWL);
IGMP_FREE_NOT_NULL(pTable->HashTableByIndex);
IGMP_FREE_NOT_NULL(g_pIfTable);
// I dont delete the different dynamic locks. They should have been deleted
// by now
return;
}
//------------------------------------------------------------------------------
// _InitializeGroupTable //
//------------------------------------------------------------------------------
DWORD
InitializeGroupTable (
)
{
BOOL bErr = TRUE;
DWORD Error = NO_ERROR;
PGROUP_TABLE pGroupTable;
DWORD i;
BEGIN_BREAKOUT_BLOCK1 {
//
// allocate space for the group table
//
g_pGroupTable = IGMP_ALLOC(sizeof(GROUP_TABLE), 0x800004,0);
PROCESS_ALLOC_FAILURE2(g_pGroupTable,
"error %d allocating %d bytes for Group table",
Error, sizeof(GROUP_TABLE),
GOTO_END_BLOCK1);
pGroupTable = g_pGroupTable;
//
// initialize group tables' dynamically locked lists
//
for (i=0; i<GROUP_HASH_TABLE_SZ; i++) {
InitDynamicCSLockedList(&pGroupTable->HashTableByGroup[i]);
}
//
// initialize list of all groups
//
try {
CREATE_LOCKED_LIST(&pGroupTable->ListByGroup);
}
except (EXCEPTION_EXECUTE_HANDLER) {
Error = GetExceptionCode();
Trace1(ERR, "Exception %d creating locked list for Group Table",
Error);
Logerr0(INIT_CRITSEC_FAILED, Error);
GOTO_END_BLOCK1;
}
//
// initialize the list of new groups
//
InitializeListHead(&pGroupTable->ListByGroupNew);
pGroupTable->NumGroupsInNewList = 0;
pGroupTable->Status = 0;
bErr = FALSE;
} END_BREAKOUT_BLOCK1;
if (!bErr) {
return Error==NO_ERROR ? ERROR_CAN_NOT_COMPLETE: Error;
}
else {
return Error;
}
} //end _InitializeGroupTable
//------------------------------------------------------------------------------
// DeInitializeGroupTable //
// Just delete the critical sections //
//------------------------------------------------------------------------------
VOID
DeInitializeGroupTable (
)
{
PGROUP_TABLE pGroupTable = g_pGroupTable;
DWORD i;
if (pGroupTable==NULL)
return;
//
// I dont try to delete the dynamically allocated locks as they should
// have all been deleted by the last thread executing in that lock
//
DeleteCriticalSection(&pGroupTable->ListByGroup.Lock);
IGMP_FREE_NOT_NULL(pGroupTable);
}
//------------------------------------------------------------------------------
// _InitializeRasTable
// creates ras table and initializes the fields.
// called by _DeActivateInterfaceInitial() _AddIfEntry()
// The interface table is created during _AddIfEntry, as _ConnectRasClients can
// be called even when the ras server interface is not activated
//------------------------------------------------------------------------------
DWORD
InitializeRasTable(
DWORD IfIndex,
PIF_TABLE_ENTRY pite
)
{
DWORD Error = NO_ERROR, i;
PRAS_TABLE prt;
//
// allocate Ras table
//
prt = IGMP_ALLOC(sizeof(RAS_TABLE), 0x800008,IfIndex);
PROCESS_ALLOC_FAILURE2(prt, "error %d allocating %d bytes for Ras Table",
Error, sizeof(RAS_TABLE),
return Error);
//set the ras table entry in pite
pite->pRasTable = prt;
// initialize list pointing to Ras Clients ordered by IpAddr
InitializeListHead(&prt->ListByAddr);
// initialize hash table containing lists pointing to Ras Clients
// hashed on IpAddr
for (i=0; i<RAS_HASH_TABLE_SZ; i++)
InitializeListHead(&prt->HashTableByAddr[i]);
// set backpointer to the interface table entry
prt->pIfTable = pite;
// set RefCount and Status
prt->RefCount = 1;
prt->Status = IF_CREATED_FLAG;
return NO_ERROR;
} //end _InitializeRasTable
//todo:remove
//------------------------------------------------------------------------------
// DeInitializeRasTable
//------------------------------------------------------------------------------
VOID
DeInitializeRasTable (
PIF_TABLE_ENTRY pite,
BOOL bFullCleanup
)
{
PRAS_TABLE prt = pite->pRasTable;
PRAS_TABLE_ENTRY prte;
PLIST_ENTRY pHeadRas, pleRas;
pHeadRas = &prt->ListByAddr;
for (pleRas=pHeadRas->Flink; pleRas!=pHeadRas; pleRas=pleRas->Flink) {
prte = CONTAINING_RECORD(pleRas, RAS_TABLE_ENTRY, LinkByAddr);
if (prte->CreationFlags & TAKEN_INTERFACE_OWNERSHIP_WITH_MGM)
{
MgmReleaseInterfaceOwnership(g_MgmIgmprtrHandle, pite->IfIndex,
prte->NHAddr);
}
}
return;
}
//------------------------------------------------------------------------------
// _MergeIfGroupsLists
//
// Merges the new GI list with the main GI list.
// Locks: Assumes the IF-GI list to be locked.
//------------------------------------------------------------------------------
VOID
MergeIfGroupsLists(
PIF_TABLE_ENTRY pite
)
{
// sentinel is set at the end of the Main list so that all entries is inserted
// before it. its group value is set to all 1's.
GROUP_TABLE_ENTRY pgeSentinel;
GI_ENTRY giSentinel;
PGI_ENTRY giNew, giMain;
PLIST_ENTRY pHeadNew, pHeadMain, pleMain, pleNew;
Trace1(ENTER1, "Entering _MergeIfGroupLists(): IfIndex:%0x", pite->IfIndex);
pHeadNew = &pite->ListOfSameIfGroupsNew;
pHeadMain = &pite->ListOfSameIfGroups;
//
// if main list is empty, then just move the new list to main list
// and I am done
//
if (IsListEmpty(pHeadMain)) {
// insert pHeadMain into new list
InsertHeadList(pHeadNew, pHeadMain);
// remove new list header
RemoveEntryList(pHeadNew);
InitializeListHead(pHeadNew);
return;
}
//
// insert the sentinel at the end of the main list
//
pgeSentinel.GroupLittleEndian = ~0;
giSentinel.pGroupTableEntry = &pgeSentinel;
InsertTailList(pHeadMain, &giSentinel.LinkBySameIfGroups);
pleMain = pHeadMain->Flink;
giMain = CONTAINING_RECORD(pleMain, GI_ENTRY, LinkBySameIfGroups);
// merge the lists by inserting the entries from new list into main list.
for (pleNew=pHeadNew->Flink; pleNew!=pHeadNew; ) {
giNew = CONTAINING_RECORD(pleNew, GI_ENTRY, LinkBySameIfGroups);
pleNew=pleNew->Flink;
while (giNew->pGroupTableEntry->GroupLittleEndian >
giMain->pGroupTableEntry->GroupLittleEndian)
{
pleMain = pleMain->Flink;
giMain = CONTAINING_RECORD(pleMain, GI_ENTRY, LinkBySameIfGroups);
}
InsertTailList(pleMain, &giNew->LinkBySameIfGroups);
}
//
// reinitialize the New list
//
pite->NumGIEntriesInNewList = 0;
InitializeListHead(&pite->ListOfSameIfGroupsNew);
// remove the sentinel entry from the main list
RemoveEntryList(&giSentinel.LinkBySameIfGroups);
//DebugPrintIfGroups(pite, 0); //deldel
Trace0(LEAVE1, "Leaving _MergeIfGroupsLists");
return;
} //end _MergeIfGroupsLists
//------------------------------------------------------------------------------
// _MergeProxyLists
//
// Merges the new GI list with the main GI list.
// Locks: Assumes the IF-GI list to be locked.
//------------------------------------------------------------------------------
VOID
MergeProxyLists(
PIF_TABLE_ENTRY pite
)
{
// sentinel is set at the end of the Main list so that all entries is inserted
// before it. its group value is set to all 1's.
PROXY_GROUP_ENTRY ProxySentinel, *pProxyNew, *pProxyMain;
PLIST_ENTRY pHeadNew, pHeadMain, pleMain, pleNew;
Trace1(ENTER1, "Entering MergeProxyLists(): IfIndex:%0x", pite->IfIndex);
pHeadNew = &pite->ListOfSameIfGroupsNew;
pHeadMain = &pite->ListOfSameIfGroups;
//
// if main list is empty, then just move the new list to main list
// and I am done
//
if (IsListEmpty(pHeadMain)) {
CONCATENATE_LISTS(pite->ListOfSameIfGroups, pite->ListOfSameIfGroupsNew);
pite->NumGIEntriesInNewList = 0;
return;
}
//
// insert the sentinel at the end of the main list
//
ProxySentinel.GroupLittleEndian = ~0;
InsertTailList(pHeadMain, &ProxySentinel.LinkBySameIfGroups);
pleMain = pHeadMain->Flink;
pProxyMain = CONTAINING_RECORD(pleMain, PROXY_GROUP_ENTRY,
LinkBySameIfGroups);
// merge the lists by inserting the entries from new list into main list.
for (pleNew=pHeadNew->Flink; pleNew!=pHeadNew; ) {
pProxyNew = CONTAINING_RECORD(pleNew, PROXY_GROUP_ENTRY,
LinkBySameIfGroups);
pleNew=pleNew->Flink;
while (pProxyNew->GroupLittleEndian > pProxyMain->GroupLittleEndian)
{
pleMain = pleMain->Flink;
pProxyMain = CONTAINING_RECORD(pleMain, PROXY_GROUP_ENTRY,
LinkBySameIfGroups);
}
InsertTailList(pleMain, &pProxyNew->LinkBySameIfGroups);
}
//
// reinitialize the New list
//
pite->NumGIEntriesInNewList = 0;
InitializeListHead(&pite->ListOfSameIfGroupsNew);
// remove the sentinel entry from the main list
RemoveEntryList(&ProxySentinel.LinkBySameIfGroups);
Trace0(LEAVE1, "Leaving _MergeProxyLists");
return;
} //end _MergeProxyLists
//------------------------------------------------------------------------------
// _MergeGroupLists
//
// Merges the new group list with the main group list.
//
// Locks: Assumes the group list to be locked.
// Called by: MibGetInternalGroupIfsInfo() or InsertInGroupsList()
//------------------------------------------------------------------------------
VOID
MergeGroupLists(
)
{
// sentinel is set at the end of the Main list so that all entries is inserted
// before it. its group value is set to all 1's.
GROUP_TABLE_ENTRY pgeSentinel;
PGROUP_TABLE_ENTRY pgeNew, pgeMain;
PLIST_ENTRY pHeadNew, pHeadMain, pleMain, pleNew;
Trace0(ENTER1, "Entering _MergeGroupLists()");
#if DBG
DebugPrintGroupsList(1);
#endif
pHeadNew = &g_pGroupTable->ListByGroupNew;
pHeadMain = &g_pGroupTable->ListByGroup.Link;
//
// if main list is empty, then just move the new list to main list
// and I am done
//
if (IsListEmpty(pHeadMain)) {
// insert pHeadMain into new list
InsertHeadList(pHeadNew, pHeadMain);
// remove new list header
RemoveEntryList(pHeadNew);
InitializeListHead(pHeadNew);
return;
}
//
// insert the sentinel at the end of the main list
//
pgeSentinel.GroupLittleEndian = ~0;
InsertTailList(pHeadMain, &pgeSentinel.LinkByGroup);
pleMain = pHeadMain->Flink;
pgeMain = CONTAINING_RECORD(pleMain, GROUP_TABLE_ENTRY, LinkByGroup);
// merge the lists by inserting the entries from new list into main list.
for (pleNew=pHeadNew->Flink; pleNew!=pHeadNew; ) {
pgeNew = CONTAINING_RECORD(pleNew, GROUP_TABLE_ENTRY, LinkByGroup);
pleNew=pleNew->Flink;
while (pgeNew->GroupLittleEndian > pgeMain->GroupLittleEndian) {
pleMain = pleMain->Flink;
pgeMain = CONTAINING_RECORD(pleMain, GROUP_TABLE_ENTRY,
LinkByGroup);
}
InsertTailList(pleMain, &pgeNew->LinkByGroup);
}
//
// reinitialize the New list
//
g_pGroupTable->NumGroupsInNewList = 0;
InitializeListHead(&g_pGroupTable->ListByGroupNew);
// remove the sentinel entry from the main list
RemoveEntryList(&pgeSentinel.LinkByGroup);
return;
} //end _MergeGroupLists