NetBSD/usr.sbin/mrouted/snmp.c
hwr 729bc0fae0 The ioctls have been issued on the wrong socket, so they failed with a
EINVAL. This has been confirmed by Bill Fenner. The wrong socket led to
masses of syslog entries on hosts connected to the mbone and cache entries
deleted to early.

XXX As the socket need to be the one that is ip_mrouter in netinet/ip_mroute.c,
XXX the kernel could be modified to always return the data for ip_mrouter.

XXX Bill Fenner suggests to upgrade to 3.9.beta-3 with -DIOCTL_OK_ON_RAW_SOCKET
1999-01-23 22:44:43 +00:00

1288 lines
37 KiB
C

/* $NetBSD: snmp.c,v 1.4 1999/01/23 22:44:43 hwr Exp $ */
#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"
u_short 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)
u_short 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;
}
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)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register 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];
sprintf(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)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register 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)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register 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];
sprintf(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)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register 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)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register 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];
register 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)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register 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];
register 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)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register 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)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register 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)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register 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)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register 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;
}