/* m2Igmp.c - helper file for igmp Mib */ /* Copyright 2000 - 2005 Wind River Systems, Inc. */ /* modification history -------------------- 01o,01apr05,kch Removed ROUTER_STACK define. 01n,02mar05,kc Fixed warning. 01m,12jan05,vvv osdep.h cleanup 01l,13sep04,rae fix hooks 01k,11aug04,rae fix VIRTUAL_STACK 01j,14jan03,rae Merged from velocecp branch 01i,11jul01,rae code clean up 01h,29mar01,spm file creation: copied from version 01g of tor2_0.open_stack branch (wpwr VOB) for unified code base 01g,21jul00,gnn adjusted for include file move into a subdirectory of wrn 01f,20jul00,rae adjusted for move of src/WRN/include to h/wrn 01e,20jul00,rae added igmpMSem 01d,14jul00,rae turn off debug code 01c,22may00,kbw minor man page changes to allow refgen processing 01b,15may00,rae added VIRTUAL_STACK support 01a,08mar00,rae written */ /* DESCRIPTION This library provides an interface between the Berkeley multicast code and the IGMP Mib code INCLUDE FILES: */ /* includes */ #include "vxWorks.h" #include "stdio.h" #include "sysLib.h" #include "logLib.h" #include "semLib.h" #include "errnoLib.h" #include "stdlib.h" #include "tickLib.h" #include "m2Lib.h" #include "netinet/in.h" #include "netinet/in_var.h" #include "netinet/igmp_var.h" #include "net/protosw.h" #include "IGMPv2/igmpR.h" #include "IGMPv2/igmp_externs.h" #include "IGMPv2/igmpRouterLib.h" #include "IGMPv2/igmpPortLib.h" #include "IGMPv2/igmpCacheLib.h" #ifdef VIRTUAL_STACK #include "netinet/vsLib.h" #include "netinet/vsData.h" #include "netinet/vsIgmpR.h" #include "netinet/vsIgmp.h" #endif /* defines */ #define DEBUG noOperation /* change noOperation to printf for debugging */ /* externs */ /* globals */ #ifndef VIRTUAL_STACK extern SEM_ID igmpMSem; extern VOIDFUNCPTR _igmpJoinAlertHook; extern VOIDFUNCPTR _igmpLeaveAlertHook; extern VOIDFUNCPTR _igmpQuerierTimeUpdateHook; #endif /* locals */ /* forward declarations */ void igmpJoinAlert(int if_index); void igmpLeaveAlert(int if_index); void igmpQuerierTimeUpdate(int if_index, int time); /******************************************************************************* * * noOperation - ignores its many arguments * * This do nothing code is replaced by printf, if debugging is enabled. * * NOMANUAL * * RETURNS: N/A */ void noOperation ( const char *cptr_format, ... ) { } /******************************************************************************* * * m2IgmpInit - fills in some hooks * * Fills in hooks with appropriate routines. For scalability. * * NOMANUAL * * RETURNS: OK always */ STATUS m2IgmpInit ( void ) { _igmpJoinAlertHook = (VOIDFUNCPTR)igmpJoinAlert; /* fill in functions */ _igmpLeaveAlertHook = (VOIDFUNCPTR)igmpLeaveAlert; _igmpQuerierTimeUpdateHook = (VOIDFUNCPTR)igmpQuerierTimeUpdate; return (OK); } /******************************************************************************* * * m2IgmpCacheEntryGet - fills in M2_IGMP_CACHE struct with cache data * * Uses the cache address, and cache interface index to look up the cache entry * associated with those values. Fills in provided structure with information * from that entry. * * NOMANUAL * * RETURNS: OK or ERROR if if_index not valid */ STATUS m2IgmpCacheEntryGet ( M2_IGMP_CACHE *pData /* this is filled in */ ) { struct in_multi * inm; struct ifnet * ifnet; struct in_addr addr; IGMP_GROUP_CLASS groupClass; IGMP_GROUP_CLASS * pgroupClass = &groupClass; if (igmpCacheGet (pData->igmpCacheAddress, pData->igmpCacheIfIndex, (void*)&pgroupClass) != OK) return ERROR; if (pgroupClass == NULL) { DEBUG ("Null groupClass returned \n"); return ERROR; } if (semTake (igmpMSem, WAIT_FOREVER) == ERROR) return ERROR; addr.s_addr = htonl (pData->igmpCacheAddress); if ((ifnet = portToIfnet (pgroupClass->port_number)) != NULL) { IN_LOOKUP_MULTI (addr, ifnet, inm); /* are we in this group? */ pData->igmpCacheSelf = inm ? M2_TRUE : M2_FALSE; } else { DEBUG ("lookup of ifnet failed on port %d\n", pgroupClass->port_number); pData->igmpCacheSelf = M2_FALSE; } pData->igmpCacheLastReporter = pgroupClass->ip_address_of_last_reporter; pData->igmpCacheUpTime = ((tickGet() - pgroupClass->start_time) * 100) / sysClkRateGet(); if (pgroupClass->router_group.group_specific_timer.enabled) pData->igmpCacheExpiryTime = (pgroupClass-> router_group.group_specific_timer.expiry_time - pgroupClass-> router_group.group_specific_timer.second_counter) * 100; else pData->igmpCacheExpiryTime = 0; pData->igmpCacheStatus = pgroupClass->enabled ? ROW_ACTIVE: ROW_NOTINSERVICE; if (pgroupClass->router_group.v1_host_timer.enabled) pData->igmpCacheVersion1HostTimer = (pgroupClass-> router_group.v1_host_timer.expiry_time - pgroupClass-> router_group.v1_host_timer.second_counter) * 100; else pData->igmpCacheVersion1HostTimer = 0; semGive (igmpMSem); return OK; } /******************************************************************************* * * m2IgmpCacheEntryNextGet - fills in M2_IGMP_CACHE struct with cache data * * Uses the cache address, and cache interface index to look up the next cache entry * lexicographically greater than those values. Fills in provided structure with * information from that entry. * * NOMANUAL * * RETURNS: OK or ERROR if if_index not valid */ STATUS m2IgmpCacheEntryNextGet ( M2_IGMP_CACHE *pData ) { UINT32 nextMcastAddr = 0; UINT32 nextIfIndex =0; IGMP_GROUP_CLASS groupClass; IGMP_GROUP_CLASS * pGroupClass = &groupClass; if (igmpCacheNextGet (pData->igmpCacheAddress, pData->igmpCacheIfIndex, &nextMcastAddr, &nextIfIndex, (void*)&pGroupClass) != OK) { return ERROR; } pData->igmpCacheIfIndex = nextIfIndex; pData->igmpCacheAddress = nextMcastAddr; if (m2IgmpCacheEntryGet (pData) != OK) { return ERROR; } return OK; } /******************************************************************************* * * m2IgmpInterfaceEntryNextGet - fills in M2_IGMP struct with interface data * * Uses the compl argument (which is if_index) to look up the igmp port associated * with the next interface. Fills in provided structure with information gathered * from the interface. * * RETURNS: OK or ERROR if if_index not valid * * NOMANUAL */ STATUS m2IgmpInterfaceEntryNextGet ( M2_IGMP * pData /* Interface Data structure */ ) { UINT32 nextIndex; UINT32 vif; if (igmpPortNextGet (pData->igmpInterfaceIfIndex, &nextIndex, &vif) == ERROR) { DEBUG ("NextGet on if_index %d failed \n", (int)(pData->igmpInterfaceIfIndex)); return ERROR; } pData->igmpInterfaceIfIndex = nextIndex; if (m2IgmpInterfaceEntryGet (pData) == ERROR) { DEBUG ("Get on index %d failed \n", nextIndex); return ERROR; } return OK; } /******************************************************************************* * * m2IgmpInterfaceEntryGet - fills in M2_IGMP struct with interface data * * Uses the if_index to look up the igmp port associated * with that interface. Fills in provided structure with information gathered * from the interface. * * NOMANUAL * * RETURNS: OK or ERROR if if_index not valid */ STATUS m2IgmpInterfaceEntryGet ( M2_IGMP *pData ) { UINT32 vif; if (igmpPortGet (pData->igmpInterfaceIfIndex, &vif) == ERROR) return ERROR; if (semTake(igmpMSem, WAIT_FOREVER) == ERROR) return ERROR; pData->igmpInterfaceQueryInterval = vs_igmp.port_table[vif].router_port.general_query_interval; pData->igmpInterfaceStatus= vs_igmp.port_table[vif].router_enabled ? ROW_ACTIVE : ROW_NOTINSERVICE; pData->igmpInterfaceVersion= vs_igmp.port_table[vif].version; pData->igmpInterfaceQuerier= vs_igmp.port_table[vif].igmpInterfaceEntry.igmpInterfaceQuerier; pData->igmpInterfaceQueryMaxResponseTime= vs_igmp.port_table[vif].router_port.general_query_max_response_time; pData->igmpInterfaceQuerierPresentTimeout= vs_igmp.port_table[vif].router_port.other_querier_present_timer.enabled ? (vs_igmp.port_table[vif].router_port.other_querier_present_timer.expiry_time - vs_igmp.port_table[vif].router_port.other_querier_present_timer.second_counter) * 100 : 0; pData->igmpInterfaceVersion1QuerierTimer= /* updated by BSD code */ vs_igmp.port_table[vif].igmpInterfaceEntry.igmpInterfaceVersion1QuerierTimer; pData->igmpInterfaceWrongVersionQueries= vs_igmp.port_table[vif].igmpInterfaceEntry.igmpInterfaceWrongVersionQueries; pData->igmpInterfaceJoins= vs_igmp.port_table[vif].igmpInterfaceEntry.igmpInterfaceJoins; pData->igmpInterfaceGroups= vs_igmp.port_table[vif].igmpInterfaceEntry.igmpInterfaceGroups; pData->igmpInterfaceRobustness= vs_igmp.port_table[vif].robustness; pData->igmpInterfaceQuerierUpTime= ((tickGet() - vs_igmp.port_table[vif].igmpInterfaceEntry.igmpInterfaceQuerierUpTime) * 100) / sysClkRateGet(); pData->igmpInterfaceLastMembQueryIntvl= vs_igmp.port_table[vif].igmpInterfaceEntry.igmpInterfaceLastMembQueryIntvl; semGive(igmpMSem); return OK; } /******************************************************************************* * * m2IgmpInterfaceEntrySet - fills in interface data as per SNMP request * * Uses the if_index to look up the igmp port associated * with that interface. Fills in interface structure with information provided * by SNMP * * NOMANUAL * * RETURNS: OK or ERROR if if_index not valid */ STATUS m2IgmpInterfaceEntrySet ( M2_IGMP *pData, /* the data from SNMP */ int varsToSet /* which of the above we really use */ ) { UINT32 vif; if (igmpPortGet (pData->igmpInterfaceIfIndex, &vif) == ERROR) return ERROR; if (semTake (igmpMSem, WAIT_FOREVER) == ERROR) return ERROR; if (varsToSet & M2_var_igmpInterfaceStatus) { /* bring if up or down */ } if (varsToSet & M2_var_igmpInterfaceQueryInterval) vs_igmp.port_table[vif].router_port.general_query_interval = pData->igmpInterfaceQueryInterval; if (varsToSet & M2_var_igmpInterfaceVersion) vs_igmp.port_table[vif].version = pData->igmpInterfaceVersion; if (varsToSet & M2_var_igmpInterfaceQueryMaxResponseTime) vs_igmp.port_table[vif].router_port.general_query_max_response_time = pData->igmpInterfaceQueryMaxResponseTime; if (varsToSet & M2_var_igmpInterfaceRobustness) vs_igmp.port_table[vif].robustness = pData->igmpInterfaceRobustness; if (varsToSet & M2_var_igmpInterfaceLastMembQueryIntvl) vs_igmp.port_table[vif].igmpInterfaceEntry.igmpInterfaceLastMembQueryIntvl = pData->igmpInterfaceLastMembQueryIntvl; semGive (igmpMSem); return OK; } /****************************************************************************** * * igmpJoinAlert - updates Mib variables on join * * Increments the igmpInterfaceJoins and igmpInterfaceGroups values on the given * interface. * * RETURNS: N/A * * NOMANUAL */ void igmpJoinAlert ( int if_index /* index of port on which to add */ ) { UINT32 port; if ((igmpPortGet (if_index, &port) == ERROR)) return; semTake (igmpMSem, WAIT_FOREVER); ++vs_igmp.port_table[port].igmpInterfaceEntry.igmpInterfaceJoins; ++vs_igmp.port_table[port].igmpInterfaceEntry.igmpInterfaceGroups; semGive (igmpMSem); } /****************************************************************************** * * igmpLeaveAlert - update Mib variables on leave * * Decrements the igmpInterfaceGroups value on the given interface. * * RETURNS: N/A * * NOMANUAL */ void igmpLeaveAlert ( int if_index /* index of port where leave occurred */ ) { UINT32 port; if ((igmpPortGet(if_index, &port) == ERROR)) return; semTake (igmpMSem, WAIT_FOREVER); --vs_igmp.port_table[port].igmpInterfaceEntry.igmpInterfaceGroups; semGive (igmpMSem); } /****************************************************************************** * * igmpQuerierTimeUpdate - update Mib variable for version one querier * * Sets the igmpInterfaceEntry.igmpInterfaceVersion1QuerierTimer to the * new value. * * RETURNS: N/A * * NOMANUAL */ void igmpQuerierTimeUpdate ( int if_index, /* index of port on which to add */ int time /* half seconds left until v1 querier timer expires */ ) { UINT32 port; if ((igmpPortGet (if_index, &port) == ERROR)) return; if (time < 0) /* sanity check */ time = 0; semTake (igmpMSem, WAIT_FOREVER); vs_igmp.port_table[port].igmpInterfaceEntry.igmpInterfaceVersion1QuerierTimer = (IGMP_AGE_THRESHOLD - time) * 100/PR_SLOWHZ; semGive (igmpMSem); /* must convert from halfs to hundredths */ }