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