457 lines
14 KiB
C
457 lines
14 KiB
C
/* 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 */
|
|
}
|