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