30 */ 31 32#include <sys/queue.h> 33#include <sys/socket.h> 34#include <sys/time.h> 35#include <sys/types.h> 36 37#include <net/ethernet.h> 38#include <net/if.h> 39#include <net/if_mib.h> 40#include <net/if_types.h> 41 42#include <errno.h> 43#include <stdarg.h> 44#include <stdlib.h> 45#include <string.h> 46#include <syslog.h> 47 48#include <bsnmp/snmpmod.h> 49#include <bsnmp/snmp_mibII.h> 50 51#include "bridge_tree.h" 52#include "bridge_snmp.h" 53#include "bridge_oid.h" 54 55static const struct asn_oid oid_newRoot = OIDX_newRoot; 56static const struct asn_oid oid_TopologyChange = OIDX_topologyChange; 57static const struct asn_oid oid_begemotBrigeName = \ 58 OIDX_begemotBridgeBaseName; 59static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot; 60static const struct asn_oid oid_begemotTopologyChange = \ 61 OIDX_begemotBridgeTopologyChange; 62 63TAILQ_HEAD(bridge_ifs, bridge_if); 64 65/* 66 * Free the bridge interface list. 67 */ 68static void 69bridge_ifs_free(struct bridge_ifs *headp) 70{ 71 struct bridge_if *b; 72 73 while ((b = TAILQ_FIRST(headp)) != NULL) { 74 TAILQ_REMOVE(headp, b, b_if); 75 free(b); 76 } 77} 78 79/* 80 * Insert an entry in the bridge interface TAILQ. Keep the 81 * TAILQ sorted by the bridge's interface name. 82 */ 83static void 84bridge_ifs_insert(struct bridge_ifs *headp, 85 struct bridge_if *b) 86{ 87 struct bridge_if *temp; 88 89 if ((temp = TAILQ_FIRST(headp)) == NULL || 90 strcmp(b->bif_name, temp->bif_name) < 0) { 91 TAILQ_INSERT_HEAD(headp, b, b_if); 92 return; 93 } 94 95 TAILQ_FOREACH(temp, headp, b_if) 96 if(strcmp(b->bif_name, temp->bif_name) < 0) 97 TAILQ_INSERT_BEFORE(temp, b, b_if); 98 99 TAILQ_INSERT_TAIL(headp, b, b_if); 100} 101 102/* The global bridge interface list. */ 103static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs); 104static time_t bridge_list_age; 105 106/* 107 * Free the global list. 108 */ 109void 110bridge_ifs_fini(void) 111{ 112 bridge_ifs_free(&bridge_ifs); 113} 114 115/* 116 * Find a bridge interface entry by the bridge interface system index. 117 */ 118struct bridge_if * 119bridge_if_find_ifs(uint32_t sysindex) 120{ 121 struct bridge_if *b; 122 123 TAILQ_FOREACH(b, &bridge_ifs, b_if) 124 if (b->sysindex == sysindex) 125 return (b); 126 127 return (NULL); 128} 129 130/* 131 * Find a bridge interface entry by the bridge interface name. 132 */ 133struct bridge_if * 134bridge_if_find_ifname(const char *b_name) 135{ 136 struct bridge_if *b; 137 138 TAILQ_FOREACH(b, &bridge_ifs, b_if) 139 if (strcmp(b_name, b->bif_name) == 0) 140 return (b); 141 142 return (NULL); 143} 144 145/* 146 * Find a bridge name by the bridge interface system index. 147 */ 148const char * 149bridge_if_find_name(uint32_t sysindex) 150{ 151 struct bridge_if *b; 152 153 TAILQ_FOREACH(b, &bridge_ifs, b_if) 154 if (b->sysindex == sysindex) 155 return (b->bif_name); 156 157 return (NULL); 158} 159 160/* 161 * Given two bridge interfaces' system indexes, find their 162 * corresponding names and return the result of the name 163 * comparison. Returns: 164 * error : -2 165 * i1 < i2 : -1 166 * i1 > i2 : +1 167 * i1 = i2 : 0 168 */ 169int 170bridge_compare_sysidx(uint32_t i1, uint32_t i2) 171{ 172 int c; 173 const char *b1, *b2; 174 175 if (i1 == i2) 176 return (0); 177 178 if ((b1 = bridge_if_find_name(i1)) == NULL) { 179 syslog(LOG_ERR, "Bridge interface %d does not exist", i1); 180 return (-2); 181 } 182 183 if ((b2 = bridge_if_find_name(i2)) == NULL) { 184 syslog(LOG_ERR, "Bridge interface %d does not exist", i2); 185 return (-2); 186 } 187 188 if ((c = strcmp(b1, b2)) < 0) 189 return (-1); 190 else if (c > 0) 191 return (1); 192 193 return (0); 194} 195 196/* 197 * Fetch the first bridge interface from the list. 198 */ 199struct bridge_if * 200bridge_first_bif(void) 201{ 202 return (TAILQ_FIRST(&bridge_ifs)); 203} 204 205/* 206 * Fetch the next bridge interface from the list. 207 */ 208struct bridge_if * 209bridge_next_bif(struct bridge_if *b_pr) 210{ 211 return (TAILQ_NEXT(b_pr, b_if)); 212} 213 214/* 215 * Create a new entry for a bridge interface and insert 216 * it in the list. 217 */ 218static struct bridge_if * 219bridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr) 220{ 221 struct bridge_if *bif; 222 223 if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) { 224 syslog(LOG_ERR, "bridge new interface failed: %s", 225 strerror(errno)); 226 return (NULL); 227 } 228 229 bzero(bif, sizeof(struct bridge_if)); 230 strlcpy(bif->bif_name, bif_n, IFNAMSIZ); 231 bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN); 232 bif->sysindex = sysindex; 233 bif->br_type = BaseType_transparent_only; 234 /* 1 - all bridges default hold time * 100 - centi-seconds */ 235 bif->hold_time = 1 * 100; 236 bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d; 237 bridge_ifs_insert(&bridge_ifs, bif); 238 239 return (bif); 240} 241 242/* 243 * Remove a bridge interface from the list, freeing all it's ports 244 * and address entries. 245 */ 246void 247bridge_remove_bif(struct bridge_if *bif) 248{ 249 bridge_members_free(bif); 250 bridge_addrs_free(bif); 251 TAILQ_REMOVE(&bridge_ifs, bif, b_if); 252 free(bif); 253} 254 255 256/* 257 * Prepare the variable (bridge interface name) for the private 258 * begemot notifications. 259 */ 260static struct snmp_value* 261bridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val) 262{ 263 uint i; 264 265 b_val->var = oid_begemotBrigeName; 266 b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name); 267 268 if ((b_val->v.octetstring.octets = (u_char *) 269 malloc(strlen(bif->bif_name))) == NULL) 270 return (NULL); 271 272 for (i = 0; i < strlen(bif->bif_name); i++) 273 b_val->var.subs[b_val->var.len++] = bif->bif_name[i]; 274 275 b_val->v.octetstring.len = strlen(bif->bif_name); 276 bcopy(bif->bif_name, b_val->v.octetstring.octets, 277 strlen(bif->bif_name)); 278 b_val->syntax = SNMP_SYNTAX_OCTETSTRING; 279 280 return (b_val); 281} 282 283/* 284 * Compare the values of the old and the new root port and 285 * send a new root notification, if they are not matching. 286 */ 287static void 288bridge_new_root(struct bridge_if *bif) 289{ 290 struct snmp_value bif_idx; 291 292 if (bridge_get_default() == bif) 293 snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL); 294 295 if (bridge_basename_var(bif, &bif_idx) == NULL) 296 return; 297 298 snmp_send_trap(&oid_begemotTopologyChange, 299 &bif_idx, (struct snmp_value *) NULL); 300} 301 302/* 303 * Compare the new and old topology change times and send a 304 * topology change notification if necessary. 305 */ 306static void 307bridge_top_change(struct bridge_if *bif) 308{ 309 struct snmp_value bif_idx; 310 311 if (bridge_get_default() == bif) 312 snmp_send_trap(&oid_TopologyChange, 313 (struct snmp_value *) NULL); 314 315 if (bridge_basename_var(bif, &bif_idx) == NULL) 316 return; 317 318 snmp_send_trap(&oid_begemotNewRoot, 319 &bif_idx, (struct snmp_value *) NULL); 320} 321 322static int 323bridge_if_create(const char* b_name, int8_t up) 324{ 325 if (bridge_create(b_name) < 0) 326 return (-1); 327 328 if (up == 1 && (bridge_set_if_up(b_name, 1) < 0)) 329 return (-1); 330 331 /* 332 * Do not create a new bridge entry here - 333 * wait until the mibII module notifies us. 334 */ 335 return (0); 336} 337 338static int 339bridge_if_destroy(struct bridge_if *bif) 340{ 341 if (bridge_destroy(bif->bif_name) < 0) 342 return (-1); 343 344 bridge_remove_bif(bif); 345 346 return (0); 347} 348 349/* 350 * Calculate the timeticks since the last topology change. 351 */ 352static int 353bridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks) 354{ 355 struct timeval ct; 356 357 if (gettimeofday(&ct, NULL) < 0) { 358 syslog(LOG_ERR, "bridge get time since last TC:" 359 "getttimeofday failed: %s", strerror(errno)); 360 return (-1); 361 } 362 363 if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) { 364 ct.tv_sec -= 1; 365 ct.tv_usec += 1000000; 366 } 367 368 ct.tv_sec -= bif->last_tc_time.tv_sec; 369 ct.tv_usec -= bif->last_tc_time.tv_usec; 370 371 *ticks = ct.tv_sec * 100 + ct.tv_usec/10000; 372 373 return (0); 374} 375 376/* 377 * Update the info we have for a single bridge interface. 378 * Return: 379 * 1, if successful 380 * 0, if the interface was deleted 381 * -1, error occured while fetching the info from the kernel. 382 */ 383static int 384bridge_update_bif(struct bridge_if *bif) 385{ 386 struct mibif *ifp; 387 388 /* Walk through the mibII interface list. */ 389 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) 390 if (strcmp(ifp->name, bif->bif_name) == 0) 391 break; 392 393 if (ifp == NULL) { 394 /* Ops, we do not exist anymore. */ 395 bridge_remove_bif(bif); 396 return (0); 397 } 398 399 if (ifp->physaddr != NULL ) 400 bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN); 401 else 402 bridge_get_basemac(bif->bif_name, bif->br_addr.octet); 403 404 if (ifp->mib.ifmd_flags & IFF_RUNNING) 405 bif->if_status = RowStatus_active; 406 else 407 bif->if_status = RowStatus_notInService; 408 409 switch (bridge_getinfo_bif(bif)) { 410 case 2: 411 bridge_new_root(bif); 412 break; 413 case 1: 414 bridge_top_change(bif); 415 break; 416 case -1: 417 bridge_remove_bif(bif); 418 return (-1); 419 default: 420 break; 421 } 422 423 /* 424 * The number of ports is accessible via SNMP - 425 * update the ports each time the bridge interface data 426 * is refreshed too. 427 */ 428 bif->num_ports = bridge_update_memif(bif); 429 bif->entry_age = time(NULL); 430 431 return (1); 432} 433 434/* 435 * Update all bridge interfaces' ports only - 436 * make sure each bridge interface exists first. 437 */ 438void 439bridge_update_all_ports(void) 440{ 441 struct mibif *ifp; 442 struct bridge_if *bif, *t_bif; 443 444 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 445 t_bif = bridge_next_bif(bif); 446 447 for (ifp = mib_first_if(); ifp != NULL; 448 ifp = mib_next_if(ifp)) 449 if (strcmp(ifp->name, bif->bif_name) == 0) 450 break; 451 452 if (ifp != NULL) 453 bif->num_ports = bridge_update_memif(bif); 454 else /* Ops, we do not exist anymore. */ 455 bridge_remove_bif(bif); 456 } 457 458 bridge_ports_update_listage(); 459} 460 461/* 462 * Update all addresses only. 463 */ 464void 465bridge_update_all_addrs(void) 466{ 467 struct mibif *ifp; 468 struct bridge_if *bif, *t_bif; 469 470 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 471 t_bif = bridge_next_bif(bif); 472 473 for (ifp = mib_first_if(); ifp != NULL; 474 ifp = mib_next_if(ifp)) 475 if (strcmp(ifp->name, bif->bif_name) == 0) 476 break; 477 478 if (ifp != NULL) 479 bif->num_addrs = bridge_update_addrs(bif); 480 else /* Ops, we don't exist anymore. */ 481 bridge_remove_bif(bif); 482 } 483 484 bridge_addrs_update_listage(); 485} 486 487/* 488 * Update only the bridge interfaces' data - skip addresses. 489 */ 490void 491bridge_update_all_ifs(void) 492{ 493 struct bridge_if *bif, *t_bif; 494 495 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 496 t_bif = bridge_next_bif(bif); 497 bridge_update_bif(bif); 498 } 499 500 bridge_ports_update_listage(); 501 bridge_list_age = time(NULL); 502} 503 504/* 505 * Update all info we have for all bridges. 506 */ 507void 508bridge_update_all(void *arg __unused) 509{ 510 struct bridge_if *bif, *t_bif; 511 512 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 513 t_bif = bridge_next_bif(bif); 514 if (bridge_update_bif(bif) <= 0) 515 continue; 516 517 /* Update our learnt addresses. */ 518 bif->num_addrs = bridge_update_addrs(bif); 519 } 520 521 bridge_list_age = time(NULL); 522 bridge_ports_update_listage(); 523 bridge_addrs_update_listage(); 524} 525 526/* 527 * Callback for polling our last topology change time - 528 * check whether we are root or whether a TC was detected once every 529 * 30 seconds, so that we can send the newRoot and TopologyChange traps 530 * on time. The rest of the data is polled only once every 5 min. 531 */ 532void 533bridge_update_tc_time(void *arg __unused) 534{ 535 struct bridge_if *bif; 536 struct mibif *ifp; 537 538 TAILQ_FOREACH(bif, &bridge_ifs, b_if) { 539 /* Walk through the mibII interface list. */ 540 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) 541 if (strcmp(ifp->name, bif->bif_name) == 0) 542 break; 543 544 if (ifp == NULL) { 545 bridge_remove_bif(bif); 546 continue; 547 } 548 549 switch (bridge_get_op_param(bif)) { 550 case 2: 551 bridge_new_root(bif); 552 break; 553 case 1: 554 bridge_top_change(bif); 555 break; 556 } 557 } 558} 559 560/* 561 * Callback for handling new bridge interface creation. 562 */ 563int 564bridge_attach_newif(struct mibif *ifp) 565{ 566 u_char *p_mac, mac[ETHER_ADDR_LEN]; 567 struct bridge_if *bif; 568 569 if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE) 570 return (0); 571 572 /* Make sure it does not exist in our list. */ 573 TAILQ_FOREACH(bif, &bridge_ifs, b_if) 574 if(strcmp(bif->bif_name, ifp->name) == 0) { 575 syslog(LOG_ERR, "bridge interface %s already " 576 "in list", bif->bif_name); 577 return (-1); 578 } 579 580 if ((p_mac = ifp->physaddr) == NULL && 581 (p_mac = bridge_get_basemac(ifp->name, mac)) == NULL) { 582 syslog(LOG_ERR, "bridge attach new %s failed - " 583 "no bridge mac address", ifp->name); 584 return (-1); 585 } 586 587 if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, p_mac)) == NULL) 588 return (-1); 589 590 if (ifp->mib.ifmd_flags & IFF_RUNNING) 591 bif->if_status = RowStatus_active; 592 else 593 bif->if_status = RowStatus_notInService; 594 595 /* Skip sending notifications if the interface was just created. */ 596 if (bridge_getinfo_bif(bif) < 0 || 597 (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 || 598 (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) { 599 bridge_remove_bif(bif); 600 return (-1); 601 } 602 603 /* Check whether we are the default bridge interface. */ 604 if (strcmp(ifp->name, bridge_get_default_name()) == 0) 605 bridge_set_default(bif); 606 607 return (0); 608} 609 610void 611bridge_ifs_dump(void) 612{ 613 struct bridge_if *bif; 614 615 for (bif = bridge_first_bif(); bif != NULL; 616 bif = bridge_next_bif(bif)) { 617 syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name, 618 bif->sysindex); 619 bridge_ports_dump(bif); 620 bridge_addrs_dump(bif); 621 } 622} 623 624/* 625 * RFC4188 specifics. 626 */ 627int 628op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value, 629 uint sub, uint iidx __unused, enum snmp_op op) 630{ 631 int ret; 632 struct bridge_if *bif; 633 634 if ((bif = bridge_get_default()) == NULL) 635 return (SNMP_ERR_NOSUCHNAME); 636 637 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 638 bridge_update_bif(bif) <= 0) /* It was just deleted. */ 639 return (SNMP_ERR_NOSUCHNAME); 640 641 ret = SNMP_ERR_NOERROR; 642 643 switch (op) { 644 case SNMP_OP_GET: 645 switch (value->var.subs[sub - 1]) { 646 case LEAF_dot1dBaseBridgeAddress: 647 ret = string_get(value, bif->br_addr.octet, 648 ETHER_ADDR_LEN); 649 break; 650 case LEAF_dot1dBaseNumPorts: 651 value->v.integer = bif->num_ports; 652 break; 653 case LEAF_dot1dBaseType: 654 value->v.integer = bif->br_type; 655 break; 656 abort(); 657 } 658 break; 659 660 case SNMP_OP_SET: 661 ret = SNMP_ERR_NOT_WRITEABLE; 662 break; 663 664 case SNMP_OP_GETNEXT: 665 case SNMP_OP_ROLLBACK: 666 case SNMP_OP_COMMIT: 667 abort(); 668 } 669 670 return (ret); 671} 672 673int 674op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *value, 675 uint sub, uint iidx __unused, enum snmp_op op) 676{ 677 int ret; 678 struct bridge_if *bif; 679 680 if ((bif = bridge_get_default()) == NULL) 681 return (SNMP_ERR_NOSUCHNAME); 682 683 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 684 bridge_update_bif(bif) <= 0) /* It was just deleted. */ 685 return (SNMP_ERR_NOSUCHNAME); 686 687 switch (op) { 688 case SNMP_OP_GET: 689 switch (value->var.subs[sub - 1]) { 690 case LEAF_dot1dStpProtocolSpecification: 691 value->v.integer = bif->prot_spec; 692 break; 693 694 case LEAF_dot1dStpPriority: 695 value->v.integer = bif->priority; 696 break; 697 698 case LEAF_dot1dStpTimeSinceTopologyChange: 699 if (bridge_get_time_since_tc(bif, 700 &(value->v.uint32)) < 0) 701 return (SNMP_ERR_GENERR); 702 break; 703 704 case LEAF_dot1dStpTopChanges: 705 value->v.uint32 = bif->top_changes; 706 break; 707 708 case LEAF_dot1dStpDesignatedRoot: 709 return (string_get(value, bif->design_root, 710 SNMP_BRIDGE_ID_LEN)); 711 712 case LEAF_dot1dStpRootCost: 713 value->v.integer = bif->root_cost; 714 break; 715 716 case LEAF_dot1dStpRootPort: 717 value->v.integer = bif->root_port; 718 break; 719 720 case LEAF_dot1dStpMaxAge: 721 value->v.integer = bif->max_age; 722 break; 723 724 case LEAF_dot1dStpHelloTime: 725 value->v.integer = bif->hello_time; 726 break; 727 728 case LEAF_dot1dStpHoldTime: 729 value->v.integer = bif->hold_time; 730 break; 731 732 case LEAF_dot1dStpForwardDelay: 733 value->v.integer = bif->fwd_delay; 734 break; 735 736 case LEAF_dot1dStpBridgeMaxAge: 737 value->v.integer = bif->bridge_max_age; 738 break; 739 740 case LEAF_dot1dStpBridgeHelloTime: 741 value->v.integer = bif->bridge_hello_time; 742 break; 743 744 case LEAF_dot1dStpBridgeForwardDelay: 745 value->v.integer = bif->bridge_fwd_delay; 746 break; 747 case LEAF_dot1dStpVersion: 748 value->v.integer = bif->stp_version; 749 break; 750 case LEAF_dot1dStpTxHoldCount: 751 value->v.integer = bif->tx_hold_count; 752 } 753 754 return (SNMP_ERR_NOERROR); 755 756 case SNMP_OP_GETNEXT: 757 abort(); 758 759 case SNMP_OP_SET: 760 switch (value->var.subs[sub - 1]) { 761 case LEAF_dot1dStpPriority: 762 ctx->scratch->int1 = bif->priority; 763 ret = bridge_set_priority(bif, value->v.integer); 764 break; 765 766 case LEAF_dot1dStpBridgeMaxAge: 767 ctx->scratch->int1 = bif->bridge_max_age; 768 ret = bridge_set_maxage(bif, value->v.integer); 769 break; 770 771 case LEAF_dot1dStpBridgeHelloTime: 772 ctx->scratch->int1 = bif->bridge_hello_time; 773 ret = bridge_set_hello_time(bif, value->v.integer); 774 break; 775 776 case LEAF_dot1dStpBridgeForwardDelay: 777 ctx->scratch->int1 = bif->bridge_fwd_delay; 778 ret = bridge_set_forward_delay(bif, value->v.integer); 779 break; 780 781 case LEAF_dot1dStpVersion: 782 ctx->scratch->int1 = bif->stp_version; 783 ret = bridge_set_stp_version(bif, value->v.integer); 784 break; 785 786 case LEAF_dot1dStpTxHoldCount: 787 ctx->scratch->int1 = bif->tx_hold_count; 788 ret = bridge_set_tx_hold_count(bif, value->v.integer); 789 break; 790 791 case LEAF_dot1dStpProtocolSpecification: 792 case LEAF_dot1dStpTimeSinceTopologyChange: 793 case LEAF_dot1dStpTopChanges: 794 case LEAF_dot1dStpDesignatedRoot: 795 case LEAF_dot1dStpRootCost: 796 case LEAF_dot1dStpRootPort: 797 case LEAF_dot1dStpMaxAge: 798 case LEAF_dot1dStpHelloTime: 799 case LEAF_dot1dStpHoldTime: 800 case LEAF_dot1dStpForwardDelay: 801 return (SNMP_ERR_NOT_WRITEABLE); 802 default: 803 return (SNMP_ERR_NOSUCHNAME); 804 } 805 806 if (ret == -2) 807 return (SNMP_ERR_WRONG_VALUE); 808 else if (ret < 0) 809 return (SNMP_ERR_GENERR); 810 return (SNMP_ERR_NOERROR); 811 812 case SNMP_OP_ROLLBACK: 813 switch (value->var.subs[sub - 1]) { 814 case LEAF_dot1dStpPriority: 815 bridge_set_priority(bif, ctx->scratch->int1); 816 break; 817 case LEAF_dot1dStpBridgeMaxAge: 818 bridge_set_maxage(bif, ctx->scratch->int1); 819 break; 820 case LEAF_dot1dStpBridgeHelloTime: 821 bridge_set_hello_time(bif, ctx->scratch->int1); 822 break; 823 case LEAF_dot1dStpBridgeForwardDelay: 824 bridge_set_forward_delay(bif, ctx->scratch->int1); 825 break; 826 case LEAF_dot1dStpVersion: 827 bridge_set_stp_version(bif, ctx->scratch->int1); 828 break; 829 case LEAF_dot1dStpTxHoldCount: 830 bridge_set_tx_hold_count(bif, ctx->scratch->int1); 831 break; 832 } 833 return (SNMP_ERR_NOERROR); 834 835 case SNMP_OP_COMMIT: 836 return (SNMP_ERR_NOERROR); 837 } 838 839 return (SNMP_ERR_NOERROR); 840} 841 842int 843op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value, 844 uint sub, uint iidx __unused, enum snmp_op op) 845{ 846 struct bridge_if *bif; 847 848 if ((bif = bridge_get_default()) == NULL) 849 return (SNMP_ERR_NOSUCHNAME); 850 851 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 852 bridge_update_bif(bif) <= 0) /* It was just deleted. */ 853 return (SNMP_ERR_NOSUCHNAME); 854 855 switch (op) { 856 case SNMP_OP_GET: 857 switch (value->var.subs[sub - 1]) { 858 case LEAF_dot1dTpLearnedEntryDiscards: 859 value->v.uint32 = bif->lrnt_drops; 860 break; 861 case LEAF_dot1dTpAgingTime: 862 value->v.integer = bif->age_time; 863 break; 864 } 865 return (SNMP_ERR_NOERROR); 866 867 case SNMP_OP_GETNEXT: 868 abort(); 869 870 case SNMP_OP_SET: 871 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime) { 872 ctx->scratch->int1 = bif->age_time; 873 if (bridge_set_aging_time(bif, value->v.integer) < 0) 874 return (SNMP_ERR_GENERR); 875 } 876 return (SNMP_ERR_NOERROR); 877 878 case SNMP_OP_ROLLBACK: 879 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime) 880 bridge_set_aging_time(bif, ctx->scratch->int1); 881 return (SNMP_ERR_NOERROR); 882 883 case SNMP_OP_COMMIT: 884 return (SNMP_ERR_NOERROR); 885 } 886 887 return (SNMP_ERR_NOERROR); 888} 889 890/* 891 * Private BEGEMOT-BRIDGE-MIB specifics. 892 */ 893 894/* 895 * Get the bridge name from an OID index. 896 */ 897static char * 898bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name) 899{ 900 uint i; 901 902 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 903 return (NULL); 904 905 for (i = 0; i < oid->subs[sub]; i++) 906 b_name[i] = oid->subs[sub + i + 1]; 907 b_name[i] = '\0'; 908 909 return (b_name); 910} 911 912static void 913bridge_if_index_append(struct asn_oid *oid, uint sub, 914 const struct bridge_if *bif) 915{ 916 uint i; 917 918 oid->len = sub + strlen(bif->bif_name) + 1; 919 oid->subs[sub] = strlen(bif->bif_name); 920 921 for (i = 1; i <= strlen(bif->bif_name); i++) 922 oid->subs[sub + i] = bif->bif_name[i - 1]; 923} 924 925static struct bridge_if * 926bridge_if_index_get(const struct asn_oid *oid, uint sub) 927{ 928 uint i; 929 char bif_name[IFNAMSIZ]; 930 931 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 932 return (NULL); 933 934 for (i = 0; i < oid->subs[sub]; i++) 935 bif_name[i] = oid->subs[sub + i + 1]; 936 bif_name[i] = '\0'; 937 938 return (bridge_if_find_ifname(bif_name)); 939} 940 941static struct bridge_if * 942bridge_if_index_getnext(const struct asn_oid *oid, uint sub) 943{ 944 uint i; 945 char bif_name[IFNAMSIZ]; 946 struct bridge_if *bif; 947 948 if (oid->len - sub == 0) 949 return (bridge_first_bif()); 950 951 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 952 return (NULL); 953 954 for (i = 0; i < oid->subs[sub]; i++) 955 bif_name[i] = oid->subs[sub + i + 1]; 956 bif_name[i] = '\0'; 957 958 if ((bif = bridge_if_find_ifname(bif_name)) == NULL) 959 return (NULL); 960 961 return (bridge_next_bif(bif)); 962} 963 964static int 965bridge_set_if_status(struct snmp_context *ctx, 966 struct snmp_value *val, uint sub) 967{ 968 struct bridge_if *bif; 969 char bif_name[IFNAMSIZ]; 970 971 bif = bridge_if_index_get(&val->var, sub); 972 973 switch (val->v.integer) { 974 case RowStatus_active: 975 if (bif == NULL) 976 return (SNMP_ERR_INCONS_VALUE); 977 978 ctx->scratch->int1 = bif->if_status; 979 980 switch (bif->if_status) { 981 case RowStatus_active: 982 return (SNMP_ERR_NOERROR); 983 case RowStatus_notInService: 984 if (bridge_set_if_up(bif->bif_name, 1) < 0) 985 return (SNMP_ERR_GENERR); 986 return (SNMP_ERR_NOERROR); 987 default: 988 break; 989 } 990 return (SNMP_ERR_INCONS_VALUE); 991 992 case RowStatus_notInService: 993 if (bif == NULL) 994 return (SNMP_ERR_INCONS_VALUE); 995 996 ctx->scratch->int1 = bif->if_status; 997 998 switch (bif->if_status) { 999 case RowStatus_active: 1000 if (bridge_set_if_up(bif->bif_name, 1) < 0) 1001 return (SNMP_ERR_GENERR); 1002 return (SNMP_ERR_NOERROR); 1003 case RowStatus_notInService: 1004 return (SNMP_ERR_NOERROR); 1005 default: 1006 break; 1007 } 1008 return (SNMP_ERR_INCONS_VALUE); 1009 1010 case RowStatus_notReady: 1011 return (SNMP_ERR_INCONS_VALUE); 1012 1013 case RowStatus_createAndGo: 1014 if (bif != NULL) 1015 return (SNMP_ERR_INCONS_VALUE); 1016 1017 ctx->scratch->int1 = RowStatus_destroy; 1018 1019 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL) 1020 return (SNMP_ERR_BADVALUE); 1021 if (bridge_if_create(bif_name, 1) < 0) 1022 return (SNMP_ERR_GENERR); 1023 return (SNMP_ERR_NOERROR); 1024 1025 case RowStatus_createAndWait: 1026 if (bif != NULL) 1027 return (SNMP_ERR_INCONS_VALUE); 1028 1029 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL) 1030 return (SNMP_ERR_BADVALUE); 1031 1032 ctx->scratch->int1 = RowStatus_destroy; 1033 1034 if (bridge_if_create(bif_name, 0) < 0) 1035 return (SNMP_ERR_GENERR); 1036 return (SNMP_ERR_NOERROR); 1037 1038 case RowStatus_destroy: 1039 if (bif == NULL) 1040 return (SNMP_ERR_NOSUCHNAME); 1041 1042 ctx->scratch->int1 = bif->if_status; 1043 bif->if_status = RowStatus_destroy; 1044 } 1045 1046 return (SNMP_ERR_NOERROR); 1047} 1048 1049static int 1050bridge_rollback_if_status(struct snmp_context *ctx, 1051 struct snmp_value *val, uint sub) 1052{ 1053 struct bridge_if *bif; 1054 1055 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1056 return (SNMP_ERR_GENERR); 1057 1058 switch (ctx->scratch->int1) { 1059 case RowStatus_destroy: 1060 bridge_if_destroy(bif); 1061 return (SNMP_ERR_NOERROR); 1062 1063 case RowStatus_notInService: 1064 if (bif->if_status != ctx->scratch->int1) 1065 bridge_set_if_up(bif->bif_name, 0); 1066 bif->if_status = RowStatus_notInService; 1067 return (SNMP_ERR_NOERROR); 1068 1069 case RowStatus_active: 1070 if (bif->if_status != ctx->scratch->int1) 1071 bridge_set_if_up(bif->bif_name, 1); 1072 bif->if_status = RowStatus_active; 1073 return (SNMP_ERR_NOERROR); 1074 } 1075 1076 abort(); 1077} 1078 1079static int 1080bridge_commit_if_status(struct snmp_value *val, uint sub) 1081{ 1082 struct bridge_if *bif; 1083 1084 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1085 return (SNMP_ERR_GENERR); 1086 1087 if (bif->if_status == RowStatus_destroy && 1088 bridge_if_destroy(bif) < 0) 1089 return (SNMP_ERR_COMMIT_FAILED); 1090 1091 return (SNMP_ERR_NOERROR); 1092} 1093 1094int 1095op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val, 1096 uint sub, uint iidx __unused, enum snmp_op op) 1097{ 1098 int ret;
| 30 */ 31 32#include <sys/queue.h> 33#include <sys/socket.h> 34#include <sys/time.h> 35#include <sys/types.h> 36 37#include <net/ethernet.h> 38#include <net/if.h> 39#include <net/if_mib.h> 40#include <net/if_types.h> 41 42#include <errno.h> 43#include <stdarg.h> 44#include <stdlib.h> 45#include <string.h> 46#include <syslog.h> 47 48#include <bsnmp/snmpmod.h> 49#include <bsnmp/snmp_mibII.h> 50 51#include "bridge_tree.h" 52#include "bridge_snmp.h" 53#include "bridge_oid.h" 54 55static const struct asn_oid oid_newRoot = OIDX_newRoot; 56static const struct asn_oid oid_TopologyChange = OIDX_topologyChange; 57static const struct asn_oid oid_begemotBrigeName = \ 58 OIDX_begemotBridgeBaseName; 59static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot; 60static const struct asn_oid oid_begemotTopologyChange = \ 61 OIDX_begemotBridgeTopologyChange; 62 63TAILQ_HEAD(bridge_ifs, bridge_if); 64 65/* 66 * Free the bridge interface list. 67 */ 68static void 69bridge_ifs_free(struct bridge_ifs *headp) 70{ 71 struct bridge_if *b; 72 73 while ((b = TAILQ_FIRST(headp)) != NULL) { 74 TAILQ_REMOVE(headp, b, b_if); 75 free(b); 76 } 77} 78 79/* 80 * Insert an entry in the bridge interface TAILQ. Keep the 81 * TAILQ sorted by the bridge's interface name. 82 */ 83static void 84bridge_ifs_insert(struct bridge_ifs *headp, 85 struct bridge_if *b) 86{ 87 struct bridge_if *temp; 88 89 if ((temp = TAILQ_FIRST(headp)) == NULL || 90 strcmp(b->bif_name, temp->bif_name) < 0) { 91 TAILQ_INSERT_HEAD(headp, b, b_if); 92 return; 93 } 94 95 TAILQ_FOREACH(temp, headp, b_if) 96 if(strcmp(b->bif_name, temp->bif_name) < 0) 97 TAILQ_INSERT_BEFORE(temp, b, b_if); 98 99 TAILQ_INSERT_TAIL(headp, b, b_if); 100} 101 102/* The global bridge interface list. */ 103static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs); 104static time_t bridge_list_age; 105 106/* 107 * Free the global list. 108 */ 109void 110bridge_ifs_fini(void) 111{ 112 bridge_ifs_free(&bridge_ifs); 113} 114 115/* 116 * Find a bridge interface entry by the bridge interface system index. 117 */ 118struct bridge_if * 119bridge_if_find_ifs(uint32_t sysindex) 120{ 121 struct bridge_if *b; 122 123 TAILQ_FOREACH(b, &bridge_ifs, b_if) 124 if (b->sysindex == sysindex) 125 return (b); 126 127 return (NULL); 128} 129 130/* 131 * Find a bridge interface entry by the bridge interface name. 132 */ 133struct bridge_if * 134bridge_if_find_ifname(const char *b_name) 135{ 136 struct bridge_if *b; 137 138 TAILQ_FOREACH(b, &bridge_ifs, b_if) 139 if (strcmp(b_name, b->bif_name) == 0) 140 return (b); 141 142 return (NULL); 143} 144 145/* 146 * Find a bridge name by the bridge interface system index. 147 */ 148const char * 149bridge_if_find_name(uint32_t sysindex) 150{ 151 struct bridge_if *b; 152 153 TAILQ_FOREACH(b, &bridge_ifs, b_if) 154 if (b->sysindex == sysindex) 155 return (b->bif_name); 156 157 return (NULL); 158} 159 160/* 161 * Given two bridge interfaces' system indexes, find their 162 * corresponding names and return the result of the name 163 * comparison. Returns: 164 * error : -2 165 * i1 < i2 : -1 166 * i1 > i2 : +1 167 * i1 = i2 : 0 168 */ 169int 170bridge_compare_sysidx(uint32_t i1, uint32_t i2) 171{ 172 int c; 173 const char *b1, *b2; 174 175 if (i1 == i2) 176 return (0); 177 178 if ((b1 = bridge_if_find_name(i1)) == NULL) { 179 syslog(LOG_ERR, "Bridge interface %d does not exist", i1); 180 return (-2); 181 } 182 183 if ((b2 = bridge_if_find_name(i2)) == NULL) { 184 syslog(LOG_ERR, "Bridge interface %d does not exist", i2); 185 return (-2); 186 } 187 188 if ((c = strcmp(b1, b2)) < 0) 189 return (-1); 190 else if (c > 0) 191 return (1); 192 193 return (0); 194} 195 196/* 197 * Fetch the first bridge interface from the list. 198 */ 199struct bridge_if * 200bridge_first_bif(void) 201{ 202 return (TAILQ_FIRST(&bridge_ifs)); 203} 204 205/* 206 * Fetch the next bridge interface from the list. 207 */ 208struct bridge_if * 209bridge_next_bif(struct bridge_if *b_pr) 210{ 211 return (TAILQ_NEXT(b_pr, b_if)); 212} 213 214/* 215 * Create a new entry for a bridge interface and insert 216 * it in the list. 217 */ 218static struct bridge_if * 219bridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr) 220{ 221 struct bridge_if *bif; 222 223 if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) { 224 syslog(LOG_ERR, "bridge new interface failed: %s", 225 strerror(errno)); 226 return (NULL); 227 } 228 229 bzero(bif, sizeof(struct bridge_if)); 230 strlcpy(bif->bif_name, bif_n, IFNAMSIZ); 231 bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN); 232 bif->sysindex = sysindex; 233 bif->br_type = BaseType_transparent_only; 234 /* 1 - all bridges default hold time * 100 - centi-seconds */ 235 bif->hold_time = 1 * 100; 236 bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d; 237 bridge_ifs_insert(&bridge_ifs, bif); 238 239 return (bif); 240} 241 242/* 243 * Remove a bridge interface from the list, freeing all it's ports 244 * and address entries. 245 */ 246void 247bridge_remove_bif(struct bridge_if *bif) 248{ 249 bridge_members_free(bif); 250 bridge_addrs_free(bif); 251 TAILQ_REMOVE(&bridge_ifs, bif, b_if); 252 free(bif); 253} 254 255 256/* 257 * Prepare the variable (bridge interface name) for the private 258 * begemot notifications. 259 */ 260static struct snmp_value* 261bridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val) 262{ 263 uint i; 264 265 b_val->var = oid_begemotBrigeName; 266 b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name); 267 268 if ((b_val->v.octetstring.octets = (u_char *) 269 malloc(strlen(bif->bif_name))) == NULL) 270 return (NULL); 271 272 for (i = 0; i < strlen(bif->bif_name); i++) 273 b_val->var.subs[b_val->var.len++] = bif->bif_name[i]; 274 275 b_val->v.octetstring.len = strlen(bif->bif_name); 276 bcopy(bif->bif_name, b_val->v.octetstring.octets, 277 strlen(bif->bif_name)); 278 b_val->syntax = SNMP_SYNTAX_OCTETSTRING; 279 280 return (b_val); 281} 282 283/* 284 * Compare the values of the old and the new root port and 285 * send a new root notification, if they are not matching. 286 */ 287static void 288bridge_new_root(struct bridge_if *bif) 289{ 290 struct snmp_value bif_idx; 291 292 if (bridge_get_default() == bif) 293 snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL); 294 295 if (bridge_basename_var(bif, &bif_idx) == NULL) 296 return; 297 298 snmp_send_trap(&oid_begemotTopologyChange, 299 &bif_idx, (struct snmp_value *) NULL); 300} 301 302/* 303 * Compare the new and old topology change times and send a 304 * topology change notification if necessary. 305 */ 306static void 307bridge_top_change(struct bridge_if *bif) 308{ 309 struct snmp_value bif_idx; 310 311 if (bridge_get_default() == bif) 312 snmp_send_trap(&oid_TopologyChange, 313 (struct snmp_value *) NULL); 314 315 if (bridge_basename_var(bif, &bif_idx) == NULL) 316 return; 317 318 snmp_send_trap(&oid_begemotNewRoot, 319 &bif_idx, (struct snmp_value *) NULL); 320} 321 322static int 323bridge_if_create(const char* b_name, int8_t up) 324{ 325 if (bridge_create(b_name) < 0) 326 return (-1); 327 328 if (up == 1 && (bridge_set_if_up(b_name, 1) < 0)) 329 return (-1); 330 331 /* 332 * Do not create a new bridge entry here - 333 * wait until the mibII module notifies us. 334 */ 335 return (0); 336} 337 338static int 339bridge_if_destroy(struct bridge_if *bif) 340{ 341 if (bridge_destroy(bif->bif_name) < 0) 342 return (-1); 343 344 bridge_remove_bif(bif); 345 346 return (0); 347} 348 349/* 350 * Calculate the timeticks since the last topology change. 351 */ 352static int 353bridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks) 354{ 355 struct timeval ct; 356 357 if (gettimeofday(&ct, NULL) < 0) { 358 syslog(LOG_ERR, "bridge get time since last TC:" 359 "getttimeofday failed: %s", strerror(errno)); 360 return (-1); 361 } 362 363 if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) { 364 ct.tv_sec -= 1; 365 ct.tv_usec += 1000000; 366 } 367 368 ct.tv_sec -= bif->last_tc_time.tv_sec; 369 ct.tv_usec -= bif->last_tc_time.tv_usec; 370 371 *ticks = ct.tv_sec * 100 + ct.tv_usec/10000; 372 373 return (0); 374} 375 376/* 377 * Update the info we have for a single bridge interface. 378 * Return: 379 * 1, if successful 380 * 0, if the interface was deleted 381 * -1, error occured while fetching the info from the kernel. 382 */ 383static int 384bridge_update_bif(struct bridge_if *bif) 385{ 386 struct mibif *ifp; 387 388 /* Walk through the mibII interface list. */ 389 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) 390 if (strcmp(ifp->name, bif->bif_name) == 0) 391 break; 392 393 if (ifp == NULL) { 394 /* Ops, we do not exist anymore. */ 395 bridge_remove_bif(bif); 396 return (0); 397 } 398 399 if (ifp->physaddr != NULL ) 400 bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN); 401 else 402 bridge_get_basemac(bif->bif_name, bif->br_addr.octet); 403 404 if (ifp->mib.ifmd_flags & IFF_RUNNING) 405 bif->if_status = RowStatus_active; 406 else 407 bif->if_status = RowStatus_notInService; 408 409 switch (bridge_getinfo_bif(bif)) { 410 case 2: 411 bridge_new_root(bif); 412 break; 413 case 1: 414 bridge_top_change(bif); 415 break; 416 case -1: 417 bridge_remove_bif(bif); 418 return (-1); 419 default: 420 break; 421 } 422 423 /* 424 * The number of ports is accessible via SNMP - 425 * update the ports each time the bridge interface data 426 * is refreshed too. 427 */ 428 bif->num_ports = bridge_update_memif(bif); 429 bif->entry_age = time(NULL); 430 431 return (1); 432} 433 434/* 435 * Update all bridge interfaces' ports only - 436 * make sure each bridge interface exists first. 437 */ 438void 439bridge_update_all_ports(void) 440{ 441 struct mibif *ifp; 442 struct bridge_if *bif, *t_bif; 443 444 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 445 t_bif = bridge_next_bif(bif); 446 447 for (ifp = mib_first_if(); ifp != NULL; 448 ifp = mib_next_if(ifp)) 449 if (strcmp(ifp->name, bif->bif_name) == 0) 450 break; 451 452 if (ifp != NULL) 453 bif->num_ports = bridge_update_memif(bif); 454 else /* Ops, we do not exist anymore. */ 455 bridge_remove_bif(bif); 456 } 457 458 bridge_ports_update_listage(); 459} 460 461/* 462 * Update all addresses only. 463 */ 464void 465bridge_update_all_addrs(void) 466{ 467 struct mibif *ifp; 468 struct bridge_if *bif, *t_bif; 469 470 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 471 t_bif = bridge_next_bif(bif); 472 473 for (ifp = mib_first_if(); ifp != NULL; 474 ifp = mib_next_if(ifp)) 475 if (strcmp(ifp->name, bif->bif_name) == 0) 476 break; 477 478 if (ifp != NULL) 479 bif->num_addrs = bridge_update_addrs(bif); 480 else /* Ops, we don't exist anymore. */ 481 bridge_remove_bif(bif); 482 } 483 484 bridge_addrs_update_listage(); 485} 486 487/* 488 * Update only the bridge interfaces' data - skip addresses. 489 */ 490void 491bridge_update_all_ifs(void) 492{ 493 struct bridge_if *bif, *t_bif; 494 495 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 496 t_bif = bridge_next_bif(bif); 497 bridge_update_bif(bif); 498 } 499 500 bridge_ports_update_listage(); 501 bridge_list_age = time(NULL); 502} 503 504/* 505 * Update all info we have for all bridges. 506 */ 507void 508bridge_update_all(void *arg __unused) 509{ 510 struct bridge_if *bif, *t_bif; 511 512 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 513 t_bif = bridge_next_bif(bif); 514 if (bridge_update_bif(bif) <= 0) 515 continue; 516 517 /* Update our learnt addresses. */ 518 bif->num_addrs = bridge_update_addrs(bif); 519 } 520 521 bridge_list_age = time(NULL); 522 bridge_ports_update_listage(); 523 bridge_addrs_update_listage(); 524} 525 526/* 527 * Callback for polling our last topology change time - 528 * check whether we are root or whether a TC was detected once every 529 * 30 seconds, so that we can send the newRoot and TopologyChange traps 530 * on time. The rest of the data is polled only once every 5 min. 531 */ 532void 533bridge_update_tc_time(void *arg __unused) 534{ 535 struct bridge_if *bif; 536 struct mibif *ifp; 537 538 TAILQ_FOREACH(bif, &bridge_ifs, b_if) { 539 /* Walk through the mibII interface list. */ 540 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) 541 if (strcmp(ifp->name, bif->bif_name) == 0) 542 break; 543 544 if (ifp == NULL) { 545 bridge_remove_bif(bif); 546 continue; 547 } 548 549 switch (bridge_get_op_param(bif)) { 550 case 2: 551 bridge_new_root(bif); 552 break; 553 case 1: 554 bridge_top_change(bif); 555 break; 556 } 557 } 558} 559 560/* 561 * Callback for handling new bridge interface creation. 562 */ 563int 564bridge_attach_newif(struct mibif *ifp) 565{ 566 u_char *p_mac, mac[ETHER_ADDR_LEN]; 567 struct bridge_if *bif; 568 569 if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE) 570 return (0); 571 572 /* Make sure it does not exist in our list. */ 573 TAILQ_FOREACH(bif, &bridge_ifs, b_if) 574 if(strcmp(bif->bif_name, ifp->name) == 0) { 575 syslog(LOG_ERR, "bridge interface %s already " 576 "in list", bif->bif_name); 577 return (-1); 578 } 579 580 if ((p_mac = ifp->physaddr) == NULL && 581 (p_mac = bridge_get_basemac(ifp->name, mac)) == NULL) { 582 syslog(LOG_ERR, "bridge attach new %s failed - " 583 "no bridge mac address", ifp->name); 584 return (-1); 585 } 586 587 if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, p_mac)) == NULL) 588 return (-1); 589 590 if (ifp->mib.ifmd_flags & IFF_RUNNING) 591 bif->if_status = RowStatus_active; 592 else 593 bif->if_status = RowStatus_notInService; 594 595 /* Skip sending notifications if the interface was just created. */ 596 if (bridge_getinfo_bif(bif) < 0 || 597 (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 || 598 (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) { 599 bridge_remove_bif(bif); 600 return (-1); 601 } 602 603 /* Check whether we are the default bridge interface. */ 604 if (strcmp(ifp->name, bridge_get_default_name()) == 0) 605 bridge_set_default(bif); 606 607 return (0); 608} 609 610void 611bridge_ifs_dump(void) 612{ 613 struct bridge_if *bif; 614 615 for (bif = bridge_first_bif(); bif != NULL; 616 bif = bridge_next_bif(bif)) { 617 syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name, 618 bif->sysindex); 619 bridge_ports_dump(bif); 620 bridge_addrs_dump(bif); 621 } 622} 623 624/* 625 * RFC4188 specifics. 626 */ 627int 628op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value, 629 uint sub, uint iidx __unused, enum snmp_op op) 630{ 631 int ret; 632 struct bridge_if *bif; 633 634 if ((bif = bridge_get_default()) == NULL) 635 return (SNMP_ERR_NOSUCHNAME); 636 637 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 638 bridge_update_bif(bif) <= 0) /* It was just deleted. */ 639 return (SNMP_ERR_NOSUCHNAME); 640 641 ret = SNMP_ERR_NOERROR; 642 643 switch (op) { 644 case SNMP_OP_GET: 645 switch (value->var.subs[sub - 1]) { 646 case LEAF_dot1dBaseBridgeAddress: 647 ret = string_get(value, bif->br_addr.octet, 648 ETHER_ADDR_LEN); 649 break; 650 case LEAF_dot1dBaseNumPorts: 651 value->v.integer = bif->num_ports; 652 break; 653 case LEAF_dot1dBaseType: 654 value->v.integer = bif->br_type; 655 break; 656 abort(); 657 } 658 break; 659 660 case SNMP_OP_SET: 661 ret = SNMP_ERR_NOT_WRITEABLE; 662 break; 663 664 case SNMP_OP_GETNEXT: 665 case SNMP_OP_ROLLBACK: 666 case SNMP_OP_COMMIT: 667 abort(); 668 } 669 670 return (ret); 671} 672 673int 674op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *value, 675 uint sub, uint iidx __unused, enum snmp_op op) 676{ 677 int ret; 678 struct bridge_if *bif; 679 680 if ((bif = bridge_get_default()) == NULL) 681 return (SNMP_ERR_NOSUCHNAME); 682 683 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 684 bridge_update_bif(bif) <= 0) /* It was just deleted. */ 685 return (SNMP_ERR_NOSUCHNAME); 686 687 switch (op) { 688 case SNMP_OP_GET: 689 switch (value->var.subs[sub - 1]) { 690 case LEAF_dot1dStpProtocolSpecification: 691 value->v.integer = bif->prot_spec; 692 break; 693 694 case LEAF_dot1dStpPriority: 695 value->v.integer = bif->priority; 696 break; 697 698 case LEAF_dot1dStpTimeSinceTopologyChange: 699 if (bridge_get_time_since_tc(bif, 700 &(value->v.uint32)) < 0) 701 return (SNMP_ERR_GENERR); 702 break; 703 704 case LEAF_dot1dStpTopChanges: 705 value->v.uint32 = bif->top_changes; 706 break; 707 708 case LEAF_dot1dStpDesignatedRoot: 709 return (string_get(value, bif->design_root, 710 SNMP_BRIDGE_ID_LEN)); 711 712 case LEAF_dot1dStpRootCost: 713 value->v.integer = bif->root_cost; 714 break; 715 716 case LEAF_dot1dStpRootPort: 717 value->v.integer = bif->root_port; 718 break; 719 720 case LEAF_dot1dStpMaxAge: 721 value->v.integer = bif->max_age; 722 break; 723 724 case LEAF_dot1dStpHelloTime: 725 value->v.integer = bif->hello_time; 726 break; 727 728 case LEAF_dot1dStpHoldTime: 729 value->v.integer = bif->hold_time; 730 break; 731 732 case LEAF_dot1dStpForwardDelay: 733 value->v.integer = bif->fwd_delay; 734 break; 735 736 case LEAF_dot1dStpBridgeMaxAge: 737 value->v.integer = bif->bridge_max_age; 738 break; 739 740 case LEAF_dot1dStpBridgeHelloTime: 741 value->v.integer = bif->bridge_hello_time; 742 break; 743 744 case LEAF_dot1dStpBridgeForwardDelay: 745 value->v.integer = bif->bridge_fwd_delay; 746 break; 747 case LEAF_dot1dStpVersion: 748 value->v.integer = bif->stp_version; 749 break; 750 case LEAF_dot1dStpTxHoldCount: 751 value->v.integer = bif->tx_hold_count; 752 } 753 754 return (SNMP_ERR_NOERROR); 755 756 case SNMP_OP_GETNEXT: 757 abort(); 758 759 case SNMP_OP_SET: 760 switch (value->var.subs[sub - 1]) { 761 case LEAF_dot1dStpPriority: 762 ctx->scratch->int1 = bif->priority; 763 ret = bridge_set_priority(bif, value->v.integer); 764 break; 765 766 case LEAF_dot1dStpBridgeMaxAge: 767 ctx->scratch->int1 = bif->bridge_max_age; 768 ret = bridge_set_maxage(bif, value->v.integer); 769 break; 770 771 case LEAF_dot1dStpBridgeHelloTime: 772 ctx->scratch->int1 = bif->bridge_hello_time; 773 ret = bridge_set_hello_time(bif, value->v.integer); 774 break; 775 776 case LEAF_dot1dStpBridgeForwardDelay: 777 ctx->scratch->int1 = bif->bridge_fwd_delay; 778 ret = bridge_set_forward_delay(bif, value->v.integer); 779 break; 780 781 case LEAF_dot1dStpVersion: 782 ctx->scratch->int1 = bif->stp_version; 783 ret = bridge_set_stp_version(bif, value->v.integer); 784 break; 785 786 case LEAF_dot1dStpTxHoldCount: 787 ctx->scratch->int1 = bif->tx_hold_count; 788 ret = bridge_set_tx_hold_count(bif, value->v.integer); 789 break; 790 791 case LEAF_dot1dStpProtocolSpecification: 792 case LEAF_dot1dStpTimeSinceTopologyChange: 793 case LEAF_dot1dStpTopChanges: 794 case LEAF_dot1dStpDesignatedRoot: 795 case LEAF_dot1dStpRootCost: 796 case LEAF_dot1dStpRootPort: 797 case LEAF_dot1dStpMaxAge: 798 case LEAF_dot1dStpHelloTime: 799 case LEAF_dot1dStpHoldTime: 800 case LEAF_dot1dStpForwardDelay: 801 return (SNMP_ERR_NOT_WRITEABLE); 802 default: 803 return (SNMP_ERR_NOSUCHNAME); 804 } 805 806 if (ret == -2) 807 return (SNMP_ERR_WRONG_VALUE); 808 else if (ret < 0) 809 return (SNMP_ERR_GENERR); 810 return (SNMP_ERR_NOERROR); 811 812 case SNMP_OP_ROLLBACK: 813 switch (value->var.subs[sub - 1]) { 814 case LEAF_dot1dStpPriority: 815 bridge_set_priority(bif, ctx->scratch->int1); 816 break; 817 case LEAF_dot1dStpBridgeMaxAge: 818 bridge_set_maxage(bif, ctx->scratch->int1); 819 break; 820 case LEAF_dot1dStpBridgeHelloTime: 821 bridge_set_hello_time(bif, ctx->scratch->int1); 822 break; 823 case LEAF_dot1dStpBridgeForwardDelay: 824 bridge_set_forward_delay(bif, ctx->scratch->int1); 825 break; 826 case LEAF_dot1dStpVersion: 827 bridge_set_stp_version(bif, ctx->scratch->int1); 828 break; 829 case LEAF_dot1dStpTxHoldCount: 830 bridge_set_tx_hold_count(bif, ctx->scratch->int1); 831 break; 832 } 833 return (SNMP_ERR_NOERROR); 834 835 case SNMP_OP_COMMIT: 836 return (SNMP_ERR_NOERROR); 837 } 838 839 return (SNMP_ERR_NOERROR); 840} 841 842int 843op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value, 844 uint sub, uint iidx __unused, enum snmp_op op) 845{ 846 struct bridge_if *bif; 847 848 if ((bif = bridge_get_default()) == NULL) 849 return (SNMP_ERR_NOSUCHNAME); 850 851 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 852 bridge_update_bif(bif) <= 0) /* It was just deleted. */ 853 return (SNMP_ERR_NOSUCHNAME); 854 855 switch (op) { 856 case SNMP_OP_GET: 857 switch (value->var.subs[sub - 1]) { 858 case LEAF_dot1dTpLearnedEntryDiscards: 859 value->v.uint32 = bif->lrnt_drops; 860 break; 861 case LEAF_dot1dTpAgingTime: 862 value->v.integer = bif->age_time; 863 break; 864 } 865 return (SNMP_ERR_NOERROR); 866 867 case SNMP_OP_GETNEXT: 868 abort(); 869 870 case SNMP_OP_SET: 871 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime) { 872 ctx->scratch->int1 = bif->age_time; 873 if (bridge_set_aging_time(bif, value->v.integer) < 0) 874 return (SNMP_ERR_GENERR); 875 } 876 return (SNMP_ERR_NOERROR); 877 878 case SNMP_OP_ROLLBACK: 879 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime) 880 bridge_set_aging_time(bif, ctx->scratch->int1); 881 return (SNMP_ERR_NOERROR); 882 883 case SNMP_OP_COMMIT: 884 return (SNMP_ERR_NOERROR); 885 } 886 887 return (SNMP_ERR_NOERROR); 888} 889 890/* 891 * Private BEGEMOT-BRIDGE-MIB specifics. 892 */ 893 894/* 895 * Get the bridge name from an OID index. 896 */ 897static char * 898bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name) 899{ 900 uint i; 901 902 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 903 return (NULL); 904 905 for (i = 0; i < oid->subs[sub]; i++) 906 b_name[i] = oid->subs[sub + i + 1]; 907 b_name[i] = '\0'; 908 909 return (b_name); 910} 911 912static void 913bridge_if_index_append(struct asn_oid *oid, uint sub, 914 const struct bridge_if *bif) 915{ 916 uint i; 917 918 oid->len = sub + strlen(bif->bif_name) + 1; 919 oid->subs[sub] = strlen(bif->bif_name); 920 921 for (i = 1; i <= strlen(bif->bif_name); i++) 922 oid->subs[sub + i] = bif->bif_name[i - 1]; 923} 924 925static struct bridge_if * 926bridge_if_index_get(const struct asn_oid *oid, uint sub) 927{ 928 uint i; 929 char bif_name[IFNAMSIZ]; 930 931 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 932 return (NULL); 933 934 for (i = 0; i < oid->subs[sub]; i++) 935 bif_name[i] = oid->subs[sub + i + 1]; 936 bif_name[i] = '\0'; 937 938 return (bridge_if_find_ifname(bif_name)); 939} 940 941static struct bridge_if * 942bridge_if_index_getnext(const struct asn_oid *oid, uint sub) 943{ 944 uint i; 945 char bif_name[IFNAMSIZ]; 946 struct bridge_if *bif; 947 948 if (oid->len - sub == 0) 949 return (bridge_first_bif()); 950 951 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 952 return (NULL); 953 954 for (i = 0; i < oid->subs[sub]; i++) 955 bif_name[i] = oid->subs[sub + i + 1]; 956 bif_name[i] = '\0'; 957 958 if ((bif = bridge_if_find_ifname(bif_name)) == NULL) 959 return (NULL); 960 961 return (bridge_next_bif(bif)); 962} 963 964static int 965bridge_set_if_status(struct snmp_context *ctx, 966 struct snmp_value *val, uint sub) 967{ 968 struct bridge_if *bif; 969 char bif_name[IFNAMSIZ]; 970 971 bif = bridge_if_index_get(&val->var, sub); 972 973 switch (val->v.integer) { 974 case RowStatus_active: 975 if (bif == NULL) 976 return (SNMP_ERR_INCONS_VALUE); 977 978 ctx->scratch->int1 = bif->if_status; 979 980 switch (bif->if_status) { 981 case RowStatus_active: 982 return (SNMP_ERR_NOERROR); 983 case RowStatus_notInService: 984 if (bridge_set_if_up(bif->bif_name, 1) < 0) 985 return (SNMP_ERR_GENERR); 986 return (SNMP_ERR_NOERROR); 987 default: 988 break; 989 } 990 return (SNMP_ERR_INCONS_VALUE); 991 992 case RowStatus_notInService: 993 if (bif == NULL) 994 return (SNMP_ERR_INCONS_VALUE); 995 996 ctx->scratch->int1 = bif->if_status; 997 998 switch (bif->if_status) { 999 case RowStatus_active: 1000 if (bridge_set_if_up(bif->bif_name, 1) < 0) 1001 return (SNMP_ERR_GENERR); 1002 return (SNMP_ERR_NOERROR); 1003 case RowStatus_notInService: 1004 return (SNMP_ERR_NOERROR); 1005 default: 1006 break; 1007 } 1008 return (SNMP_ERR_INCONS_VALUE); 1009 1010 case RowStatus_notReady: 1011 return (SNMP_ERR_INCONS_VALUE); 1012 1013 case RowStatus_createAndGo: 1014 if (bif != NULL) 1015 return (SNMP_ERR_INCONS_VALUE); 1016 1017 ctx->scratch->int1 = RowStatus_destroy; 1018 1019 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL) 1020 return (SNMP_ERR_BADVALUE); 1021 if (bridge_if_create(bif_name, 1) < 0) 1022 return (SNMP_ERR_GENERR); 1023 return (SNMP_ERR_NOERROR); 1024 1025 case RowStatus_createAndWait: 1026 if (bif != NULL) 1027 return (SNMP_ERR_INCONS_VALUE); 1028 1029 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL) 1030 return (SNMP_ERR_BADVALUE); 1031 1032 ctx->scratch->int1 = RowStatus_destroy; 1033 1034 if (bridge_if_create(bif_name, 0) < 0) 1035 return (SNMP_ERR_GENERR); 1036 return (SNMP_ERR_NOERROR); 1037 1038 case RowStatus_destroy: 1039 if (bif == NULL) 1040 return (SNMP_ERR_NOSUCHNAME); 1041 1042 ctx->scratch->int1 = bif->if_status; 1043 bif->if_status = RowStatus_destroy; 1044 } 1045 1046 return (SNMP_ERR_NOERROR); 1047} 1048 1049static int 1050bridge_rollback_if_status(struct snmp_context *ctx, 1051 struct snmp_value *val, uint sub) 1052{ 1053 struct bridge_if *bif; 1054 1055 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1056 return (SNMP_ERR_GENERR); 1057 1058 switch (ctx->scratch->int1) { 1059 case RowStatus_destroy: 1060 bridge_if_destroy(bif); 1061 return (SNMP_ERR_NOERROR); 1062 1063 case RowStatus_notInService: 1064 if (bif->if_status != ctx->scratch->int1) 1065 bridge_set_if_up(bif->bif_name, 0); 1066 bif->if_status = RowStatus_notInService; 1067 return (SNMP_ERR_NOERROR); 1068 1069 case RowStatus_active: 1070 if (bif->if_status != ctx->scratch->int1) 1071 bridge_set_if_up(bif->bif_name, 1); 1072 bif->if_status = RowStatus_active; 1073 return (SNMP_ERR_NOERROR); 1074 } 1075 1076 abort(); 1077} 1078 1079static int 1080bridge_commit_if_status(struct snmp_value *val, uint sub) 1081{ 1082 struct bridge_if *bif; 1083 1084 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1085 return (SNMP_ERR_GENERR); 1086 1087 if (bif->if_status == RowStatus_destroy && 1088 bridge_if_destroy(bif) < 0) 1089 return (SNMP_ERR_COMMIT_FAILED); 1090 1091 return (SNMP_ERR_NOERROR); 1092} 1093 1094int 1095op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val, 1096 uint sub, uint iidx __unused, enum snmp_op op) 1097{ 1098 int ret;
|