snmp.c revision 1.10 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(>,&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(>, &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_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(>, &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(>, &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