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