Home | History | Annotate | Line # | Download | only in mrouted
snmp.c revision 1.10
      1 /*	$NetBSD: snmp.c,v 1.10 2003/03/05 21:12:26 wiz 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        sprintf(buff, "mrouted%d.%d", PROTOCOL_VERSION, MROUTED_VERSION);
    220        *var_len = strlen(buff);
    221        return (u_char *)buff;
    222     }
    223 
    224     case dvmrpGenerationId:
    225        long_return = dvmrp_genid;
    226        return (u_char *) &long_return;
    227 
    228     default:
    229        ERROR("");
    230     }
    231     return NULL;
    232 }
    233 
    234 /*
    235  * Find if a specific scoped boundary exists on a Vif
    236  */
    237 struct vif_acl *
    238 find_boundary(vifi, addr, mask)
    239    vifi_t vifi;
    240    u_long addr;
    241    u_long mask;
    242 {
    243    struct vif_acl *n;
    244 
    245    for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) {
    246       if (addr == n->acl_addr && mask==n->acl_mask)
    247          return n;
    248    }
    249    return NULL;
    250 }
    251 
    252 /*
    253  * Find the lowest boundary >= (V,A,M) spec
    254  */
    255 struct vif_acl *
    256 next_boundary(vifi, addr, mask)
    257    vifi_t *vifi;
    258    u_long  addr;
    259    u_long  mask;
    260 {
    261    struct vif_acl *bestn, *n;
    262    int  i;
    263 
    264    for (i = *vifi; i < numvifs; i++) {
    265       bestn = NULL;
    266       for (n = uvifs[i].uv_acl; n; n=n->acl_next) {
    267          if ((i > *vifi || n->acl_addr > addr
    268            || (n->acl_addr == addr && n->acl_mask >= mask))
    269           && (!bestn || n->acl_addr < bestn->acl_addr
    270            || (n->acl_addr==bestn->acl_addr && n->acl_mask<bestn->acl_mask)))
    271             bestn = n;
    272       }
    273       if (bestn) {
    274          *vifi = i;
    275          return bestn;
    276       }
    277    }
    278    return NULL;
    279 }
    280 
    281 /*
    282  * Implements the Boundary Table portion of the DVMRP MIB
    283  */
    284 u_char *
    285 o_dvmrpBoundaryTable(vp, name, length, exact, var_len, write_method)
    286     struct variable *vp;   /* IN - pointer to variable entry that points here */
    287     oid	*name;	    /* IN/OUT - input name requested, output name found */
    288     int	*length;    /* IN/OUT - length of input and output oid's */
    289     int			exact;	    /* IN - TRUE if an exact match was requested. */
    290     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    291     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    292 {
    293     vifi_t     vifi;
    294     u_long	   addr, mask;
    295     struct vif_acl *bound;
    296     oid        newname[MAX_NAME_LEN];
    297     int        len;
    298 
    299     /* Copy name OID to new OID */
    300     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    301 
    302     if (exact) {
    303 	    if (*length != vp->namelen + 9)
    304 		return NULL;
    305 
    306       if ((vifi = name[vp->namelen]) >= numvifs)
    307       return NULL;
    308 
    309       if (!get_address(name, *length, &addr, vp->namelen+1)
    310        || !get_address(name, *length, &mask, vp->namelen+5))
    311 		return NULL;
    312 
    313       if (!(bound = find_boundary(vifi, addr, mask)))
    314 		return NULL;
    315 
    316        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
    317 	 } else {
    318        len = *length;
    319        if (compare(name, *length, vp->name, vp->namelen) < 0)
    320           len = vp->namelen;
    321 
    322 	    if (len < vp->namelen + 9) { /* get first entry */
    323 
    324          if (len == vp->namelen) {
    325             vifi = addr = mask = 0;
    326          } else {
    327             vifi = name[vp->namelen];
    328             get_address(name, len, &addr, vp->namelen+1);
    329             get_address(name, len, &mask, vp->namelen+5);
    330          }
    331 
    332          bound = next_boundary(&vifi,addr,mask);
    333          if (!bound)
    334             return NULL;
    335 
    336    		newname[vp->namelen] = vifi;
    337          put_address(newname, bound->acl_addr, vp->namelen+1);
    338          put_address(newname, bound->acl_mask, vp->namelen+5);
    339 	    } else {  /* get next entry given previous */
    340 		   vifi = name[vp->namelen];
    341          get_address(name, *length, &addr, vp->namelen+1);
    342          get_address(name, *length, &mask, vp->namelen+5);
    343 
    344          if (!(bound = next_boundary(&vifi,addr,mask+1)))
    345             return NULL;
    346 
    347 		   newname[vp->namelen] = vifi;
    348          put_address(newname, bound->acl_addr, vp->namelen+1);
    349          put_address(newname, bound->acl_mask, vp->namelen+5);
    350 	    }
    351     }
    352 
    353     /* Save new OID */
    354     *length = vp->namelen + 9;
    355     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
    356     *write_method = 0;
    357     *var_len = sizeof(long);
    358 
    359     switch (vp->magic) {
    360 
    361    case dvmrpBoundaryVifIndex:
    362        long_return = vifi;
    363        return (u_char *) &long_return;
    364 
    365     default:
    366        ERROR("");
    367     }
    368     return NULL;
    369 }
    370 
    371 /*
    372  * Find the lowest neighbor >= (V,A) spec
    373  */
    374 struct listaddr *
    375 next_neighbor(vifi, addr)
    376    vifi_t *vifi;
    377    u_long  addr;
    378 {
    379    struct listaddr *bestn, *n;
    380    int  i;
    381 
    382    for (i = *vifi; i < numvifs; i++) {
    383       bestn = NULL;
    384       for (n = uvifs[i].uv_neighbors; n; n=n->al_next) {
    385          if ((i > *vifi || n->al_addr >= addr)
    386           && (!bestn || n->al_addr < bestn->al_addr))
    387             bestn = n;
    388       }
    389       if (bestn) {
    390          *vifi = i;
    391          return bestn;
    392       }
    393    }
    394    return NULL;
    395 }
    396 
    397 /*
    398  * Find a neighbor, if it exists off a given Vif
    399  */
    400 struct listaddr *
    401 find_neighbor(vifi, addr)
    402    vifi_t vifi;
    403    u_long addr;
    404 {
    405    struct listaddr *n;
    406 
    407    for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) {
    408       if (addr == n->al_addr)
    409          return n;
    410    }
    411    return NULL;
    412 }
    413 
    414 u_char *
    415 o_dvmrpNeighborTable(vp, name, length, exact, var_len, write_method)
    416     struct variable *vp;   /* IN - pointer to variable entry that points here */
    417     oid	*name;	    /* IN/OUT - input name requested, output name found */
    418     int	*length;    /* IN/OUT - length of input and output oid's */
    419     int			exact;	    /* IN - TRUE if an exact match was requested. */
    420     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    421     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    422 {
    423     vifi_t     vifi;
    424     u_long     addr, mask;
    425     struct listaddr *neighbor;
    426     oid        newname[MAX_NAME_LEN];
    427     int        len;
    428 
    429     /* Copy name OID to new OID */
    430     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    431 
    432     if (exact) {
    433 	    if (*length != vp->namelen + 5)
    434 		return NULL;
    435 
    436       if ((vifi = name[vp->namelen]) >= numvifs)
    437       return NULL;
    438 
    439       if (!get_address(name, *length, &addr, vp->namelen+1))
    440 		return NULL;
    441 
    442       if (!(neighbor = find_neighbor(vifi, addr)))
    443 		return NULL;
    444 
    445        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
    446 	 } else {
    447        len = *length;
    448        if (compare(name, *length, vp->name, vp->namelen) < 0)
    449           len = vp->namelen;
    450 
    451 	    if (len < vp->namelen + 5) { /* get first entry */
    452 
    453          if (len == vp->namelen) {
    454             vifi = addr = 0;
    455          } else {
    456             vifi = name[vp->namelen];
    457             get_address(name, len, &addr, vp->namelen+1);
    458          }
    459 
    460          neighbor = next_neighbor(&vifi,addr);
    461          if (!neighbor)
    462             return NULL;
    463 
    464    		newname[vp->namelen] = vifi;
    465          put_address(newname, neighbor->al_addr, vp->namelen+1);
    466 	    } else {  /* get next entry given previous */
    467 		   vifi = name[vp->namelen];
    468          get_address(name, *length, &addr, vp->namelen+1);
    469 
    470          if (!(neighbor = next_neighbor(&vifi,addr+1)))
    471             return NULL;
    472 
    473 		   newname[vp->namelen] = vifi;
    474          put_address(newname, neighbor->al_addr, vp->namelen+1);
    475 	    }
    476     }
    477 
    478     /* Save new OID */
    479     *length = vp->namelen + 5;
    480     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
    481     *write_method = 0;
    482     *var_len = sizeof(long);
    483 
    484     switch (vp->magic) {
    485 
    486    case dvmrpNeighborUpTime: {
    487        time_t currtime;
    488        time(&currtime);
    489        long_return = (currtime - neighbor->al_ctime)*100;
    490        return (u_char *) &long_return;
    491    }
    492 
    493    case dvmrpNeighborExpiryTime:
    494        long_return = (NEIGHBOR_EXPIRE_TIME - neighbor->al_timer
    495         + secs_remaining_offset()) * 100;
    496        return (u_char *) &long_return;
    497 
    498    case dvmrpNeighborVersion: {
    499        static char buff[15];
    500 
    501        sprintf(buff, "%d.%d", neighbor->al_pv, neighbor->al_mv);
    502        *var_len = strlen(buff);
    503        return (u_char *)buff;
    504    }
    505 
    506    case dvmrpNeighborGenerationId:
    507        long_return = neighbor->al_genid;
    508        return (u_char *) &long_return;
    509 
    510     default:
    511        ERROR("");
    512     }
    513     return NULL;
    514 }
    515 
    516 /* Look up ifIndex given uvifs[ifnum].uv_lcl_addr */
    517 struct in_ifaddr *        /* returns: in_ifaddr structure, or null on error */
    518 ipaddr_to_ifindex(ipaddr, ifIndex)
    519    u_long ipaddr;
    520    int   *ifIndex;
    521 {
    522     int interface;
    523 static struct in_ifaddr in_ifaddr;
    524 
    525     Interface_Scan_Init();
    526     for (;;) {
    527        if (Interface_Scan_Next(&interface, (char *)0, NULL, &in_ifaddr) == 0)
    528           return NULL;
    529 
    530        if (((struct sockaddr_in *) &(in_ifaddr.ia_addr))->sin_addr.s_addr
    531         == ipaddr) {
    532           *ifIndex = interface;
    533           return &in_ifaddr;
    534        }
    535     }
    536 }
    537 
    538 /*
    539  * Find if a specific scoped boundary exists on a Vif
    540  */
    541 struct listaddr *
    542 find_cache(grp, vifi)
    543    u_long grp;
    544    vifi_t vifi;
    545 {
    546    struct listaddr *n;
    547 
    548    for (n = uvifs[vifi].uv_groups; n != NULL; n = n->al_next) {
    549       if (grp == n->al_addr)
    550          return n;
    551    }
    552    return NULL;
    553 }
    554 
    555 /*
    556  * Find the next group cache entry >= (A,V) spec
    557  */
    558 struct listaddr *
    559 next_cache(addr, vifi)
    560    u_long  addr;
    561    vifi_t *vifi;
    562 {
    563    struct listaddr *bestn=NULL, *n;
    564    int  i, besti;
    565 
    566    /* Step through all entries looking for the next one */
    567    for (i = 0; i < numvifs; i++) {
    568       for (n = uvifs[i].uv_groups; n; n=n->al_next) {
    569          if ((n->al_addr > addr || (n->al_addr == addr && i >= *vifi))
    570           && (!bestn || n->al_addr < bestn->al_addr
    571            || (n->al_addr == bestn->al_addr && i < besti))) {
    572             bestn = n;
    573             besti = i;
    574          }
    575       }
    576    }
    577 
    578    if (bestn) {
    579       *vifi = besti;
    580       return bestn;
    581    }
    582    return NULL;
    583 }
    584 
    585 /*
    586  * Implements the IGMP Cache Table portion of the IGMP MIB
    587  */
    588 u_char *
    589 o_igmpCacheTable(vp, name, length, exact, var_len, write_method)
    590     struct variable *vp;   /* IN - pointer to variable entry that points here */
    591     oid	*name;	    /* IN/OUT - input name requested, output name found */
    592     int	*length;    /* IN/OUT - length of input and output oid's */
    593     int			exact;	    /* IN - TRUE if an exact match was requested. */
    594     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    595     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    596 {
    597     vifi_t     vifi;
    598     u_long     grp;
    599     int	      ifIndex;
    600     struct listaddr *cache;
    601     oid        newname[MAX_NAME_LEN];
    602     int        len;
    603     struct in_ifaddr *in_ifaddr;
    604     struct in_multi   in_multi, *inm;
    605 
    606     /* Copy name OID to new OID */
    607     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    608 
    609     if (exact) {
    610 	    if (*length != vp->namelen + 5)
    611 		return NULL;
    612 
    613       if ((vifi = name[vp->namelen+4]) >= numvifs)
    614       return NULL;
    615 
    616       if (!get_address(name, *length, &grp, vp->namelen))
    617 		return NULL;
    618 
    619       if (!(cache = find_cache(grp, vifi)))
    620 		return NULL;
    621 
    622        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
    623 	 } else {
    624        len = *length;
    625        if (compare(name, *length, vp->name, vp->namelen) < 0)
    626           len = vp->namelen;
    627 
    628 	    if (len < vp->namelen + 5) { /* get first entry */
    629 
    630          if (len == vp->namelen) {
    631             vifi = grp = 0;
    632          } else {
    633             get_address(name, len, &grp, vp->namelen);
    634             vifi = name[vp->namelen+4];
    635          }
    636 
    637          cache = next_cache(grp,&vifi);
    638          if (!cache)
    639             return NULL;
    640 
    641          put_address(newname, cache->al_addr, vp->namelen);
    642    		newname[vp->namelen+4] = vifi;
    643 	    } else {  /* get next entry given previous */
    644          get_address(name, *length, &grp, vp->namelen);
    645 		   vifi = name[vp->namelen+4]+1;
    646 
    647          if (!(cache = next_cache(grp,&vifi)))
    648             return NULL;
    649 
    650          put_address(newname, cache->al_addr, vp->namelen);
    651 		   newname[vp->namelen+4] = vifi;
    652 	    }
    653     }
    654 
    655     /* Save new OID */
    656     *length = vp->namelen + 5;
    657     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
    658     *write_method = 0;
    659     *var_len = sizeof(long);
    660 
    661     /* Look up ifIndex given uvifs[vifi].uv_lcl_addr */
    662     in_ifaddr = ipaddr_to_ifindex(uvifs[vifi].uv_lcl_addr, &ifIndex);
    663 
    664     switch (vp->magic) {
    665 
    666    case igmpCacheSelf:
    667        inm = in_ifaddr->ia_multiaddrs;
    668        while (inm) {
    669           klookup( (int)inm, (char *)&in_multi, sizeof(in_multi));
    670 
    671           if (in_multi.inm_addr.s_addr == cache->al_addr) {
    672              long_return = 1; /* true */
    673              return (u_char *) &long_return;
    674           }
    675 
    676           inm = in_multi.inm_next;
    677        }
    678        long_return = 2; /* false */
    679        return (u_char *) &long_return;
    680 
    681    case igmpCacheLastReporter:
    682        return (u_char *) &cache->al_genid;
    683 
    684    case igmpCacheUpTime: {
    685       time_t currtime;
    686       time(&currtime);
    687       long_return = (currtime - cache->al_ctime)*100;
    688       return (u_char *) &long_return;
    689    }
    690 
    691    case igmpCacheExpiryTime:
    692        long_return = secs_remaining(cache->al_timerid)*100;
    693        return (u_char *) &long_return;
    694 
    695    case igmpCacheStatus:
    696        long_return = 1;
    697        return (u_char *) &long_return;
    698 
    699     default:
    700        ERROR("");
    701     }
    702     return NULL;
    703 }
    704 
    705 /*
    706  * Implements the IGMP Interface Table portion of the IGMP MIB
    707  */
    708 u_char *
    709 o_igmpInterfaceTable(vp, name, length, exact, var_len, write_method)
    710     struct variable *vp;   /* IN - pointer to variable entry that points here */
    711     oid	*name;	    /* IN/OUT - input name requested, output name found */
    712     int	*length;    /* IN/OUT - length of input and output oid's */
    713     int			exact;	    /* IN - TRUE if an exact match was requested. */
    714     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    715     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    716 {
    717     oid			newname[MAX_NAME_LEN];
    718     int	ifnum;
    719     int result;
    720 static struct sioc_vif_req v_req;
    721 
    722     /* Copy name OID to new OID */
    723     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    724 
    725     /* find "next" interface */
    726     for(ifnum = 0; ifnum < numvifs; ifnum++){
    727        if (!(uvifs[ifnum].uv_flags & VIFF_QUERIER))
    728            continue;
    729        newname[vp->namelen] = (oid)ifnum;
    730        result = compare(name, *length, newname, (int)vp->namelen + 1);
    731        if ((exact && (result == 0)) || (!exact && (result < 0)))
    732           break;
    733     }
    734     if (ifnum >= numvifs)
    735        return NULL;
    736 
    737     /* Save new OID */
    738     bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid));
    739     *length = vp->namelen + 1;
    740     *write_method = 0;
    741     *var_len = sizeof(long);
    742 
    743     switch (vp->magic){
    744 
    745 	case igmpInterfaceQueryInterval:
    746 		long_return = GROUP_QUERY_INTERVAL;
    747       return (u_char *) &long_return;
    748 
    749 	case igmpInterfaceStatus:
    750 		long_return = 1; /* active */
    751       return (u_char *) &long_return;
    752 
    753 	default:
    754 	    ERROR("");
    755     }
    756     return NULL;
    757 }
    758 
    759 /*
    760  * Given a virtual interface number, make sure we have the current
    761  * kernel information for that Vif.
    762  */
    763 refresh_vif(v_req, ifnum)
    764    struct sioc_vif_req *v_req;
    765    int ifnum;
    766 {
    767    static   int lastq = -1;
    768 
    769    if (quantum!=lastq || v_req->vifi != ifnum) {
    770        lastq = quantum;
    771        v_req->vifi = ifnum;
    772        if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)v_req) < 0)
    773           v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0;
    774    }
    775 }
    776 
    777 /*
    778  * Implements the Multicast Routing Interface Table portion of the Multicast MIB
    779  */
    780 u_char *
    781 o_ipMRouteInterfaceTable(vp, name, length, exact, var_len, write_method)
    782     struct variable *vp;   /* IN - pointer to variable entry that points here */
    783     oid	*name;	    /* IN/OUT - input name requested, output name found */
    784     int	*length;    /* IN/OUT - length of input and output oid's */
    785     int			exact;	    /* IN - TRUE if an exact match was requested. */
    786     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    787     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    788 {
    789     oid			newname[MAX_NAME_LEN];
    790     int	ifnum;
    791     int result;
    792 static struct sioc_vif_req v_req;
    793 
    794     /* Copy name OID to new OID */
    795     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    796 
    797     /* find "next" interface */
    798     for(ifnum = 0; ifnum < numvifs; ifnum++){
    799 	newname[vp->namelen] = (oid)ifnum;
    800 	result = compare(name, *length, newname, (int)vp->namelen + 1);
    801 	if ((exact && (result == 0)) || (!exact && (result < 0)))
    802 	    break;
    803     }
    804     if (ifnum >= numvifs)
    805 	return NULL;
    806 
    807     /* Save new OID */
    808     bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid));
    809     *length = vp->namelen + 1;
    810     *write_method = 0;
    811     *var_len = sizeof(long);
    812 
    813     switch (vp->magic){
    814 
    815    case ipMRouteInterfaceTtl:
    816        long_return = uvifs[ifnum].uv_threshold;
    817        return (u_char *) &long_return;
    818 
    819    case dvmrpVInterfaceType:
    820       if (uvifs[ifnum].uv_flags & VIFF_SRCRT)
    821          long_return = 2;
    822       else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL)
    823          long_return = 1;
    824       else if (uvifs[ifnum].uv_flags & VIFF_QUERIER)
    825          long_return = 3;
    826       else                               /* SUBNET */
    827          long_return = 4;
    828       return (u_char *) &long_return;
    829 
    830    case dvmrpVInterfaceState:
    831       if (uvifs[ifnum].uv_flags & VIFF_DISABLED)
    832          long_return = 3;
    833       else if ((uvifs[ifnum].uv_flags & VIFF_DOWN)
    834        || ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) && (uvifs[ifnum].uv_neighbors==NULL)))
    835          long_return = 2;
    836       else /* UP */
    837          long_return = 1;
    838       return (u_char *) &long_return;
    839 
    840    case dvmrpVInterfaceLocalAddress:
    841       return (u_char *) &uvifs[ifnum].uv_lcl_addr;
    842 
    843    case dvmrpVInterfaceRemoteAddress:
    844       return (u_char *) ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) ?
    845          &uvifs[ifnum].uv_rmt_addr :
    846          &uvifs[ifnum].uv_subnet);
    847 
    848    case dvmrpVInterfaceRemoteSubnetMask:
    849       return (u_char *) &uvifs[ifnum].uv_subnetmask;
    850 
    851    case dvmrpVInterfaceMetric:
    852        long_return = uvifs[ifnum].uv_metric;
    853        return (u_char *) &long_return;
    854 
    855    case dvmrpVInterfaceRateLimit:
    856        long_return = uvifs[ifnum].uv_rate_limit;
    857        return (u_char *) &long_return;
    858 
    859    case dvmrpVInterfaceInPkts:
    860        refresh_vif(&v_req, ifnum);
    861        long_return = v_req.icount;
    862        return (u_char *) &long_return;
    863 
    864    case dvmrpVInterfaceOutPkts:
    865        refresh_vif(&v_req, ifnum);
    866        long_return = v_req.ocount;
    867        return (u_char *) &long_return;
    868 
    869    case dvmrpVInterfaceInOctets:
    870        refresh_vif(&v_req, ifnum);
    871        long_return = v_req.ibytes;
    872        return (u_char *) &long_return;
    873 
    874    case dvmrpVInterfaceOutOctets:
    875        refresh_vif(&v_req, ifnum);
    876        long_return = v_req.obytes;
    877        return (u_char *) &long_return;
    878 
    879 	default:
    880 	    ERROR("");
    881     }
    882     return NULL;
    883 }
    884 
    885 /*
    886  * Implements the DVMRP Route Table portion of the DVMRP MIB
    887  */
    888 u_char *
    889 o_dvmrpRouteTable(vp, name, length, exact, var_len, write_method)
    890     struct variable *vp;   /* IN - pointer to variable entry that points here */
    891     oid	*name;	    /* IN/OUT - input name requested, output name found */
    892     int	*length;    /* IN/OUT - length of input and output oid's */
    893     int			exact;	    /* IN - TRUE if an exact match was requested. */
    894     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    895     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    896 {
    897     u_long src, mask;
    898     oid        newname[MAX_NAME_LEN];
    899     int        len;
    900     struct rtentry *rt = NULL;
    901 
    902     /* Copy name OID to new OID */
    903     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    904 
    905     if (exact) {
    906 	    if (*length != vp->namelen + 8)
    907 		return NULL;
    908 
    909       if (!get_address(name, *length, &src, vp->namelen)
    910        || !get_address(name, *length, &mask, vp->namelen+4))
    911 		return NULL;
    912 
    913       if (!(rt = snmp_find_route(src, mask)))
    914 		return NULL;
    915 
    916        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
    917 	 } else {
    918        len = *length;
    919        if (compare(name, *length, vp->name, vp->namelen) < 0)
    920           len = vp->namelen;
    921 
    922 	    if (len < vp->namelen + 8) { /* get first entry */
    923 
    924          if (len == vp->namelen) {
    925             src = mask = 0;
    926          } else {
    927             get_address(name, len, &src, vp->namelen);
    928             get_address(name, len, &mask, vp->namelen+4);
    929          }
    930 
    931          if (!next_route(&rt,src,mask)) /* Get first entry */
    932             return NULL;
    933 
    934          put_address(newname, rt->rt_origin    , vp->namelen);
    935          put_address(newname, rt->rt_originmask, vp->namelen+4);
    936 	    } else {  /* get next entry given previous */
    937          get_address(name, *length, &src,  vp->namelen);
    938          get_address(name, *length, &mask, vp->namelen+4);
    939 
    940          if (!next_route(&rt, src,mask))
    941             return NULL;
    942 
    943          put_address(newname, rt->rt_origin,     vp->namelen);
    944          put_address(newname, rt->rt_originmask, vp->namelen+4);
    945 	    }
    946     }
    947 
    948     /* Save new OID */
    949     *length = vp->namelen + 8;
    950     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
    951     *write_method = 0;
    952     *var_len = sizeof(long);
    953 
    954     switch (vp->magic) {
    955 
    956       case dvmrpRouteUpstreamNeighbor:
    957          return (u_char *) &rt->rt_gateway;
    958 
    959       case dvmrpRouteInVifIndex:
    960          long_return = rt->rt_parent;
    961          return (u_char *) &long_return;
    962 
    963       case dvmrpRouteMetric:
    964          long_return = rt->rt_metric;
    965          return (u_char *) &long_return;
    966 
    967       case dvmrpRouteExpiryTime:
    968          long_return = (ROUTE_EXPIRE_TIME - rt->rt_timer
    969           + secs_remaining_offset()) * 100;
    970          return (u_char *) &long_return;
    971 
    972     default:
    973        ERROR("");
    974     }
    975     return NULL;
    976 }
    977 
    978 /*
    979  * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB
    980  */
    981 u_char *
    982 o_dvmrpRouteNextHopTable(vp, name, length, exact, var_len, write_method)
    983     struct variable *vp;   /* IN - pointer to variable entry that points here */
    984     oid	*name;	    /* IN/OUT - input name requested, output name found */
    985     int	*length;    /* IN/OUT - length of input and output oid's */
    986     int			exact;	    /* IN - TRUE if an exact match was requested. */
    987     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
    988     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
    989 {
    990     u_long     src, mask;
    991     vifi_t     vifi;
    992     struct rtentry *rt = NULL;
    993     oid        newname[MAX_NAME_LEN];
    994     int        len;
    995 
    996     /* Copy name OID to new OID */
    997     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    998 
    999     if (exact) {
   1000 	    if (*length != vp->namelen + 9)
   1001 		return NULL;
   1002 
   1003       if (!get_address(name, *length, &src, vp->namelen)
   1004        || !get_address(name, *length, &mask, vp->namelen+4)
   1005        || (!(rt=snmp_find_route(src,mask))))
   1006 		return NULL;
   1007 
   1008       vifi = name[vp->namelen+8];
   1009       if (!(VIFM_ISSET(vifi, rt->rt_children)))
   1010       return NULL;
   1011 
   1012        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
   1013 	 } else {
   1014        len = *length;
   1015        if (compare(name, *length, vp->name, vp->namelen) < 0)
   1016           len = vp->namelen;
   1017 
   1018 	    if (len < vp->namelen + 9) { /* get first entry */
   1019 
   1020          get_address(name, len, &src,  vp->namelen);
   1021          get_address(name, len, &mask, vp->namelen+4);
   1022 
   1023          /* Find first child vif */
   1024          vifi=0;
   1025          if (!next_route_child(&rt, src, mask, &vifi))
   1026             return NULL;
   1027 
   1028          put_address(newname, rt->rt_origin,     vp->namelen);
   1029          put_address(newname, rt->rt_originmask, vp->namelen+4);
   1030    		newname[vp->namelen+8] = vifi;
   1031 	    } else {  /* get next entry given previous */
   1032 		   vifi = name[vp->namelen+8] + 1;
   1033          if (!get_address(name, *length, &src,  vp->namelen)
   1034           || !get_address(name, *length, &mask, vp->namelen+4)
   1035           || !next_route_child(&rt, src, mask, &vifi))
   1036             return NULL;
   1037 
   1038          put_address(newname, rt->rt_origin,     vp->namelen);
   1039          put_address(newname, rt->rt_originmask, vp->namelen+4);
   1040 		   newname[vp->namelen+8] = vifi;
   1041 	    }
   1042     }
   1043 
   1044     /* Save new OID */
   1045     *length = vp->namelen + 9;
   1046     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
   1047     *write_method = 0;
   1048     *var_len = sizeof(long);
   1049 
   1050     switch (vp->magic) {
   1051 
   1052     case dvmrpRouteNextHopType:
   1053        long_return = (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2;
   1054        return (u_char *) &long_return;
   1055 
   1056     default:
   1057        ERROR("");
   1058     }
   1059     return NULL;
   1060 }
   1061 
   1062 /*
   1063  * Implements the IP Multicast Route Table portion of the Multicast MIB
   1064  */
   1065 u_char *
   1066 o_ipMRouteTable(vp, name, length, exact, var_len, write_method)
   1067     struct variable *vp;   /* IN - pointer to variable entry that points here */
   1068     oid	*name;	    /* IN/OUT - input name requested, output name found */
   1069     int	*length;    /* IN/OUT - length of input and output oid's */
   1070     int			exact;	    /* IN - TRUE if an exact match was requested. */
   1071     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
   1072     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
   1073 {
   1074     u_long src, grp, mask;
   1075     struct gtable *gt = NULL;
   1076     struct stable *st = NULL;
   1077 static struct sioc_sg_req sg_req;
   1078     oid        newname[MAX_NAME_LEN];
   1079     int        len;
   1080 
   1081     /* Copy name OID to new OID */
   1082     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
   1083 
   1084     if (exact) {
   1085 	    if (*length != vp->namelen + 12)
   1086 		return NULL;
   1087 
   1088       if (!get_address(name, *length, &grp,  vp->namelen)
   1089        || !get_address(name, *length, &src,  vp->namelen+4)
   1090        || !get_address(name, *length, &mask, vp->namelen+8)
   1091        || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */
   1092        || !(gt = find_grp(grp))
   1093        || !(st = find_grp_src(gt,src)))
   1094 		return NULL;
   1095 
   1096        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
   1097 	 } else {
   1098        len = *length;
   1099        if (compare(name, *length, vp->name, vp->namelen) < 0)
   1100           len = vp->namelen;
   1101 
   1102 	    if (len < vp->namelen + 12) { /* get first entry */
   1103 
   1104          get_address(name, len, &grp,  vp->namelen);
   1105          get_address(name, len, &src,  vp->namelen+4);
   1106          get_address(name, len, &mask, vp->namelen+8);
   1107 
   1108          if (!next_grp_src_mask(&gt,&st,grp,src,mask)) /* Get first entry */
   1109             return NULL;
   1110 
   1111          put_address(newname, gt->gt_mcastgrp, vp->namelen);
   1112          put_address(newname, st->st_origin,   vp->namelen+4);
   1113          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
   1114 	    } else {  /* get next entry given previous */
   1115          get_address(name, *length, &grp , vp->namelen);
   1116          get_address(name, *length, &src , vp->namelen+4);
   1117          get_address(name, *length, &mask, vp->namelen+8);
   1118 
   1119          if (!next_grp_src_mask(&gt, &st, grp,src,mask))
   1120             return NULL;
   1121 
   1122          put_address(newname, gt->gt_mcastgrp, vp->namelen);
   1123          put_address(newname, st->st_origin,   vp->namelen+4);
   1124          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
   1125 	    }
   1126     }
   1127 
   1128     /* Save new OID */
   1129     *length = vp->namelen + 12;
   1130     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
   1131     *write_method = 0;
   1132     *var_len = sizeof(long);
   1133 
   1134     switch (vp->magic) {
   1135 
   1136       case ipMRouteUpstreamNeighbor:
   1137          return (u_char *) &gt->gt_route->rt_gateway;
   1138 
   1139       case ipMRouteInIfIndex:
   1140          long_return = gt->gt_route->rt_parent;
   1141          return (u_char *) &long_return;
   1142 
   1143       case ipMRouteUpTime: {
   1144          time_t currtime;
   1145          time(&currtime);
   1146          long_return = (currtime - gt->gt_ctime)*100;
   1147          return (u_char *) &long_return;
   1148       }
   1149 
   1150       case ipMRouteExpiryTime:
   1151          long_return = 5*((gt->gt_timer+4)/5); /* round up to nearest 5 */
   1152          long_return = (long_return + secs_remaining_offset()) * 100;
   1153          return (u_char *) &long_return;
   1154 
   1155       case ipMRoutePkts:
   1156          refresh_sg(&sg_req, gt, st);
   1157          long_return = sg_req.pktcnt;
   1158          return (u_char *) &long_return;
   1159 
   1160       case ipMRouteOctets:
   1161          refresh_sg(&sg_req, gt, st);
   1162          long_return = sg_req.bytecnt;
   1163          return (u_char *) &long_return;
   1164 
   1165       case ipMRouteDifferentInIfIndexes:
   1166          refresh_sg(&sg_req, gt, st);
   1167          long_return = sg_req.wrong_if;
   1168          return (u_char *) &long_return;
   1169 
   1170       case ipMRouteProtocol:
   1171          long_return = 4;
   1172          return (u_char *) &long_return;
   1173 
   1174     default:
   1175        ERROR("");
   1176     }
   1177     return NULL;
   1178 }
   1179 
   1180 /*
   1181  * Implements the IP Multicast Routing Next Hop Table portion of the Multicast
   1182  * MIB
   1183  */
   1184 u_char *
   1185 o_ipMRouteNextHopTable(vp, name, length, exact, var_len, write_method)
   1186     struct variable *vp;   /* IN - pointer to variable entry that points here */
   1187     oid	*name;	    /* IN/OUT - input name requested, output name found */
   1188     int	*length;    /* IN/OUT - length of input and output oid's */
   1189     int			exact;	    /* IN - TRUE if an exact match was requested. */
   1190     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
   1191     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
   1192 {
   1193     u_long src, grp, mask, addr;
   1194     vifi_t   vifi;
   1195     struct gtable *gt;
   1196     struct stable *st;
   1197     oid        newname[MAX_NAME_LEN];
   1198     int        len;
   1199 
   1200     /* Copy name OID to new OID */
   1201     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
   1202 
   1203     if (exact) {
   1204 	    if (*length != vp->namelen + 17)
   1205 		return NULL;
   1206 
   1207       if (!get_address(name, *length, &grp, vp->namelen)
   1208        || !get_address(name, *length, &src, vp->namelen+4)
   1209        || !get_address(name, *length, &mask, vp->namelen+8)
   1210        || !get_address(name, *length, &addr, vp->namelen+13)
   1211        || grp!=addr
   1212        || mask!=0xFFFFFFFF
   1213        || (!(gt=find_grp(grp)))
   1214        || (!(st=find_grp_src(gt,src))))
   1215 		return NULL;
   1216 
   1217       vifi = name[vp->namelen+12];
   1218       if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children)))
   1219       return NULL;
   1220 
   1221        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
   1222 	 } else {
   1223        len = *length;
   1224        if (compare(name, *length, vp->name, vp->namelen) < 0)
   1225           len = vp->namelen;
   1226 
   1227 	    if (len < vp->namelen + 17) { /* get first entry */
   1228 
   1229          get_address(name, len, &grp, vp->namelen);
   1230          get_address(name, len, &src, vp->namelen+4);
   1231          get_address(name, len, &mask, vp->namelen+8);
   1232 
   1233          /* Find first child vif */
   1234          vifi=0;
   1235          if (!next_child(&gt, &st, grp, src, mask, &vifi))
   1236             return NULL;
   1237 
   1238          put_address(newname, gt->gt_mcastgrp, vp->namelen);
   1239          put_address(newname, st->st_origin,   vp->namelen+4);
   1240          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
   1241    		newname[vp->namelen+12] = vifi;
   1242          put_address(newname, gt->gt_mcastgrp, vp->namelen+13);
   1243 
   1244 	    } else {  /* get next entry given previous */
   1245 		   vifi = name[vp->namelen+12]+1;
   1246          if (!get_address(name, *length, &grp,  vp->namelen)
   1247           || !get_address(name, *length, &src,  vp->namelen+4)
   1248           || !get_address(name, *length, &mask, vp->namelen+8)
   1249           || !next_child(&gt, &st, grp, src, mask, &vifi))
   1250             return NULL;
   1251 
   1252          put_address(newname, gt->gt_mcastgrp, vp->namelen);
   1253          put_address(newname, st->st_origin,   vp->namelen+4);
   1254          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
   1255 		   newname[vp->namelen+12] = vifi;
   1256          put_address(newname, gt->gt_mcastgrp, vp->namelen+13);
   1257 	    }
   1258     }
   1259 
   1260     /* Save new OID */
   1261     *length = vp->namelen + 17;
   1262     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
   1263     *write_method = 0;
   1264     *var_len = sizeof(long);
   1265 
   1266     switch (vp->magic) {
   1267 
   1268       case ipMRouteNextHopState:
   1269          long_return = (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1;
   1270          return (u_char *) &long_return;
   1271 
   1272       /* Currently equal to ipMRouteUpTime */
   1273       case ipMRouteNextHopUpTime: {
   1274          time_t currtime;
   1275          time(&currtime);
   1276          long_return = (currtime - gt->gt_ctime)*100;
   1277          return (u_char *) &long_return;
   1278       }
   1279 
   1280       case ipMRouteNextHopExpiryTime:
   1281          long_return = 5*((gt->gt_prsent_timer+4)/5); /* round up to nearest 5*/
   1282          long_return = (long_return + secs_remaining_offset()) * 100;
   1283          return (u_char *) &long_return;
   1284 
   1285       case ipMRouteNextHopClosestMemberHops:
   1286          long_return = 0;
   1287          return (u_char *) &long_return;
   1288 
   1289       case ipMRouteNextHopProtocol:
   1290          long_return = 4;
   1291          return (u_char *) &long_return;
   1292 
   1293     default:
   1294        ERROR("");
   1295     }
   1296     return NULL;
   1297 }
   1298 
   1299 /* sync_timer is called by timer() every TIMER_INTERVAL seconds.
   1300  * Its job is to record this time so that we can compute on demand
   1301  * the approx # seconds remaining until the next timer() call
   1302  */
   1303 static time_t lasttimer;
   1304 
   1305 void
   1306 sync_timer()
   1307 {
   1308     time(&lasttimer);
   1309 }
   1310 
   1311 int /* in range [-TIMER_INTERVAL..0] */
   1312 secs_remaining_offset()
   1313 {
   1314    time_t tm;
   1315 
   1316    time(&tm);
   1317    return lasttimer-tm;
   1318 }
   1319