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