//============================================================================= // 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 %d (%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 %d (%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; DWORD dwRetval; 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 %d", 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 %d", 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 %d (%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 %d", 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 %d 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; PSOCKET_EVENT_ENTRY psee = pse->pSocketEventsEntry; 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(%d)(%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; iListOfSameIfGroups; 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; iFlink; 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(%d)", 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; iNumStaticGroups; 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; jNumSources; 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 ( (NewOtherQuerierPresentIntervalOtherQuerierPresentInterval) && (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) && (llNewLastMemQueryIntervalLastMemQueryTimer.Timeout)) { UpdateLocalTimer(&pgie->LastMemQueryTimer, NewLastMemQueryInterval, DBG_Y); } if (bLastMemQueryTimer && IS_TIMER_ACTIVE(pgie->V3SourcesQueryTimer) && (llNewLastMemQueryIntervalV3SourcesQueryTimer.Timeout)) { UpdateLocalTimer(&pgie->V3SourcesQueryTimer, NewLastMemQueryInterval, DBG_Y); } // update GroupMembershipTimeout if it is active and has a higher value if (bGroupMembershipTimer && IS_TIMER_ACTIVE(pgie->GroupMembershipTimer) && (llNewGroupMembershipTimeoutGroupMembershipTimer.Timeout)) { UpdateLocalTimer(&pgie->GroupMembershipTimer, NewGroupMembershipTimeout, DBG_Y); } // update LastVer1ReportTimer/LastVer2ReportTimer if it is active and has a higher value // LastVer1ReportTimeout is set to GroupMembershipTimeout if (bGroupMembershipTimer && IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer) && (llNewGroupMembershipTimeoutLastVer1ReportTimer.Timeout)) { UpdateLocalTimer(&pgie->LastVer1ReportTimer, NewGroupMembershipTimeout, DBG_Y); } if (bGroupMembershipTimer && IS_TIMER_ACTIVE(pgie->LastVer2ReportTimer) && (llNewGroupMembershipTimeoutLastVer2ReportTimer.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 GroupMembershipTimer.Timeout)) { UpdateLocalTimer(&pgie->GroupMembershipTimer, NewGroupMembershipTimeout, DBG_Y); } } } } } 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; iNumStaticGroups; 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; iNumSources; 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; iNumStaticGroups; 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; iNumSources; 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; iNumSources; 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; iNumSources; 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; iNumSources; 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; iNumStaticGroups; 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 (ulStructureSizeVersion); { 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; iNumStaticGroups; i++) { Size += pStaticGroupV3->NumSources*sizeof(IPADDR); if (ulStructureSizeVersion >= 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->VersionVersion>=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->VersionVersion>=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) { DWORD i; PIGMP_STATIC_GROUP pStaticGroup = GET_FIRST_IGMP_STATIC_GROUP(pConfigExt); PSTATIC_GROUP_V3 pStaticGroupV3 = GET_FIRST_STATIC_GROUP_V3(pConfigExt); for (i=0; iNumStaticGroups; 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(%d) 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; iHashTableByIndex[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; iHashTableByGroup[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; iHashTableByAddr[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); 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