Home | History | Annotate | Line # | Download | only in mrouted
snmp.c revision 1.2
      1 /*	$NetBSD: snmp.c,v 1.2 1995/10/09 03:51:58 thorpej Exp $	*/
      2 
      3 /*
      4  * snmp.c
      5  *
      6  * Code written by David Thaler <thalerd (at) eecs.umich.edu>
      7  * Moved to a seperate file by Bill Fenner <fenner (at) parc.xerox.com>
      8  */
      9 
     10 
     11 #include "defs.h"
     12 #include <string.h>
     13 #include "snmp.h"
     14 
     15 #define NUMMIBS 2
     16 #define SNMPD_RETRY_INTERVAL 300 /* periodic snmpd probe interval */
     17 
     18 char *mibs[]={ "ipMRouteMIB", "dvmrpMIB" };
     19 
     20 extern int o_ipMRouteTable();
     21 extern int o_ipMRouteNextHopTable();
     22 extern int o_dvmrpRouteTable();
     23 extern int o_dvmrpRouteNextHopTable();
     24 
     25        int smux_fd = NOTOK;
     26        int rock_and_roll = 0;
     27        int dont_bother_anymore = 0;
     28        int quantum = 0;
     29 static OID   subtree[NUMMIBS] = NULLOID;
     30 static struct smuxEntry *se = NULL;
     31 extern int smux_errno;
     32 extern char smux_info[BUFSIZ];
     33 
     34 /*
     35  * Place an IP address into an OID starting at element n
     36  */
     37 void
     38 put_address(oid, addr, n)
     39    OID oid;
     40    u_long addr;
     41    int n;
     42 {
     43    int i;
     44 
     45    for (i=n+3; i>=n+0; i--) {
     46       oid->oid_elements[i] = addr & 0xFF;
     47       addr >>= 8;
     48    }
     49 }
     50 
     51 /* Get an IP address from an OID starting at element n */
     52 int
     53 get_address(oid, addr, n)
     54    OID oid;
     55    u_long *addr;
     56    int n;
     57 {
     58    int i;
     59    int ok = 1;
     60 
     61    (*addr) = 0;
     62 
     63    if (oid -> oid_nelem < n+4)
     64       return 0;
     65 
     66    for (i=n; i<n+4; i++) {
     67       (*addr) <<= 8;
     68       if (i >= oid->oid_nelem)
     69           ok = 0;
     70       else
     71          (*addr) |= oid->oid_elements[i];
     72    }
     73 
     74    return ok;
     75 }
     76 
     77 /*
     78  *  Attempt to start up SMUX protocol
     79  */
     80 void
     81 try_smux_init()
     82 {
     83     if (smux_fd != NOTOK || dont_bother_anymore)
     84        return;
     85     if ((smux_fd = smux_init(debug)) == NOTOK) {
     86        log(LOG_WARNING, 0,"smux_init: %s [%s]", smux_error(smux_errno),
     87         smux_info);
     88     } else
     89        rock_and_roll = 0;
     90 }
     91 
     92 /*
     93  * Implements scalar objects from both MIBs
     94  */
     95 static int
     96 o_scalar(oi, v, offset)
     97    OI oi;
     98    register struct type_SNMP_VarBind *v;
     99    int offset;
    100 {
    101     int     ifvar;
    102     register OID    oid = oi -> oi_name;
    103     register OT     ot = oi -> oi_type;
    104 
    105     ifvar = (int) ot -> ot_info;
    106     switch (offset) {
    107         case type_SNMP_SMUX__PDUs_get__request:
    108             if (oid -> oid_nelem !=
    109                         ot -> ot_name -> oid_nelem + 1
    110                     || oid -> oid_elements[oid -> oid_nelem - 1]
    111                             != 0)
    112                 return int_SNMP_error__status_noSuchName;
    113             break;
    114 
    115         case type_SNMP_SMUX__PDUs_get__next__request:
    116             if (oid -> oid_nelem
    117                     == ot -> ot_name -> oid_nelem) {
    118                 OID     new;
    119 
    120                 if ((new = oid_extend (oid, 1)) == NULLOID)
    121                     return int_SNMP_error__status_genErr;
    122                 new -> oid_elements[new -> oid_nelem - 1] = 0;
    123 
    124                 if (v -> name)
    125                     free_SNMP_ObjectName (v -> name);
    126                 v -> name = new;
    127             }
    128             else
    129                 return NOTOK;
    130             break;
    131 
    132         default:
    133             return int_SNMP_error__status_genErr;
    134     }
    135 
    136     switch (ifvar) {
    137         case ipMRouteEnable:
    138             return o_integer (oi, v, 1);
    139 
    140         case dvmrpVersion: {
    141             static char buff[15];
    142 
    143             sprintf(buff, "mrouted%d.%d", PROTOCOL_VERSION, MROUTED_VERSION);
    144             return o_string (oi, v, buff, strlen (buff));
    145         }
    146 
    147         case dvmrpGenerationId:
    148             return o_integer (oi, v, dvmrp_genid);
    149 
    150         default:
    151             return int_SNMP_error__status_noSuchName;
    152     }
    153 }
    154 
    155 /*
    156  * Find if a specific scoped boundary exists on a Vif
    157  */
    158 struct vif_acl *
    159 find_boundary(vifi, addr, mask)
    160    int vifi;
    161    int addr;
    162    int mask;
    163 {
    164    struct vif_acl *n;
    165 
    166    for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) {
    167       if (addr == n->acl_addr && mask==n->acl_mask)
    168          return n;
    169    }
    170    return NULL;
    171 }
    172 
    173 /*
    174  * Find the next scoped boundary in order after a given spec
    175  */
    176 struct vif_acl *
    177 next_boundary(vifi, addr, mask)
    178    int *vifi;
    179    int  addr;
    180    int  mask;
    181 {
    182    struct vif_acl *bestn, *n;
    183    int  i;
    184 
    185    for (i = *vifi; i < numvifs; i++) {
    186       bestn = NULL;
    187       for (n = uvifs[i].uv_acl; n; n=n->acl_next) {
    188          if ((i > *vifi || n->acl_addr > addr
    189            || (n->acl_addr==addr && n->acl_mask>mask))
    190           && (!bestn || n->acl_addr < bestn->acl_addr
    191            || (n->acl_addr==bestn->acl_addr && n->acl_mask<bestn->acl_mask)))
    192             bestn = n;
    193       }
    194       if (bestn) {
    195          *vifi = i;
    196          return bestn;
    197       }
    198    }
    199    return NULL;
    200 }
    201 
    202 /*
    203  * Implements the Boundary Table portion of the DVMRP MIB
    204  */
    205 static int
    206 o_dvmrpBoundaryTable (oi, v, offset)
    207 OI	oi;
    208 register struct type_SNMP_VarBind *v;
    209 {
    210     int	    ifvar, vifi,
    211 	    addr, mask;
    212     register OID    oid = oi -> oi_name;
    213     register OT	   ot = oi -> oi_type;
    214     struct vif_acl *bound;
    215 
    216     ifvar = (int) ot -> ot_info;
    217     switch (offset) {
    218 	case type_SNMP_SMUX__PDUs_get__request:
    219 	    if (oid->oid_nelem != ot->ot_name->oid_nelem + 9)
    220 		return int_SNMP_error__status_noSuchName;
    221 
    222       if ((vifi = oid -> oid_elements[ot-> ot_name->oid_nelem]) >= numvifs)
    223       return int_SNMP_error__status_noSuchName;
    224 
    225       if (!get_address(oid, &addr, ot->ot_name->oid_nelem+1)
    226        || !get_address(oid, &mask, ot->ot_name->oid_nelem+5))
    227 		return int_SNMP_error__status_noSuchName;
    228 
    229       if (!(bound = find_boundary(vifi, addr, mask)))
    230 		return int_SNMP_error__status_noSuchName;
    231 	    break;
    232 
    233 	case type_SNMP_SMUX__PDUs_get__next__request:
    234 	    if (oid->oid_nelem < ot->ot_name->oid_nelem + 9) {
    235 		OID	new;
    236 
    237       if (oid->oid_nelem == ot->ot_name->oid_nelem) {
    238          vifi = addr = mask = 0;
    239       } else {
    240          vifi = oid->oid_elements[ot->ot_name->oid_nelem];
    241          get_address(oid, &addr, ot->ot_name->oid_nelem+1);
    242          get_address(oid, &mask, ot->ot_name->oid_nelem+5);
    243       }
    244 
    245       bound = next_boundary(&vifi,addr,mask);
    246       if (!bound)
    247          return NOTOK;
    248 
    249 		new = oid_extend (oid, ot->ot_name->oid_nelem+9-oid->oid_nelem);
    250 		if (new == NULLOID)
    251 		    return NOTOK;
    252 		new -> oid_elements[ot->ot_name->oid_nelem] = vifi;
    253       put_address(new, bound->acl_addr, ot->ot_name->oid_nelem+1);
    254       put_address(new, bound->acl_mask, ot->ot_name->oid_nelem+5);
    255 
    256 		if (v -> name)
    257 		    free_SNMP_ObjectName (v -> name);
    258 		v -> name = new;
    259 	    } else {  /* get next entry given previous */
    260 		int	i = ot -> ot_name -> oid_nelem;
    261 
    262 		   vifi = oid->oid_elements[i];
    263          get_address(oid, &addr, ot->ot_name->oid_nelem+1);
    264          get_address(oid, &mask, ot->ot_name->oid_nelem+5);
    265          if (!(bound = next_boundary(&vifi,addr,mask+1)))
    266             return NOTOK;
    267 
    268          put_address(oid, bound->acl_addr, ot->ot_name->oid_nelem+1);
    269          put_address(oid, bound->acl_mask, ot->ot_name->oid_nelem+5);
    270 		   oid->oid_elements[i] = vifi;
    271 		   oid->oid_nelem = i + 9;
    272 	    }
    273 	    break;
    274 
    275 	default:
    276 	    return int_SNMP_error__status_genErr;
    277     }
    278 
    279     switch (ifvar) {
    280 
    281    case dvmrpBoundaryVifIndex:
    282        return o_integer (oi, v, vifi);
    283 
    284 	default:
    285 	    return int_SNMP_error__status_noSuchName;
    286     }
    287 }
    288 
    289 /*
    290  * Given a vif index and address, return the next greater neighbor entry
    291  */
    292 struct listaddr *
    293 next_neighbor(vifi, addr)
    294    int *vifi;
    295    int  addr;
    296 {
    297    struct listaddr *bestn, *n;
    298    int  i;
    299 
    300    for (i = *vifi; i < numvifs; i++) {
    301       bestn = NULL;
    302       for (n = uvifs[i].uv_neighbors; n; n=n->al_next) {
    303          if ((i > *vifi || n->al_addr > addr)
    304           && (!bestn || n->al_addr < bestn->al_addr))
    305             bestn = n;
    306       }
    307       if (bestn) {
    308          *vifi = i;
    309          return bestn;
    310       }
    311    }
    312    return NULL;
    313 }
    314 
    315 /*
    316  * Find a neighbor, if it exists off a given Vif
    317  */
    318 struct listaddr *
    319 find_neighbor(vifi, addr)
    320    int vifi;
    321    int addr;
    322 {
    323    struct listaddr *n;
    324 
    325    for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) {
    326       if (addr == n->al_addr)
    327          return n;
    328    }
    329    return NULL;
    330 }
    331 
    332 /*
    333  * Implements the Neighbor Table portion of the DVMRP MIB
    334  */
    335 static int
    336 o_dvmrpNeighborTable (oi, v, offset)
    337 OI	oi;
    338 register struct type_SNMP_VarBind *v;
    339 {
    340     int	    ifvar, vifi,
    341 	    addr;
    342     register OID    oid = oi -> oi_name;
    343     register OT	   ot = oi -> oi_type;
    344     struct listaddr *neighbor;
    345 
    346     ifvar = (int) ot -> ot_info;
    347     switch (offset) {
    348 	case type_SNMP_SMUX__PDUs_get__request:
    349 	    if (oid->oid_nelem != ot->ot_name->oid_nelem + 5)
    350 		return int_SNMP_error__status_noSuchName;
    351 
    352       if ((vifi = oid -> oid_elements[ot-> ot_name->oid_nelem]) >= numvifs)
    353       return int_SNMP_error__status_noSuchName;
    354 
    355       if (!get_address(oid, &addr, ot->ot_name->oid_nelem+1))
    356 		return int_SNMP_error__status_noSuchName;
    357 
    358       if (!(neighbor = find_neighbor(vifi, addr)))
    359 		return int_SNMP_error__status_noSuchName;
    360 	    break;
    361 
    362 	case type_SNMP_SMUX__PDUs_get__next__request:
    363 	    if (oid->oid_nelem < ot->ot_name->oid_nelem + 5) {
    364 		OID	new;
    365 
    366       if (oid->oid_nelem == ot->ot_name->oid_nelem) {
    367          vifi = addr = 0;
    368       } else {
    369          vifi = oid->oid_elements[ot->ot_name->oid_nelem];
    370          get_address(oid, &addr, ot->ot_name->oid_nelem+1);
    371       }
    372 
    373       neighbor = next_neighbor(&vifi,addr); /* Get first entry */
    374       if (!neighbor)
    375          return NOTOK;
    376 
    377 		new = oid_extend (oid, ot->ot_name->oid_nelem+5-oid->oid_nelem);
    378 		if (new == NULLOID)
    379 		    return NOTOK;
    380 		new -> oid_elements[ot->ot_name->oid_nelem] = vifi;
    381       put_address(new, neighbor->al_addr, ot->ot_name->oid_nelem+1);
    382 
    383 		if (v -> name)
    384 		    free_SNMP_ObjectName (v -> name);
    385 		v -> name = new;
    386 
    387 	    } else {  /* get next entry given previous */
    388 		int	i = ot -> ot_name -> oid_nelem;
    389 
    390 		   vifi = oid->oid_elements[i];
    391          get_address(oid, &addr, ot->ot_name->oid_nelem+1);
    392          if (!(neighbor = next_neighbor(&vifi,addr+1)))
    393             return NOTOK;
    394 
    395          put_address(oid, neighbor->al_addr, ot->ot_name->oid_nelem+1);
    396 		   oid->oid_elements[i] = vifi;
    397 		   oid->oid_nelem = i + 5;
    398 	    }
    399 	    break;
    400 
    401 	default:
    402 	    return int_SNMP_error__status_genErr;
    403     }
    404 
    405     switch (ifvar) {
    406 
    407    case dvmrpNeighborUpTime: {
    408        time_t currtime;
    409        time(&currtime);
    410        return o_integer (oi, v, (currtime - neighbor->al_ctime)*100);
    411    }
    412 
    413    case dvmrpNeighborExpiryTime:
    414        return o_integer (oi, v, (NEIGHBOR_EXPIRE_TIME-neighbor->al_timer) * 100);
    415 
    416    case dvmrpNeighborVersion: {
    417        static char buff[15];
    418 
    419        sprintf(buff, "%d.%d", neighbor->al_pv, neighbor->al_mv);
    420        return o_string (oi, v, buff, strlen (buff));
    421    }
    422 
    423    case dvmrpNeighborGenerationId:
    424        return o_integer (oi, v, neighbor->al_genid);
    425 
    426 	default:
    427 	    return int_SNMP_error__status_noSuchName;
    428     }
    429 }
    430 
    431 /*
    432  * Given a virtual interface number, make sure we have the current
    433  * kernel information for that Vif.
    434  */
    435 refresh_vif(v_req, ifnum)
    436    struct sioc_vif_req *v_req;
    437    int ifnum;
    438 {
    439    static   int lastq = -1;
    440 
    441    if (quantum!=lastq || v_req->vifi != ifnum) {
    442        lastq = quantum;
    443        v_req->vifi = ifnum;
    444        if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)v_req) < 0)
    445           v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0;
    446    }
    447 }
    448 
    449 /*
    450  * Implements the Multicast Routing Interface Table portion of the Multicast MIB
    451  */
    452 static int
    453 o_ipMRouteInterfaceTable (oi, v, offset)
    454 OI	oi;
    455 register struct type_SNMP_VarBind *v;
    456 int	offset;
    457 {
    458     int	    ifnum,
    459 	    ifvar;
    460     register OID    oid = oi -> oi_name;
    461     register OT	   ot = oi -> oi_type;
    462 static struct sioc_vif_req v_req;
    463 
    464     ifvar = (int) ot -> ot_info;
    465     switch (offset) {
    466 	case type_SNMP_SMUX__PDUs_get__request:
    467 	    if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1)
    468 		return int_SNMP_error__status_noSuchName;
    469 	    if ((ifnum = oid -> oid_elements[oid -> oid_nelem - 1]) >= numvifs)
    470 		return int_SNMP_error__status_noSuchName;
    471 	    break;
    472 
    473 	case type_SNMP_SMUX__PDUs_get__next__request:
    474 	    if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
    475 		OID	new;
    476 
    477 		ifnum = 0;
    478 
    479 		if ((new = oid_extend (oid, 1)) == NULLOID)
    480 		    return NOTOK;
    481 		new -> oid_elements[new -> oid_nelem - 1] = ifnum;
    482 
    483 		if (v -> name)
    484 		    free_SNMP_ObjectName (v -> name);
    485 		v -> name = new;
    486 
    487 	    } else {
    488 		int	i = ot -> ot_name -> oid_nelem;
    489 
    490 		if ((ifnum = oid -> oid_elements[i] + 1) >= numvifs)
    491 		    return NOTOK;
    492 
    493 		oid -> oid_elements[i] = ifnum;
    494 		oid -> oid_nelem = i + 1;
    495 	    }
    496 	    break;
    497 
    498 	default:
    499 	    return int_SNMP_error__status_genErr;
    500     }
    501 
    502     switch (ifvar) {
    503 	case ipMRouteInterfaceTtl:
    504 	    return o_integer (oi, v, uvifs[ifnum].uv_threshold);
    505 
    506 	case dvmrpVInterfaceType:
    507       if (uvifs[ifnum].uv_flags & VIFF_SRCRT)
    508          return o_integer (oi, v, 2);
    509       else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL)
    510          return o_integer (oi, v, 1);
    511       else if (uvifs[ifnum].uv_flags & VIFF_QUERIER)
    512          return o_integer (oi, v, 3);
    513       else                               /* SUBNET */
    514          return o_integer (oi, v, 4);
    515 
    516 	case dvmrpVInterfaceState:
    517       if (uvifs[ifnum].uv_flags & VIFF_DISABLED)
    518          return o_integer (oi, v, 3);
    519       else if (uvifs[ifnum].uv_flags & VIFF_DOWN)
    520          return o_integer (oi, v, 2);
    521       else /* UP */
    522          return o_integer (oi, v, 1);
    523 
    524    case dvmrpVInterfaceLocalAddress: {
    525       struct sockaddr_in tmp;
    526       tmp.sin_addr.s_addr = uvifs[ifnum].uv_lcl_addr;
    527       return o_ipaddr (oi, v, &tmp);
    528    }
    529 
    530    case dvmrpVInterfaceRemoteAddress: {
    531       struct sockaddr_in tmp;
    532       tmp.sin_addr.s_addr = (uvifs[ifnum].uv_flags & VIFF_TUNNEL) ?
    533          uvifs[ifnum].uv_rmt_addr :
    534          uvifs[ifnum].uv_subnet;
    535       return o_ipaddr (oi, v, &tmp);
    536    }
    537 
    538    case dvmrpVInterfaceRemoteSubnetMask: {
    539       struct sockaddr_in tmp;
    540       tmp.sin_addr.s_addr = uvifs[ifnum].uv_subnetmask;
    541       return o_ipaddr (oi, v, &tmp);
    542    }
    543 
    544 	case dvmrpVInterfaceMetric:
    545 	    return o_integer (oi, v, uvifs[ifnum].uv_metric);
    546 
    547 	case dvmrpVInterfaceRateLimit:
    548 	    return o_integer (oi, v, uvifs[ifnum].uv_rate_limit);
    549 
    550 	case dvmrpVInterfaceInPkts:
    551        refresh_vif(&v_req, ifnum);
    552 	    return o_integer(oi, v, v_req.icount);
    553 
    554 	case dvmrpVInterfaceOutPkts:
    555        refresh_vif(&v_req, ifnum);
    556 	    return o_integer(oi, v, v_req.ocount);
    557 
    558 	case dvmrpVInterfaceInOctets:
    559        refresh_vif(&v_req, ifnum);
    560 	    return o_integer(oi, v, v_req.ibytes);
    561 
    562 	case dvmrpVInterfaceOutOctets:
    563        refresh_vif(&v_req, ifnum);
    564 	    return o_integer(oi, v, v_req.obytes);
    565 
    566 	default:
    567 	    return int_SNMP_error__status_noSuchName;
    568     }
    569 }
    570 
    571 struct mib_variable {
    572    char     *name;        /* MIB variable name */
    573    int     (*function)(); /* Function to call */
    574    int       info;        /* Which variable */
    575 } mib_vars[] = {
    576  "ipMRouteEnable",               o_scalar, ipMRouteEnable,
    577  "ipMRouteUpstreamNeighbor",     o_ipMRouteTable,  ipMRouteUpstreamNeighbor,
    578  "ipMRouteInIfIndex",            o_ipMRouteTable,  ipMRouteInIfIndex,
    579  "ipMRouteUpTime",               o_ipMRouteTable,  ipMRouteUpTime,
    580  "ipMRouteExpiryTime",           o_ipMRouteTable,  ipMRouteExpiryTime,
    581  "ipMRoutePkts",                 o_ipMRouteTable,  ipMRoutePkts,
    582  "ipMRouteDifferentInIfIndexes", o_ipMRouteTable,  ipMRouteDifferentInIfIndexes,
    583  "ipMRouteOctets",               o_ipMRouteTable,  ipMRouteOctets,
    584  "ipMRouteProtocol",             o_ipMRouteTable,  ipMRouteProtocol,
    585  "ipMRouteNextHopState",      o_ipMRouteNextHopTable, ipMRouteNextHopState,
    586  "ipMRouteNextHopUpTime",     o_ipMRouteNextHopTable, ipMRouteNextHopUpTime,
    587  "ipMRouteNextHopExpiryTime", o_ipMRouteNextHopTable, ipMRouteNextHopExpiryTime,
    588  "ipMRouteNextHopClosestMemberHops", o_ipMRouteNextHopTable, ipMRouteNextHopClosestMemberHops,
    589  "ipMRouteNextHopProtocol",   o_ipMRouteNextHopTable, ipMRouteNextHopProtocol,
    590  "ipMRouteInterfaceTtl",  o_ipMRouteInterfaceTable, ipMRouteInterfaceTtl,
    591  "dvmrpVersion",               o_scalar, dvmrpVersion,
    592  "dvmrpGenerationId",          o_scalar, dvmrpGenerationId,
    593  "dvmrpVInterfaceType",     o_ipMRouteInterfaceTable, dvmrpVInterfaceType,
    594  "dvmrpVInterfaceState",    o_ipMRouteInterfaceTable, dvmrpVInterfaceState,
    595  "dvmrpVInterfaceLocalAddress", o_ipMRouteInterfaceTable, dvmrpVInterfaceLocalAddress,
    596  "dvmrpVInterfaceRemoteAddress", o_ipMRouteInterfaceTable, dvmrpVInterfaceRemoteAddress,
    597  "dvmrpVInterfaceRemoteSubnetMask", o_ipMRouteInterfaceTable, dvmrpVInterfaceRemoteSubnetMask,
    598  "dvmrpVInterfaceMetric",    o_ipMRouteInterfaceTable, dvmrpVInterfaceMetric,
    599  "dvmrpVInterfaceRateLimit", o_ipMRouteInterfaceTable, dvmrpVInterfaceRateLimit,
    600  "dvmrpVInterfaceInPkts",    o_ipMRouteInterfaceTable, dvmrpVInterfaceInPkts,
    601  "dvmrpVInterfaceOutPkts",   o_ipMRouteInterfaceTable, dvmrpVInterfaceOutPkts,
    602  "dvmrpVInterfaceInOctets",  o_ipMRouteInterfaceTable, dvmrpVInterfaceInOctets,
    603  "dvmrpVInterfaceOutOctets", o_ipMRouteInterfaceTable, dvmrpVInterfaceOutOctets,
    604  "dvmrpNeighborUpTime",      o_dvmrpNeighborTable, dvmrpNeighborUpTime,
    605  "dvmrpNeighborExpiryTime",  o_dvmrpNeighborTable, dvmrpNeighborExpiryTime,
    606  "dvmrpNeighborVersion",     o_dvmrpNeighborTable, dvmrpNeighborVersion,
    607  "dvmrpNeighborGenerationId",o_dvmrpNeighborTable, dvmrpNeighborGenerationId,
    608  "dvmrpRouteUpstreamNeighbor", o_dvmrpRouteTable, dvmrpRouteUpstreamNeighbor,
    609  "dvmrpRouteInVifIndex",       o_dvmrpRouteTable, dvmrpRouteInVifIndex,
    610  "dvmrpRouteMetric",           o_dvmrpRouteTable, dvmrpRouteMetric,
    611  "dvmrpRouteExpiryTime",       o_dvmrpRouteTable, dvmrpRouteExpiryTime,
    612  "dvmrpRouteNextHopType",    o_dvmrpRouteNextHopTable, dvmrpRouteNextHopType,
    613  "dvmrpBoundaryVifIndex",    o_dvmrpBoundaryTable, dvmrpBoundaryVifIndex,
    614  0, 0, 0
    615 };
    616 
    617 /*
    618  * Register variables as part of the MIBs
    619  */
    620 void
    621 init_mib()
    622 {
    623    register OT ot;
    624    int i;
    625 
    626    for (i=0; mib_vars[i].name; i++)
    627       if (ot=text2obj(mib_vars[i].name)) {
    628          ot->ot_getfnx = mib_vars[i].function;
    629          ot->ot_info = (caddr_t)mib_vars[i].info;
    630       }
    631 }
    632 
    633 /*
    634  * Initialize the SNMP part of mrouted
    635  */
    636 void
    637 snmp_init()
    638 {
    639     OT ot;
    640     int i;
    641 
    642     if (readobjects("mrouted.defs") == NOTOK)
    643        log(LOG_ERR, 0, "readobjects: %s", PY_pepy);
    644     for (i=0; i < NUMMIBS; i++) {
    645        if ((ot = text2obj(mibs[i])) == NULL)
    646           log(LOG_ERR, 0, "object \"%s\" not in \"%s\"",
    647 		  mibs[i], "mrouted.defs");
    648        subtree[i] = ot -> ot_name;
    649     }
    650     init_mib();
    651     try_smux_init();
    652 }
    653 
    654 /*
    655  * Process an SNMP "get" or "get-next" request
    656  */
    657 static
    658 get_smux (pdu, offset)
    659    register struct type_SNMP_GetRequest__PDU *pdu;
    660    int     offset;
    661 {
    662     int     idx,
    663             status;
    664     object_instance ois;
    665     register struct type_SNMP_VarBindList *vp;
    666     IFP method;
    667 
    668     quantum = pdu -> request__id;
    669     idx = 0;
    670     for (vp = pdu -> variable__bindings; vp; vp = vp -> next) {
    671         register OI     oi;
    672         register OT     ot;
    673         register struct type_SNMP_VarBind *v = vp -> VarBind;
    674 
    675         idx++;
    676 
    677         if (offset == type_SNMP_SMUX__PDUs_get__next__request) {
    678             if ((oi = name2inst (v -> name)) == NULLOI
    679                     && (oi = next2inst (v -> name)) == NULLOI)
    680                 goto no_name;
    681 
    682             if ((ot = oi -> oi_type) -> ot_getfnx == NULLIFP)
    683                 goto get_next;
    684         }
    685         else
    686             if ((oi = name2inst (v -> name)) == NULLOI
    687                     || (ot = oi -> oi_type) -> ot_getfnx
    688                             == NULLIFP) {
    689 no_name: ;
    690                 pdu -> error__status =
    691                         int_SNMP_error__status_noSuchName;
    692                 goto out;
    693             }
    694 
    695 try_again: ;
    696    switch (offset) {
    697        case type_SNMP_SMUX__PDUs_get__request:
    698       if (!(method = ot -> ot_getfnx))
    699           goto no_name;
    700       break;
    701 
    702        case type_SNMP_SMUX__PDUs_get__next__request:
    703     if (!(method = ot -> ot_getfnx))
    704           goto get_next;
    705       break;
    706 
    707        case type_SNMP_SMUX__PDUs_set__request:
    708       if (!(method = ot -> ot_setfnx))
    709           goto no_name;
    710       break;
    711 
    712        default:
    713       goto no_name;
    714    }
    715 
    716         switch (status = (*ot -> ot_getfnx) (oi, v, offset)) {
    717             case NOTOK:     /* get-next wants a bump */
    718 get_next: ;
    719                 oi = &ois;
    720                 for (;;) {
    721                     if ((ot = ot -> ot_next) == NULLOT) {
    722                         pdu -> error__status =
    723                               int_SNMP_error__status_noSuchName;
    724                         goto out;
    725                     }
    726                     oi -> oi_name =
    727                                 (oi -> oi_type = ot) -> ot_name;
    728                     if (ot -> ot_getfnx)
    729                         goto try_again;
    730                 }
    731 
    732             case int_SNMP_error__status_noError:
    733                 break;
    734 
    735             default:
    736                 pdu -> error__status = status;
    737                 goto out;
    738         }
    739     }
    740     idx = 0;
    741 
    742 out: ;
    743     pdu -> error__index = idx;
    744 
    745     if (smux_response (pdu) == NOTOK) {
    746         log(LOG_WARNING,0,"smux_response: %s [%s]",
    747                smux_error (smux_errno), smux_info);
    748         smux_fd = NOTOK;
    749     }
    750 }
    751 
    752 /*
    753  * Handle SNMP "set" request by replying that it is illegal
    754  */
    755 static
    756 set_smux(event)
    757    struct type_SNMP_SMUX__PDUs *event;
    758 {
    759     switch (event -> offset) {
    760         case type_SNMP_SMUX__PDUs_set__request:
    761             {
    762                 register struct type_SNMP_GetResponse__PDU *pdu =
    763                                     event -> un.get__response;
    764 
    765                 pdu -> error__status = int_SNMP_error__status_noSuchName;
    766                 pdu -> error__index = pdu -> variable__bindings ? 1 : 0;
    767 
    768                 if (smux_response (pdu) == NOTOK) {
    769                     log(LOG_WARNING, 0,
    770                             "smux_response: %s [%s]",
    771                             smux_error (smux_errno),
    772                             smux_info);
    773                     smux_fd = NOTOK;
    774                 }
    775             }
    776             break;
    777 
    778         case type_SNMP_SMUX__PDUs_commitOrRollback:
    779             {
    780                 struct type_SNMP_SOutPDU *cor =
    781                                 event -> un.commitOrRollback;
    782 
    783                 if (cor -> parm == int_SNMP_SOutPDU_commit) {
    784                                     /* "should not happen" */
    785                     (void) smux_close (protocolError);
    786                     smux_fd = NOTOK;
    787                 }
    788             }
    789             break;
    790     }
    791 }
    792 
    793 /*
    794  *  Handle an incoming SNMP message
    795  */
    796 void
    797 doit_smux()
    798 {
    799    struct type_SNMP_SMUX__PDUs *event;
    800 
    801    if (smux_wait(&event, NOTOK)==NOTOK) {
    802       if (smux_errno==inProgress)
    803          return;
    804       log(LOG_WARNING, 0, "smux_wait: %s [%s]", smux_error(smux_errno),
    805        smux_info);
    806       smux_fd = NOTOK;
    807       return;
    808    }
    809 
    810    switch (event -> offset) {
    811     case type_SNMP_SMUX__PDUs_registerResponse:
    812         {
    813             struct type_SNMP_RRspPDU *rsp =
    814                         event -> un.registerResponse;
    815 
    816             if (rsp -> parm == int_SNMP_RRspPDU_failure) {
    817                 log(LOG_WARNING,0,"SMUX registration of subtree failed");
    818                 dont_bother_anymore = 1;
    819                 (void) smux_close (goingDown);
    820                 break;
    821             }
    822         }
    823         if (smux_trap(NULLOID, int_SNMP_generic__trap_coldStart, 0,
    824                        (struct type_SNMP_VarBindList *)0) == NOTOK) {
    825             log(LOG_WARNING,0,"smux_trap: %s [%s]", smux_error (smux_errno),
    826              smux_info);
    827             break;
    828         }
    829         return;
    830 
    831     case type_SNMP_SMUX__PDUs_get__request:
    832     case type_SNMP_SMUX__PDUs_get__next__request:
    833         get_smux (event -> un.get__request, event -> offset);
    834         return;
    835 
    836     case type_SNMP_SMUX__PDUs_close:
    837         log(LOG_WARNING, 0, "SMUX close: %s",
    838          smux_error (event -> un.close -> parm));
    839         break;
    840 
    841     case type_SNMP_SMUX__PDUs_set__request:
    842     case type_SNMP_SMUX__PDUs_commitOrRollback:
    843         set_smux (event);
    844         return;
    845 
    846     default:
    847         log(LOG_WARNING,0,"bad SMUX operation: %d", event -> offset);
    848         (void) smux_close (protocolError);
    849         break;
    850    }
    851    smux_fd = NOTOK;
    852 }
    853 
    854 /*
    855  * Inform snmpd that we are here and handling our MIBs
    856  */
    857 void
    858 start_smux()
    859 {
    860    int i;
    861 
    862    for (i=0; i<NUMMIBS; i++) {
    863       if ((se = getsmuxEntrybyname (mibs[i])) == NULL) {
    864          log(LOG_WARNING,0,"no SMUX entry for \"%s\"", mibs[i]);
    865          return;
    866       }
    867 
    868       /* Only open a new connection the first time through */
    869       if (!i) {
    870          if (smux_simple_open(&se->se_identity, mibs[i],
    871           se->se_password, strlen(se->se_password))==NOTOK) {
    872             if (smux_errno == inProgress)
    873                return;
    874 
    875             log(LOG_WARNING, 0,"smux_simple_open: %s [%s]",
    876              smux_error(smux_errno), smux_info);
    877             smux_fd = NOTOK;
    878             return;
    879          }
    880          log(LOG_NOTICE,0, "SMUX open: %s \"%s\"",
    881           oid2ode (&se->se_identity), se->se_name);
    882          rock_and_roll = 1;
    883       }
    884 
    885       if (smux_register(subtree[i], -1, readWrite)==NOTOK) {
    886          log(LOG_WARNING, 0,"smux_register: %s [%s]", smux_error(smux_errno),
    887           smux_info);
    888          smux_fd = NOTOK;
    889          return;
    890       }
    891    }
    892    log(LOG_NOTICE, 0, "SMUX registered");
    893 }
    894 
    895 /*
    896  * Implements the DVMRP Route Table portion of the DVMRP MIB
    897  */
    898 int
    899 o_dvmrpRouteTable (oi, v, offset)
    900 OI oi;
    901 register struct type_SNMP_VarBind *v;
    902 int	offset;
    903 {
    904     u_long   src, mask;
    905     int	    ifvar;
    906     register OID    oid = oi -> oi_name;
    907     register OT	    ot = oi -> oi_type;
    908     struct rtentry *rt = NULL;
    909 
    910     ifvar = (int) ot -> ot_info;
    911     switch (offset) {
    912 	case type_SNMP_SMUX__PDUs_get__request:
    913       if (!get_address(oid, &src, ot->ot_name->oid_nelem)
    914        || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
    915        || !(rt = snmp_find_route(src,mask)))
    916          return int_SNMP_error__status_noSuchName;
    917       break;
    918 
    919 	case type_SNMP_SMUX__PDUs_get__next__request:
    920 
    921        /* Check if we're requesting the first row */
    922       if (oid->oid_nelem < ot->ot_name->oid_nelem+8) {
    923          OID	new;
    924 
    925          /* Get partial specification (if any) */
    926          get_address(oid, &src, ot->ot_name->oid_nelem);
    927          get_address(oid, &mask, ot->ot_name->oid_nelem+4);
    928 
    929          if (!next_route(&rt,src,mask)) /* Get first entry */
    930             return NOTOK;
    931 
    932          /* Extend by 8 more ints to hold index columns */
    933          new = oid_extend (oid, ot->ot_name->oid_nelem+8-oid->oid_nelem);
    934          if (new == NULLOID)
    935             return NOTOK;
    936 
    937          put_address(new, rt->rt_origin,     ot->ot_name->oid_nelem);
    938          put_address(new, rt->rt_originmask, ot->ot_name->oid_nelem+4);
    939 
    940          if (v -> name)
    941             free_SNMP_ObjectName (v -> name);
    942          v -> name = new;
    943 
    944       /* Else we start from a previous row */
    945       } else {
    946          int	i = ot -> ot_name -> oid_nelem;
    947 
    948          /* Get the lowest entry in the table > the given grp/src/mask */
    949          get_address(oid, &src, ot->ot_name->oid_nelem);
    950          get_address(oid, &mask, ot->ot_name->oid_nelem+4);
    951          if (!next_route(&rt, src,mask))
    952             return NOTOK;
    953 
    954          put_address(oid, rt->rt_origin, ot->ot_name->oid_nelem);
    955          put_address(oid, rt->rt_originmask, ot->ot_name->oid_nelem+4);
    956       }
    957       break;
    958 
    959 	default:
    960 	   return int_SNMP_error__status_genErr;
    961    }
    962 
    963    switch (ifvar) {
    964       case dvmrpRouteUpstreamNeighbor: {
    965          struct sockaddr_in tmp;
    966          tmp.sin_addr.s_addr = rt->rt_gateway;
    967          return o_ipaddr (oi, v, &tmp);
    968       }
    969 
    970       case dvmrpRouteInVifIndex:
    971          return o_integer (oi, v, rt->rt_parent);
    972 
    973       case dvmrpRouteMetric:
    974          return o_integer (oi, v, rt->rt_metric);
    975 
    976       case dvmrpRouteExpiryTime:
    977          return o_integer (oi, v, rt->rt_timer*100);
    978 
    979       default:
    980          return int_SNMP_error__status_noSuchName;
    981    }
    982 }
    983 
    984 /*
    985  * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB
    986  */
    987 int
    988 o_dvmrpRouteNextHopTable (oi, v, offset)
    989 OI oi;
    990 register struct type_SNMP_VarBind *v;
    991 int   offset;
    992 {
    993     u_long   src, mask;
    994     vifi_t   vifi;
    995     int	    ifvar;
    996     register OID    oid = oi -> oi_name;
    997     register OT	    ot = oi -> oi_type;
    998     struct rtentry *rt = NULL;
    999 
   1000     ifvar = (int) ot -> ot_info;
   1001     switch (offset) {
   1002 	case type_SNMP_SMUX__PDUs_get__request:
   1003       if (oid->oid_nelem != ot->ot_name->oid_nelem+9)
   1004          return int_SNMP_error__status_noSuchName;
   1005 
   1006       if (!get_address(oid, &src, ot->ot_name->oid_nelem)
   1007        || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
   1008        || (!(rt=snmp_find_route(src,mask))))
   1009          return int_SNMP_error__status_noSuchName;
   1010 
   1011       vifi = oid->oid_elements[ot->ot_name->oid_nelem+8];
   1012       if (!(VIFM_ISSET(vifi, rt->rt_children)))
   1013          return int_SNMP_error__status_noSuchName;
   1014       break;
   1015 
   1016 	case type_SNMP_SMUX__PDUs_get__next__request:
   1017 
   1018       /* Check if we're requesting the first row */
   1019       if (oid->oid_nelem < ot->ot_name->oid_nelem+9) {
   1020          OID	new;
   1021 
   1022          get_address(oid, &src, ot->ot_name->oid_nelem);
   1023          get_address(oid, &mask, ot->ot_name->oid_nelem+4);
   1024 
   1025          /* Find first child vif */
   1026          vifi=0;
   1027          if (!next_route_child(&rt, src, mask, &vifi))
   1028             return NOTOK;
   1029 
   1030          /* Extend by 9 more ints to hold index columns */
   1031          new = oid_extend (oid, ot->ot_name->oid_nelem+9-oid->oid_nelem);
   1032          if (new == NULLOID)
   1033             return NOTOK;
   1034 
   1035          put_address(new, rt->rt_origin, ot->ot_name->oid_nelem);
   1036          put_address(new, rt->rt_originmask, ot->ot_name->oid_nelem+4);
   1037          new->oid_elements[ot->ot_name->oid_nelem+8] = vifi;
   1038 
   1039          if (v -> name)
   1040             free_SNMP_ObjectName (v -> name);
   1041          v -> name = new;
   1042 
   1043       /* Else we start from a previous row */
   1044       } else {
   1045          int	i = ot -> ot_name -> oid_nelem;
   1046 
   1047          /* Get the lowest entry in the table > the given grp/src/mask */
   1048          vifi = oid->oid_elements[oid->oid_nelem-1] + 1;
   1049          if (!get_address(oid, &src, ot->ot_name->oid_nelem)
   1050           || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
   1051           || !next_route_child(&rt, src, mask, &vifi))
   1052             return NOTOK;
   1053 
   1054          put_address(oid, rt->rt_origin, ot->ot_name->oid_nelem);
   1055          put_address(oid, rt->rt_originmask, ot->ot_name->oid_nelem+4);
   1056          oid->oid_elements[ot->ot_name->oid_nelem+8] = vifi;
   1057       }
   1058       break;
   1059 
   1060 	default:
   1061 	   return int_SNMP_error__status_genErr;
   1062    }
   1063 
   1064    switch (ifvar) {
   1065 
   1066       case dvmrpRouteNextHopType:
   1067          return o_integer (oi, v, (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2);
   1068 
   1069       default:
   1070          return int_SNMP_error__status_noSuchName;
   1071    }
   1072 }
   1073 
   1074 /*
   1075  * Implements the IP Multicast Route Table portion of the Multicast MIB
   1076  */
   1077 int
   1078 o_ipMRouteTable (oi, v, offset)
   1079 OI	oi;
   1080 register struct type_SNMP_VarBind *v;
   1081 int	offset;
   1082 {
   1083     u_long src, grp, mask;
   1084     int	    ifvar;
   1085     register OID    oid = oi -> oi_name;
   1086     register OT	    ot = oi -> oi_type;
   1087     struct gtable *gt = NULL;
   1088     struct stable *st = NULL;
   1089 static struct sioc_sg_req sg_req;
   1090 
   1091     ifvar = (int) ot -> ot_info;
   1092     switch (offset) {
   1093 	case type_SNMP_SMUX__PDUs_get__request:
   1094       if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
   1095        || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
   1096        || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
   1097        || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */
   1098        || !(gt = find_grp(grp))
   1099        || !(st = find_grp_src(gt,src)))
   1100          return int_SNMP_error__status_noSuchName;
   1101       break;
   1102 
   1103 	case type_SNMP_SMUX__PDUs_get__next__request:
   1104 
   1105        /* Check if we're requesting the first row */
   1106       if (oid->oid_nelem < ot->ot_name->oid_nelem+12) {
   1107          OID	new;
   1108 
   1109          /* Get partial specification (if any) */
   1110          get_address(oid, &grp, ot->ot_name->oid_nelem);
   1111          get_address(oid, &src, ot->ot_name->oid_nelem+4);
   1112          get_address(oid, &mask, ot->ot_name->oid_nelem+8);
   1113 
   1114          if (!next_grp_src_mask(&gt,&st,grp,src,mask)) /* Get first entry */
   1115             return NOTOK;
   1116 
   1117          /* Extend by 12 more ints to hold index columns */
   1118          new = oid_extend (oid, ot->ot_name->oid_nelem+12-oid->oid_nelem);
   1119          if (new == NULLOID)
   1120             return NOTOK;
   1121 
   1122          put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
   1123          put_address(new, st->st_origin, ot->ot_name->oid_nelem+4);
   1124          put_address(new, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
   1125 
   1126          if (v -> name)
   1127             free_SNMP_ObjectName (v -> name);
   1128          v -> name = new;
   1129 
   1130       /* Else we start from a previous row */
   1131       } else {
   1132          int	i = ot -> ot_name -> oid_nelem;
   1133 
   1134          /* Get the lowest entry in the table > the given grp/src/mask */
   1135          get_address(oid, &grp, ot->ot_name->oid_nelem);
   1136          get_address(oid, &src, ot->ot_name->oid_nelem+4);
   1137          get_address(oid, &mask, ot->ot_name->oid_nelem+8);
   1138          if (!next_grp_src_mask(&gt, &st, grp,src,mask))
   1139             return NOTOK;
   1140 
   1141          put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
   1142          put_address(oid, st->st_origin, ot->ot_name->oid_nelem+4);
   1143          put_address(oid, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
   1144       }
   1145       break;
   1146 
   1147 	default:
   1148 	   return int_SNMP_error__status_genErr;
   1149    }
   1150 
   1151    switch (ifvar) {
   1152       case ipMRouteUpstreamNeighbor: {
   1153          struct sockaddr_in tmp;
   1154          tmp.sin_addr.s_addr = gt->gt_route->rt_gateway;
   1155          return o_ipaddr (oi, v, &tmp);
   1156       }
   1157 
   1158       case ipMRouteInIfIndex:
   1159          return o_integer (oi, v, gt->gt_route->rt_parent);
   1160 
   1161       case ipMRouteUpTime: {
   1162          time_t currtime;
   1163          time(&currtime);
   1164          return o_integer (oi, v, (currtime - gt->gt_ctime)*100);
   1165       }
   1166 
   1167       case ipMRouteExpiryTime:
   1168          return o_integer (oi, v, gt->gt_timer*100);
   1169 
   1170       case ipMRoutePkts:
   1171          refresh_sg(&sg_req, gt, st);
   1172          return o_integer (oi, v, sg_req.pktcnt);
   1173 
   1174       case ipMRouteOctets:
   1175          refresh_sg(&sg_req, gt, st);
   1176          return o_integer (oi, v, sg_req.bytecnt);
   1177 
   1178       case ipMRouteDifferentInIfIndexes:
   1179          refresh_sg(&sg_req, gt, st);
   1180          return o_integer (oi, v, sg_req.wrong_if);
   1181 
   1182       case ipMRouteProtocol:
   1183          return o_integer (oi, v, 4);
   1184 
   1185       default:
   1186          return int_SNMP_error__status_noSuchName;
   1187    }
   1188 }
   1189 
   1190 /*
   1191  * Implements the IP Multicast Routing Next Hop Table portion of the Multicast
   1192  * MIB
   1193  */
   1194 int
   1195 o_ipMRouteNextHopTable (oi, v, offset)
   1196 OI	oi;
   1197 register struct type_SNMP_VarBind *v;
   1198 int	offset;
   1199 {
   1200     u_long src, grp, mask, addr;
   1201     vifi_t   vifi;
   1202     int	    ifvar;
   1203     register OID    oid = oi -> oi_name;
   1204     register OT	    ot = oi -> oi_type;
   1205     struct gtable *gt;
   1206     struct stable *st;
   1207 
   1208     ifvar = (int) ot -> ot_info;
   1209     switch (offset) {
   1210 	case type_SNMP_SMUX__PDUs_get__request:
   1211       if (oid->oid_nelem != ot->ot_name->oid_nelem+17)
   1212          return int_SNMP_error__status_noSuchName;
   1213 
   1214       if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
   1215        || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
   1216        || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
   1217        || !get_address(oid, &addr, ot->ot_name->oid_nelem+13)
   1218        || grp!=addr
   1219        || mask!=0xFFFFFFFF
   1220        || (!(gt=find_grp(grp)))
   1221        || (!(st=find_grp_src(gt,src))))
   1222          return int_SNMP_error__status_noSuchName;
   1223 
   1224       vifi = oid->oid_elements[ot->ot_name->oid_nelem+12];
   1225       if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children)))
   1226          return int_SNMP_error__status_noSuchName;
   1227       break;
   1228 
   1229 	case type_SNMP_SMUX__PDUs_get__next__request:
   1230 
   1231       /* Check if we're requesting the first row */
   1232       if (oid->oid_nelem < ot->ot_name->oid_nelem+17) {
   1233          OID	new;
   1234 
   1235          get_address(oid, &grp, ot->ot_name->oid_nelem);
   1236          get_address(oid, &src, ot->ot_name->oid_nelem+4);
   1237          get_address(oid, &mask, ot->ot_name->oid_nelem+8);
   1238 
   1239          /* Find first child vif */
   1240          vifi=0;
   1241          if (!next_child(&gt, &st, grp, src, mask, &vifi))
   1242             return NOTOK;
   1243 
   1244          /* Extend by 17 more ints to hold index columns */
   1245          new = oid_extend (oid, ot->ot_name->oid_nelem+17-oid->oid_nelem);
   1246          if (new == NULLOID)
   1247             return NOTOK;
   1248 
   1249          put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
   1250          put_address(new, st->st_origin, ot->ot_name->oid_nelem+4);
   1251          put_address(new, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
   1252          new->oid_elements[ot->ot_name->oid_nelem+12] = vifi;
   1253          put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem+13);
   1254 
   1255          if (v -> name)
   1256             free_SNMP_ObjectName (v -> name);
   1257          v -> name = new;
   1258 
   1259       /* Else we start from a previous row */
   1260       } else {
   1261          int	i = ot -> ot_name -> oid_nelem;
   1262 
   1263          /* Get the lowest entry in the table > the given grp/src/mask */
   1264          vifi = oid->oid_elements[oid->oid_nelem-1] + 1;
   1265          if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
   1266           || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
   1267           || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
   1268           || !next_child(&gt, &st, grp, src, mask, &vifi))
   1269             return NOTOK;
   1270 
   1271          put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
   1272          put_address(oid, st->st_origin, ot->ot_name->oid_nelem+4);
   1273          put_address(oid, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
   1274          oid->oid_elements[ot->ot_name->oid_nelem+12] = vifi;
   1275          put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem+13);
   1276       }
   1277       break;
   1278 
   1279 	default:
   1280 	   return int_SNMP_error__status_genErr;
   1281    }
   1282 
   1283    switch (ifvar) {
   1284 
   1285       case ipMRouteNextHopState:
   1286          return o_integer (oi, v, (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1);
   1287 
   1288       /* Currently equal to ipMRouteUpTime */
   1289       case ipMRouteNextHopUpTime: {
   1290          time_t currtime;
   1291          time(&currtime);
   1292          return o_integer (oi, v, (currtime - gt->gt_ctime)*100);
   1293       }
   1294 
   1295       case ipMRouteNextHopExpiryTime:
   1296          return o_integer (oi, v, gt->gt_prsent_timer);
   1297 
   1298       case ipMRouteNextHopClosestMemberHops:
   1299          return o_integer (oi, v, 0);
   1300 
   1301       case ipMRouteNextHopProtocol:
   1302          return o_integer (oi, v, 4);
   1303 
   1304       default:
   1305          return int_SNMP_error__status_noSuchName;
   1306    }
   1307 }
   1308