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