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