NetBSD/usr.sbin/mrouted/snmp.c

1320 lines
38 KiB
C

/* $NetBSD: snmp.c,v 1.11 2003/05/16 18:10:38 itojun Exp $ */
/*
* 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.
*/
#include "defs.h"
#include <netinet/in_var.h>
#include "snmp.h"
#include "snmplib/asn1.h"
#include "snmplib/party.h"
#include "snmplib/snmp_impl.h"
#define MROUTED
#include "snmpd/snmp_vars.h"
in_port_t dest_port = 0;
int sdlen = 0;
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);
}
}
printf("Opening port(s): ");
fflush(stdout);
party_scanInit();
for(pp = party_scanNext(); pp; pp = party_scanNext()){
if ((pp->partyTDomain != DOMAINSNMPUDP)
|| bcmp((char *)&myaddr, pp->partyTAddress, 4))
continue; /* don't listen for non-local parties */
dest_port = 0;
bcopy(pp->partyTAddress + 4, &dest_port, 2);
for(index = 0; index < sdlen; index++)
if (dest_port == portlist[index])
break;
if (index < sdlen) /* found a hit before the end of the list */
continue;
printf("%u ", dest_port);
fflush(stdout);
/* Set up connections */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0){
perror("socket");
return 1;
}
memset(&me, 0, sizeof(me));
me.sin_family = AF_INET;
me.sin_addr.s_addr = INADDR_ANY;
/* already in network byte order (I think) */
me.sin_port = dest_port;
if (bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0){
perror("bind");
return 2;
}
register_input_handler(sd, snmp_read_packet);
portlist[sdlen] = dest_port;
if (++sdlen == 32){
printf("No more sockets... ignoring rest of file\n");
break;
}
}
printf("\n");
bzero((char *)addrCache, sizeof(addrCache));
}
/*
* Place an IP address into an OID starting at element n
*/
void
put_address(name, addr, n)
oid *name;
u_long addr;
int n;
{
int i;
for (i=n+3; i>=n+0; i--) {
name[i] = addr & 0xFF;
addr >>= 8;
}
}
/* 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;
*write_method = 0;
result = compare(name, *length, vp->name, (int)vp->namelen);
if ((exact && (result != 0)) || (!exact && (result >= 0)))
return NULL;
bcopy((char *)vp->name, (char *)name,
(int)vp->namelen * sizeof(oid));
*length = vp->namelen;
*var_len = sizeof(long);
switch (vp->magic) {
case ipMRouteEnable:
long_return = 1;
return (u_char *) &long_return;
case dvmrpVersion: {
static char buff[15];
snprintf(buff, sizeof(buff), "mrouted%d.%d", PROTOCOL_VERSION,
MROUTED_VERSION);
*var_len = strlen(buff);
return (u_char *)buff;
}
case dvmrpGenerationId:
long_return = dvmrp_genid;
return (u_char *) &long_return;
default:
ERROR("");
}
return NULL;
}
/*
* Find if a specific scoped boundary exists on a Vif
*/
struct vif_acl *
find_boundary(vifi, addr, mask)
vifi_t vifi;
u_long addr;
u_long mask;
{
struct vif_acl *n;
for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) {
if (addr == n->acl_addr && mask==n->acl_mask)
return n;
}
return NULL;
}
/*
* Find the lowest boundary >= (V,A,M) spec
*/
struct vif_acl *
next_boundary(vifi, addr, mask)
vifi_t *vifi;
u_long addr;
u_long mask;
{
struct vif_acl *bestn, *n;
int i;
for (i = *vifi; i < numvifs; i++) {
bestn = NULL;
for (n = uvifs[i].uv_acl; n; n=n->acl_next) {
if ((i > *vifi || n->acl_addr > addr
|| (n->acl_addr == addr && n->acl_mask >= mask))
&& (!bestn || n->acl_addr < bestn->acl_addr
|| (n->acl_addr==bestn->acl_addr && n->acl_mask<bestn->acl_mask)))
bestn = n;
}
if (bestn) {
*vifi = i;
return bestn;
}
}
return NULL;
}
/*
* 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;
if (!get_address(name, *length, &addr, vp->namelen+1)
|| !get_address(name, *length, &mask, vp->namelen+5))
return NULL;
if (!(bound = find_boundary(vifi, addr, mask)))
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 + 9) { /* get first entry */
if (len == vp->namelen) {
vifi = addr = mask = 0;
} else {
vifi = name[vp->namelen];
get_address(name, len, &addr, vp->namelen+1);
get_address(name, len, &mask, vp->namelen+5);
}
bound = next_boundary(&vifi,addr,mask);
if (!bound)
return NULL;
newname[vp->namelen] = vifi;
put_address(newname, bound->acl_addr, vp->namelen+1);
put_address(newname, bound->acl_mask, vp->namelen+5);
} else { /* get next entry given previous */
vifi = name[vp->namelen];
get_address(name, *length, &addr, vp->namelen+1);
get_address(name, *length, &mask, vp->namelen+5);
if (!(bound = next_boundary(&vifi,addr,mask+1)))
return NULL;
newname[vp->namelen] = vifi;
put_address(newname, bound->acl_addr, vp->namelen+1);
put_address(newname, bound->acl_mask, vp->namelen+5);
}
}
/* Save new OID */
*length = vp->namelen + 9;
bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
*write_method = 0;
*var_len = sizeof(long);
switch (vp->magic) {
case dvmrpBoundaryVifIndex:
long_return = vifi;
return (u_char *) &long_return;
default:
ERROR("");
}
return NULL;
}
/*
* Find the lowest neighbor >= (V,A) spec
*/
struct listaddr *
next_neighbor(vifi, addr)
vifi_t *vifi;
u_long addr;
{
struct listaddr *bestn, *n;
int i;
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 */
if (len == vp->namelen) {
vifi = addr = 0;
} else {
vifi = name[vp->namelen];
get_address(name, len, &addr, vp->namelen+1);
}
neighbor = next_neighbor(&vifi,addr);
if (!neighbor)
return NULL;
newname[vp->namelen] = vifi;
put_address(newname, neighbor->al_addr, vp->namelen+1);
} else { /* get next entry given previous */
vifi = name[vp->namelen];
get_address(name, *length, &addr, vp->namelen+1);
if (!(neighbor = next_neighbor(&vifi,addr+1)))
return NULL;
newname[vp->namelen] = vifi;
put_address(newname, neighbor->al_addr, vp->namelen+1);
}
}
/* Save new OID */
*length = vp->namelen + 5;
bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
*write_method = 0;
*var_len = sizeof(long);
switch (vp->magic) {
case dvmrpNeighborUpTime: {
time_t currtime;
time(&currtime);
long_return = (currtime - neighbor->al_ctime)*100;
return (u_char *) &long_return;
}
case dvmrpNeighborExpiryTime:
long_return = (NEIGHBOR_EXPIRE_TIME - neighbor->al_timer
+ secs_remaining_offset()) * 100;
return (u_char *) &long_return;
case dvmrpNeighborVersion: {
static char buff[15];
snprintf(buff, sizeof(buff), "%d.%d", neighbor->al_pv, neighbor->al_mv);
*var_len = strlen(buff);
return (u_char *)buff;
}
case dvmrpNeighborGenerationId:
long_return = neighbor->al_genid;
return (u_char *) &long_return;
default:
ERROR("");
}
return NULL;
}
/* Look up ifIndex given uvifs[ifnum].uv_lcl_addr */
struct in_ifaddr * /* returns: in_ifaddr structure, or null on error */
ipaddr_to_ifindex(ipaddr, ifIndex)
u_long ipaddr;
int *ifIndex;
{
int interface;
static struct in_ifaddr in_ifaddr;
Interface_Scan_Init();
for (;;) {
if (Interface_Scan_Next(&interface, (char *)0, NULL, &in_ifaddr) == 0)
return NULL;
if (((struct sockaddr_in *) &(in_ifaddr.ia_addr))->sin_addr.s_addr
== ipaddr) {
*ifIndex = interface;
return &in_ifaddr;
}
}
}
/*
* 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;
}
}
}
if (bestn) {
*vifi = besti;
return bestn;
}
return NULL;
}
/*
* 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 */
if (len == vp->namelen) {
vifi = grp = 0;
} else {
get_address(name, len, &grp, vp->namelen);
vifi = name[vp->namelen+4];
}
cache = next_cache(grp,&vifi);
if (!cache)
return NULL;
put_address(newname, cache->al_addr, vp->namelen);
newname[vp->namelen+4] = vifi;
} else { /* get next entry given previous */
get_address(name, *length, &grp, vp->namelen);
vifi = name[vp->namelen+4]+1;
if (!(cache = next_cache(grp,&vifi)))
return NULL;
put_address(newname, cache->al_addr, vp->namelen);
newname[vp->namelen+4] = vifi;
}
}
/* Save new OID */
*length = vp->namelen + 5;
bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
*write_method = 0;
*var_len = sizeof(long);
/* Look up ifIndex given uvifs[vifi].uv_lcl_addr */
in_ifaddr = ipaddr_to_ifindex(uvifs[vifi].uv_lcl_addr, &ifIndex);
switch (vp->magic) {
case igmpCacheSelf:
inm = in_ifaddr->ia_multiaddrs;
while (inm) {
klookup( (int)inm, (char *)&in_multi, sizeof(in_multi));
if (in_multi.inm_addr.s_addr == cache->al_addr) {
long_return = 1; /* true */
return (u_char *) &long_return;
}
inm = in_multi.inm_next;
}
long_return = 2; /* false */
return (u_char *) &long_return;
case igmpCacheLastReporter:
return (u_char *) &cache->al_genid;
case igmpCacheUpTime: {
time_t currtime;
time(&currtime);
long_return = (currtime - cache->al_ctime)*100;
return (u_char *) &long_return;
}
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));
/* find "next" interface */
for(ifnum = 0; ifnum < numvifs; ifnum++){
if (!(uvifs[ifnum].uv_flags & VIFF_QUERIER))
continue;
newname[vp->namelen] = (oid)ifnum;
result = compare(name, *length, newname, (int)vp->namelen + 1);
if ((exact && (result == 0)) || (!exact && (result < 0)))
break;
}
if (ifnum >= numvifs)
return NULL;
/* 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;
if (quantum!=lastq || v_req->vifi != ifnum) {
lastq = quantum;
v_req->vifi = ifnum;
if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)v_req) < 0)
v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0;
}
}
/*
* 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));
/* find "next" interface */
for(ifnum = 0; ifnum < numvifs; ifnum++){
newname[vp->namelen] = (oid)ifnum;
result = compare(name, *length, newname, (int)vp->namelen + 1);
if ((exact && (result == 0)) || (!exact && (result < 0)))
break;
}
if (ifnum >= numvifs)
return NULL;
/* 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 ipMRouteInterfaceTtl:
long_return = uvifs[ifnum].uv_threshold;
return (u_char *) &long_return;
case dvmrpVInterfaceType:
if (uvifs[ifnum].uv_flags & VIFF_SRCRT)
long_return = 2;
else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL)
long_return = 1;
else if (uvifs[ifnum].uv_flags & VIFF_QUERIER)
long_return = 3;
else /* SUBNET */
long_return = 4;
return (u_char *) &long_return;
case dvmrpVInterfaceState:
if (uvifs[ifnum].uv_flags & VIFF_DISABLED)
long_return = 3;
else if ((uvifs[ifnum].uv_flags & VIFF_DOWN)
|| ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) && (uvifs[ifnum].uv_neighbors==NULL)))
long_return = 2;
else /* UP */
long_return = 1;
return (u_char *) &long_return;
case dvmrpVInterfaceLocalAddress:
return (u_char *) &uvifs[ifnum].uv_lcl_addr;
case dvmrpVInterfaceRemoteAddress:
return (u_char *) ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) ?
&uvifs[ifnum].uv_rmt_addr :
&uvifs[ifnum].uv_subnet);
case dvmrpVInterfaceRemoteSubnetMask:
return (u_char *) &uvifs[ifnum].uv_subnetmask;
case dvmrpVInterfaceMetric:
long_return = uvifs[ifnum].uv_metric;
return (u_char *) &long_return;
case dvmrpVInterfaceRateLimit:
long_return = uvifs[ifnum].uv_rate_limit;
return (u_char *) &long_return;
case dvmrpVInterfaceInPkts:
refresh_vif(&v_req, ifnum);
long_return = v_req.icount;
return (u_char *) &long_return;
case dvmrpVInterfaceOutPkts:
refresh_vif(&v_req, ifnum);
long_return = v_req.ocount;
return (u_char *) &long_return;
case dvmrpVInterfaceInOctets:
refresh_vif(&v_req, ifnum);
long_return = v_req.ibytes;
return (u_char *) &long_return;
case dvmrpVInterfaceOutOctets:
refresh_vif(&v_req, ifnum);
long_return = v_req.obytes;
return (u_char *) &long_return;
default:
ERROR("");
}
return NULL;
}
/*
* 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;
if (!get_address(name, *length, &src, vp->namelen)
|| !get_address(name, *length, &mask, vp->namelen+4))
return NULL;
if (!(rt = snmp_find_route(src, mask)))
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 + 8) { /* get first entry */
if (len == vp->namelen) {
src = mask = 0;
} else {
get_address(name, len, &src, vp->namelen);
get_address(name, len, &mask, vp->namelen+4);
}
if (!next_route(&rt,src,mask)) /* Get first entry */
return NULL;
put_address(newname, rt->rt_origin , vp->namelen);
put_address(newname, rt->rt_originmask, vp->namelen+4);
} else { /* get next entry given previous */
get_address(name, *length, &src, vp->namelen);
get_address(name, *length, &mask, vp->namelen+4);
if (!next_route(&rt, src,mask))
return NULL;
put_address(newname, rt->rt_origin, vp->namelen);
put_address(newname, rt->rt_originmask, vp->namelen+4);
}
}
/* Save new OID */
*length = vp->namelen + 8;
bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
*write_method = 0;
*var_len = sizeof(long);
switch (vp->magic) {
case dvmrpRouteUpstreamNeighbor:
return (u_char *) &rt->rt_gateway;
case dvmrpRouteInVifIndex:
long_return = rt->rt_parent;
return (u_char *) &long_return;
case dvmrpRouteMetric:
long_return = rt->rt_metric;
return (u_char *) &long_return;
case dvmrpRouteExpiryTime:
long_return = (ROUTE_EXPIRE_TIME - rt->rt_timer
+ secs_remaining_offset()) * 100;
return (u_char *) &long_return;
default:
ERROR("");
}
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;
if (!get_address(name, *length, &src, vp->namelen)
|| !get_address(name, *length, &mask, vp->namelen+4)
|| (!(rt=snmp_find_route(src,mask))))
return NULL;
vifi = name[vp->namelen+8];
if (!(VIFM_ISSET(vifi, rt->rt_children)))
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 + 9) { /* get first entry */
get_address(name, len, &src, vp->namelen);
get_address(name, len, &mask, vp->namelen+4);
/* Find first child vif */
vifi=0;
if (!next_route_child(&rt, src, mask, &vifi))
return NULL;
put_address(newname, rt->rt_origin, vp->namelen);
put_address(newname, rt->rt_originmask, vp->namelen+4);
newname[vp->namelen+8] = vifi;
} else { /* get next entry given previous */
vifi = name[vp->namelen+8] + 1;
if (!get_address(name, *length, &src, vp->namelen)
|| !get_address(name, *length, &mask, vp->namelen+4)
|| !next_route_child(&rt, src, mask, &vifi))
return NULL;
put_address(newname, rt->rt_origin, vp->namelen);
put_address(newname, rt->rt_originmask, vp->namelen+4);
newname[vp->namelen+8] = vifi;
}
}
/* Save new OID */
*length = vp->namelen + 9;
bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
*write_method = 0;
*var_len = sizeof(long);
switch (vp->magic) {
case dvmrpRouteNextHopType:
long_return = (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2;
return (u_char *) &long_return;
default:
ERROR("");
}
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;
if (!get_address(name, *length, &grp, vp->namelen)
|| !get_address(name, *length, &src, vp->namelen+4)
|| !get_address(name, *length, &mask, vp->namelen+8)
|| (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */
|| !(gt = find_grp(grp))
|| !(st = find_grp_src(gt,src)))
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 + 12) { /* get first entry */
get_address(name, len, &grp, vp->namelen);
get_address(name, len, &src, vp->namelen+4);
get_address(name, len, &mask, vp->namelen+8);
if (!next_grp_src_mask(&gt,&st,grp,src,mask)) /* Get first entry */
return NULL;
put_address(newname, gt->gt_mcastgrp, vp->namelen);
put_address(newname, st->st_origin, vp->namelen+4);
put_address(newname, 0xFFFFFFFF, vp->namelen+8);
} else { /* get next entry given previous */
get_address(name, *length, &grp , vp->namelen);
get_address(name, *length, &src , vp->namelen+4);
get_address(name, *length, &mask, vp->namelen+8);
if (!next_grp_src_mask(&gt, &st, grp,src,mask))
return NULL;
put_address(newname, gt->gt_mcastgrp, vp->namelen);
put_address(newname, st->st_origin, vp->namelen+4);
put_address(newname, 0xFFFFFFFF, vp->namelen+8);
}
}
/* Save new OID */
*length = vp->namelen + 12;
bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
*write_method = 0;
*var_len = sizeof(long);
switch (vp->magic) {
case ipMRouteUpstreamNeighbor:
return (u_char *) &gt->gt_route->rt_gateway;
case ipMRouteInIfIndex:
long_return = gt->gt_route->rt_parent;
return (u_char *) &long_return;
case ipMRouteUpTime: {
time_t currtime;
time(&currtime);
long_return = (currtime - gt->gt_ctime)*100;
return (u_char *) &long_return;
}
case ipMRouteExpiryTime:
long_return = 5*((gt->gt_timer+4)/5); /* round up to nearest 5 */
long_return = (long_return + secs_remaining_offset()) * 100;
return (u_char *) &long_return;
case ipMRoutePkts:
refresh_sg(&sg_req, gt, st);
long_return = sg_req.pktcnt;
return (u_char *) &long_return;
case ipMRouteOctets:
refresh_sg(&sg_req, gt, st);
long_return = sg_req.bytecnt;
return (u_char *) &long_return;
case ipMRouteDifferentInIfIndexes:
refresh_sg(&sg_req, gt, st);
long_return = sg_req.wrong_if;
return (u_char *) &long_return;
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;
if (!get_address(name, *length, &grp, vp->namelen)
|| !get_address(name, *length, &src, vp->namelen+4)
|| !get_address(name, *length, &mask, vp->namelen+8)
|| !get_address(name, *length, &addr, vp->namelen+13)
|| grp!=addr
|| mask!=0xFFFFFFFF
|| (!(gt=find_grp(grp)))
|| (!(st=find_grp_src(gt,src))))
return NULL;
vifi = name[vp->namelen+12];
if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children)))
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 + 17) { /* get first entry */
get_address(name, len, &grp, vp->namelen);
get_address(name, len, &src, vp->namelen+4);
get_address(name, len, &mask, vp->namelen+8);
/* Find first child vif */
vifi=0;
if (!next_child(&gt, &st, grp, src, mask, &vifi))
return NULL;
put_address(newname, gt->gt_mcastgrp, vp->namelen);
put_address(newname, st->st_origin, vp->namelen+4);
put_address(newname, 0xFFFFFFFF, vp->namelen+8);
newname[vp->namelen+12] = vifi;
put_address(newname, gt->gt_mcastgrp, vp->namelen+13);
} else { /* get next entry given previous */
vifi = name[vp->namelen+12]+1;
if (!get_address(name, *length, &grp, vp->namelen)
|| !get_address(name, *length, &src, vp->namelen+4)
|| !get_address(name, *length, &mask, vp->namelen+8)
|| !next_child(&gt, &st, grp, src, mask, &vifi))
return NULL;
put_address(newname, gt->gt_mcastgrp, vp->namelen);
put_address(newname, st->st_origin, vp->namelen+4);
put_address(newname, 0xFFFFFFFF, vp->namelen+8);
newname[vp->namelen+12] = vifi;
put_address(newname, gt->gt_mcastgrp, vp->namelen+13);
}
}
/* Save new OID */
*length = vp->namelen + 17;
bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
*write_method = 0;
*var_len = sizeof(long);
switch (vp->magic) {
case ipMRouteNextHopState:
long_return = (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1;
return (u_char *) &long_return;
/* 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;
time(&tm);
return lasttimer-tm;
}