Home | History | Annotate | Line # | Download | only in mrouted
      1 /*	$NetBSD: snmp.c,v 1.11 2003/05/16 18:10:38 itojun Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1992, 2001 Xerox Corporation.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without modification,
      7  * are permitted provided that the following conditions are met:
      8  *
      9  * Redistributions of source code must retain the above copyright notice,
     10  * this list of conditions and the following disclaimer.
     11  *
     12  * Redistributions in binary form must reproduce the above copyright notice,
     13  * this list of conditions and the following disclaimer in the documentation
     14  * and/or other materials provided with the distribution.
     15  *
     16  * Neither name of the Xerox, PARC, nor the names of its contributors may be used
     17  * to endorse or promote products derived from this software
     18  * without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
     21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XEROX CORPORATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include "defs.h"
     34 #include <netinet/in_var.h>
     35 #include "snmp.h"
     36 #include "snmplib/asn1.h"
     37 #include "snmplib/party.h"
     38 #include "snmplib/snmp_impl.h"
     39 #define MROUTED
     40 #include "snmpd/snmp_vars.h"
     41 
     42     in_port_t dest_port = 0;
     43     int sdlen = 0;
     44 
     45 struct addrCache {
     46     u_long addr;
     47     int status;
     48 #define UNUSED 0
     49 #define USED   1
     50 #define OLD 2
     51 };
     52 
     53 static struct addrCache addrCache[10];
     54 
     55 /*
     56  * Initialize the SNMP part of mrouted
     57  */
     58 int /* returns: 0 on success, true on error */
     59 snmp_init(dest_port)
     60     in_port_t dest_port;
     61 {
     62    u_long myaddr;
     63    int ret;
     64    struct partyEntry *pp;
     65    struct sockaddr_in  me;
     66    int index, sd, portlist[32];
     67 
     68    init_snmp();
     69    /* init_mib(); why was this here? */
     70     if (read_party_database("/etc/party.conf") > 0){
     71    fprintf(stderr, "Couldn't read party database from /etc/party.conf\n");
     72    exit(0);
     73     }
     74     if (read_context_database("/etc/context.conf") > 0){
     75    fprintf(stderr, "Couldn't read context database from /etc/context.conf\n");
     76    exit(0);
     77     }
     78     if (read_acl_database("/etc/acl.conf") > 0){
     79    fprintf(stderr, "Couldn't read acl database from /etc/acl.conf\n");
     80    exit(0);
     81     }
     82     if (read_view_database("/etc/view.conf") > 0){
     83    fprintf(stderr, "Couldn't read view database from /etc/view.conf\n");
     84    exit(0);
     85     }
     86 
     87     myaddr = get_myaddr();
     88     if (ret = agent_party_init(myaddr, ".1.3.6.1")){
     89    if (ret == 1){
     90        fprintf(stderr, "Conflict found with initial noAuth/noPriv parties... continuing\n");
     91    } else if (ret == -1){
     92        fprintf(stderr, "Error installing initial noAuth/noPriv parties, exiting\n");
     93        exit(1);
     94    } else {
     95        fprintf(stderr, "Unknown error, exiting\n");
     96        exit(2);
     97    }
     98     }
     99 
    100     printf("Opening port(s): ");
    101     fflush(stdout);
    102     party_scanInit();
    103     for(pp = party_scanNext(); pp; pp = party_scanNext()){
    104    if ((pp->partyTDomain != DOMAINSNMPUDP)
    105        || bcmp((char *)&myaddr, pp->partyTAddress, 4))
    106        continue;  /* don't listen for non-local parties */
    107 
    108    dest_port = 0;
    109    bcopy(pp->partyTAddress + 4, &dest_port, 2);
    110    for(index = 0; index < sdlen; index++)
    111        if (dest_port == portlist[index])
    112       break;
    113    if (index < sdlen)  /* found a hit before the end of the list */
    114        continue;
    115    printf("%u ", dest_port);
    116    fflush(stdout);
    117    /* Set up connections */
    118    sd = socket(AF_INET, SOCK_DGRAM, 0);
    119    if (sd < 0){
    120        perror("socket");
    121        return 1;
    122    }
    123    memset(&me, 0, sizeof(me));
    124    me.sin_family = AF_INET;
    125    me.sin_addr.s_addr = INADDR_ANY;
    126    /* already in network byte order (I think) */
    127    me.sin_port = dest_port;
    128    if (bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0){
    129        perror("bind");
    130        return 2;
    131    }
    132    register_input_handler(sd, snmp_read_packet);
    133    portlist[sdlen] = dest_port;
    134    if (++sdlen == 32){
    135        printf("No more sockets... ignoring rest of file\n");
    136        break;
    137    }
    138     }
    139     printf("\n");
    140     bzero((char *)addrCache, sizeof(addrCache));
    141 }
    142 
    143 /*
    144  * Place an IP address into an OID starting at element n
    145  */
    146 void
    147 put_address(name, addr, n)
    148    oid	 *name;
    149    u_long addr;
    150    int n;
    151 {
    152    int i;
    153 
    154    for (i=n+3; i>=n+0; i--) {
    155       name[i] = addr & 0xFF;
    156       addr >>= 8;
    157    }
    158 }
    159 
    160 /* Get an IP address from an OID starting at element n */
    161 int
    162 get_address(name, length, addr, n)
    163    oid	 *name;
    164    int	  length;
    165    u_long *addr;
    166    int n;
    167 {
    168    int i;
    169    int ok = 1;
    170 
    171    (*addr) = 0;
    172 
    173    if (length < n+4)
    174       return 0;
    175 
    176    for (i=n; i<n+4; i++) {
    177       (*addr) <<= 8;
    178       if (i >= length)
    179           ok = 0;
    180       else
    181          (*addr) |= name[i];
    182    }
    183    return ok;
    184 }
    185 
    186 /*
    187  * Implements scalar objects from DVMRP and Multicast MIBs
    188  */
    189 u_char *
    190 o_scalar(vp, name, length, exact, var_len, write_method)
    191     struct variable *vp;   /* IN - pointer to variable entry that points here */
    192     oid	*name;	    /* IN/OUT - input name requested, output name found */
    193     int	*length;    /* IN/OUT - length of input and output oid's */
    194     int			exact;	    /* IN - TRUE if an exact match was requested. */
    195     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    196     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    197 {
    198     int result;
    199 
    200     *write_method = 0;
    201     result = compare(name, *length, vp->name, (int)vp->namelen);
    202     if ((exact && (result != 0)) || (!exact && (result >= 0)))
    203    return NULL;
    204 
    205 	bcopy((char *)vp->name, (char *)name,
    206      (int)vp->namelen * sizeof(oid));
    207 	*length = vp->namelen;
    208 	*var_len = sizeof(long);
    209 
    210     switch (vp->magic) {
    211 
    212     case ipMRouteEnable:
    213        long_return = 1;
    214        return (u_char *) &long_return;
    215 
    216     case dvmrpVersion: {
    217        static char buff[15];
    218 
    219        snprintf(buff, sizeof(buff), "mrouted%d.%d", PROTOCOL_VERSION,
    220 	       MROUTED_VERSION);
    221        *var_len = strlen(buff);
    222        return (u_char *)buff;
    223     }
    224 
    225     case dvmrpGenerationId:
    226        long_return = dvmrp_genid;
    227        return (u_char *) &long_return;
    228 
    229     default:
    230        ERROR("");
    231     }
    232     return NULL;
    233 }
    234 
    235 /*
    236  * Find if a specific scoped boundary exists on a Vif
    237  */
    238 struct vif_acl *
    239 find_boundary(vifi, addr, mask)
    240    vifi_t vifi;
    241    u_long addr;
    242    u_long mask;
    243 {
    244    struct vif_acl *n;
    245 
    246    for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) {
    247       if (addr == n->acl_addr && mask==n->acl_mask)
    248          return n;
    249    }
    250    return NULL;
    251 }
    252 
    253 /*
    254  * Find the lowest boundary >= (V,A,M) spec
    255  */
    256 struct vif_acl *
    257 next_boundary(vifi, addr, mask)
    258    vifi_t *vifi;
    259    u_long  addr;
    260    u_long  mask;
    261 {
    262    struct vif_acl *bestn, *n;
    263    int  i;
    264 
    265    for (i = *vifi; i < numvifs; i++) {
    266       bestn = NULL;
    267       for (n = uvifs[i].uv_acl; n; n=n->acl_next) {
    268          if ((i > *vifi || n->acl_addr > addr
    269            || (n->acl_addr == addr && n->acl_mask >= mask))
    270           && (!bestn || n->acl_addr < bestn->acl_addr
    271            || (n->acl_addr==bestn->acl_addr && n->acl_mask<bestn->acl_mask)))
    272             bestn = n;
    273       }
    274       if (bestn) {
    275          *vifi = i;
    276          return bestn;
    277       }
    278    }
    279    return NULL;
    280 }
    281 
    282 /*
    283  * Implements the Boundary Table portion of the DVMRP MIB
    284  */
    285 u_char *
    286 o_dvmrpBoundaryTable(vp, name, length, exact, var_len, write_method)
    287     struct variable *vp;   /* IN - pointer to variable entry that points here */
    288     oid	*name;	    /* IN/OUT - input name requested, output name found */
    289     int	*length;    /* IN/OUT - length of input and output oid's */
    290     int			exact;	    /* IN - TRUE if an exact match was requested. */
    291     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    292     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    293 {
    294     vifi_t     vifi;
    295     u_long	   addr, mask;
    296     struct vif_acl *bound;
    297     oid        newname[MAX_NAME_LEN];
    298     int        len;
    299 
    300     /* Copy name OID to new OID */
    301     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    302 
    303     if (exact) {
    304 	    if (*length != vp->namelen + 9)
    305 		return NULL;
    306 
    307       if ((vifi = name[vp->namelen]) >= numvifs)
    308       return NULL;
    309 
    310       if (!get_address(name, *length, &addr, vp->namelen+1)
    311        || !get_address(name, *length, &mask, vp->namelen+5))
    312 		return NULL;
    313 
    314       if (!(bound = find_boundary(vifi, addr, mask)))
    315 		return NULL;
    316 
    317        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
    318 	 } else {
    319        len = *length;
    320        if (compare(name, *length, vp->name, vp->namelen) < 0)
    321           len = vp->namelen;
    322 
    323 	    if (len < vp->namelen + 9) { /* get first entry */
    324 
    325          if (len == vp->namelen) {
    326             vifi = addr = mask = 0;
    327          } else {
    328             vifi = name[vp->namelen];
    329             get_address(name, len, &addr, vp->namelen+1);
    330             get_address(name, len, &mask, vp->namelen+5);
    331          }
    332 
    333          bound = next_boundary(&vifi,addr,mask);
    334          if (!bound)
    335             return NULL;
    336 
    337    		newname[vp->namelen] = vifi;
    338          put_address(newname, bound->acl_addr, vp->namelen+1);
    339          put_address(newname, bound->acl_mask, vp->namelen+5);
    340 	    } else {  /* get next entry given previous */
    341 		   vifi = name[vp->namelen];
    342          get_address(name, *length, &addr, vp->namelen+1);
    343          get_address(name, *length, &mask, vp->namelen+5);
    344 
    345          if (!(bound = next_boundary(&vifi,addr,mask+1)))
    346             return NULL;
    347 
    348 		   newname[vp->namelen] = vifi;
    349          put_address(newname, bound->acl_addr, vp->namelen+1);
    350          put_address(newname, bound->acl_mask, vp->namelen+5);
    351 	    }
    352     }
    353 
    354     /* Save new OID */
    355     *length = vp->namelen + 9;
    356     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
    357     *write_method = 0;
    358     *var_len = sizeof(long);
    359 
    360     switch (vp->magic) {
    361 
    362    case dvmrpBoundaryVifIndex:
    363        long_return = vifi;
    364        return (u_char *) &long_return;
    365 
    366     default:
    367        ERROR("");
    368     }
    369     return NULL;
    370 }
    371 
    372 /*
    373  * Find the lowest neighbor >= (V,A) spec
    374  */
    375 struct listaddr *
    376 next_neighbor(vifi, addr)
    377    vifi_t *vifi;
    378    u_long  addr;
    379 {
    380    struct listaddr *bestn, *n;
    381    int  i;
    382 
    383    for (i = *vifi; i < numvifs; i++) {
    384       bestn = NULL;
    385       for (n = uvifs[i].uv_neighbors; n; n=n->al_next) {
    386          if ((i > *vifi || n->al_addr >= addr)
    387           && (!bestn || n->al_addr < bestn->al_addr))
    388             bestn = n;
    389       }
    390       if (bestn) {
    391          *vifi = i;
    392          return bestn;
    393       }
    394    }
    395    return NULL;
    396 }
    397 
    398 /*
    399  * Find a neighbor, if it exists off a given Vif
    400  */
    401 struct listaddr *
    402 find_neighbor(vifi, addr)
    403    vifi_t vifi;
    404    u_long addr;
    405 {
    406    struct listaddr *n;
    407 
    408    for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) {
    409       if (addr == n->al_addr)
    410          return n;
    411    }
    412    return NULL;
    413 }
    414 
    415 u_char *
    416 o_dvmrpNeighborTable(vp, name, length, exact, var_len, write_method)
    417     struct variable *vp;   /* IN - pointer to variable entry that points here */
    418     oid	*name;	    /* IN/OUT - input name requested, output name found */
    419     int	*length;    /* IN/OUT - length of input and output oid's */
    420     int			exact;	    /* IN - TRUE if an exact match was requested. */
    421     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    422     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    423 {
    424     vifi_t     vifi;
    425     u_long     addr, mask;
    426     struct listaddr *neighbor;
    427     oid        newname[MAX_NAME_LEN];
    428     int        len;
    429 
    430     /* Copy name OID to new OID */
    431     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    432 
    433     if (exact) {
    434 	    if (*length != vp->namelen + 5)
    435 		return NULL;
    436 
    437       if ((vifi = name[vp->namelen]) >= numvifs)
    438       return NULL;
    439 
    440       if (!get_address(name, *length, &addr, vp->namelen+1))
    441 		return NULL;
    442 
    443       if (!(neighbor = find_neighbor(vifi, addr)))
    444 		return NULL;
    445 
    446        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
    447 	 } else {
    448        len = *length;
    449        if (compare(name, *length, vp->name, vp->namelen) < 0)
    450           len = vp->namelen;
    451 
    452 	    if (len < vp->namelen + 5) { /* get first entry */
    453 
    454          if (len == vp->namelen) {
    455             vifi = addr = 0;
    456          } else {
    457             vifi = name[vp->namelen];
    458             get_address(name, len, &addr, vp->namelen+1);
    459          }
    460 
    461          neighbor = next_neighbor(&vifi,addr);
    462          if (!neighbor)
    463             return NULL;
    464 
    465    		newname[vp->namelen] = vifi;
    466          put_address(newname, neighbor->al_addr, vp->namelen+1);
    467 	    } else {  /* get next entry given previous */
    468 		   vifi = name[vp->namelen];
    469          get_address(name, *length, &addr, vp->namelen+1);
    470 
    471          if (!(neighbor = next_neighbor(&vifi,addr+1)))
    472             return NULL;
    473 
    474 		   newname[vp->namelen] = vifi;
    475          put_address(newname, neighbor->al_addr, vp->namelen+1);
    476 	    }
    477     }
    478 
    479     /* Save new OID */
    480     *length = vp->namelen + 5;
    481     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
    482     *write_method = 0;
    483     *var_len = sizeof(long);
    484 
    485     switch (vp->magic) {
    486 
    487    case dvmrpNeighborUpTime: {
    488        time_t currtime;
    489        time(&currtime);
    490        long_return = (currtime - neighbor->al_ctime)*100;
    491        return (u_char *) &long_return;
    492    }
    493 
    494    case dvmrpNeighborExpiryTime:
    495        long_return = (NEIGHBOR_EXPIRE_TIME - neighbor->al_timer
    496         + secs_remaining_offset()) * 100;
    497        return (u_char *) &long_return;
    498 
    499    case dvmrpNeighborVersion: {
    500        static char buff[15];
    501 
    502        snprintf(buff, sizeof(buff), "%d.%d", neighbor->al_pv, neighbor->al_mv);
    503        *var_len = strlen(buff);
    504        return (u_char *)buff;
    505    }
    506 
    507    case dvmrpNeighborGenerationId:
    508        long_return = neighbor->al_genid;
    509        return (u_char *) &long_return;
    510 
    511     default:
    512        ERROR("");
    513     }
    514     return NULL;
    515 }
    516 
    517 /* Look up ifIndex given uvifs[ifnum].uv_lcl_addr */
    518 struct in_ifaddr *        /* returns: in_ifaddr structure, or null on error */
    519 ipaddr_to_ifindex(ipaddr, ifIndex)
    520    u_long ipaddr;
    521    int   *ifIndex;
    522 {
    523     int interface;
    524 static struct in_ifaddr in_ifaddr;
    525 
    526     Interface_Scan_Init();
    527     for (;;) {
    528        if (Interface_Scan_Next(&interface, (char *)0, NULL, &in_ifaddr) == 0)
    529           return NULL;
    530 
    531        if (((struct sockaddr_in *) &(in_ifaddr.ia_addr))->sin_addr.s_addr
    532         == ipaddr) {
    533           *ifIndex = interface;
    534           return &in_ifaddr;
    535        }
    536     }
    537 }
    538 
    539 /*
    540  * Find if a specific scoped boundary exists on a Vif
    541  */
    542 struct listaddr *
    543 find_cache(grp, vifi)
    544    u_long grp;
    545    vifi_t vifi;
    546 {
    547    struct listaddr *n;
    548 
    549    for (n = uvifs[vifi].uv_groups; n != NULL; n = n->al_next) {
    550       if (grp == n->al_addr)
    551          return n;
    552    }
    553    return NULL;
    554 }
    555 
    556 /*
    557  * Find the next group cache entry >= (A,V) spec
    558  */
    559 struct listaddr *
    560 next_cache(addr, vifi)
    561    u_long  addr;
    562    vifi_t *vifi;
    563 {
    564    struct listaddr *bestn=NULL, *n;
    565    int  i, besti;
    566 
    567    /* Step through all entries looking for the next one */
    568    for (i = 0; i < numvifs; i++) {
    569       for (n = uvifs[i].uv_groups; n; n=n->al_next) {
    570          if ((n->al_addr > addr || (n->al_addr == addr && i >= *vifi))
    571           && (!bestn || n->al_addr < bestn->al_addr
    572            || (n->al_addr == bestn->al_addr && i < besti))) {
    573             bestn = n;
    574             besti = i;
    575          }
    576       }
    577    }
    578 
    579    if (bestn) {
    580       *vifi = besti;
    581       return bestn;
    582    }
    583    return NULL;
    584 }
    585 
    586 /*
    587  * Implements the IGMP Cache Table portion of the IGMP MIB
    588  */
    589 u_char *
    590 o_igmpCacheTable(vp, name, length, exact, var_len, write_method)
    591     struct variable *vp;   /* IN - pointer to variable entry that points here */
    592     oid	*name;	    /* IN/OUT - input name requested, output name found */
    593     int	*length;    /* IN/OUT - length of input and output oid's */
    594     int			exact;	    /* IN - TRUE if an exact match was requested. */
    595     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    596     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    597 {
    598     vifi_t     vifi;
    599     u_long     grp;
    600     int	      ifIndex;
    601     struct listaddr *cache;
    602     oid        newname[MAX_NAME_LEN];
    603     int        len;
    604     struct in_ifaddr *in_ifaddr;
    605     struct in_multi   in_multi, *inm;
    606 
    607     /* Copy name OID to new OID */
    608     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    609 
    610     if (exact) {
    611 	    if (*length != vp->namelen + 5)
    612 		return NULL;
    613 
    614       if ((vifi = name[vp->namelen+4]) >= numvifs)
    615       return NULL;
    616 
    617       if (!get_address(name, *length, &grp, vp->namelen))
    618 		return NULL;
    619 
    620       if (!(cache = find_cache(grp, vifi)))
    621 		return NULL;
    622 
    623        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
    624 	 } else {
    625        len = *length;
    626        if (compare(name, *length, vp->name, vp->namelen) < 0)
    627           len = vp->namelen;
    628 
    629 	    if (len < vp->namelen + 5) { /* get first entry */
    630 
    631          if (len == vp->namelen) {
    632             vifi = grp = 0;
    633          } else {
    634             get_address(name, len, &grp, vp->namelen);
    635             vifi = name[vp->namelen+4];
    636          }
    637 
    638          cache = next_cache(grp,&vifi);
    639          if (!cache)
    640             return NULL;
    641 
    642          put_address(newname, cache->al_addr, vp->namelen);
    643    		newname[vp->namelen+4] = vifi;
    644 	    } else {  /* get next entry given previous */
    645          get_address(name, *length, &grp, vp->namelen);
    646 		   vifi = name[vp->namelen+4]+1;
    647 
    648          if (!(cache = next_cache(grp,&vifi)))
    649             return NULL;
    650 
    651          put_address(newname, cache->al_addr, vp->namelen);
    652 		   newname[vp->namelen+4] = vifi;
    653 	    }
    654     }
    655 
    656     /* Save new OID */
    657     *length = vp->namelen + 5;
    658     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
    659     *write_method = 0;
    660     *var_len = sizeof(long);
    661 
    662     /* Look up ifIndex given uvifs[vifi].uv_lcl_addr */
    663     in_ifaddr = ipaddr_to_ifindex(uvifs[vifi].uv_lcl_addr, &ifIndex);
    664 
    665     switch (vp->magic) {
    666 
    667    case igmpCacheSelf:
    668        inm = in_ifaddr->ia_multiaddrs;
    669        while (inm) {
    670           klookup( (int)inm, (char *)&in_multi, sizeof(in_multi));
    671 
    672           if (in_multi.inm_addr.s_addr == cache->al_addr) {
    673              long_return = 1; /* true */
    674              return (u_char *) &long_return;
    675           }
    676 
    677           inm = in_multi.inm_next;
    678        }
    679        long_return = 2; /* false */
    680        return (u_char *) &long_return;
    681 
    682    case igmpCacheLastReporter:
    683        return (u_char *) &cache->al_genid;
    684 
    685    case igmpCacheUpTime: {
    686       time_t currtime;
    687       time(&currtime);
    688       long_return = (currtime - cache->al_ctime)*100;
    689       return (u_char *) &long_return;
    690    }
    691 
    692    case igmpCacheExpiryTime:
    693        long_return = secs_remaining(cache->al_timerid)*100;
    694        return (u_char *) &long_return;
    695 
    696    case igmpCacheStatus:
    697        long_return = 1;
    698        return (u_char *) &long_return;
    699 
    700     default:
    701        ERROR("");
    702     }
    703     return NULL;
    704 }
    705 
    706 /*
    707  * Implements the IGMP Interface Table portion of the IGMP MIB
    708  */
    709 u_char *
    710 o_igmpInterfaceTable(vp, name, length, exact, var_len, write_method)
    711     struct variable *vp;   /* IN - pointer to variable entry that points here */
    712     oid	*name;	    /* IN/OUT - input name requested, output name found */
    713     int	*length;    /* IN/OUT - length of input and output oid's */
    714     int			exact;	    /* IN - TRUE if an exact match was requested. */
    715     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    716     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    717 {
    718     oid			newname[MAX_NAME_LEN];
    719     int	ifnum;
    720     int result;
    721 static struct sioc_vif_req v_req;
    722 
    723     /* Copy name OID to new OID */
    724     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    725 
    726     /* find "next" interface */
    727     for(ifnum = 0; ifnum < numvifs; ifnum++){
    728        if (!(uvifs[ifnum].uv_flags & VIFF_QUERIER))
    729            continue;
    730        newname[vp->namelen] = (oid)ifnum;
    731        result = compare(name, *length, newname, (int)vp->namelen + 1);
    732        if ((exact && (result == 0)) || (!exact && (result < 0)))
    733           break;
    734     }
    735     if (ifnum >= numvifs)
    736        return NULL;
    737 
    738     /* Save new OID */
    739     bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid));
    740     *length = vp->namelen + 1;
    741     *write_method = 0;
    742     *var_len = sizeof(long);
    743 
    744     switch (vp->magic){
    745 
    746 	case igmpInterfaceQueryInterval:
    747 		long_return = GROUP_QUERY_INTERVAL;
    748       return (u_char *) &long_return;
    749 
    750 	case igmpInterfaceStatus:
    751 		long_return = 1; /* active */
    752       return (u_char *) &long_return;
    753 
    754 	default:
    755 	    ERROR("");
    756     }
    757     return NULL;
    758 }
    759 
    760 /*
    761  * Given a virtual interface number, make sure we have the current
    762  * kernel information for that Vif.
    763  */
    764 refresh_vif(v_req, ifnum)
    765    struct sioc_vif_req *v_req;
    766    int ifnum;
    767 {
    768    static   int lastq = -1;
    769 
    770    if (quantum!=lastq || v_req->vifi != ifnum) {
    771        lastq = quantum;
    772        v_req->vifi = ifnum;
    773        if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)v_req) < 0)
    774           v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0;
    775    }
    776 }
    777 
    778 /*
    779  * Implements the Multicast Routing Interface Table portion of the Multicast MIB
    780  */
    781 u_char *
    782 o_ipMRouteInterfaceTable(vp, name, length, exact, var_len, write_method)
    783     struct variable *vp;   /* IN - pointer to variable entry that points here */
    784     oid	*name;	    /* IN/OUT - input name requested, output name found */
    785     int	*length;    /* IN/OUT - length of input and output oid's */
    786     int			exact;	    /* IN - TRUE if an exact match was requested. */
    787     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    788     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    789 {
    790     oid			newname[MAX_NAME_LEN];
    791     int	ifnum;
    792     int result;
    793 static struct sioc_vif_req v_req;
    794 
    795     /* Copy name OID to new OID */
    796     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    797 
    798     /* find "next" interface */
    799     for(ifnum = 0; ifnum < numvifs; ifnum++){
    800 	newname[vp->namelen] = (oid)ifnum;
    801 	result = compare(name, *length, newname, (int)vp->namelen + 1);
    802 	if ((exact && (result == 0)) || (!exact && (result < 0)))
    803 	    break;
    804     }
    805     if (ifnum >= numvifs)
    806 	return NULL;
    807 
    808     /* Save new OID */
    809     bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid));
    810     *length = vp->namelen + 1;
    811     *write_method = 0;
    812     *var_len = sizeof(long);
    813 
    814     switch (vp->magic){
    815 
    816    case ipMRouteInterfaceTtl:
    817        long_return = uvifs[ifnum].uv_threshold;
    818        return (u_char *) &long_return;
    819 
    820    case dvmrpVInterfaceType:
    821       if (uvifs[ifnum].uv_flags & VIFF_SRCRT)
    822          long_return = 2;
    823       else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL)
    824          long_return = 1;
    825       else if (uvifs[ifnum].uv_flags & VIFF_QUERIER)
    826          long_return = 3;
    827       else                               /* SUBNET */
    828          long_return = 4;
    829       return (u_char *) &long_return;
    830 
    831    case dvmrpVInterfaceState:
    832       if (uvifs[ifnum].uv_flags & VIFF_DISABLED)
    833          long_return = 3;
    834       else if ((uvifs[ifnum].uv_flags & VIFF_DOWN)
    835        || ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) && (uvifs[ifnum].uv_neighbors==NULL)))
    836          long_return = 2;
    837       else /* UP */
    838          long_return = 1;
    839       return (u_char *) &long_return;
    840 
    841    case dvmrpVInterfaceLocalAddress:
    842       return (u_char *) &uvifs[ifnum].uv_lcl_addr;
    843 
    844    case dvmrpVInterfaceRemoteAddress:
    845       return (u_char *) ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) ?
    846          &uvifs[ifnum].uv_rmt_addr :
    847          &uvifs[ifnum].uv_subnet);
    848 
    849    case dvmrpVInterfaceRemoteSubnetMask:
    850       return (u_char *) &uvifs[ifnum].uv_subnetmask;
    851 
    852    case dvmrpVInterfaceMetric:
    853        long_return = uvifs[ifnum].uv_metric;
    854        return (u_char *) &long_return;
    855 
    856    case dvmrpVInterfaceRateLimit:
    857        long_return = uvifs[ifnum].uv_rate_limit;
    858        return (u_char *) &long_return;
    859 
    860    case dvmrpVInterfaceInPkts:
    861        refresh_vif(&v_req, ifnum);
    862        long_return = v_req.icount;
    863        return (u_char *) &long_return;
    864 
    865    case dvmrpVInterfaceOutPkts:
    866        refresh_vif(&v_req, ifnum);
    867        long_return = v_req.ocount;
    868        return (u_char *) &long_return;
    869 
    870    case dvmrpVInterfaceInOctets:
    871        refresh_vif(&v_req, ifnum);
    872        long_return = v_req.ibytes;
    873        return (u_char *) &long_return;
    874 
    875    case dvmrpVInterfaceOutOctets:
    876        refresh_vif(&v_req, ifnum);
    877        long_return = v_req.obytes;
    878        return (u_char *) &long_return;
    879 
    880 	default:
    881 	    ERROR("");
    882     }
    883     return NULL;
    884 }
    885 
    886 /*
    887  * Implements the DVMRP Route Table portion of the DVMRP MIB
    888  */
    889 u_char *
    890 o_dvmrpRouteTable(vp, name, length, exact, var_len, write_method)
    891     struct variable *vp;   /* IN - pointer to variable entry that points here */
    892     oid	*name;	    /* IN/OUT - input name requested, output name found */
    893     int	*length;    /* IN/OUT - length of input and output oid's */
    894     int			exact;	    /* IN - TRUE if an exact match was requested. */
    895     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    896     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    897 {
    898     u_long src, mask;
    899     oid        newname[MAX_NAME_LEN];
    900     int        len;
    901     struct rtentry *rt = NULL;
    902 
    903     /* Copy name OID to new OID */
    904     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    905 
    906     if (exact) {
    907 	    if (*length != vp->namelen + 8)
    908 		return NULL;
    909 
    910       if (!get_address(name, *length, &src, vp->namelen)
    911        || !get_address(name, *length, &mask, vp->namelen+4))
    912 		return NULL;
    913 
    914       if (!(rt = snmp_find_route(src, mask)))
    915 		return NULL;
    916 
    917        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
    918 	 } else {
    919        len = *length;
    920        if (compare(name, *length, vp->name, vp->namelen) < 0)
    921           len = vp->namelen;
    922 
    923 	    if (len < vp->namelen + 8) { /* get first entry */
    924 
    925          if (len == vp->namelen) {
    926             src = mask = 0;
    927          } else {
    928             get_address(name, len, &src, vp->namelen);
    929             get_address(name, len, &mask, vp->namelen+4);
    930          }
    931 
    932          if (!next_route(&rt,src,mask)) /* Get first entry */
    933             return NULL;
    934 
    935          put_address(newname, rt->rt_origin    , vp->namelen);
    936          put_address(newname, rt->rt_originmask, vp->namelen+4);
    937 	    } else {  /* get next entry given previous */
    938          get_address(name, *length, &src,  vp->namelen);
    939          get_address(name, *length, &mask, vp->namelen+4);
    940 
    941          if (!next_route(&rt, src,mask))
    942             return NULL;
    943 
    944          put_address(newname, rt->rt_origin,     vp->namelen);
    945          put_address(newname, rt->rt_originmask, vp->namelen+4);
    946 	    }
    947     }
    948 
    949     /* Save new OID */
    950     *length = vp->namelen + 8;
    951     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
    952     *write_method = 0;
    953     *var_len = sizeof(long);
    954 
    955     switch (vp->magic) {
    956 
    957       case dvmrpRouteUpstreamNeighbor:
    958          return (u_char *) &rt->rt_gateway;
    959 
    960       case dvmrpRouteInVifIndex:
    961          long_return = rt->rt_parent;
    962          return (u_char *) &long_return;
    963 
    964       case dvmrpRouteMetric:
    965          long_return = rt->rt_metric;
    966          return (u_char *) &long_return;
    967 
    968       case dvmrpRouteExpiryTime:
    969          long_return = (ROUTE_EXPIRE_TIME - rt->rt_timer
    970           + secs_remaining_offset()) * 100;
    971          return (u_char *) &long_return;
    972 
    973     default:
    974        ERROR("");
    975     }
    976     return NULL;
    977 }
    978 
    979 /*
    980  * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB
    981  */
    982 u_char *
    983 o_dvmrpRouteNextHopTable(vp, name, length, exact, var_len, write_method)
    984     struct variable *vp;   /* IN - pointer to variable entry that points here */
    985     oid	*name;	    /* IN/OUT - input name requested, output name found */
    986     int	*length;    /* IN/OUT - length of input and output oid's */
    987     int			exact;	    /* IN - TRUE if an exact match was requested. */
    988     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    989     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    990 {
    991     u_long     src, mask;
    992     vifi_t     vifi;
    993     struct rtentry *rt = NULL;
    994     oid        newname[MAX_NAME_LEN];
    995     int        len;
    996 
    997     /* Copy name OID to new OID */
    998     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    999 
   1000     if (exact) {
   1001 	    if (*length != vp->namelen + 9)
   1002 		return NULL;
   1003 
   1004       if (!get_address(name, *length, &src, vp->namelen)
   1005        || !get_address(name, *length, &mask, vp->namelen+4)
   1006        || (!(rt=snmp_find_route(src,mask))))
   1007 		return NULL;
   1008 
   1009       vifi = name[vp->namelen+8];
   1010       if (!(VIFM_ISSET(vifi, rt->rt_children)))
   1011       return NULL;
   1012 
   1013        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
   1014 	 } else {
   1015        len = *length;
   1016        if (compare(name, *length, vp->name, vp->namelen) < 0)
   1017           len = vp->namelen;
   1018 
   1019 	    if (len < vp->namelen + 9) { /* get first entry */
   1020 
   1021          get_address(name, len, &src,  vp->namelen);
   1022          get_address(name, len, &mask, vp->namelen+4);
   1023 
   1024          /* Find first child vif */
   1025          vifi=0;
   1026          if (!next_route_child(&rt, src, mask, &vifi))
   1027             return NULL;
   1028 
   1029          put_address(newname, rt->rt_origin,     vp->namelen);
   1030          put_address(newname, rt->rt_originmask, vp->namelen+4);
   1031    		newname[vp->namelen+8] = vifi;
   1032 	    } else {  /* get next entry given previous */
   1033 		   vifi = name[vp->namelen+8] + 1;
   1034          if (!get_address(name, *length, &src,  vp->namelen)
   1035           || !get_address(name, *length, &mask, vp->namelen+4)
   1036           || !next_route_child(&rt, src, mask, &vifi))
   1037             return NULL;
   1038 
   1039          put_address(newname, rt->rt_origin,     vp->namelen);
   1040          put_address(newname, rt->rt_originmask, vp->namelen+4);
   1041 		   newname[vp->namelen+8] = vifi;
   1042 	    }
   1043     }
   1044 
   1045     /* Save new OID */
   1046     *length = vp->namelen + 9;
   1047     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
   1048     *write_method = 0;
   1049     *var_len = sizeof(long);
   1050 
   1051     switch (vp->magic) {
   1052 
   1053     case dvmrpRouteNextHopType:
   1054        long_return = (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2;
   1055        return (u_char *) &long_return;
   1056 
   1057     default:
   1058        ERROR("");
   1059     }
   1060     return NULL;
   1061 }
   1062 
   1063 /*
   1064  * Implements the IP Multicast Route Table portion of the Multicast MIB
   1065  */
   1066 u_char *
   1067 o_ipMRouteTable(vp, name, length, exact, var_len, write_method)
   1068     struct variable *vp;   /* IN - pointer to variable entry that points here */
   1069     oid	*name;	    /* IN/OUT - input name requested, output name found */
   1070     int	*length;    /* IN/OUT - length of input and output oid's */
   1071     int			exact;	    /* IN - TRUE if an exact match was requested. */
   1072     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
   1073     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
   1074 {
   1075     u_long src, grp, mask;
   1076     struct gtable *gt = NULL;
   1077     struct stable *st = NULL;
   1078 static struct sioc_sg_req sg_req;
   1079     oid        newname[MAX_NAME_LEN];
   1080     int        len;
   1081 
   1082     /* Copy name OID to new OID */
   1083     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
   1084 
   1085     if (exact) {
   1086 	    if (*length != vp->namelen + 12)
   1087 		return NULL;
   1088 
   1089       if (!get_address(name, *length, &grp,  vp->namelen)
   1090        || !get_address(name, *length, &src,  vp->namelen+4)
   1091        || !get_address(name, *length, &mask, vp->namelen+8)
   1092        || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */
   1093        || !(gt = find_grp(grp))
   1094        || !(st = find_grp_src(gt,src)))
   1095 		return NULL;
   1096 
   1097        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
   1098 	 } else {
   1099        len = *length;
   1100        if (compare(name, *length, vp->name, vp->namelen) < 0)
   1101           len = vp->namelen;
   1102 
   1103 	    if (len < vp->namelen + 12) { /* get first entry */
   1104 
   1105          get_address(name, len, &grp,  vp->namelen);
   1106          get_address(name, len, &src,  vp->namelen+4);
   1107          get_address(name, len, &mask, vp->namelen+8);
   1108 
   1109          if (!next_grp_src_mask(&gt,&st,grp,src,mask)) /* Get first entry */
   1110             return NULL;
   1111 
   1112          put_address(newname, gt->gt_mcastgrp, vp->namelen);
   1113          put_address(newname, st->st_origin,   vp->namelen+4);
   1114          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
   1115 	    } else {  /* get next entry given previous */
   1116          get_address(name, *length, &grp , vp->namelen);
   1117          get_address(name, *length, &src , vp->namelen+4);
   1118          get_address(name, *length, &mask, vp->namelen+8);
   1119 
   1120          if (!next_grp_src_mask(&gt, &st, grp,src,mask))
   1121             return NULL;
   1122 
   1123          put_address(newname, gt->gt_mcastgrp, vp->namelen);
   1124          put_address(newname, st->st_origin,   vp->namelen+4);
   1125          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
   1126 	    }
   1127     }
   1128 
   1129     /* Save new OID */
   1130     *length = vp->namelen + 12;
   1131     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
   1132     *write_method = 0;
   1133     *var_len = sizeof(long);
   1134 
   1135     switch (vp->magic) {
   1136 
   1137       case ipMRouteUpstreamNeighbor:
   1138          return (u_char *) &gt->gt_route->rt_gateway;
   1139 
   1140       case ipMRouteInIfIndex:
   1141          long_return = gt->gt_route->rt_parent;
   1142          return (u_char *) &long_return;
   1143 
   1144       case ipMRouteUpTime: {
   1145          time_t currtime;
   1146          time(&currtime);
   1147          long_return = (currtime - gt->gt_ctime)*100;
   1148          return (u_char *) &long_return;
   1149       }
   1150 
   1151       case ipMRouteExpiryTime:
   1152          long_return = 5*((gt->gt_timer+4)/5); /* round up to nearest 5 */
   1153          long_return = (long_return + secs_remaining_offset()) * 100;
   1154          return (u_char *) &long_return;
   1155 
   1156       case ipMRoutePkts:
   1157          refresh_sg(&sg_req, gt, st);
   1158          long_return = sg_req.pktcnt;
   1159          return (u_char *) &long_return;
   1160 
   1161       case ipMRouteOctets:
   1162          refresh_sg(&sg_req, gt, st);
   1163          long_return = sg_req.bytecnt;
   1164          return (u_char *) &long_return;
   1165 
   1166       case ipMRouteDifferentInIfIndexes:
   1167          refresh_sg(&sg_req, gt, st);
   1168          long_return = sg_req.wrong_if;
   1169          return (u_char *) &long_return;
   1170 
   1171       case ipMRouteProtocol:
   1172          long_return = 4;
   1173          return (u_char *) &long_return;
   1174 
   1175     default:
   1176        ERROR("");
   1177     }
   1178     return NULL;
   1179 }
   1180 
   1181 /*
   1182  * Implements the IP Multicast Routing Next Hop Table portion of the Multicast
   1183  * MIB
   1184  */
   1185 u_char *
   1186 o_ipMRouteNextHopTable(vp, name, length, exact, var_len, write_method)
   1187     struct variable *vp;   /* IN - pointer to variable entry that points here */
   1188     oid	*name;	    /* IN/OUT - input name requested, output name found */
   1189     int	*length;    /* IN/OUT - length of input and output oid's */
   1190     int			exact;	    /* IN - TRUE if an exact match was requested. */
   1191     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
   1192     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
   1193 {
   1194     u_long src, grp, mask, addr;
   1195     vifi_t   vifi;
   1196     struct gtable *gt;
   1197     struct stable *st;
   1198     oid        newname[MAX_NAME_LEN];
   1199     int        len;
   1200 
   1201     /* Copy name OID to new OID */
   1202     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
   1203 
   1204     if (exact) {
   1205 	    if (*length != vp->namelen + 17)
   1206 		return NULL;
   1207 
   1208       if (!get_address(name, *length, &grp, vp->namelen)
   1209        || !get_address(name, *length, &src, vp->namelen+4)
   1210        || !get_address(name, *length, &mask, vp->namelen+8)
   1211        || !get_address(name, *length, &addr, vp->namelen+13)
   1212        || grp!=addr
   1213        || mask!=0xFFFFFFFF
   1214        || (!(gt=find_grp(grp)))
   1215        || (!(st=find_grp_src(gt,src))))
   1216 		return NULL;
   1217 
   1218       vifi = name[vp->namelen+12];
   1219       if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children)))
   1220       return NULL;
   1221 
   1222        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
   1223 	 } else {
   1224        len = *length;
   1225        if (compare(name, *length, vp->name, vp->namelen) < 0)
   1226           len = vp->namelen;
   1227 
   1228 	    if (len < vp->namelen + 17) { /* get first entry */
   1229 
   1230          get_address(name, len, &grp, vp->namelen);
   1231          get_address(name, len, &src, vp->namelen+4);
   1232          get_address(name, len, &mask, vp->namelen+8);
   1233 
   1234          /* Find first child vif */
   1235          vifi=0;
   1236          if (!next_child(&gt, &st, grp, src, mask, &vifi))
   1237             return NULL;
   1238 
   1239          put_address(newname, gt->gt_mcastgrp, vp->namelen);
   1240          put_address(newname, st->st_origin,   vp->namelen+4);
   1241          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
   1242    		newname[vp->namelen+12] = vifi;
   1243          put_address(newname, gt->gt_mcastgrp, vp->namelen+13);
   1244 
   1245 	    } else {  /* get next entry given previous */
   1246 		   vifi = name[vp->namelen+12]+1;
   1247          if (!get_address(name, *length, &grp,  vp->namelen)
   1248           || !get_address(name, *length, &src,  vp->namelen+4)
   1249           || !get_address(name, *length, &mask, vp->namelen+8)
   1250           || !next_child(&gt, &st, grp, src, mask, &vifi))
   1251             return NULL;
   1252 
   1253          put_address(newname, gt->gt_mcastgrp, vp->namelen);
   1254          put_address(newname, st->st_origin,   vp->namelen+4);
   1255          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
   1256 		   newname[vp->namelen+12] = vifi;
   1257          put_address(newname, gt->gt_mcastgrp, vp->namelen+13);
   1258 	    }
   1259     }
   1260 
   1261     /* Save new OID */
   1262     *length = vp->namelen + 17;
   1263     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
   1264     *write_method = 0;
   1265     *var_len = sizeof(long);
   1266 
   1267     switch (vp->magic) {
   1268 
   1269       case ipMRouteNextHopState:
   1270          long_return = (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1;
   1271          return (u_char *) &long_return;
   1272 
   1273       /* Currently equal to ipMRouteUpTime */
   1274       case ipMRouteNextHopUpTime: {
   1275          time_t currtime;
   1276          time(&currtime);
   1277          long_return = (currtime - gt->gt_ctime)*100;
   1278          return (u_char *) &long_return;
   1279       }
   1280 
   1281       case ipMRouteNextHopExpiryTime:
   1282          long_return = 5*((gt->gt_prsent_timer+4)/5); /* round up to nearest 5*/
   1283          long_return = (long_return + secs_remaining_offset()) * 100;
   1284          return (u_char *) &long_return;
   1285 
   1286       case ipMRouteNextHopClosestMemberHops:
   1287          long_return = 0;
   1288          return (u_char *) &long_return;
   1289 
   1290       case ipMRouteNextHopProtocol:
   1291          long_return = 4;
   1292          return (u_char *) &long_return;
   1293 
   1294     default:
   1295        ERROR("");
   1296     }
   1297     return NULL;
   1298 }
   1299 
   1300 /* sync_timer is called by timer() every TIMER_INTERVAL seconds.
   1301  * Its job is to record this time so that we can compute on demand
   1302  * the approx # seconds remaining until the next timer() call
   1303  */
   1304 static time_t lasttimer;
   1305 
   1306 void
   1307 sync_timer()
   1308 {
   1309     time(&lasttimer);
   1310 }
   1311 
   1312 int /* in range [-TIMER_INTERVAL..0] */
   1313 secs_remaining_offset()
   1314 {
   1315    time_t tm;
   1316 
   1317    time(&tm);
   1318    return lasttimer-tm;
   1319 }
   1320