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