1319 lines
38 KiB
C
1319 lines
38 KiB
C
/* $NetBSD: snmp.c,v 1.10 2003/03/05 21:12:26 wiz 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];
|
|
|
|
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)
|
|
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];
|
|
|
|
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)
|
|
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(>,&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(>, &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_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(>, &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(>, &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;
|
|
}
|