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