/*
* Copyright (c) 1992, 2001 Xerox Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither name of the Xerox, PARC, nor the names of its contributors may be used
* to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XEROX CORPORATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
struct addrCache {
u_long addr;
int status;
#define UNUSED 0
#define USED 1
#define OLD 2
};
static struct addrCache addrCache[10];
/*
* Initialize the SNMP part of mrouted
*/
int /* returns: 0 on success, true on error */
snmp_init(dest_port)
in_port_t dest_port;
{
u_long myaddr;
int ret;
struct partyEntry *pp;
struct sockaddr_in me;
int index, sd, portlist[32];
init_snmp();
/* init_mib(); why was this here? */
if (read_party_database("/etc/party.conf") > 0){
fprintf(stderr, "Couldn't read party database from /etc/party.conf\n");
exit(0);
}
if (read_context_database("/etc/context.conf") > 0){
fprintf(stderr, "Couldn't read context database from /etc/context.conf\n");
exit(0);
}
if (read_acl_database("/etc/acl.conf") > 0){
fprintf(stderr, "Couldn't read acl database from /etc/acl.conf\n");
exit(0);
}
if (read_view_database("/etc/view.conf") > 0){
fprintf(stderr, "Couldn't read view database from /etc/view.conf\n");
exit(0);
}
myaddr = get_myaddr();
if (ret = agent_party_init(myaddr, ".1.3.6.1")){
if (ret == 1){
fprintf(stderr, "Conflict found with initial noAuth/noPriv parties... continuing\n");
} else if (ret == -1){
fprintf(stderr, "Error installing initial noAuth/noPriv parties, exiting\n");
exit(1);
} else {
fprintf(stderr, "Unknown error, exiting\n");
exit(2);
}
}
/* Get an IP address from an OID starting at element n */
int
get_address(name, length, addr, n)
oid *name;
int length;
u_long *addr;
int n;
{
int i;
int ok = 1;
(*addr) = 0;
if (length < n+4)
return 0;
for (i=n; i<n+4; i++) {
(*addr) <<= 8;
if (i >= length)
ok = 0;
else
(*addr) |= name[i];
}
return ok;
}
/*
* Implements scalar objects from DVMRP and Multicast MIBs
*/
u_char *
o_scalar(vp, name, length, exact, var_len, write_method)
struct variable *vp; /* IN - pointer to variable entry that points here */
oid *name; /* IN/OUT - input name requested, output name found */
int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
int result;
/*
* Implements the Boundary Table portion of the DVMRP MIB
*/
u_char *
o_dvmrpBoundaryTable(vp, name, length, exact, var_len, write_method)
struct variable *vp; /* IN - pointer to variable entry that points here */
oid *name; /* IN/OUT - input name requested, output name found */
int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
vifi_t vifi;
u_long addr, mask;
struct vif_acl *bound;
oid newname[MAX_NAME_LEN];
int len;
/* Copy name OID to new OID */
bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
if (exact) {
if (*length != vp->namelen + 9)
return NULL;
if ((vifi = name[vp->namelen]) >= numvifs)
return NULL;
for (i = *vifi; i < numvifs; i++) {
bestn = NULL;
for (n = uvifs[i].uv_neighbors; n; n=n->al_next) {
if ((i > *vifi || n->al_addr >= addr)
&& (!bestn || n->al_addr < bestn->al_addr))
bestn = n;
}
if (bestn) {
*vifi = i;
return bestn;
}
}
return NULL;
}
/*
* Find a neighbor, if it exists off a given Vif
*/
struct listaddr *
find_neighbor(vifi, addr)
vifi_t vifi;
u_long addr;
{
struct listaddr *n;
for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) {
if (addr == n->al_addr)
return n;
}
return NULL;
}
u_char *
o_dvmrpNeighborTable(vp, name, length, exact, var_len, write_method)
struct variable *vp; /* IN - pointer to variable entry that points here */
oid *name; /* IN/OUT - input name requested, output name found */
int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
vifi_t vifi;
u_long addr, mask;
struct listaddr *neighbor;
oid newname[MAX_NAME_LEN];
int len;
/* Copy name OID to new OID */
bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
if (exact) {
if (*length != vp->namelen + 5)
return NULL;
if ((vifi = name[vp->namelen]) >= numvifs)
return NULL;
if (!get_address(name, *length, &addr, vp->namelen+1))
return NULL;
if (!(neighbor = find_neighbor(vifi, addr)))
return NULL;
bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
} else {
len = *length;
if (compare(name, *length, vp->name, vp->namelen) < 0)
len = vp->namelen;
if (len < vp->namelen + 5) { /* get first entry */
/*
* Find if a specific scoped boundary exists on a Vif
*/
struct listaddr *
find_cache(grp, vifi)
u_long grp;
vifi_t vifi;
{
struct listaddr *n;
for (n = uvifs[vifi].uv_groups; n != NULL; n = n->al_next) {
if (grp == n->al_addr)
return n;
}
return NULL;
}
/*
* Find the next group cache entry >= (A,V) spec
*/
struct listaddr *
next_cache(addr, vifi)
u_long addr;
vifi_t *vifi;
{
struct listaddr *bestn=NULL, *n;
int i, besti;
/* Step through all entries looking for the next one */
for (i = 0; i < numvifs; i++) {
for (n = uvifs[i].uv_groups; n; n=n->al_next) {
if ((n->al_addr > addr || (n->al_addr == addr && i >= *vifi))
&& (!bestn || n->al_addr < bestn->al_addr
|| (n->al_addr == bestn->al_addr && i < besti))) {
bestn = n;
besti = i;
}
}
}
/*
* Implements the IGMP Cache Table portion of the IGMP MIB
*/
u_char *
o_igmpCacheTable(vp, name, length, exact, var_len, write_method)
struct variable *vp; /* IN - pointer to variable entry that points here */
oid *name; /* IN/OUT - input name requested, output name found */
int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
vifi_t vifi;
u_long grp;
int ifIndex;
struct listaddr *cache;
oid newname[MAX_NAME_LEN];
int len;
struct in_ifaddr *in_ifaddr;
struct in_multi in_multi, *inm;
/* Copy name OID to new OID */
bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
if (exact) {
if (*length != vp->namelen + 5)
return NULL;
if ((vifi = name[vp->namelen+4]) >= numvifs)
return NULL;
if (!get_address(name, *length, &grp, vp->namelen))
return NULL;
if (!(cache = find_cache(grp, vifi)))
return NULL;
bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
} else {
len = *length;
if (compare(name, *length, vp->name, vp->namelen) < 0)
len = vp->namelen;
if (len < vp->namelen + 5) { /* get first entry */
case igmpCacheExpiryTime:
long_return = secs_remaining(cache->al_timerid)*100;
return (u_char *) &long_return;
case igmpCacheStatus:
long_return = 1;
return (u_char *) &long_return;
default:
ERROR("");
}
return NULL;
}
/*
* Implements the IGMP Interface Table portion of the IGMP MIB
*/
u_char *
o_igmpInterfaceTable(vp, name, length, exact, var_len, write_method)
struct variable *vp; /* IN - pointer to variable entry that points here */
oid *name; /* IN/OUT - input name requested, output name found */
int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
oid newname[MAX_NAME_LEN];
int ifnum;
int result;
static struct sioc_vif_req v_req;
/* Copy name OID to new OID */
bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
/* Save new OID */
bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid));
*length = vp->namelen + 1;
*write_method = 0;
*var_len = sizeof(long);
switch (vp->magic){
case igmpInterfaceQueryInterval:
long_return = GROUP_QUERY_INTERVAL;
return (u_char *) &long_return;
case igmpInterfaceStatus:
long_return = 1; /* active */
return (u_char *) &long_return;
default:
ERROR("");
}
return NULL;
}
/*
* Given a virtual interface number, make sure we have the current
* kernel information for that Vif.
*/
refresh_vif(v_req, ifnum)
struct sioc_vif_req *v_req;
int ifnum;
{
static int lastq = -1;
/*
* Implements the Multicast Routing Interface Table portion of the Multicast MIB
*/
u_char *
o_ipMRouteInterfaceTable(vp, name, length, exact, var_len, write_method)
struct variable *vp; /* IN - pointer to variable entry that points here */
oid *name; /* IN/OUT - input name requested, output name found */
int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
oid newname[MAX_NAME_LEN];
int ifnum;
int result;
static struct sioc_vif_req v_req;
/* Copy name OID to new OID */
bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
/*
* Implements the DVMRP Route Table portion of the DVMRP MIB
*/
u_char *
o_dvmrpRouteTable(vp, name, length, exact, var_len, write_method)
struct variable *vp; /* IN - pointer to variable entry that points here */
oid *name; /* IN/OUT - input name requested, output name found */
int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
u_long src, mask;
oid newname[MAX_NAME_LEN];
int len;
struct rtentry *rt = NULL;
/* Copy name OID to new OID */
bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
if (exact) {
if (*length != vp->namelen + 8)
return NULL;
/*
* Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB
*/
u_char *
o_dvmrpRouteNextHopTable(vp, name, length, exact, var_len, write_method)
struct variable *vp; /* IN - pointer to variable entry that points here */
oid *name; /* IN/OUT - input name requested, output name found */
int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
u_long src, mask;
vifi_t vifi;
struct rtentry *rt = NULL;
oid newname[MAX_NAME_LEN];
int len;
/* Copy name OID to new OID */
bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
if (exact) {
if (*length != vp->namelen + 9)
return NULL;
/*
* Implements the IP Multicast Route Table portion of the Multicast MIB
*/
u_char *
o_ipMRouteTable(vp, name, length, exact, var_len, write_method)
struct variable *vp; /* IN - pointer to variable entry that points here */
oid *name; /* IN/OUT - input name requested, output name found */
int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
u_long src, grp, mask;
struct gtable *gt = NULL;
struct stable *st = NULL;
static struct sioc_sg_req sg_req;
oid newname[MAX_NAME_LEN];
int len;
/* Copy name OID to new OID */
bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
if (exact) {
if (*length != vp->namelen + 12)
return NULL;
case ipMRouteProtocol:
long_return = 4;
return (u_char *) &long_return;
default:
ERROR("");
}
return NULL;
}
/*
* Implements the IP Multicast Routing Next Hop Table portion of the Multicast
* MIB
*/
u_char *
o_ipMRouteNextHopTable(vp, name, length, exact, var_len, write_method)
struct variable *vp; /* IN - pointer to variable entry that points here */
oid *name; /* IN/OUT - input name requested, output name found */
int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
u_long src, grp, mask, addr;
vifi_t vifi;
struct gtable *gt;
struct stable *st;
oid newname[MAX_NAME_LEN];
int len;
/* Copy name OID to new OID */
bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
if (exact) {
if (*length != vp->namelen + 17)
return NULL;
/* Currently equal to ipMRouteUpTime */
case ipMRouteNextHopUpTime: {
time_t currtime;
time(&currtime);
long_return = (currtime - gt->gt_ctime)*100;
return (u_char *) &long_return;
}
case ipMRouteNextHopExpiryTime:
long_return = 5*((gt->gt_prsent_timer+4)/5); /* round up to nearest 5*/
long_return = (long_return + secs_remaining_offset()) * 100;
return (u_char *) &long_return;
case ipMRouteNextHopClosestMemberHops:
long_return = 0;
return (u_char *) &long_return;
case ipMRouteNextHopProtocol:
long_return = 4;
return (u_char *) &long_return;
default:
ERROR("");
}
return NULL;
}
/* sync_timer is called by timer() every TIMER_INTERVAL seconds.
* Its job is to record this time so that we can compute on demand
* the approx # seconds remaining until the next timer() call
*/
static time_t lasttimer;
void
sync_timer()
{
time(&lasttimer);
}
int /* in range [-TIMER_INTERVAL..0] */
secs_remaining_offset()
{
time_t tm;