//============================================================================= // Copyright (c) 1997 Microsoft Corporation // Module Name: Mib.c // // Abstract: // This module implements the mib API's: // MibGet, MibGetFirst and MibGetNext. // It also implements the Mib Display tracing, which displays the mib // // Author: K.S.Lokesh (lokeshs@) 11-1-97 // // Revision History: //============================================================================= #include "pchigmp.h" #pragma hdrstop #pragma prefast(disable:69, "dont need to optimize. used in debug tracing only") DWORD g_IgmpMibDisplay = 1; //------------------------------------------------------------------------------ // Functions to display the MibTable on the TraceWindow periodically //------------------------------------------------------------------------------ #ifdef MIB_DEBUG #define ClearScreen(h) { \ DWORD _dwin,_dwout; \ COORD _c = {0, 0}; \ CONSOLE_SCREEN_BUFFER_INFO _csbi; \ GetConsoleScreenBufferInfo(h,&_csbi); \ _dwin = _csbi.dwSize.X * _csbi.dwSize.Y; \ FillConsoleOutputCharacter(h,' ',_dwin,_c,&_dwout); \ } #define WRITELINE(h,c,fmt,arg) { \ DWORD _dw; \ CHAR _sz[200], _fmt[200]; \ wsprintf(_fmt,"%-100s",fmt); \ wsprintf(_sz,_fmt,arg); \ WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \ ++(c).Y; \ } #define WRITE_NEWLINE(h,c) \ WRITELINE( \ hConsole, c, "%s", \ "" \ ); #define WRITELINE2(h,c,fmt,arg1, arg2) { \ DWORD _dw; \ CHAR _sz[200], _fmt[200]; \ wsprintf(_fmt,"%-100s",fmt); \ wsprintf(_sz,_fmt,arg1, arg2); \ WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \ ++(c).Y; \ } #define WRITELINE3(h,c,fmt,arg1, arg2, arg3) { \ DWORD _dw; \ CHAR _sz[200], _fmt[200]; \ wsprintf(_fmt,"%-100s",fmt); \ wsprintf(_sz,_fmt,arg1, (arg2), (arg3)); \ WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \ ++(c).Y; \ } #define WRITELINE4(h,c,fmt,arg1, arg2, arg3, arg4) { \ DWORD _dw; \ CHAR _sz[200], _fmt[200]; \ wsprintf(_fmt,"%-100s",fmt); \ wsprintf(_sz,_fmt,arg1, arg2, arg3, arg4); \ WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \ ++(c).Y; \ } #define WRITELINE5(h,c,fmt,arg1, arg2, arg3, arg4, arg5) { \ DWORD _dw; \ CHAR _sz[200], _fmt[200]; \ wsprintf(_fmt,"%-100s",fmt); \ wsprintf(_sz,_fmt,arg1, arg2, arg3, arg4, arg5); \ WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \ ++(c).Y; \ } #define WRITELINE6(h,c,fmt,arg1, arg2, arg3, arg4, arg5, arg6) { \ DWORD _dw; \ CHAR _sz[200], _fmt[200]; \ wsprintf(_fmt,"%-100s",fmt); \ wsprintf(_sz,_fmt,arg1, arg2, arg3, arg4, arg5, arg6); \ WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \ ++(c).Y; \ } #define WRITELINE7(h,c,fmt,arg1, arg2,arg3,arg4,arg5,arg6,arg7) {\ DWORD _dw; \ CHAR _sz[200], _fmt[200]; \ wsprintf(_fmt,"%-100s",fmt); \ wsprintf(_sz,_fmt,arg1, arg2, arg3, arg4, arg5, arg6, arg7);\ WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \ ++(c).Y; \ } #define WRITELINE8(h,c,fmt,arg1, arg2,arg3,arg4,arg5,arg6,arg7,arg8) {\ DWORD _dw; \ CHAR _sz[200], _fmt[200]; \ wsprintf(_fmt,"%-100s",fmt); \ wsprintf(_sz,_fmt,arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);\ WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \ ++(c).Y; \ } #define WRITELINE9(h,c,fmt,arg1, arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) {\ DWORD _dw; \ CHAR _sz[200], _fmt[200]; \ wsprintf(_fmt,"%-100s",fmt); \ wsprintf(_sz,_fmt,arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);\ WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \ ++(c).Y; \ } #define WRITELINE10(h,c,fmt,arg1, arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) {\ DWORD _dw; \ CHAR _sz[200], _fmt[200]; \ wsprintf(_fmt,"%-100s",fmt); \ wsprintf(_sz,_fmt,arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,arg10);\ WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \ ++(c).Y; \ } DWORD WT_MibDisplay ( PVOID pContext ) { //enter/leaveIgmpApi not required as the timer queue is persistent QueueIgmpWorker(WF_MibDisplay, NULL); return 0; } //------------------------------------------------------------------------------ // _WF_MibDisplay //------------------------------------------------------------------------------ VOID WF_MibDisplay( PVOID pContext ) { COORD c; HANDLE hConsole; DWORD Error=NO_ERROR, dwTraceId, dwCurTableId=0, dwEnumCount; DWORD dwExactSize, dwInSize, dwBufferSize, dwOutSize; IGMP_MIB_GET_INPUT_DATA Query; PIGMP_MIB_GET_OUTPUT_DATA pResponse; LARGE_INTEGER llCurrentTime; BOOL bChanged, bEndOfTables; if (!EnterIgmpWorker()) { return; } if (g_IgmpMibDisplay==0) { ACQUIRE_TIMER_LOCK("_WF_MibDisplay"); g_MibTimer.Status = TIMER_STATUS_CREATED; #if DEBUG_TIMER_TIMERID SET_TIMER_ID(&g_MibTimer, 920, 0, 0, 0); #endif if (g_Info.CurrentGroupMemberships<=20) InsertTimer(&g_MibTimer, 30000, TRUE, DBG_Y);//kslksl else if (g_Info.CurrentGroupMemberships<=320) InsertTimer(&g_MibTimer, 120000, TRUE, DBG_N);//kslksl else InsertTimer(&g_MibTimer, 1200000, TRUE, DBG_N); RELEASE_TIMER_LOCK("_WF_MibDisplay"); LeaveIgmpWorker(); return; } else if (g_IgmpMibDisplay==0xff) { LeaveIgmpWorker(); return; } TraceGetConsole(g_MibTraceId, &hConsole); if (hConsole == NULL) { LeaveIgmpWorker(); return; } ClearScreen(hConsole); Sleep(200); c.X = c.Y = 0; dwInSize = sizeof(Query); Query.GroupAddr = 0; Query.TypeId = IGMP_GLOBAL_CONFIG_ID; Query.Flags = IGMP_ENUM_ALL_INTERFACES_GROUPS | IGMP_ENUM_ALL_TABLES | IGMP_ENUM_SUPPORT_FORMAT_IGMPV3; Query.Count = 20; pResponse = NULL; // // get size of the first entry in the first table // Query.Count = 20; dwOutSize = dwBufferSize = 0; Error = MibGetFirst(dwInSize, &Query, &dwOutSize, pResponse); if (Error == ERROR_INSUFFICIENT_BUFFER) { // // allocate a buffer, and set its size // dwOutSize = dwBufferSize = (dwOutSizeTypeId) { // // move to the next line on the console // ++c.Y; WRITELINE( hConsole, c, "%s", "---------------------------------------------------------------" ); dwCurTableId = pResponse->TypeId; bChanged = TRUE; } else bChanged = FALSE; // // print the current element and set up the query // for the next element (the display functions change Query // so that it can be used to query the next element) // switch(pResponse->TypeId) { case IGMP_GLOBAL_CONFIG_ID: { if (bChanged) { WRITELINE( hConsole, c, "%s", "Global Configuration" ); WRITELINE( hConsole, c, "%s", "--------------------" ); } PrintGlobalConfig(hConsole,&c, &Query, pResponse); break; } case IGMP_GLOBAL_STATS_ID: { if (bChanged) { WRITELINE( hConsole, c, "%s", "Global Statistics Information" ); WRITELINE( hConsole, c, "%s", "-----------------------------" ); } PrintGlobalStats(hConsole, &c, &Query, pResponse); break; } case IGMP_IF_CONFIG_ID: { if (bChanged) { WRITELINE( hConsole, c, "%s", "Interface Config Table" ); WRITELINE( hConsole, c, "%s", "----------------------" ); } PrintIfConfig(hConsole, &c, &Query, pResponse); break; } case IGMP_IF_STATS_ID: if (bChanged) { WRITELINE( hConsole, c, "%s", "Interface Statistics Table" ); WRITELINE( hConsole, c, "%s", "--------------------------" ); } PrintIfStats(hConsole, &c, &Query, pResponse); break; case IGMP_IF_BINDING_ID: { if (bChanged) { WRITELINE( hConsole, c, "%s", "Interface Binding Table" ); WRITELINE( hConsole, c, "%s", "-----------------------" ); } PrintIfBinding(hConsole, &c, &Query, pResponse); break; } case IGMP_IF_GROUPS_LIST_ID: { if (bChanged) { WRITELINE( hConsole, c, "%s", "Interface-MulticastGroups Table" ); WRITELINE( hConsole, c, "%s", "--------------------------------" ); } PrintIfGroupsList(hConsole, &c, &Query, pResponse); break; } case IGMP_GROUP_IFS_LIST_ID: { if (bChanged) { WRITELINE( hConsole, c, "%s", "MulticastGroups-Interface Table" ); WRITELINE( hConsole, c, "%s", "-------------------------------" ); WRITELINE( hConsole, c, "%s", "(Ver) GroupAddr (Up/Exp)Time Flg LastReporter " " V1Host V2Host" ); WRITE_NEWLINE(hConsole, c); } PrintGroupIfsList(hConsole, &c, &Query, pResponse); break; } case IGMP_PROXY_IF_INDEX_ID: { WRITELINE( hConsole, c, "%s", "Proxy Interface Index" ); WRITELINE( hConsole, c, "%s", "---------------------" ); PrintProxyIfIndex(hConsole, &c, &Query, pResponse); break; } default: bEndOfTables = TRUE; break; } // // query the next MIB element // Query.Count = 20; //kslksl IGMP_FREE(pResponse); pResponse = IGMP_ALLOC(dwBufferSize, 0xb000,0); dwOutSize = dwBufferSize; Error = MibGetNext(dwInSize, &Query, &dwOutSize, pResponse); if (Error == ERROR_INSUFFICIENT_BUFFER) { // // allocate a new buffer, and set its size // dwOutSize = dwBufferSize = (dwOutSizeBuffer; WRITELINE( hConsole, *pc, "Current Group Memberships: %d", pgs->CurrentGroupMemberships ); WRITELINE( hConsole, *pc, "Group Memberships Added: %d", pgs->GroupMembershipsAdded ); pQuery->TypeId = IGMP_GLOBAL_STATS_ID; } //------------------------------------------------------------------------------ // _PrintProxyIfIndex //------------------------------------------------------------------------------ VOID PrintProxyIfIndex( HANDLE hConsole, PCOORD pc, PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse ) { DWORD *pProxyIfIndex = (PDWORD)pResponse->Buffer; WRITELINE( hConsole, *pc, "Proxy Interface Index: 0x%0x", *pProxyIfIndex ); pQuery->TypeId = IGMP_PROXY_IF_INDEX_ID; } //------------------------------------------------------------------------------ // _PrintGlobalConfig //------------------------------------------------------------------------------ VOID PrintGlobalConfig( HANDLE hConsole, PCOORD pc, PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse ) { PIGMP_MIB_GLOBAL_CONFIG pConfig; LARGE_INTEGER llTime; static DWORD dwCount; llTime.QuadPart = GetCurrentIgmpTime(); pConfig = (PIGMP_MIB_GLOBAL_CONFIG)pResponse->Buffer; WRITELINE2( hConsole, *pc, "%d. Seconds since start: %lu", ++dwCount, (ULONG)((llTime.QuadPart - g_Info.TimeWhenRtrStarted.QuadPart)/1000) ); WRITELINE( hConsole, *pc, "Version: %x", pConfig->Version ); WRITELINE( hConsole, *pc, "Logging Level: %d", pConfig->LoggingLevel ); WRITELINE( hConsole, *pc, "Ras Client Stats kept: %d", pConfig->RasClientStats ); pQuery->TypeId = IGMP_GLOBAL_CONFIG_ID; } //------------------------------------------------------------------------------ // _PrintIfConfig //------------------------------------------------------------------------------ VOID PrintIfConfig( HANDLE hConsole, PCOORD pc, PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse ) { PIGMP_MIB_IF_CONFIG pConfig; CHAR szIfType[50], szProtoType[50]; DWORD LastIfIndex=0, Count; pConfig = (PIGMP_MIB_IF_CONFIG)pResponse->Buffer; for (Count=0; CountCount; Count++) { WRITE_NEWLINE(hConsole, *pc); LastIfIndex = pConfig->IfIndex; switch (pConfig->IfType) { case IGMP_IF_NOT_RAS : lstrcpy(szIfType, "Permanent"); break; case IGMP_IF_RAS_ROUTER : lstrcpy(szIfType, "Demand-dial (Ras router)"); break; case IGMP_IF_RAS_SERVER : lstrcpy(szIfType, "LocalWorkstation-dial (Ras server)"); break; //ras client config will never be returned // is proxy type. default : if (IS_IFTYPE_PROXY(pConfig->IfType)) { if (pConfig->IfType&IGMP_IF_NOT_RAS) lstrcpy(szIfType, "Permanent (Igmp Proxy)"); else lstrcpy(szIfType, "Demand-dial (Igmp Proxy)"); } else lstrcpy(szIfType, "Unknown type"); break; } WRITELINE( hConsole, *pc, "Interface Index: 0x%0x", pConfig->IfIndex ); WRITELINE( hConsole, *pc, "Interface Ip Address: %s", INET_NTOA(pConfig->IpAddr) ); WRITELINE( hConsole, *pc, "Interface Type: %s", szIfType ); switch (pConfig->IgmpProtocolType) { case IGMP_ROUTER_V1 : lstrcpy(szProtoType, "Igmp Router ver-1"); break; case IGMP_ROUTER_V2 : lstrcpy(szProtoType, "Igmp Router ver-2"); break; case IGMP_ROUTER_V3 : lstrcpy(szProtoType, "Igmp Router ver-3"); break; case IGMP_PROXY : case IGMP_PROXY_V3 : lstrcpy(szProtoType, "Igmp Proxy"); break; default: { BYTE str[40]; sprintf(str, "Illegal protocol Id: %d", pConfig->IgmpProtocolType); lstrcpy(szProtoType, str); break; } } WRITELINE( hConsole, *pc, "Protocol: %s", szProtoType ); // // No config info for proxy // if (IS_CONFIG_IGMPPROXY(pConfig)) { ; } // // print igmp-router config info // else { WRITELINE( hConsole, *pc, "Robustness variable: %d", pConfig->RobustnessVariable ); WRITELINE( hConsole, *pc, "Startup query interval: %d", pConfig->StartupQueryInterval ); WRITELINE( hConsole, *pc, "Startup query count: %d", pConfig->StartupQueryCount ); WRITELINE( hConsole, *pc, "General query interval: %d", pConfig->GenQueryInterval ); WRITELINE( hConsole, *pc, "General query max response time: %d", pConfig->GenQueryMaxResponseTime ); WRITELINE( hConsole, *pc, "Last member query interval: %d (ms)", pConfig->LastMemQueryInterval ); WRITELINE( hConsole, *pc, "Last member query count: %d", pConfig->LastMemQueryCount ); WRITELINE( hConsole, *pc, "Other querier present interval: %d", pConfig->OtherQuerierPresentInterval ); WRITELINE( hConsole, *pc, "Group membership timeout: %d", pConfig->GroupMembershipTimeout ); } //end if not proxy interface // // print static groups // if (pConfig->NumStaticGroups>0) { PIGMP_STATIC_GROUP pStaticGroup; DWORD i; PCHAR StaticModes[3] = {"", "IGMP_HOST_JOIN", "IGMPRTR_JOIN_MGM_ONLY"}; WRITELINE( hConsole, *pc, "NumStaticGroups: %d", pConfig->NumStaticGroups ); pStaticGroup = GET_FIRST_IGMP_STATIC_GROUP(pConfig); for (i=0; iNumStaticGroups; i++,pStaticGroup++) { WRITELINE3( hConsole, *pc, " %d. %-15s %s", i+1, INET_NTOA(pStaticGroup->GroupAddr), StaticModes[pStaticGroup->Mode] ); } } pConfig = (PIGMP_MIB_IF_CONFIG) ((PBYTE)(pConfig) + IGMP_MIB_IF_CONFIG_SIZE(pConfig)); } //end for loop; print each global config pQuery->TypeId = IGMP_IF_CONFIG_ID; pQuery->IfIndex = LastIfIndex; return; } //end _PrintIfConfig //------------------------------------------------------------------------------ // _PrintIfStats //------------------------------------------------------------------------------ VOID PrintIfStats( HANDLE hConsole, PCOORD pc, PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse ) { PIGMP_MIB_IF_STATS pStats; CHAR szIfType[50]; CHAR szProtoType[50], szState[100]; DWORD LastIfIndex=0, Count; pStats = (PIGMP_MIB_IF_STATS)pResponse->Buffer; for (Count=0; CountCount; Count++,pStats++) { WRITE_NEWLINE(hConsole, *pc); LastIfIndex = pStats->IfIndex; switch (pStats->IfType) { case IGMP_IF_NOT_RAS : lstrcpy(szIfType, "Permanent"); break; case IGMP_IF_RAS_ROUTER : lstrcpy(szIfType, "Demand-dial (Ras router)"); break; case IGMP_IF_RAS_SERVER : lstrcpy(szIfType, "LocalWorkstation-dial (Ras server)"); break; case IGMP_IF_RAS_CLIENT : lstrcpy(szIfType, "RemoteWorkstation-dial (Ras client)"); break; // is proxy type. default : if (IS_IFTYPE_PROXY(pStats->IfType)) { if (pStats->IfType&IGMP_IF_NOT_RAS) lstrcpy(szIfType, "Permanent (Igmp Proxy)"); else lstrcpy(szIfType, "Demand-dial (Igmp Proxy)"); } else lstrcpy(szIfType, "Unknown type"); break; } WRITELINE( hConsole, *pc, "Interface Index: 0x%0x", pStats->IfIndex ); WRITELINE( hConsole, *pc, "Interface Type: %s", szIfType ); WRITELINE( hConsole, *pc, "Interface Ip Address: %s", INET_NTOA(pStats->IpAddr) ); // // print the protocol type // switch (pStats->IgmpProtocolType) { case IGMP_ROUTER_V1 : lstrcpy(szProtoType, "Igmp Router ver-1"); break; case IGMP_ROUTER_V2 : lstrcpy(szProtoType, "Igmp Router ver-2"); break; case IGMP_ROUTER_V3 : lstrcpy(szProtoType, "Igmp Router ver-3"); break; case IGMP_PROXY : case IGMP_PROXY_V3 : lstrcpy(szProtoType, "Igmp Proxy"); break; } WRITELINE( hConsole, *pc, "Protocol: %s", szProtoType ); // // print the state // { PCHAR szBool[2] = {"N", "Y"}; szState[0] = '\0'; if (!(pStats->State&IGMP_STATE_BOUND)) lstrcat(szState, " "); lstrcat(szState, "State&IGMP_STATE_ENABLED_BY_RTRMGR)>0]); lstrcat(szState, " Config-"); lstrcat(szState, szBool[(pStats->State&IGMP_STATE_ENABLED_IN_CONFIG)>0]); lstrcat(szState, " MGM-"); lstrcat(szState, szBool[(pStats->State&IGMP_STATE_ENABLED_BY_MGM)>0]); lstrcat(szState, "> "); if (!IS_IFTYPE_PROXY(pStats->IfType)) { if ( (pStats->State&IGMP_STATE_MGM_JOINS_ENABLED) ==IGMP_STATE_MGM_JOINS_ENABLED ) { lstrcat(szState, "JoinsFwdToMGM-Y"); } else lstrcat(szState, "JoinsFwdToMGM-N"); } } WRITELINE( hConsole, *pc, "If-Status: %s", szState ); // // if state is not both bound & enabled, I am done // if ((pStats->State&IGMP_STATE_ACTIVATED)!=IGMP_STATE_ACTIVATED) continue; WRITELINE( hConsole, *pc, "Uptime: %d", pStats->Uptime ); /////////////////// // Stats for proxy /////////////////// if (IS_IFTYPE_PROXY(pStats->IfType)) { WRITELINE( hConsole, *pc, "Num current group members: %d", pStats->CurrentGroupMemberships ); WRITELINE( hConsole, *pc, "Num group memberships added: %d", pStats->GroupMembershipsAdded ); } //////////////////////////////////////////////////////////////// // print igmp-router/ras-server/ras-router/ras client Stats info //////////////////////////////////////////////////////////////// else { // // if Not ras client, print these // if (pStats->IfType!=IGMP_IF_RAS_CLIENT) { //querier or not querier if (pStats->QuerierState&QUERIER) { WRITELINE( hConsole, *pc, "State: %s", "Querier" ); // querier ip addr WRITELINE( hConsole, *pc, "Querier Ip Addr: %s", INET_NTOA(pStats->QuerierIpAddr) ); } else { WRITELINE( hConsole, *pc, "State: %s", "Not Querier" ); // querier ip addr WRITELINE( hConsole, *pc, "Querier Ip Addr: %s", INET_NTOA(pStats->QuerierIpAddr) ); // querier present time left WRITELINE( hConsole, *pc, "QuerierPresentTimeLeft: %d", pStats->QuerierPresentTimeLeft ); } WRITELINE( hConsole, *pc, "LastQuerierChangeTime: %d", pStats->LastQuerierChangeTime ); if (pStats->V1QuerierPresentTimeLeft) { WRITELINE( hConsole, *pc, "V1QuerierPresentTime: %d", pStats->V1QuerierPresentTimeLeft ); } } //end not ras-client WRITELINE( hConsole, *pc, "Num current group members: %d", pStats->CurrentGroupMemberships ); WRITELINE( hConsole, *pc, "Num group memberships added: %d", pStats->GroupMembershipsAdded ); WRITELINE( hConsole, *pc, "Num of Igmp packets received: %d", pStats->TotalIgmpPacketsReceived ); WRITELINE( hConsole, *pc, "Num Igmp-router proto packets recv: %d", pStats->TotalIgmpPacketsForRouter ); WRITELINE( hConsole, *pc, "Num general queries received: %d", pStats->GeneralQueriesReceived ); WRITELINE( hConsole, *pc, "Num wrong version queries: %d", pStats->WrongVersionQueries ); WRITELINE( hConsole, *pc, "Num Joins received: %d", pStats->JoinsReceived ); WRITELINE( hConsole, *pc, "Num leaves received: %d", pStats->LeavesReceived ); WRITELINE( hConsole, *pc, "Num wrong checksum packets: %d", pStats->WrongChecksumPackets ); WRITELINE( hConsole, *pc, "Num short packets received: %d", pStats->ShortPacketsReceived ); WRITELINE( hConsole, *pc, "Num long packets received: %d", pStats->LongPacketsReceived ); WRITELINE( hConsole, *pc, "Num packets without RtrAlert: %d", pStats->PacketsWithoutRtrAlert ); } //end print igmp-router/ras-router/ras-server Stats info } //end for loop; print each stats info pQuery->TypeId = IGMP_IF_STATS_ID; pQuery->IfIndex = LastIfIndex; return; }//end _PrintIfStats //------------------------------------------------------------------------------ // _PrintIfBinding //------------------------------------------------------------------------------ VOID PrintIfBinding( HANDLE hConsole, PCOORD pc, PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse ) { DWORD NumIfs, NumAddrs, NumClients, LastIfIndex; CHAR szAddr[64]; PIGMP_MIB_IF_BINDING pib; PIGMP_MIB_IP_ADDRESS paddr; PDWORD pRasClientAddr; PBYTE ptr; //pointer to next binding ptr = pResponse->Buffer; if (pResponse->Count<=0) //prefast return; for (NumIfs=0; NumIfsCount; NumIfs++) { pib = (PIGMP_MIB_IF_BINDING)ptr; WRITE_NEWLINE(hConsole, *pc); WRITELINE( hConsole, *pc, "Interface Index: 0x%0x", pib->IfIndex ); WRITELINE( hConsole, *pc, "Address Count: %d", pib->AddrCount ); // // Not ras client // if (pib->IfType!=IGMP_IF_RAS_CLIENT) { paddr = IGMP_BINDING_FIRST_ADDR(pib); for (NumAddrs=0; NumAddrsAddrCount; NumAddrs++,paddr++) { INET_COPY(szAddr, paddr->IpAddr); lstrcat(szAddr, " - "); INET_CAT(szAddr, paddr->SubnetMask); WRITELINE( hConsole, *pc, "Address Entry: %s", szAddr ); INET_COPY(szAddr, paddr->IpAddr); lstrcat(szAddr, " - "); INET_CAT(szAddr, paddr->SubnetMask); WRITELINE( hConsole, *pc, "Address Entry: %s", szAddr ); } //Set pointer to the next Interface binding ptr = (PBYTE) (paddr); } //end if not ras client // // Ras client. Print address of ras server, followed by the clients // else { // print ras server address paddr = IGMP_BINDING_FIRST_ADDR(pib); INET_COPY(szAddr, paddr->IpAddr); lstrcat(szAddr, " - "); INET_CAT(szAddr, paddr->SubnetMask); WRITELINE( hConsole, *pc, "Ras server Addr %s", szAddr ); // print addresses of ras clients pRasClientAddr = (PDWORD)(paddr+1); for (NumClients= 0; NumClientsAddrCount-1; NumClients++,pRasClientAddr++) { WRITELINE( hConsole, *pc, "Ras client Addr: %s", INET_NTOA(*pRasClientAddr) ); } //Set pointer to the next Interface binding ptr = (PBYTE) (pRasClientAddr); } } //end print statistics of the interface LastIfIndex = pib->IfIndex; pQuery->TypeId = IGMP_IF_BINDING_ID; pQuery->IfIndex = LastIfIndex; return; }//end _PrintIfBinding //------------------------------------------------------------------------------ // _PrintIfGroupsList //------------------------------------------------------------------------------ VOID PrintIfGroupsList( HANDLE hConsole, PCOORD pc, PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse ) { DWORD i, j, LastIfIndex, Flags; CHAR szAddr[64], szFlags[4]; PIGMP_MIB_IF_GROUPS_LIST pIfGroupList; PBYTE ptr; PMIB_GROUP_INFO_V3 pGIInfo; PMIB_PROXY_GROUP_INFO_V3 pGIProxyInfo; BOOL bProxy; DWORD bVer3; ptr = pResponse->Buffer; pIfGroupList = (PIGMP_MIB_IF_GROUPS_LIST) ptr; bProxy = IS_IFTYPE_PROXY(pIfGroupList->IfType); bVer3 = pResponse->Flags & IGMP_ENUM_FORMAT_IGMPV3; if (pQuery->Flags&IGMP_ENUM_INTERFACE_TABLE_BEGIN) { WRITE_NEWLINE(hConsole, *pc); if (bProxy) { WRITELINE( hConsole, *pc, "%s", "ProxyInterface" ); } WRITELINE( hConsole, *pc, "Interface Index: %0x", pIfGroupList->IfIndex ); if (pIfGroupList->NumGroups!=0) { if (bProxy) { WRITELINE( hConsole, *pc, " %s", "GroupAddr UpTime Flags" ); } else { if (!bVer3) { WRITELINE( hConsole, *pc, " %s", "(Ver)GroupAddr LastReporter (Up/Exp)Time Flags V1Host(TimeLeft)" ); } else { WRITELINE( hConsole, *pc, "%s", "(Ver) GroupAddr (Up/Exp)Time Flags V1Host V2Host" ); } } } } // // print all groups which are members on this interface // if (bProxy) pGIProxyInfo = (PMIB_PROXY_GROUP_INFO_V3)pIfGroupList->Buffer; else pGIInfo = (PMIB_GROUP_INFO_V3)pIfGroupList->Buffer; for (j=0; jNumGroups; j++) { Flags = (bProxy)? pGIProxyInfo->Flags: pGIInfo->Flags; sprintf(szFlags, " "); if (Flags&IGMP_GROUP_TYPE_NON_STATIC) szFlags[0] = 'L'; if (Flags&IGMP_GROUP_TYPE_STATIC) szFlags[1] = 'S'; if (Flags&IGMP_GROUP_FWD_TO_MGM) szFlags[2] = 'F'; // // proxy interface // if (bProxy) { WRITELINE3( hConsole, *pc, " %-15s %10d %s", INET_NTOA(pGIProxyInfo->GroupAddr), pGIProxyInfo->GroupUpTime, szFlags ); if (bVer3) { DWORD SrcCnt; CHAR JoinMode = ' '; CHAR JoinModeIntended = ' '; for (SrcCnt=0; SrcCntNumSources; SrcCnt++) { if (pGIProxyInfo->Sources[SrcCnt].Flags & IGMP_GROUP_ALLOW) JoinMode = 'A'; if (pGIProxyInfo->Sources[SrcCnt].Flags & IGMP_GROUP_BLOCK) JoinMode = 'B'; if (pGIProxyInfo->Sources[SrcCnt].Flags & IGMP_GROUP_NO_STATE) JoinMode = '-'; if (pGIProxyInfo->Sources[SrcCnt].Flags & (IGMP_GROUP_ALLOW<<4)) JoinModeIntended = 'A'; if (pGIProxyInfo->Sources[SrcCnt].Flags & (IGMP_GROUP_BLOCK<<4)) JoinModeIntended = 'B'; if (pGIProxyInfo->Sources[SrcCnt].Flags & (IGMP_GROUP_NO_STATE<<4)) JoinModeIntended = '-'; WRITELINE3( hConsole, *pc, " - %-15s:%c:%c", INET_NTOA(pGIProxyInfo->Sources[SrcCnt].Source), JoinMode,JoinModeIntended ); } } } // // non-proxy interface // else if (!bProxy && !bVer3){ CHAR szGroupAddr[64], szLastReporter[64], szExpTime[50]; DWORD GroupVersion = (pGIInfo->V1HostPresentTimeLeft)?1:2; CHAR szV1HostPresent[10]; INET_COPY(szGroupAddr, pGIInfo->GroupAddr); INET_COPY(szLastReporter, pGIInfo->LastReporter); szV1HostPresent[0] = 'N'; szV1HostPresent[1] = '\0'; if (pGIInfo->V1HostPresentTimeLeft!=0) sprintf(szV1HostPresent, "%d", pGIInfo->V1HostPresentTimeLeft); sprintf(szExpTime, "%d", pGIInfo->GroupExpiryTime); if ( (Flags&IGMP_GROUP_TYPE_STATIC) && !(Flags&IGMP_GROUP_TYPE_NON_STATIC) ) { sprintf(szExpTime, "inf"); sprintf(szLastReporter, " -"); } WRITELINE7( hConsole, *pc, "[%d] %-13s %-15s %7d|%3s %3s %-10s", GroupVersion, szGroupAddr, szLastReporter, pGIInfo->GroupUpTime, szExpTime, szFlags, szV1HostPresent ); } else if (!bProxy && bVer3) { CHAR szGroupAddr[64], szExpTime[50], szFilter[10]; CHAR szV1HostPresent[10], szV2HostPresent[10]; DWORD GroupVersion = pGIInfo->Version, SrcCnt=0; INET_COPY(szGroupAddr, pGIInfo->GroupAddr); szV1HostPresent[0] = szV2HostPresent[0] = 'N'; szV1HostPresent[1] = szV2HostPresent[1] = '\0'; if (pGIInfo->V1HostPresentTimeLeft!=0) sprintf(szV1HostPresent, "%d", pGIInfo->V1HostPresentTimeLeft); if (pGIInfo->V2HostPresentTimeLeft!=0) sprintf(szV2HostPresent, "%d", pGIInfo->V2HostPresentTimeLeft); if (GroupVersion==3 && pGIInfo->FilterType==INCLUSION) sprintf(szExpTime, "-na"); else //if (pGIInfo->FilterType==exclusion) sprintf(szExpTime, "%d", pGIInfo->GroupExpiryTime); if ( (Flags&IGMP_GROUP_TYPE_STATIC) && !(Flags&IGMP_GROUP_TYPE_NON_STATIC) ) { sprintf(szExpTime, "inf"); } if (GroupVersion==3) { sprintf(szFilter, "%s", pGIInfo->FilterType==INCLUSION? "[IN]" : "[EX]"); } else strcpy(szFilter, " "); WRITELINE8( hConsole, *pc, "[%d] %-13s%s %7d|%3s %3s %5s %-5s", GroupVersion, szGroupAddr, szFilter, pGIInfo->GroupUpTime, szExpTime, szFlags, szV1HostPresent, szV2HostPresent ); if (GroupVersion==3) { for (SrcCnt=0; SrcCntNumSources; SrcCnt++) { if (pGIInfo->Sources[SrcCnt].SourceExpiryTime==~0) sprintf(szExpTime, "%s", "inf"); else { sprintf(szExpTime, "%d", pGIInfo->Sources[SrcCnt].SourceExpiryTime/1000); } WRITELINE3( hConsole, *pc, " - %-13s %7d|%-s", INET_NTOA(pGIInfo->Sources[SrcCnt].Source), pGIInfo->Sources[SrcCnt].SourceUpTime, szExpTime ); } } } // // increment pGIInfo/pGIProxyInfo // if (bProxy) { if (bVer3) pGIProxyInfo = (PMIB_PROXY_GROUP_INFO_V3) &pGIProxyInfo->Sources[pGIProxyInfo->NumSources]; else pGIProxyInfo = (PMIB_PROXY_GROUP_INFO_V3) ((PMIB_PROXY_GROUP_INFO)pGIProxyInfo+1); } else { if (bVer3) pGIInfo = (PMIB_GROUP_INFO_V3) &pGIInfo->Sources[pGIInfo->NumSources]; else pGIInfo = (PMIB_GROUP_INFO_V3) ((PMIB_GROUP_INFO)pGIInfo+1); } } pQuery->TypeId = IGMP_IF_GROUPS_LIST_ID; pQuery->IfIndex = pIfGroupList->IfIndex; return; }//end _PrintIfGroupsList //------------------------------------------------------------------------------ // _PrintGroupIfsList //------------------------------------------------------------------------------ VOID PrintGroupIfsList( HANDLE hConsole, PCOORD pc, PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse ) { DWORD i, j, LastGroupAddr; CHAR szGroupAddr[22]; PIGMP_MIB_GROUP_IFS_LIST pGroupIfsList; PMIB_GROUP_INFO_V3 pGIInfo; PBYTE ptr; DWORD bVer3; ptr = pResponse->Buffer; bVer3 = pResponse->Flags & IGMP_ENUM_FORMAT_IGMPV3; if (pResponse->Count<=0) //prefast return; for (i=0; iCount; i++) { pGroupIfsList = (PIGMP_MIB_GROUP_IFS_LIST) ptr; INET_COPY(szGroupAddr, pGroupIfsList->GroupAddr); // // print all GIs which are members on this group // pGIInfo = (PMIB_GROUP_INFO_V3)pGroupIfsList->Buffer; for (j=0; jNumInterfaces; j++) { CHAR szIpAddr[16], szLastReporter[16], szV1Host[4], szV1HostTimeLeft[10], szFlags[5], szGroupExpTime[10]; sprintf(szFlags, " "); if (pGIInfo->Flags&IGMP_GROUP_TYPE_NON_STATIC) szFlags[0] = 'L'; if (pGIInfo->Flags&IGMP_GROUP_TYPE_STATIC) szFlags[1] = 'S'; if (pGIInfo->Flags&IGMP_GROUP_FWD_TO_MGM) szFlags[2] = 'F'; INET_COPY(szIpAddr, pGIInfo->IpAddr); if (!bVer3){ CHAR szExpTime[50]; DWORD GroupVersion = (pGIInfo->V1HostPresentTimeLeft)?1:2; CHAR szV1HostPresent[10]; INET_COPY(szGroupAddr, pGIInfo->GroupAddr); INET_COPY(szLastReporter, pGIInfo->LastReporter); szV1HostPresent[0] = '\0'; if (pGIInfo->V1HostPresentTimeLeft!=0) sprintf(szV1HostPresent, "%d", pGIInfo->V1HostPresentTimeLeft); sprintf(szExpTime, "%d", pGIInfo->GroupExpiryTime); if ( (pGIInfo->Flags&IGMP_GROUP_TYPE_STATIC) && !(pGIInfo->Flags&IGMP_GROUP_TYPE_NON_STATIC) ) { sprintf(szExpTime, "inf"); sprintf(szLastReporter, " -"); } WRITELINE9( hConsole, *pc, "[%d] %-12s %7d|%-3s %3s <%d:%-14s> %-12s %5s", GroupVersion, szGroupAddr, pGIInfo->GroupUpTime, szExpTime, szFlags, pGIInfo->IfIndex, szIpAddr, szLastReporter, szV1HostPresent ); } else { CHAR szExpTime[50], szFilter[10]; CHAR szV1HostPresent[10], szV2HostPresent[10]; DWORD GroupVersion = pGIInfo->Version, SrcCnt=0; INET_COPY(szGroupAddr, pGroupIfsList->GroupAddr); szV1HostPresent[0] = szV2HostPresent[0] = 'N'; szV1HostPresent[1] = szV2HostPresent[1] = '\0'; if (pGIInfo->V1HostPresentTimeLeft!=0) sprintf(szV1HostPresent, "%d", pGIInfo->V1HostPresentTimeLeft); if (pGIInfo->V2HostPresentTimeLeft!=0) sprintf(szV2HostPresent, "%d", pGIInfo->V2HostPresentTimeLeft); if (GroupVersion==3 && pGIInfo->FilterType==INCLUSION) sprintf(szExpTime, "-na"); else //if (pGIInfo->FilterType==exclusion) sprintf(szExpTime, "%d", pGIInfo->GroupExpiryTime); if ( (pGIInfo->Flags&IGMP_GROUP_TYPE_STATIC) && !(pGIInfo->Flags&IGMP_GROUP_TYPE_NON_STATIC) ) { sprintf(szExpTime, "inf"); } if (GroupVersion==3) { strcpy(szFilter, pGIInfo->FilterType==INCLUSION?"[IN]" : "[EX]"); } else strcpy(szFilter, " "); WRITELINE10( hConsole, *pc, "[%d] %-12s%s %7d|%-3s %3s <%d:%-14s> %20s %5s", GroupVersion, szGroupAddr, szFilter, pGIInfo->GroupUpTime, szExpTime, szFlags, pGIInfo->IfIndex, szIpAddr, szV1HostPresent, szV2HostPresent ); if (GroupVersion==3) { for (SrcCnt=0; SrcCntNumSources; SrcCnt++) { if (pGIInfo->Sources[SrcCnt].SourceExpiryTime==~0) sprintf(szExpTime, "%s", "inf"); else { sprintf(szExpTime, "%d", pGIInfo->Sources[SrcCnt].SourceExpiryTime/1000); } WRITELINE3( hConsole, *pc, " - %-12s %7d|%s", INET_NTOA(pGIInfo->Sources[SrcCnt].Source), pGIInfo->Sources[SrcCnt].SourceUpTime, szExpTime ); } } } if (bVer3) pGIInfo = (PMIB_GROUP_INFO_V3) &pGIInfo->Sources[pGIInfo->NumSources]; else pGIInfo = (PMIB_GROUP_INFO_V3) ((PMIB_GROUP_INFO)pGIInfo+1); } //for loop: end print all GIs ptr = (PBYTE)pGIInfo; } LastGroupAddr= pGroupIfsList->GroupAddr; pQuery->TypeId = IGMP_GROUP_IFS_LIST_ID; pQuery->GroupAddr = LastGroupAddr; return; }//end _PrintGroupIfsList #endif MIB_DEBUG DWORD ListLength( PLIST_ENTRY pHead ) { DWORD Len=0; PLIST_ENTRY ple; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink,Len++) ; return Len; } //------------------------------------------------------------------------------ // _MibGet // // Called by an admin (SNMP) utility. It actually passes through the // IP Router Manager, but all that does is demux the call to the // desired routing protocol // // Calls: _MibGetInternal() with GETMODE_EXACT. // Locks: Takes no locks. _MibGetInternal() will get the locks it requires //------------------------------------------------------------------------------ DWORD APIENTRY MibGet( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData ) { DWORD Error=NO_ERROR; PIGMP_MIB_GET_INPUT_DATA pQuery; PIGMP_MIB_GET_OUTPUT_DATA pResponse; if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; } Trace1(MIB, "entering _MibGet(): dwInputSize(%d)", dwInputSize); if ( (pInputData == NULL) || (dwInputSize < sizeof(IGMP_MIB_GET_INPUT_DATA)) || (pdwOutputSize == NULL) ) { Error = ERROR_INVALID_PARAMETER; } else { pQuery = (PIGMP_MIB_GET_INPUT_DATA)pInputData; // with GETMODE_EXACT you can get only one pQuery->Count = 1; pResponse = (PIGMP_MIB_GET_OUTPUT_DATA)pOutputData; Error = MibGetInternal(pQuery, pResponse, pdwOutputSize, GETMODE_EXACT); } Trace1(MIB, "leaving _MibGet(): %d", Error); LeaveIgmpApi(); return Error; } //------------------------------------------------------------------------------ // MibGetFirst // // Calls: _MibGetInternal() with GETMODE_FIRST // Locks: No locks taken here. _MibGetInternal() takes the locks it requires //------------------------------------------------------------------------------ DWORD APIENTRY MibGetFirst( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData ) { DWORD Error=NO_ERROR; PIGMP_MIB_GET_INPUT_DATA pQuery; PIGMP_MIB_GET_OUTPUT_DATA pResponse; if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; } Trace4(MIB, "entering _MibGetFirst(): dwInputSize(%d) pInputData(%08x)" "pdwOutputSize(%08x) pOutputData(%08x)", dwInputSize, pInputData, pdwOutputSize, pOutputData); if ( (pInputData == NULL) || (dwInputSize < sizeof(IGMP_MIB_GET_INPUT_DATA)) || (pdwOutputSize == NULL) ) { Error = ERROR_INVALID_PARAMETER; } else { pQuery = (PIGMP_MIB_GET_INPUT_DATA)pInputData; if (pQuery->Count<=0) pQuery->Count = 1; pResponse = (PIGMP_MIB_GET_OUTPUT_DATA)pOutputData; Error = MibGetInternal(pQuery, pResponse, pdwOutputSize, GETMODE_FIRST); } Trace1(MIB, "leaving _MibGetFirst: %d", Error); LeaveIgmpApi(); return Error; } //------------------------------------------------------------------------------ // _MibGetNext // // This call returns the entry in the table AFTER the one specified in the input. // If the end of the table being queried has been reached, this function will // return the FIRST entry from the NEXT table, where "NEXT" here means the // table whose ID is one greater than the ID passed in. // In any case, this function writes the required size to pdwOutputSize and // writes the ID of the object that WOULD have been returned into the output // buffer. // // Calls: // _MibGetInternal() with GETMODE_NEXT. If end of table reached, calls // _MibGetInternal() again with GETMODE_FIRST for the next table. //------------------------------------------------------------------------------ DWORD APIENTRY MibGetNext( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData ) { DWORD Error = NO_ERROR; DWORD dwOutSize = 0, dwBufSize = 0; PIGMP_MIB_GET_INPUT_DATA pQuery; PIGMP_MIB_GET_OUTPUT_DATA pResponse; if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; } Trace4(MIB, "entering _MibGetNext(): dwInputSize(%d) pInputData(%08x) " "pdwOutputSize(%08x) pOutputData(%08x)", dwInputSize, pInputData, pdwOutputSize, pOutputData); if (pInputData == NULL || dwInputSize < sizeof(IGMP_MIB_GET_INPUT_DATA) || pdwOutputSize == NULL) { Error = ERROR_INVALID_PARAMETER; } else { pQuery = (PIGMP_MIB_GET_INPUT_DATA)pInputData; pResponse = (PIGMP_MIB_GET_OUTPUT_DATA)pOutputData; if (pQuery->Count<=0) pQuery->Count = 1; dwOutSize = *pdwOutputSize; Error = MibGetInternal(pQuery, pResponse, pdwOutputSize, GETMODE_NEXT); if ((Error==ERROR_NO_MORE_ITEMS) && (pQuery->Flags&IGMP_ENUM_ALL_TABLES) ) { // // need to wrap to the first entry in the next table, // if there is a next table // *pdwOutputSize = dwOutSize; // // wrap to next table by incrementing the type ID // do { ++pQuery->TypeId; Error = MibGetInternal(pQuery, pResponse, pdwOutputSize, GETMODE_FIRST); } while ( (Error==ERROR_INVALID_PARAMETER)&&(pQuery->TypeId<=IGMP_LAST_TABLE_ID) ); --pQuery->TypeId; } } Trace1(MIB, "leaving _MibGetNext(): %d", Error); LeaveIgmpApi(); return Error; } //------------------------------------------------------------------------------ // Function: _MibGetInternal // // This handles the actual structure access required to read MIB data. // Each table supported by IGMP supports three modes of querying; // EXACT, FIRST, and NEXT, which correspond to the functions _MibGet(), // _MibGetFirst(), and _MibGetNext() respectively. //------------------------------------------------------------------------------ DWORD MibGetInternal( PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse, PDWORD pdwOutputSize, DWORD dwGetMode ) { DWORD Error = NO_ERROR, dwBufferSize; // // first we use pdwOutputSize to compute the size of the buffer // available for storing returned structures (the size of Buffer) // if (pResponse == NULL) { dwBufferSize = 0; } else { if (*pdwOutputSize < sizeof(IGMP_MIB_GET_OUTPUT_DATA)) { dwBufferSize = 0; } else { dwBufferSize = *pdwOutputSize - sizeof(IGMP_MIB_GET_OUTPUT_DATA) + 1; //kslksl if (dwBufferSize>150) dwBufferSize -= 150; } } *pdwOutputSize = 0; // set flag for ras stats if pQuery has it and config supports it if (pResponse!=NULL) { pResponse->Flags = 0; if ( (pQuery->Flags&IGMP_ENUM_FOR_RAS_CLIENTS) && (g_Config.RasClientStats) ) { pResponse->Flags |= IGMP_ENUM_FOR_RAS_CLIENTS; } } // // determine which type of data is to be returned // switch (pQuery->TypeId) { case IGMP_GLOBAL_STATS_ID: { // // there is only one global config object, // so GETMODE_NEXT will return ERROR_NO_MORE_ITEMS // if (pResponse!=NULL) pResponse->TypeId = IGMP_GLOBAL_STATS_ID; if (dwGetMode == GETMODE_NEXT) { Error = ERROR_NO_MORE_ITEMS; break; } *pdwOutputSize = sizeof(IGMP_MIB_GLOBAL_STATS); if (pResponse == NULL) { Error = ERROR_INSUFFICIENT_BUFFER; break; } // make sure that the buffer size is big enough if (dwBufferSize < sizeof(IGMP_MIB_GLOBAL_STATS)) { Error = ERROR_INSUFFICIENT_BUFFER; break; } // set the values else { PIGMP_MIB_GLOBAL_STATS pGlobalStats; pGlobalStats = (PIGMP_MIB_GLOBAL_STATS)pResponse->Buffer; pGlobalStats->CurrentGroupMemberships = g_Info.CurrentGroupMemberships; pGlobalStats->GroupMembershipsAdded = g_Info.GroupMembershipsAdded; } pResponse->Count = 1; break; }//end case IGMP_GLOBAL_STATS_ID case IGMP_GLOBAL_CONFIG_ID: { // // there is only one global config object, // so GETMODE_NEXT will return ERROR_NO_MORE_ITEMS // if (pResponse!=NULL) pResponse->TypeId = IGMP_GLOBAL_CONFIG_ID; if (dwGetMode == GETMODE_NEXT) { Error = ERROR_NO_MORE_ITEMS; break; } *pdwOutputSize = sizeof(IGMP_MIB_GLOBAL_CONFIG); if (pResponse == NULL) { Error = ERROR_INSUFFICIENT_BUFFER; break; } if (dwBufferSize < sizeof(IGMP_MIB_GLOBAL_CONFIG)) { Error = ERROR_INSUFFICIENT_BUFFER; } else { CopyMemory(pResponse->Buffer, &g_Config, sizeof(IGMP_MIB_GLOBAL_CONFIG)); } pResponse->Count = 1; break; } //end case IGMP_GLOBAL_CONFIG_ID case IGMP_PROXY_IF_INDEX_ID : { // // there can be only one proxy interface. // so GETMODE_NEXT will return ERROR_NO_MORE_ITEMS // if (pResponse!=NULL) pResponse->TypeId = IGMP_PROXY_IF_INDEX_ID; if (dwGetMode == GETMODE_NEXT) { Error = ERROR_NO_MORE_ITEMS; break; } *pdwOutputSize = sizeof(DWORD); if (pResponse == NULL) { Error = ERROR_INSUFFICIENT_BUFFER; break; } // make sure that the buffer size is big enough if (dwBufferSize < sizeof(DWORD)) { Error = ERROR_INSUFFICIENT_BUFFER; break; } // set the values else { DWORD *pProxyIndex; pProxyIndex = (DWORD*)pResponse->Buffer; *pProxyIndex = g_ProxyIfIndex; } pResponse->Count = 1; break; } //end case IGMP_PROXY_IF_INDEX_ID case IGMP_IF_BINDING_ID : { Error = MibGetInternalIfBindings(pQuery, pResponse, pdwOutputSize, dwGetMode, dwBufferSize); break; } case IGMP_IF_STATS_ID: { // // set the size needed. It will be set again at the end to the // exact size used. // if (pQuery->Count==0) { Error = ERROR_INVALID_PARAMETER; break; } Error = MibGetInternalIfStats(pQuery, pResponse, pdwOutputSize, dwGetMode, dwBufferSize); break; } //end case IGMP_IF_STATS_ID case IGMP_IF_CONFIG_ID: { if (pQuery->Count==0) { Error = ERROR_INVALID_PARAMETER; break; } Error = MibGetInternalIfConfig(pQuery, pResponse, pdwOutputSize, dwGetMode, dwBufferSize); break; } //end case IGMP_IF_CONFIG_ID // I cant get the list of groups for a RAS server interface case IGMP_IF_GROUPS_LIST_ID : { PIGMP_MIB_IF_GROUPS_LIST pIfGroupList; if (pQuery->Count==0) { Error = ERROR_INVALID_PARAMETER; break; } while (1) { Error = MibGetInternalIfGroupsInfo(pQuery, pResponse, pdwOutputSize, dwGetMode, dwBufferSize); if ( (Error!=NO_ERROR) || (pResponse==NULL) ) break; pIfGroupList = (PIGMP_MIB_IF_GROUPS_LIST)pResponse->Buffer; if ( (pIfGroupList->NumGroups==0) && (pQuery->Flags&IGMP_ENUM_ALL_INTERFACES_GROUPS) && (pQuery->Flags&IGMP_ENUM_INTERFACE_TABLE_END) && !(pQuery->Flags&IGMP_ENUM_INTERFACE_TABLE_BEGIN) && !(pQuery->Flags&IGMP_ENUM_INTERFACE_TABLE_CONTINUE) ) { continue; } else break; } break; } //end case IGMP_IF_GROUPS_LIST_ID case IGMP_GROUP_IFS_LIST_ID : { if (pQuery->Count==0) { Error = ERROR_INVALID_PARAMETER; break; } Error = MibGetInternalGroupIfsInfo(pQuery, pResponse, pdwOutputSize, dwGetMode, dwBufferSize); break; } //end case IGMP_GROUP_IFS_LIST_ID // set this for group statistics ERROR_NO_MORE_ITEMS default: { Error = ERROR_INVALID_PARAMETER; } } //end switch if (pdwOutputSize) *pdwOutputSize += sizeof(IGMP_MIB_GET_OUTPUT_DATA); //kslksl if (pdwOutputSize && Error==ERROR_INSUFFICIENT_BUFFER) *pdwOutputSize = *pdwOutputSize+500; return Error; } //_MibGetInternal //------------------------------------------------------------------------------ // MibGetInternalIfBindings // // Returns the binding info of pQuery->Count number of interfaces. // //Locks: // Takes the IfLists lock so that the InterfaceList does not change in between. // It also prevents the bindings from being changed, as (Un)Bind If takes this lock. //------------------------------------------------------------------------------ DWORD MibGetInternalIfBindings ( PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse, PDWORD pdwOutputSize, DWORD dwGetMode, DWORD dwBufferSize ) { PIF_TABLE_ENTRY pite; PIGMP_MIB_IF_BINDING pBindingDst; PIGMP_IF_BINDING pBindingSrc; DWORD dwSize, dwSizeCur=0, dwCount, Error=NO_ERROR; Trace0(MIB, "Entering _MibGetInternalIfBinding"); if (pResponse!=NULL) { pResponse->TypeId = IGMP_IF_BINDING_ID; pBindingDst = (PIGMP_MIB_IF_BINDING)pResponse->Buffer; } ACQUIRE_IF_LIST_LOCK("_MibGetInternalBindings"); for (dwCount=0, dwSize=0; dwCountCount; ) { // // retrieve the interface whose binding is to be read // pite = GetIfByListIndex(pQuery->IfIndex, dwGetMode, &Error); // // if the interface was found, it may mean that the index // specified was invalid, or it may mean that a GETMODE_NEXT // retrieval was attempted on the last interface, in which case // ERROR_NO_MORE_ITEMS would have been returned. // if (pite == NULL) { if (dwCount>0) Error = NO_ERROR; // count==0 else { if (Error == NO_ERROR) Error = ERROR_INVALID_PARAMETER; *pdwOutputSize = 0; } break; //from for loop } // dont have to take the interface lock, as IfLists lock is // taken before bindings are changed. // // compute the size of the interface binding retrieved, // and write it over the caller's supplied size // pBindingSrc = pite->pBinding; dwSizeCur = (pBindingSrc ? sizeof(IGMP_MIB_IF_BINDING) +pBindingSrc->AddrCount*(sizeof(IGMP_MIB_IP_ADDRESS)) : sizeof(IGMP_MIB_IF_BINDING)); // // if no buffer was specified, indicate one should be allocated // if (pResponse == NULL) { Error = ERROR_INSUFFICIENT_BUFFER; break; //for loop } // // if the buffer is not large enough, // indicate that it should be enlarged // if (dwBufferSize < dwSize + dwSizeCur) { if (dwCount==0) Error = ERROR_INSUFFICIENT_BUFFER; break; //from for loop } // // copy the binding // if (pBindingSrc!=NULL) { pBindingDst->AddrCount = pBindingSrc->AddrCount; CopyMemory(pBindingDst+1, pBindingSrc+1, pBindingSrc->AddrCount*(sizeof(IGMP_MIB_IP_ADDRESS))); } else { pBindingDst->AddrCount = 0; } pBindingDst->IfIndex = pite->IfIndex; pBindingDst->IfType = GET_EXTERNAL_IF_TYPE(pite); GET_EXTERNAL_IF_STATE(pite, pBindingDst->State); pQuery->IfIndex = pite->IfIndex; pQuery->RasClientAddr = 0; dwCount++; dwSize += dwSizeCur; pBindingDst = (PIGMP_MIB_IF_BINDING) ((PBYTE)pBindingDst + dwSizeCur); // if GetMode==GETMODE_FIRST change it to GETMODE_NEXT. if (dwGetMode==GETMODE_FIRST) dwGetMode = GETMODE_NEXT; }//end for loop //set size if bindings have been copied. else it has already been set if (dwCount>0) { *pdwOutputSize = dwSize; } else { *pdwOutputSize = dwSizeCur; } if (pResponse!=NULL) { pResponse->Count = dwCount; } RELEASE_IF_LIST_LOCK("_MibGetInternalBindings"); Trace0(MIB, "Leaving _MibGetInternalIfBinding"); return Error; } //end _MibGetInternalIfBindings //------------------------------------------------------------------------------ // _MibGetInternalGroupIfsInfo //------------------------------------------------------------------------------ DWORD MibGetInternalGroupIfsInfo ( PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse, PDWORD pdwOutputSize, DWORD dwGetMode, DWORD dwBufferSize ) { LONGLONG llCurTime = GetCurrentIgmpTime(); BOOL bRasTableLock=FALSE, bGroupBucketLock=FALSE; PIGMP_MIB_GROUP_IFS_LIST pHeader; PMIB_GROUP_INFO_V3 pGIInfo; PGI_ENTRY pgie; PLIST_ENTRY pHead, ple; DWORD dwSize, dwCurSize, Error=NO_ERROR, dwCount, dwNumIfs, i; DWORD PrevGroup, Group, dwNumIfsCopied; PRAS_TABLE_ENTRY prte; PRAS_TABLE prt, prtOld; PGROUP_TABLE_ENTRY pge; BOOL bEnumV3; //Trace3(MEM, "_MibGetInternalGroupIfsInfo buffer: %0x -> %0x: %d", //(DWORD)pResponse->Buffer, ((DWORD)pResponse->Buffer)+dwBufferSize, dwBufferSize);//deldel Trace0(MIB, "Entering _MibGetInternalGroupIfsInfo()"); bEnumV3 = pQuery->Flags & IGMP_ENUM_SUPPORT_FORMAT_IGMPV3; // // The data returned for each Interface is variable length // if (pResponse!=NULL) { pResponse->TypeId = IGMP_GROUP_IFS_LIST_ID; pHeader = (PIGMP_MIB_GROUP_IFS_LIST) pResponse->Buffer; // // if GETMODE_FIRST: merge the new and main group lists // if (dwGetMode==GETMODE_FIRST) { ACQUIRE_GROUP_LIST_LOCK("_MibGetInternalGroupIfsInfo"); MergeGroupLists(); RELEASE_GROUP_LIST_LOCK("_MibGetInternalGroupIfsInfo"); } } PrevGroup = pQuery->GroupAddr; for (dwCount=0, dwSize=0; dwCountCount; ) { ACQUIRE_GROUP_LIST_LOCK("_MibGetInternalGroupIfsInfo"); bRasTableLock = FALSE; // // retrieve the groups whose information is to be retrieved // pge = GetGroupByAddr(PrevGroup, dwGetMode, &Error); if (pge == NULL) { if (dwCount>0) Error = NO_ERROR; else { if (Error==NO_ERROR) Error = ERROR_INVALID_PARAMETER; *pdwOutputSize = 0; } RELEASE_GROUP_LIST_LOCK("_MibGetInternalGroupIfsInfo"); break; } Group = pge->Group; if (!IS_MCAST_ADDR(Group)) { Trace0(ERR, "=========================================================="); Trace2(ERR, "bad group(%d.%d.%d.%d)(pge:%0x) MibGetInternalGroupIfsInfo", PRINT_IPADDR(pge->Group), (ULONG_PTR)pge); Trace0(ERR, "=========================================================="); IgmpAssert(FALSE); } RELEASE_GROUP_LIST_LOCK("_MibGetInternalGroupIfsInfo"); // // have to release the group list lock before I acquire the group bucket // lock to prevent deadlock. // // // take group bucket lock // ACQUIRE_GROUP_LOCK(Group, "_MibGetInternalGroupIfsInfo"); bGroupBucketLock = TRUE; // get the group again as it could have been deleted. pge = GetGroupFromGroupTable (Group, NULL, 0); // if the group has been meanwhile deleted, then continue if (pge==NULL) { RELEASE_GROUP_LOCK(Group, "_MibGetInternalGroupIfsInfo"); bGroupBucketLock = FALSE; continue; } // // compute the size of the data returned // dwNumIfs = pge->NumVifs; if (bEnumV3) { pHead = &pge->ListOfGIs; dwCurSize = sizeof(IGMP_MIB_GROUP_IFS_LIST) + dwNumIfs*sizeof(MIB_GROUP_INFO_V3); i = 0; for (ple=pHead->Flink; (ple!=pHead)&&(iFlink,i++) { pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkByGI); if (pgie->Version==3) { dwCurSize += ( (pgie->NumSources + ListLength(&pgie->V3ExclusionList)) *sizeof(IGMP_MIB_GROUP_SOURCE_INFO_V3) ); } } } else { dwCurSize = sizeof(IGMP_MIB_GROUP_IFS_LIST) + dwNumIfs*sizeof(IGMP_MIB_GROUP_INFO); if (pResponse == NULL) { Error = ERROR_INSUFFICIENT_BUFFER; break; } } // // if the buffer is not large enough, break from the loop // if (dwBufferSize < dwSize + dwCurSize) { if (dwCount==0) Error = ERROR_INSUFFICIENT_BUFFER; break;//from for loop } // set fields for group info pHeader->GroupAddr = pge->Group; pHeader->NumInterfaces = dwNumIfs; // // set groupAddr in pQuery so that in the next query, the info for other groups will // be passed // pQuery->GroupAddr = pge->Group; // // copy stats for interfaces that have joined the group. // pGIInfo = (PMIB_GROUP_INFO_V3)pHeader->Buffer; pHead = &pge->ListOfGIs; dwNumIfsCopied = 0; for (ple=pHead->Flink; (ple!=pHead)&&(dwNumIfsCopiedFlink,dwNumIfsCopied++) { DWORD GIVersion; pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkByGI); GIVersion = pgie->Version; pGIInfo->IfIndex = pgie->IfIndex; // // if rasServerIf, then I return the NHAddr in IpAddr field // else return the IpAddr of this field // pGIInfo->IpAddr = (IS_RAS_SERVER_IF(pgie->pIfTableEntry->IfType)) ? pgie->NHAddr : pgie->pIfTableEntry->IpAddr; pGIInfo->GroupExpiryTime = (pgie->Info.GroupExpiryTime==~0) ? ~0 : SYSTEM_TIME_TO_SEC(pgie->Info.GroupExpiryTime-llCurTime); pGIInfo->LastReporter = pgie->Info.LastReporter; pGIInfo->GroupUpTime = SYSTEM_TIME_TO_SEC(llCurTime-pgie->Info.GroupUpTime); if (llCurTimeInfo.V1HostPresentTimeLeft) pGIInfo->V1HostPresentTimeLeft = SYSTEM_TIME_TO_SEC(pgie->Info.V1HostPresentTimeLeft-llCurTime); else pGIInfo->V1HostPresentTimeLeft = 0; if ( llCurTime>=pgie->Info.V2HostPresentTimeLeft) pGIInfo->V2HostPresentTimeLeft = 0; else { pGIInfo->V2HostPresentTimeLeft = SYSTEM_TIME_TO_SEC(pgie->Info.V2HostPresentTimeLeft-llCurTime); } pGIInfo->Flags = 0; if (pgie->bStaticGroup) pGIInfo->Flags |= IGMP_GROUP_TYPE_STATIC; if (pgie->GroupMembershipTimer.Status&TIMER_STATUS_ACTIVE) pGIInfo->Flags |= IGMP_GROUP_TYPE_NON_STATIC; if (CAN_ADD_GROUPS_TO_MGM(pgie->pIfTableEntry)) pGIInfo->Flags |= IGMP_GROUP_FWD_TO_MGM; if (bEnumV3) { PGI_SOURCE_ENTRY pSourceEntry; DWORD V3NumSources, V3SourcesSize; PLIST_ENTRY pHeadSrc, pLESrc; V3NumSources = pgie->NumSources + ListLength(&pgie->V3ExclusionList); V3SourcesSize = sizeof(IGMP_MIB_GROUP_SOURCE_INFO_V3)*V3NumSources; pGIInfo->Version = pgie->Version; pGIInfo->Size = sizeof(MIB_GROUP_INFO_V3) + V3SourcesSize; pGIInfo->FilterType = pgie->FilterType; pGIInfo->NumSources = V3NumSources; pHeadSrc = &pgie->V3InclusionListSorted; i = 0; for (pLESrc=pHeadSrc->Flink; pLESrc!=pHeadSrc; pLESrc=pLESrc->Flink,i++) { pSourceEntry = CONTAINING_RECORD(pLESrc, GI_SOURCE_ENTRY, LinkSourcesInclListSorted); pGIInfo->Sources[i].Source = pSourceEntry->IpAddr; pGIInfo->Sources[i].SourceExpiryTime = (pSourceEntry->bInclusionList) ? QueryRemainingTime(&pSourceEntry->SourceExpTimer, 0) : ~0; pGIInfo->Sources[i].SourceUpTime = (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000; } pHeadSrc = &pgie->V3ExclusionList; for (pLESrc=pHeadSrc->Flink; pLESrc!=pHeadSrc; pLESrc=pLESrc->Flink,i++){ pSourceEntry = CONTAINING_RECORD(pLESrc, GI_SOURCE_ENTRY, LinkSources); pGIInfo->Sources[i].Source = pSourceEntry->IpAddr; pGIInfo->Sources[i].SourceExpiryTime = (pSourceEntry->bInclusionList) ? QueryRemainingTime(&pSourceEntry->SourceExpTimer, 0) : ~0; pGIInfo->Sources[i].SourceUpTime = (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000; } pGIInfo = (PMIB_GROUP_INFO_V3) ((PCHAR)pGIInfo + pGIInfo->Size); //Trace1(MEM, "NextPGIInfo: %0x:", (DWORD)pGIInfo);//deldel } else { pGIInfo = (PMIB_GROUP_INFO_V3)((PMIB_GROUP_INFO)pGIInfo + 1); //Trace1(MEM, "NextPGIInfo: %0x:", (DWORD)pGIInfo);//deldel } } // // everything fine. Copied one more stats struct // dwCount++; dwSize += dwCurSize; pHeader = (PIGMP_MIB_GROUP_IFS_LIST) pGIInfo; PrevGroup = pge->Group; // release the group bucket lock RELEASE_GROUP_LOCK(Group, "_MibGetInternalGroupIfsInfo"); bGroupBucketLock = FALSE; // if GetMode==GETMODE_FIRST change it to GETMODE_NEXT. if (dwGetMode==GETMODE_FIRST) dwGetMode = GETMODE_NEXT; } //end for loop // check if group bucket lock has to be released if (bGroupBucketLock==TRUE) { RELEASE_GROUP_LOCK(Group, "_MibGetInternalGroupIfsInfo"); bGroupBucketLock = FALSE; } if (pResponse!=NULL) { pResponse->Count = dwCount; pResponse->Flags |= IGMP_ENUM_FORMAT_IGMPV3; } // // set the actual size if some info was copied, else let size // remain // if (dwCount>0) *pdwOutputSize = dwSize; else *pdwOutputSize = dwCurSize; Trace0(MIB, "Leaving _MibGetInternalGroupIfsInfo"); return Error; } //end _MibGetInternalGroupIfsInfo //------------------------------------------------------------------------------ // _MibGetInternalIfConfig // // no locks assumed. takes IfList lock //------------------------------------------------------------------------------ DWORD MibGetInternalIfConfig ( PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse, PDWORD pdwOutputSize, DWORD dwGetMode, DWORD dwBufferSize ) { // // the interface config struct is variable size. // there may be multiple instances. // PIGMP_IF_TABLE pTable = g_pIfTable; PIF_TABLE_ENTRY pite; PIGMP_MIB_IF_CONFIG pIfConfigDst; PIGMP_IF_CONFIG pIfConfigSrc; DWORD dwCount, dwSize, dwSizeCur=0, Error = NO_ERROR; if (pResponse!=NULL) { pResponse->TypeId = IGMP_IF_CONFIG_ID; pIfConfigDst = (PIGMP_MIB_IF_CONFIG)pResponse->Buffer; } // acquire IfLists lock so that you can access the interface lists ACQUIRE_IF_LIST_LOCK("MibGetInternalIfConfig"); for (dwCount=0,dwSize=0; dwCountCount; ) { // // retrieve the interface whose config are to be read // pite = GetIfByListIndex(pQuery->IfIndex, dwGetMode, &Error); // I dont have to take the interface lock, as the IfLists lock is // taken before interface config is changed or interface is deleted. //ACQUIRE_IF_LOCK_SHARED(IfIndex, "MibGetInternal"); // // if the interface was not found, it may mean // the specified index was invalid, or it may mean // that the GETMODE_NEXT was called on the last interface // in which case ERROR_NO_MORE_ITEMS was returned. // In any case, we make sure Error indicates an error // and then return the value. // // if the interface was found but no output buffer was passed, // indicate in the error that memory needs to be allocated. // // otherwise, copy the config struct of the interface // if (pite == NULL) { if (dwCount>0) { Error = NO_ERROR; } // count==0 else { if (Error == NO_ERROR) Error = ERROR_INVALID_PARAMETER; *pdwOutputSize = 0; } break; //from for loop } pIfConfigSrc = &pite->Config; dwSizeCur = pIfConfigSrc->ExtSize; // // if no buffer was specified, indicate one should be allocated // if (pResponse==NULL) { Error = ERROR_INSUFFICIENT_BUFFER; break; } // // see if adequate buffer is left for the next struct // if (dwBufferSize < dwSize+dwSizeCur) { if (dwCount==0) { Error = ERROR_INSUFFICIENT_BUFFER; } break;//from for loop } // // copy the interface config, and set the IP address // CopyoutIfConfig(pIfConfigDst, pite); pQuery->IfIndex = pite->IfIndex; pQuery->RasClientAddr = 0; dwCount++; dwSize += dwSizeCur; pIfConfigDst = (PIGMP_MIB_IF_CONFIG) (((PBYTE)pIfConfigDst)+ dwSizeCur); // if GetMode==GETMODE_FIRST change it to GETMODE_NEXT. if (dwGetMode==GETMODE_FIRST) dwGetMode = GETMODE_NEXT; }//end for loop // //set the actual size if some info was copied, else let size set earlier //remain // if (dwCount>0) { *pdwOutputSize = dwSize; } else { *pdwOutputSize = dwSizeCur; } if (pResponse!=NULL) pResponse->Count = dwCount; RELEASE_IF_LIST_LOCK("_MibGetInternalIfConfig"); Trace0(MIB, "Leaving _MibGetInternalIfConfig"); return Error; } //end _MibGetInternalIfConfig //------------------------------------------------------------------------------ // _MibGetInternalIfGroupsInfo // // Enumerates the list of GIs hanging from an interface // Locks: no locks assumed. //------------------------------------------------------------------------------ DWORD MibGetInternalIfGroupsInfo ( PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse, PDWORD pdwOutputSize, DWORD dwGetMode, DWORD dwBufferSize ) { LONGLONG llCurTime = GetCurrentIgmpTime(); PIGMP_MIB_IF_GROUPS_LIST pHeader; PMIB_GROUP_INFO_V3 pGroupInfo; PMIB_PROXY_GROUP_INFO_V3 pProxyGroupInfo; PGI_ENTRY pgie; PLIST_ENTRY pHead, ple; DWORD dwCurSize=0, Error=NO_ERROR, dwNumGroups, dwNumIfGroups, dwNumGroupsCopied, SizeofGroupEntry, PrevQueryFlags = pQuery->Flags; PIF_TABLE_ENTRY pite; PRAS_TABLE_ENTRY prte; PRAS_TABLE prt; BOOL bCopied, bProxy=FALSE, bRasClientEnum=FALSE, bRasServerEnum=FALSE, bRasIfLock=FALSE; DWORD lePrevGroup = NETWORK_TO_LITTLE_ENDIAN(pQuery->GroupAddr); USHORT PrevEnumSignature = pQuery->Signature; BOOL bEnumV3, bInsufficientBuffer=FALSE; //Trace3(MEM, "_MibGetInternalIfGroupsInfo buffer: %0x -> %0x: %d", //(DWORD)pResponse->Buffer, ((DWORD)pResponse->Buffer)+dwBufferSize, dwBufferSize);//deldel Trace0(MIB, "Entering _MibGetInternalIfGroupsInfo()"); bEnumV3 = PrevQueryFlags & IGMP_ENUM_SUPPORT_FORMAT_IGMPV3; CLEAR_IGMP_ENUM_INTERFACE_TABLE_FLAGS(pQuery->Flags); if ( (PrevQueryFlags & IGMP_ENUM_INTERFACE_TABLE_END) && !(PrevQueryFlags & IGMP_ENUM_ALL_INTERFACES_GROUPS) && !(PrevQueryFlags & IGMP_ENUM_FOR_RAS_CLIENTS) ) { pQuery->GroupAddr = 0; pQuery->Signature = 0; return ERROR_NO_MORE_ITEMS; } // // Initialize // if (pResponse!=NULL) { pResponse->TypeId = IGMP_IF_GROUPS_LIST_ID; pHeader = (PIGMP_MIB_IF_GROUPS_LIST) pResponse->Buffer; } // // acquire IfLists lock so that the interfaces list can be accessed // ACQUIRE_IF_LIST_LOCK("_MibGetInternalIfGroupsInfo"); // // retrieve the interface (and ras client) // if (PrevQueryFlags & IGMP_ENUM_FOR_RAS_CLIENTS) { if (pQuery->IfIndex==0) pQuery->IfIndex = g_RasIfIndex; Error = GetIfOrRasForEnum(pQuery, pResponse, dwGetMode, &pite, &prt, &prte, &bRasIfLock, IGMP_ENUM_FOR_RAS_CLIENTS); } else if ( (PrevQueryFlags & IGMP_ENUM_INTERFACE_TABLE_CONTINUE) || ((pQuery->IfIndex!=0)&&(pQuery->GroupAddr!=0)&& (!(PrevQueryFlags & IGMP_ENUM_INTERFACE_TABLE_END)) ) ) { // continuing from the previous call. so get the same interface again. Error = GetIfOrRasForEnum(pQuery, pResponse, GETMODE_EXACT, &pite, &prt, &prte, &bRasIfLock, 0); // // if the interface has meanwhile been deleted, then get the next interface // only if all interface group lists are being enumerated. // if ( (pite==NULL) && (pQuery->Flags&IGMP_ENUM_ALL_INTERFACES_GROUPS) ) { // the interface was deleted. so I continue with the next interface Error = GetIfOrRasForEnum(pQuery, pResponse, GETMODE_NEXT, &pite, &prt, &prte, &bRasIfLock, 0); if (pResponse) { pResponse->Flags |= IGMP_ENUM_INTERFACE_TABLE_BEGIN; pQuery->Flags |= IGMP_ENUM_INTERFACE_TABLE_BEGIN; } } } else { // enumerating a new interface Error = GetIfOrRasForEnum(pQuery, pResponse, dwGetMode, &pite, &prt, &prte, &bRasIfLock, 0); if (pResponse) { pResponse->Flags |= IGMP_ENUM_INTERFACE_TABLE_BEGIN; pQuery->Flags |= IGMP_ENUM_INTERFACE_TABLE_BEGIN; } } // // The required interface or the next interface not found. Return error. // if (pite == NULL) { // // GetIfOrRasForEnum returns no_error if there are no interfaces. // but I will return invalid_parameter // if (Error == NO_ERROR) Error = ERROR_INVALID_PARAMETER; *pdwOutputSize = 0; if (pResponse) pResponse->Count = 0; RELEASE_IF_LIST_LOCK("_MibGetInternalIfGroupsInfo"); Trace1(MIB, "Leaving _MibGetInternalIfGroupsInfo(%d)", Error); return Error; } // // get the shared interface lock so that its fields can no longer be // changed. As IF_LISTS lock is taken, the inteface state cannot get changed // if (!bRasIfLock) ACQUIRE_IF_LOCK_SHARED(pite->IfIndex, "_MibGetInternalIfGroupsInfo"); ACQUIRE_ENUM_LOCK_EXCLUSIVE("_MibGetInternalIfGroupsInfo"); bRasClientEnum = prte != NULL; bRasServerEnum = IS_RAS_SERVER_IF(pite->IfType) && !bRasClientEnum; bEnumV3 = bEnumV3 && (IS_PROTOCOL_TYPE_IGMPV3(pite)||IS_PROTOCOL_TYPE_PROXY(pite)); ACQUIRE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_MibGetInternalIfGroupsInfo"); BEGIN_BREAKOUT_BLOCK1 { bProxy = IS_PROTOCOL_TYPE_PROXY(pite); // set size for groupEntry SizeofGroupEntry = (bProxy) ? (bEnumV3?sizeof(MIB_PROXY_GROUP_INFO_V3):sizeof(MIB_PROXY_GROUP_INFO)) : (bEnumV3?sizeof(MIB_GROUP_INFO_V3):sizeof(IGMP_MIB_GROUP_INFO)); // // if no buffer passed or buffer less than that required for 1 group entry, // set the required buffer size to MIB_DEFAULT_BUFFER_SIZE and break. // if (bEnumV3 && bRasClientEnum) { DWORD RequiredSize = sizeof(IGMP_MIB_IF_GROUPS_LIST); pHead = &prte->ListOfSameClientGroups; for (ple = pHead->Flink; (ple!=pHead); ple=ple->Flink) { DWORD V3SourcesSize, V3NumSources; pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameClientGroups); V3NumSources = pgie->NumSources + ListLength(&pgie->V3ExclusionList); V3SourcesSize = sizeof(IGMP_MIB_GROUP_SOURCE_INFO_V3)*V3NumSources; RequiredSize += SizeofGroupEntry+V3SourcesSize; } RequiredSize += 300; if ((pResponse==NULL) || dwBufferSizeInfo.CurrentGroupMemberships) ) || (bEnumV3 && (dwBufferSizeFlags&IGMP_ENUM_ONE_ENTRY) ? sizeof(IGMP_MIB_IF_GROUPS_LIST) + sizeof(IGMP_MIB_GROUP_INFO) : bRasClientEnum ? sizeof(IGMP_MIB_IF_GROUPS_LIST) + SizeofGroupEntry*(prte->Info.CurrentGroupMemberships+5) : MIB_DEFAULT_BUFFER_SIZE; } // dont change pQuery->GroupAddr bCopied = FALSE; bInsufficientBuffer = TRUE; GOTO_END_BLOCK1; } // // set dwNumIfGroups // if (!IS_IF_ACTIVATED(pite)) { dwNumIfGroups = 0; } else { if (bProxy) { dwNumIfGroups = pite->Info.CurrentGroupMemberships; } // // if no ras client stats (if flag not set in the query, or ras // stats not being kept). // else if ( bRasClientEnum && !g_Config.RasClientStats ) { dwNumIfGroups = 0; } else { dwNumIfGroups = (bRasClientEnum) ? prte->Info.CurrentGroupMemberships : pite->Info.CurrentGroupMemberships; } } // // calculate how many group entries will fit in the buffer left. // dwNumGroups cannot be greater than dwNumIfGroups and // enumerate only 1 group if IGMP_ENUM_ONE_ENTRY flag set. // // note: dwNumGroups can be 0, only if dwNumIfGroups is 0 dwNumGroups = bEnumV3? 100 : (dwBufferSize - sizeof(IGMP_MIB_IF_GROUPS_LIST)) / SizeofGroupEntry; dwNumGroups = MIN(dwNumIfGroups, dwNumGroups); if (pQuery->Flags&IGMP_ENUM_ONE_ENTRY) dwNumGroups = MIN(dwNumGroups, 1); // initialize size required for this interface groups dwCurSize = sizeof(IGMP_MIB_IF_GROUPS_LIST); // // set fields in the Interface header that will be returned to the caller // pHeader->IfIndex = pite->IfIndex; if (bRasClientEnum) { pHeader->IpAddr = prte->NHAddr; pHeader->IfType = IGMP_IF_RAS_CLIENT; } else { pHeader->IpAddr = pite->IpAddr; pHeader->IfType = GET_EXTERNAL_IF_TYPE(pite); } // // set fields in pQuery // pQuery->IfIndex = pite->IfIndex; pQuery->RasClientAddr = (bRasClientEnum) ? prte->NHAddr : 0; // // if not activated, just copy the interface header and return with 0 groups // if (!IS_IF_ACTIVATED(pite)) { dwNumGroupsCopied = 0; // set pQuery fields pQuery->GroupAddr = 0; pQuery->Flags |= (IGMP_ENUM_INTERFACE_TABLE_BEGIN | IGMP_ENUM_INTERFACE_TABLE_END); pResponse->Flags |= (IGMP_ENUM_INTERFACE_TABLE_BEGIN | IGMP_ENUM_INTERFACE_TABLE_END); // set interface header fields pHeader->NumGroups = 0; dwCurSize = sizeof(IGMP_MIB_IF_GROUPS_LIST); bCopied = TRUE; GOTO_END_BLOCK1; } ple = NULL; //-------------------------------------------------- // if interface not proxy, then copy the group info. //--------------------------------------------------- if (!bProxy) { pGroupInfo = (PMIB_GROUP_INFO_V3)(pHeader->Buffer); // merge the lists if this interface is being enumerated for the first time. if (lePrevGroup==0) MergeIfGroupsLists(pite); pHead = (bRasClientEnum) ? &prte->ListOfSameClientGroups : &pite->ListOfSameIfGroups; // if continuing enumeration, then walk down to the next group // ras client wont get into this block if (lePrevGroup!=0) { // // get next entry from where we left off last time // if ( (PrevEnumSignature==pite->PrevIfGroupEnumSignature) && (PrevEnumSignature!=0) ){ // had reached end of enumeration if (pite->pPrevIfGroupEnumPtr==NULL) dwNumGroups = 0; else ple = &((PGI_ENTRY)pite->pPrevIfGroupEnumPtr)->LinkBySameIfGroups; } // // get next entry by searching through the list // else { for (ple=pHead->Flink; (ple!=pHead); ple=ple->Flink) { pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups); if (lePrevGrouppGroupTableEntry->GroupLittleEndian) break; } } } // // starting enumeration from the beginning of the list // else { ple = pHead->Flink; } // // finally copy the groups(!proxy) // dwNumGroupsCopied = 0; for ( ; (ple!=pHead)&&(dwNumGroupsCopiedFlink,dwNumGroupsCopied++) { PLIST_ENTRY pleNext; DWORD LastReporter, GroupUpTime, GroupExpiryTime; DWORD V3SourcesSize=0; DWORD IncrementSize=0, V3NumSources=0; pgie = bRasClientEnum ? CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameClientGroups) : CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups); if (bEnumV3){ V3NumSources = pgie->NumSources + ListLength(&pgie->V3ExclusionList); V3SourcesSize = sizeof(IGMP_MIB_GROUP_SOURCE_INFO_V3)*V3NumSources; } IncrementSize = SizeofGroupEntry+V3SourcesSize; if (dwCurSize+IncrementSize > dwBufferSize){ if (dwNumGroupsCopied==0) { dwCurSize += IncrementSize; bCopied = FALSE; bInsufficientBuffer = TRUE; } break; } dwCurSize += IncrementSize; pGroupInfo->GroupAddr = pgie->pGroupTableEntry->Group; pGroupInfo->IpAddr = pgie->pIfTableEntry->IpAddr; GroupUpTime = SYSTEM_TIME_TO_SEC(llCurTime-pgie->Info.GroupUpTime); GroupExpiryTime = (pgie->Info.GroupExpiryTime==~0) ? ~0 : SYSTEM_TIME_TO_SEC(pgie->Info.GroupExpiryTime-llCurTime); LastReporter = pgie->Info.LastReporter; if (bRasServerEnum) { DWORD GroupExpiryTimeTmp; PGI_ENTRY pgieNext; for (pleNext=ple->Flink; pleNext!=pHead; pleNext=pleNext->Flink) { pgieNext = CONTAINING_RECORD(pleNext, GI_ENTRY, LinkBySameIfGroups); if (pgieNext->pGroupTableEntry->Group != pgie->pGroupTableEntry->Group) break; GroupUpTime = MAX(GroupUpTime, SYSTEM_TIME_TO_SEC(llCurTime-pgieNext->Info.GroupUpTime)); GroupExpiryTimeTmp = (pgieNext->Info.GroupExpiryTime==~0) ? ~0 : SYSTEM_TIME_TO_SEC(pgieNext->Info.GroupExpiryTime-llCurTime); if (GroupExpiryTimeTmp > GroupExpiryTime) { GroupExpiryTime = GroupExpiryTimeTmp; LastReporter = pgieNext->Info.LastReporter; } } ple = pleNext->Blink; } pGroupInfo->GroupUpTime = GroupUpTime; pGroupInfo->GroupExpiryTime = GroupExpiryTime; pGroupInfo->LastReporter = LastReporter; if ( (llCurTime>=pgie->Info.V1HostPresentTimeLeft) || bRasServerEnum) pGroupInfo->V1HostPresentTimeLeft = 0; else { pGroupInfo->V1HostPresentTimeLeft = SYSTEM_TIME_TO_SEC(pgie->Info.V1HostPresentTimeLeft-llCurTime); } if ( (llCurTime>=pgie->Info.V2HostPresentTimeLeft) || bRasServerEnum) pGroupInfo->V2HostPresentTimeLeft = 0; else { pGroupInfo->V2HostPresentTimeLeft = SYSTEM_TIME_TO_SEC(pgie->Info.V2HostPresentTimeLeft-llCurTime); } pGroupInfo->Flags = 0; if ( (pgie->bStaticGroup) && (!bRasServerEnum) ) pGroupInfo->Flags |= IGMP_GROUP_TYPE_STATIC; if ( (pgie->GroupMembershipTimer.Status&TIMER_STATUS_ACTIVE) || (bRasServerEnum) ) pGroupInfo->Flags |= IGMP_GROUP_TYPE_NON_STATIC; if (CAN_ADD_GROUPS_TO_MGM(pite)) pGroupInfo->Flags |= IGMP_GROUP_FWD_TO_MGM; if (bEnumV3) { PGI_SOURCE_ENTRY pSourceEntry; DWORD i=0; PLIST_ENTRY pHeadSrc, pLESrc; pGroupInfo->Version = pgie->Version; pGroupInfo->Size = sizeof(MIB_GROUP_INFO_V3) + V3SourcesSize; pGroupInfo->FilterType = pgie->FilterType; pGroupInfo->NumSources = V3NumSources; pHeadSrc = &pgie->V3InclusionListSorted; for (pLESrc=pHeadSrc->Flink; pLESrc!=pHeadSrc; pLESrc=pLESrc->Flink,i++) { pSourceEntry = CONTAINING_RECORD(pLESrc, GI_SOURCE_ENTRY, LinkSourcesInclListSorted); pGroupInfo->Sources[i].Source = pSourceEntry->IpAddr; //kslksl ASSERT(pGroupInfo->Sources[i].Source !=0); pGroupInfo->Sources[i].SourceExpiryTime = (pSourceEntry->bInclusionList) ? QueryRemainingTime(&pSourceEntry->SourceExpTimer, 0) : ~0; pGroupInfo->Sources[i].SourceUpTime = (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000; } pHeadSrc = &pgie->V3ExclusionList; for (pLESrc=pHeadSrc->Flink; pLESrc!=pHeadSrc; pLESrc=pLESrc->Flink,i++) { pSourceEntry = CONTAINING_RECORD(pLESrc, GI_SOURCE_ENTRY, LinkSources); pGroupInfo->Sources[i].Source = pSourceEntry->IpAddr; pGroupInfo->Sources[i].SourceExpiryTime = (pSourceEntry->bInclusionList) ? QueryRemainingTime(&pSourceEntry->SourceExpTimer, 0) : ~0; pGroupInfo->Sources[i].SourceUpTime = (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000; } pGroupInfo = (PMIB_GROUP_INFO_V3) ((PCHAR)pGroupInfo + pGroupInfo->Size); } else pGroupInfo = (PMIB_GROUP_INFO_V3)((PMIB_GROUP_INFO)pGroupInfo + 1); //Trace1(MEM, "NextpGroupInfo:%0x", (DWORD)pGroupInfo);//deldel } // // if reached the end of the group list or the group list is empty // if (((ple==pHead&&dwNumGroupsCopied!=0) || (dwNumIfGroups==0)||(dwNumGroups==0)) &&!bInsufficientBuffer && !bRasClientEnum) { pQuery->Flags |= IGMP_ENUM_INTERFACE_TABLE_END; pQuery->GroupAddr = 0; // reset pointers for next enumeration pite->pPrevIfGroupEnumPtr = NULL; pite->PrevIfGroupEnumSignature = 0; } // // else have more GI entries to enumerate // else if (!bRasClientEnum) { pQuery->Flags |= IGMP_ENUM_INTERFACE_TABLE_CONTINUE; if (ple!=pHead) { PGI_ENTRY pgieNext; // get the next entry from which enum should continue pgieNext = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups); // update pQuery->GroupAddr pQuery->GroupAddr = pgieNext->pGroupTableEntry->Group; // update pointers for next enumeration pite->pPrevIfGroupEnumPtr = pgieNext; } else { pQuery->GroupAddr = 0xffffffff; pite->pPrevIfGroupEnumPtr = NULL; } pite->PrevIfGroupEnumSignature = GET_NEXT_SIGNATURE(); SET_SIGNATURE(pQuery->Signature, pite->PrevIfGroupEnumSignature); } } //-------------------------- // proxy interface //-------------------------- else { PPROXY_GROUP_ENTRY pProxyEntry; PLIST_ENTRY pHeadSrc, pleSrc; DWORD SrcCnt; PPROXY_SOURCE_ENTRY pSourceEntry; pProxyGroupInfo = (PMIB_PROXY_GROUP_INFO_V3)(pHeader->Buffer); // merge the lists if this interface is being enumerated for the first time. if (lePrevGroup==0) MergeProxyLists(pite); pHead = &pite->ListOfSameIfGroups; // if continuing enumeration, then walk down to the next group if (lePrevGroup!=0) { // // get next entry from where we left off last time // if ( (PrevEnumSignature==pite->PrevIfGroupEnumSignature) && (PrevEnumSignature!=0) ) { // had reached end of enumeration if (pite->pPrevIfGroupEnumPtr==NULL) dwNumGroups = 0; else ple = &((PPROXY_GROUP_ENTRY)pite->pPrevIfGroupEnumPtr)->LinkBySameIfGroups; } // // get next entry by searching through the list // else { for (ple=pHead->Flink; (ple!=pHead); ple=ple->Flink) { pProxyEntry = CONTAINING_RECORD(ple, PROXY_GROUP_ENTRY, LinkBySameIfGroups); if (lePrevGroupGroupLittleEndian) break; } } } // // starting enumeration from the beginning of the list // else { ple = pHead->Flink; } // // finally copy the groups // dwNumGroupsCopied = 0; for ( ; (ple!=pHead)&&(dwNumGroupsCopiedFlink,dwNumGroupsCopied++) { DWORD V3SourcesSize=0, IncrementSize; pProxyEntry= CONTAINING_RECORD(ple, PROXY_GROUP_ENTRY, LinkBySameIfGroups); if (bEnumV3){ V3SourcesSize = pProxyEntry->NumSources*sizeof(IGMP_MIB_GROUP_SOURCE_INFO_V3); } IncrementSize = SizeofGroupEntry+V3SourcesSize; if (dwCurSize+IncrementSize > dwBufferSize){ if (dwNumGroupsCopied==0) { dwCurSize += IncrementSize; bCopied = FALSE; bInsufficientBuffer = TRUE; } break; } dwCurSize += IncrementSize; pProxyGroupInfo->GroupAddr = pProxyEntry->Group; pProxyGroupInfo->GroupUpTime = SYSTEM_TIME_TO_SEC(llCurTime-pProxyEntry->InitTime); pProxyGroupInfo->Flags = 0; if (pProxyEntry->bStaticGroup) { pProxyGroupInfo->Flags |= IGMP_GROUP_TYPE_STATIC; if (pProxyEntry->RefCount>0) pProxyGroupInfo->Flags |= IGMP_GROUP_TYPE_NON_STATIC; } else { pProxyGroupInfo->Flags |= IGMP_GROUP_TYPE_NON_STATIC; } if (!bEnumV3) { pProxyGroupInfo = (PMIB_PROXY_GROUP_INFO_V3) ((PMIB_PROXY_GROUP_INFO)pProxyGroupInfo+1); } else { //kslksl /* PLIST_ENTRY pHeadSrc, pleSrc; DWORD SrcCnt; PPROXY_SOURCE_ENTRY pSourceEntry; */ pProxyGroupInfo->NumSources = pProxyEntry->NumSources; pProxyGroupInfo->Size = IncrementSize; pHeadSrc = &pProxyEntry->ListSources; for (pleSrc=pHeadSrc->Flink,SrcCnt=0; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink,SrcCnt++) { pSourceEntry = CONTAINING_RECORD(pleSrc, PROXY_SOURCE_ENTRY, LinkSources); pProxyGroupInfo->Sources[SrcCnt].Source = pSourceEntry->IpAddr; pProxyGroupInfo->Sources[SrcCnt].Flags = pSourceEntry->JoinMode; pProxyGroupInfo->Sources[SrcCnt].Flags += (pSourceEntry->JoinModeIntended<<4); } pProxyGroupInfo = (PMIB_PROXY_GROUP_INFO_V3) &pProxyGroupInfo->Sources[pProxyGroupInfo->NumSources]; //Trace1(MEM, "next proxy: %0x:", (DWORD)pProxyGroupInfo);//deldel } }//copy all sources // // if reached the end of the group list or the group list is empty // if ( ((ple==pHead&&dwNumGroupsCopied!=0)||(dwNumIfGroups==0)||(dwNumGroups==0)) && !bInsufficientBuffer) //||(ple->Flink==pHead)) { pQuery->Flags |= IGMP_ENUM_INTERFACE_TABLE_END; pQuery->GroupAddr = 0; // reset pointers for next enumeration pite->pPrevIfGroupEnumPtr = NULL; pite->PrevIfGroupEnumSignature = 0; } // // else have more GI entries to enumerate // else { PPROXY_GROUP_ENTRY pProxyNext; pQuery->Flags |= IGMP_ENUM_INTERFACE_TABLE_CONTINUE; if (ple!=pHead) { // get the next entry from which enum should continue pProxyNext = CONTAINING_RECORD(ple, PROXY_GROUP_ENTRY, LinkBySameIfGroups); // update pQuery->GroupAddr pQuery->GroupAddr = pProxyNext->Group; // update pointers for next enumeration pite->pPrevIfGroupEnumPtr = pProxyNext; } else { pQuery->GroupAddr = 0xffffffff; pite->pPrevIfGroupEnumPtr = NULL; } pite->PrevIfGroupEnumSignature = GET_NEXT_SIGNATURE(); SET_SIGNATURE(pQuery->Signature, pite->PrevIfGroupEnumSignature); } } //end proxy interface // // if only one interface is being enumerated, and the number of groups being // enumerated is 0 inspite of adequate buffer, then return NO_MORE_ITEMS // if ( !bInsufficientBuffer && (dwNumGroupsCopied==0) &&(!(pQuery->Flags&IGMP_ENUM_ALL_INTERFACES_GROUPS)) ) { pQuery->GroupAddr = 0; Error = ERROR_NO_MORE_ITEMS; } if (!bInsufficientBuffer) bCopied = TRUE; } END_BREAKOUT_BLOCK1; // inside shared interface lock. // release the shared interface lock RELEASE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_MibGetInternalIfGroupsInfo"); RELEASE_IF_LOCK_SHARED(pite->IfIndex, "_MibGetInternalIfGroupsInfo"); RELEASE_ENUM_LOCK_EXCLUSIVE("_MibGetInternalIfGroupsInfo"); if (pResponse!=NULL) { pResponse->Count = (bCopied) ? 1 : 0; if (bCopied) pHeader->NumGroups = dwNumGroupsCopied; if (bEnumV3) pResponse->Flags |= IGMP_ENUM_FORMAT_IGMPV3; } if (bInsufficientBuffer) pQuery->Flags |= PrevQueryFlags; // //set the actual size if some info was copied, else let size //remain // *pdwOutputSize = dwCurSize; RELEASE_IF_LIST_LOCK("_MibGetInternalIfGroupsInfo"); Trace0(MIB, "Leaving _MibGetInternalIfGroupsInfo()"); return Error; } //end _MibGetInternalIfGroupsInfo //------------------------------------------------------------------------------ // MibGetInternalIfStats //------------------------------------------------------------------------------ DWORD MibGetInternalIfStats ( PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse, PDWORD pdwOutputSize, DWORD dwGetMode, DWORD dwBufferSize ) { DWORD Error = NO_ERROR, dwCount, dwSize; PIGMP_IF_TABLE pTable = g_pIfTable; PIF_TABLE_ENTRY pite; PRAS_TABLE_ENTRY prte; PRAS_TABLE prt; PIGMP_MIB_IF_STATS pStatsDst; PIF_INFO pIfStatsSrc; LONGLONG llCurTime = GetCurrentIgmpTime(); BOOL bDone, bCopied, bRasIfLock=FALSE; Trace0(MIB, "Entering _MibGetInternalIfStats()"); *pdwOutputSize = pQuery->Count*sizeof(IGMP_MIB_IF_STATS); // // the interface statistics struct is fixed-length. // there may be multiple instances. // if (pResponse!=NULL) { pResponse->TypeId = IGMP_IF_STATS_ID; pStatsDst = (PIGMP_MIB_IF_STATS) pResponse->Buffer; } // acquire IfLists lock so that the interfaces list can be accessed ACQUIRE_IF_LIST_LOCK("_MibGetInternalIfStats"); for (dwCount=0, dwSize=0; dwCountCount; ) { // // retrieve the interface. If the ras flag was set and ras statistics // are kept, then ras client statistics are also returned. // If no more relevant structures, then return ERROR_NO_MORE_ITEMS. // // // the pResponse IfIndex,RasClientAddr fields are updated appropriately. // if a lock is acquired on the ras table, then bRasIfLock is set to // TRUE; // Error = GetIfOrRasForEnum(pQuery, pResponse, dwGetMode, &pite, &prt, &prte, &bRasIfLock, 0); if (pite == NULL) { if (dwCount>0) { Error = NO_ERROR; } // count==0 else { if (Error == NO_ERROR) Error = ERROR_INVALID_PARAMETER; *pdwOutputSize = 0; } break; //from for loop } // // if no buffer was specified, indicate one should be allocated // the required buffer size has already been set. // if (pResponse==NULL) { Error = ERROR_INSUFFICIENT_BUFFER; break; } // // acquire IfLists locks so that interfaces list cannot be changed // if (!bRasIfLock) ACQUIRE_IF_LOCK_SHARED(pite->IfIndex, "_MibGetInternalIfStats"); BEGIN_BREAKOUT_BLOCK1 { // // if the buffer is not large enough, break from the loop // if (dwBufferSize < dwSize+sizeof(IGMP_MIB_IF_STATS)) { if (dwCount==0) Error = ERROR_INSUFFICIENT_BUFFER; bDone = TRUE; bCopied = FALSE; GOTO_END_BLOCK1; } // // copy the interface stats. Copy field by field as access to this // structure is not synchronized // // // copy interface stats // if (prte==NULL) { pIfStatsSrc = &pite->Info; if (!IS_IF_ACTIVATED(pite)) ZeroMemory(pStatsDst, sizeof(*pStatsDst)); // //copy if index, addr // pStatsDst->IfIndex = pite->IfIndex; pStatsDst->IpAddr = pite->IpAddr; pStatsDst->IfType = GET_EXTERNAL_IF_TYPE(pite); GET_EXTERNAL_IF_STATE(pite, pStatsDst->State); pQuery->IfIndex = pite->IfIndex; pQuery->RasClientAddr = 0; pStatsDst->IgmpProtocolType = pite->Config.IgmpProtocolType; // // if this interface is not activated, then continue from the // next one // if (!IS_IF_ACTIVATED(pite)) { bDone = FALSE; bCopied = TRUE; GOTO_END_BLOCK1; } pStatsDst->QuerierState = pIfStatsSrc->QuerierState; pStatsDst->QuerierIpAddr = pIfStatsSrc->QuerierIpAddr; pStatsDst->ProxyIfIndex = g_ProxyIfIndex; //if I am the querier set to 0 pStatsDst->QuerierPresentTimeLeft = IS_QUERIER(pite) ? 0 : SYSTEM_TIME_TO_SEC(pIfStatsSrc->QuerierPresentTimeout - llCurTime); pStatsDst->LastQuerierChangeTime = SYSTEM_TIME_TO_SEC(llCurTime - pIfStatsSrc->LastQuerierChangeTime); pStatsDst->V1QuerierPresentTimeLeft = (IS_IF_VER2(pite) && (pIfStatsSrc->V1QuerierPresentTime > llCurTime)) ? SYSTEM_TIME_TO_SEC(pIfStatsSrc->V1QuerierPresentTime - llCurTime) : 0; { LARGE_INTEGER liUptime; liUptime.QuadPart = (llCurTime-pIfStatsSrc->TimeWhenActivated)/1000; pStatsDst->Uptime = liUptime.LowPart; } pStatsDst->TotalIgmpPacketsReceived = pIfStatsSrc->TotalIgmpPacketsReceived; pStatsDst->TotalIgmpPacketsForRouter = pIfStatsSrc->TotalIgmpPacketsForRouter; pStatsDst->GeneralQueriesReceived = pIfStatsSrc->GenQueriesReceived; pStatsDst->WrongVersionQueries = pIfStatsSrc->WrongVersionQueries; pStatsDst->JoinsReceived = pIfStatsSrc->JoinsReceived; pStatsDst->LeavesReceived = pIfStatsSrc->LeavesReceived; pStatsDst->CurrentGroupMemberships = pIfStatsSrc->CurrentGroupMemberships; pStatsDst->GroupMembershipsAdded = pIfStatsSrc->GroupMembershipsAdded; pStatsDst->WrongChecksumPackets = pIfStatsSrc->WrongChecksumPackets; pStatsDst->ShortPacketsReceived = pIfStatsSrc->ShortPacketsReceived; pStatsDst->LongPacketsReceived = pIfStatsSrc->LongPacketsReceived; pStatsDst->PacketsWithoutRtrAlert = pIfStatsSrc->PacketsWithoutRtrAlert; } // // copy ras client statistics // else { ZeroMemory(pStatsDst, sizeof(*pStatsDst)); pStatsDst->IfIndex = pite->IfIndex; pStatsDst->IpAddr = pite->IpAddr; pStatsDst->IfType = IGMP_IF_RAS_CLIENT; GET_EXTERNAL_IF_STATE(pite, pStatsDst->State); pQuery->IfIndex = pite->IfIndex; pQuery->RasClientAddr = prte->NHAddr; // // if this interface is not activated, then continue from the // next one // if (!IS_IF_ACTIVATED(pite)) { bDone = FALSE; bCopied = TRUE; GOTO_END_BLOCK1; } pStatsDst-> TotalIgmpPacketsReceived = prte->Info.TotalIgmpPacketsReceived; pStatsDst->TotalIgmpPacketsForRouter = prte->Info.TotalIgmpPacketsForRouter; pStatsDst->GeneralQueriesReceived = prte->Info.GenQueriesReceived; pStatsDst->JoinsReceived = prte->Info.JoinsReceived; pStatsDst->LeavesReceived = prte->Info.LeavesReceived; pStatsDst->CurrentGroupMemberships = prte->Info.CurrentGroupMemberships; pStatsDst->GroupMembershipsAdded = prte->Info.GroupMembershipsAdded; pStatsDst->WrongChecksumPackets = prte->Info.WrongChecksumPackets; pStatsDst->ShortPacketsReceived = prte->Info.ShortPacketsReceived; pStatsDst->LongPacketsReceived = prte->Info.LongPacketsReceived; } bCopied = TRUE; bDone = FALSE; } END_BREAKOUT_BLOCK1; RELEASE_IF_LOCK_SHARED(pite->IfIndex, "_MibGetInternalIfStats"); bRasIfLock = FALSE; if (bCopied) { // // everything fine. Copied one more stats struct // dwCount++; dwSize += sizeof(IGMP_MIB_IF_STATS); pStatsDst++; } // if current mode is get first, then change it to get next if (dwGetMode==GETMODE_FIRST) dwGetMode = GETMODE_NEXT; if (bDone) break; }//end for loop if (pResponse!=NULL) pResponse->Count = dwCount; // //set the actual size if some info was copied, else let size set earlier //remain // if (dwCount>0) { *pdwOutputSize = dwSize; } // release interface lock if (bRasIfLock && pite) RELEASE_IF_LOCK_SHARED(pite->IfIndex, "_MibGetInternalIfStats"); RELEASE_IF_LIST_LOCK("_MibGetInternalIfStats"); Trace0(MIB, "Leaving _MibGetInternalIfStats()"); return Error; } //end _MibGetInternalIfStats //------------------------------------------------------------------------------ // GetIfOrRasForEnum // First gets the required interface. If ras stats enabled and asked, // then gets the ras client. // // Locks On return: // if *bRasTableLock==TRUE then this procedure has taken read lock on the // ras table and has not released it. // Assumes shared interface lock. //------------------------------------------------------------------------------ DWORD GetIfOrRasForEnum( PIGMP_MIB_GET_INPUT_DATA pQuery, PIGMP_MIB_GET_OUTPUT_DATA pResponse, DWORD dwGetMode, PIF_TABLE_ENTRY *ppite, PRAS_TABLE *pprt, PRAS_TABLE_ENTRY *pprte, // on return set to null if no ras stats BOOL *bRasIfLock, DWORD dwEnumForRasClients ) { DWORD Error = NO_ERROR, bRasClientsEnum = dwEnumForRasClients & IGMP_ENUM_FOR_RAS_CLIENTS; *ppite = NULL; *pprt = NULL; *pprte = NULL; // // get the interface depending on the mode // if (bRasClientsEnum) *ppite = GetIfByListIndex(pQuery->IfIndex, GETMODE_EXACT, &Error); else *ppite = GetIfByListIndex(pQuery->IfIndex, dwGetMode, &Error); // // return if valid interface could not be found or not rasClient // if ( (*ppite==NULL) || (Error!=NO_ERROR) || !bRasClientsEnum) return Error; // // do ras client processing // BEGIN_BREAKOUT_BLOCK1 { ACQUIRE_IF_LOCK_SHARED((*ppite)->IfIndex, "_GetIfOrRasForEnum"); *bRasIfLock = TRUE; // // current interface not ras server interface. So done. // if (!IS_RAS_SERVER_IF((*ppite)->IfType)) GOTO_END_BLOCK1; // // no ras client stats (if flag not set in the query, or ras // stats not being kept). So done. // if ( !bRasClientsEnum || !g_Config.RasClientStats ) { GOTO_END_BLOCK1; } // // if mode: GETMODE_EXACT: then search for the ras client. // if ras client not found, then I set the interface to null // if (dwGetMode==GETMODE_EXACT) { // if pQuery->RasClientAddr==0, then he is not asking for ras client // So done. if (pQuery->RasClientAddr==0) GOTO_END_BLOCK1; *pprte = GetRasClientByAddr(pQuery->RasClientAddr, (*ppite)->pRasTable); // // if ras client not found in GETMODE_EXACT, then dont return IF // and release read lock on ras table. // if (*pprte==NULL) { if (*bRasIfLock) { *bRasIfLock = FALSE; RELEASE_IF_LOCK_SHARED((*ppite)->IfIndex, "_GetIfOrRasForEnum"); } *ppite = NULL; GOTO_END_BLOCK1; } *pprt = (*ppite)->pRasTable; } // // GETMODE_NEXT : if pQuery->RasClientAddr, then find the first ras // client, else find the next ras client // else if ( (dwGetMode==GETMODE_NEXT) || (dwGetMode==GETMODE_FIRST) ){ BOOL bFoundRasClient = FALSE; *pprt = (*ppite)->pRasTable; // // if the pQuery->RasClientAddr==0, then get the first ras client // if (pQuery->RasClientAddr==0) { if (!IsListEmpty(&(*pprt)->ListByAddr)) { bFoundRasClient = TRUE; *pprte = CONTAINING_RECORD((*pprt)->ListByAddr.Flink, RAS_TABLE_ENTRY, LinkByAddr); } } else { PRAS_TABLE_ENTRY prtePrev, prteCur; PLIST_ENTRY pHead, ple; // get the prev ras client through hash table prtePrev = GetRasClientByAddr(pQuery->RasClientAddr, (*ppite)->pRasTable); // // if ras client not found, then go through the ordered list // and get a ras client with next higher addr // if (prtePrev==NULL) { pHead = &(*pprt)->ListByAddr; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { prteCur = CONTAINING_RECORD(ple, RAS_TABLE_ENTRY, LinkByAddr); if (pQuery->RasClientAddr>prteCur->NHAddr) break; } if (ple!=pHead) { bFoundRasClient = TRUE; *pprte = prteCur; } } // // get the next ras client through the ras client list // else { ple = prtePrev->LinkByAddr.Flink; // more entries present. found next ras client entry if (ple != &(*pprt)->ListByAddr) { bFoundRasClient = TRUE; *pprte = CONTAINING_RECORD(ple, RAS_TABLE_ENTRY, LinkByAddr); *pprt = (*ppite)->pRasTable; } } } // if ras client is not found, then I set the interface also to NULL if (bFoundRasClient==FALSE) { if (*bRasIfLock) RELEASE_IF_LOCK_SHARED((*ppite)->IfIndex, "_GetIfOrRasForEnum"); *bRasIfLock = FALSE; *ppite = NULL; *pprte = NULL; *pprt = NULL; Error = ERROR_NO_MORE_ITEMS; } else *pprt = (*ppite)->pRasTable; } //getmode==GETMODE_NEXT } END_BREAKOUT_BLOCK1; if ( (Error!= NO_ERROR) && (*bRasIfLock) ) { *bRasIfLock = FALSE; RELEASE_IF_LOCK_SHARED((*ppite)->IfIndex, "_GetIfOrRasForEnum"); } return Error; } //end _GetIfOrRasForEnum //------------------------------------------------------------------------------ // Function: _GetIfByListIndex // // if GETMODE_FIRST: retrieves the 1st entry in the list ordered by index. // if GETMODE_EXACT: retrieves the entry from the hash table // if GETMODE_NEXT: retrieves the prev entry from hash table, and then // retrieves the next entry from the list ordered by index. // // Locks: Assumes IfList lock. //------------------------------------------------------------------------------ PIF_TABLE_ENTRY GetIfByListIndex( DWORD IfIndex, DWORD dwGetMode, PDWORD pdwErr ) { PIF_TABLE_ENTRY pite; PLIST_ENTRY ple, pHead; if (pdwErr != NULL) { *pdwErr = NO_ERROR; } pite = NULL; // // GETMODE_FIRST: return record at head of list; // if list is empty, return NULL. // if (dwGetMode == GETMODE_FIRST) { if (IsListEmpty(&g_pIfTable->ListByIndex)) { //*pdwErr = ERROR_NO_MORE_ITEMS; return NULL; } else { ple = g_pIfTable->ListByIndex.Flink; return CONTAINING_RECORD(ple, IF_TABLE_ENTRY, LinkByIndex); } } // // get the entry requested from the hash table. // pite = GetIfByIndex(IfIndex); // // GETMODE_EXACT: return the entry // if (dwGetMode==GETMODE_EXACT) return pite; // // GETMODE_NEXT: return the item after the one retrieved // if (dwGetMode==GETMODE_NEXT) { // the previous entry was found. return the next one. if (pite!=NULL) { ple = &pite->LinkByIndex; // // if entry found is last one, return NULL, // otherwise return the following entry // if (ple->Flink == &g_pIfTable->ListByIndex) { if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; } pite = NULL; } else { ple = ple->Flink; pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, LinkByIndex); } } // // the previous entry was not found. // go throught the list of interfaces ordered by index, and retrieve the // interface with next higher index // else { pHead = &g_pIfTable->ListByIndex; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, LinkByIndex); if (pite->IfIndex>IfIndex) break; } } } return pite; }//end _GetIfByListIndex //------------------------------------------------------------------------------ // _GetGroupByAddr // // Locks: assumes lock on the group list //------------------------------------------------------------------------------ PGROUP_TABLE_ENTRY GetGroupByAddr ( DWORD Group, DWORD dwGetMode, PDWORD pdwErr ) { PLIST_ENTRY ple, pHead; PGROUP_TABLE_ENTRY pge; DWORD GroupLittleEndian = NETWORK_TO_LITTLE_ENDIAN(Group); if (pdwErr != NULL) { *pdwErr = NO_ERROR; } pHead = &g_pGroupTable->ListByGroup.Link; pge = NULL; // // return record at head of list if mode is GETMODE_FIRST; // if list is empty, return NULL. // if (dwGetMode == GETMODE_FIRST) { if (pHead->Flink == pHead) { return NULL; } else { ple = pHead->Flink; return CONTAINING_RECORD(ple, GROUP_TABLE_ENTRY, LinkByGroup); } } // get the entry requested pge = GetGroupFromGroupTable (Group, NULL, 0); // // if mode is GETMODE_NEXT, return the item after the one retrieved // if (dwGetMode == GETMODE_NEXT) { // // if the previous group was found, then return the one following it in the list // if (pge != NULL) { ple = &pge->LinkByGroup; // // if entry found is last one, return NULL, // otherwise return the following entry // if (ple->Flink == pHead) { if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; } pge = NULL; } else { ple = ple->Flink; pge = CONTAINING_RECORD(ple, GROUP_TABLE_ENTRY, LinkByGroup); } } // // previous group was not found. Go through the list and return the greater group. // else { pHead = &g_pGroupTable->ListByGroup.Link; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { pge = CONTAINING_RECORD(ple, GROUP_TABLE_ENTRY, LinkByGroup); if (pge->GroupLittleEndian > GroupLittleEndian) break; } if (ple==pHead) { if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; } pge = NULL; } // else pge points to the entry to be returned. } } return pge; }//end _GetGroupByAddr DWORD APIENTRY MibCreate( IN DWORD dwInputSize, IN PVOID pInputData ) { // // Not supported // return NO_ERROR; } DWORD APIENTRY MibDelete( IN DWORD dwInputSize, IN PVOID pInputData ) { // // Not supported // return NO_ERROR; } DWORD APIENTRY MibSet( IN DWORD dwInputSize, IN PVOID pInputData ) { // // Not supported // return NO_ERROR; }