1 /* $NetBSD: snmp.c,v 1.7 2002/08/01 03:40:34 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 in_port_t 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 in_port_t 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 struct variable *vp; /* IN - pointer to variable entry that points here */ 162 oid *name; /* IN/OUT - input name requested, output name found */ 163 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 struct variable *vp; /* IN - pointer to variable entry that points here */ 257 oid *name; /* IN/OUT - input name requested, output name found */ 258 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 struct variable *vp; /* IN - pointer to variable entry that points here */ 387 oid *name; /* IN/OUT - input name requested, output name found */ 388 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 struct variable *vp; /* IN - pointer to variable entry that points here */ 561 oid *name; /* IN/OUT - input name requested, output name found */ 562 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 struct variable *vp; /* IN - pointer to variable entry that points here */ 681 oid *name; /* IN/OUT - input name requested, output name found */ 682 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 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 struct variable *vp; /* IN - pointer to variable entry that points here */ 753 oid *name; /* IN/OUT - input name requested, output name found */ 754 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 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 struct variable *vp; /* IN - pointer to variable entry that points here */ 861 oid *name; /* IN/OUT - input name requested, output name found */ 862 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 struct variable *vp; /* IN - pointer to variable entry that points here */ 954 oid *name; /* IN/OUT - input name requested, output name found */ 955 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 struct variable *vp; /* IN - pointer to variable entry that points here */ 1038 oid *name; /* IN/OUT - input name requested, output name found */ 1039 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 struct variable *vp; /* IN - pointer to variable entry that points here */ 1157 oid *name; /* IN/OUT - input name requested, output name found */ 1158 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