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