1 /*- 2 * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * Bridge MIB implementation for SNMPd. 27 * Bridge interface objects. 28 * 29 * $FreeBSD$ 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 55 static const struct asn_oid oid_newRoot = OIDX_newRoot; 56 static const struct asn_oid oid_TopologyChange = OIDX_topologyChange; 57 static const struct asn_oid oid_begemotBrigeName = \ 58 OIDX_begemotBridgeBaseName; 59 static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot; 60 static const struct asn_oid oid_begemotTopologyChange = \ 61 OIDX_begemotBridgeTopologyChange; 62 63 TAILQ_HEAD(bridge_ifs, bridge_if); 64 65 /* 66 * Free the bridge interface list. 67 */ 68 static void 69 bridge_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 */ 83 static void 84 bridge_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. */ 103 static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs); 104 static time_t bridge_list_age; 105 106 /* 107 * Free the global list. 108 */ 109 void 110 bridge_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 */ 118 struct bridge_if * 119 bridge_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 */ 133 struct bridge_if * 134 bridge_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 */ 148 const char * 149 bridge_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 */ 169 int 170 bridge_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 */ 199 struct bridge_if * 200 bridge_first_bif(void) 201 { 202 return (TAILQ_FIRST(&bridge_ifs)); 203 } 204 205 /* 206 * Fetch the next bridge interface from the list. 207 */ 208 struct bridge_if * 209 bridge_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 */ 218 static struct bridge_if * 219 bridge_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 */ 246 void 247 bridge_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 */ 260 static struct snmp_value* 261 bridge_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 */ 287 static void 288 bridge_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 */ 306 static void 307 bridge_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 322 static int 323 bridge_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 338 static int 339 bridge_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 */ 352 static int 353 bridge_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 "gettimeofday 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 occurred while fetching the info from the kernel. 382 */ 383 static int 384 bridge_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 ETHER_ADDR_LEN); 404 405 if (ifp->mib.ifmd_flags & IFF_RUNNING) 406 bif->if_status = RowStatus_active; 407 else 408 bif->if_status = RowStatus_notInService; 409 410 switch (bridge_getinfo_bif(bif)) { 411 case 2: 412 bridge_new_root(bif); 413 break; 414 case 1: 415 bridge_top_change(bif); 416 break; 417 case -1: 418 bridge_remove_bif(bif); 419 return (-1); 420 default: 421 break; 422 } 423 424 /* 425 * The number of ports is accessible via SNMP - 426 * update the ports each time the bridge interface data 427 * is refreshed too. 428 */ 429 bif->num_ports = bridge_update_memif(bif); 430 bif->entry_age = time(NULL); 431 432 return (1); 433 } 434 435 /* 436 * Update all bridge interfaces' ports only - 437 * make sure each bridge interface exists first. 438 */ 439 void 440 bridge_update_all_ports(void) 441 { 442 struct mibif *ifp; 443 struct bridge_if *bif, *t_bif; 444 445 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 446 t_bif = bridge_next_bif(bif); 447 448 for (ifp = mib_first_if(); ifp != NULL; 449 ifp = mib_next_if(ifp)) 450 if (strcmp(ifp->name, bif->bif_name) == 0) 451 break; 452 453 if (ifp != NULL) 454 bif->num_ports = bridge_update_memif(bif); 455 else /* Ops, we do not exist anymore. */ 456 bridge_remove_bif(bif); 457 } 458 459 bridge_ports_update_listage(); 460 } 461 462 /* 463 * Update all addresses only. 464 */ 465 void 466 bridge_update_all_addrs(void) 467 { 468 struct mibif *ifp; 469 struct bridge_if *bif, *t_bif; 470 471 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 472 t_bif = bridge_next_bif(bif); 473 474 for (ifp = mib_first_if(); ifp != NULL; 475 ifp = mib_next_if(ifp)) 476 if (strcmp(ifp->name, bif->bif_name) == 0) 477 break; 478 479 if (ifp != NULL) 480 bif->num_addrs = bridge_update_addrs(bif); 481 else /* Ops, we don't exist anymore. */ 482 bridge_remove_bif(bif); 483 } 484 485 bridge_addrs_update_listage(); 486 } 487 488 /* 489 * Update only the bridge interfaces' data - skip addresses. 490 */ 491 void 492 bridge_update_all_ifs(void) 493 { 494 struct bridge_if *bif, *t_bif; 495 496 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 497 t_bif = bridge_next_bif(bif); 498 bridge_update_bif(bif); 499 } 500 501 bridge_ports_update_listage(); 502 bridge_list_age = time(NULL); 503 } 504 505 /* 506 * Update all info we have for all bridges. 507 */ 508 void 509 bridge_update_all(void *arg __unused) 510 { 511 struct bridge_if *bif, *t_bif; 512 513 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 514 t_bif = bridge_next_bif(bif); 515 if (bridge_update_bif(bif) <= 0) 516 continue; 517 518 /* Update our learnt addresses. */ 519 bif->num_addrs = bridge_update_addrs(bif); 520 } 521 522 bridge_list_age = time(NULL); 523 bridge_ports_update_listage(); 524 bridge_addrs_update_listage(); 525 } 526 527 /* 528 * Callback for polling our last topology change time - 529 * check whether we are root or whether a TC was detected once every 530 * 30 seconds, so that we can send the newRoot and TopologyChange traps 531 * on time. The rest of the data is polled only once every 5 min. 532 */ 533 void 534 bridge_update_tc_time(void *arg __unused) 535 { 536 struct bridge_if *bif; 537 struct mibif *ifp; 538 539 TAILQ_FOREACH(bif, &bridge_ifs, b_if) { 540 /* Walk through the mibII interface list. */ 541 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) 542 if (strcmp(ifp->name, bif->bif_name) == 0) 543 break; 544 545 if (ifp == NULL) { 546 bridge_remove_bif(bif); 547 continue; 548 } 549 550 switch (bridge_get_op_param(bif)) { 551 case 2: 552 bridge_new_root(bif); 553 break; 554 case 1: 555 bridge_top_change(bif); 556 break; 557 } 558 } 559 } 560 561 /* 562 * Callback for handling new bridge interface creation. 563 */ 564 int 565 bridge_attach_newif(struct mibif *ifp) 566 { 567 u_char mac[ETHER_ADDR_LEN]; 568 struct bridge_if *bif; 569 570 if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE) 571 return (0); 572 573 /* Make sure it does not exist in our list. */ 574 TAILQ_FOREACH(bif, &bridge_ifs, b_if) 575 if(strcmp(bif->bif_name, ifp->name) == 0) { 576 syslog(LOG_ERR, "bridge interface %s already " 577 "in list", bif->bif_name); 578 return (-1); 579 } 580 581 if (ifp->physaddr == NULL) { 582 if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) { 583 syslog(LOG_ERR, "bridge attach new %s failed - " 584 "no bridge mac address", ifp->name); 585 return (-1); 586 } 587 } else 588 bcopy(ifp->physaddr, &mac, sizeof(mac)); 589 590 if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL) 591 return (-1); 592 593 if (ifp->mib.ifmd_flags & IFF_RUNNING) 594 bif->if_status = RowStatus_active; 595 else 596 bif->if_status = RowStatus_notInService; 597 598 /* Skip sending notifications if the interface was just created. */ 599 if (bridge_getinfo_bif(bif) < 0 || 600 (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 || 601 (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) { 602 bridge_remove_bif(bif); 603 return (-1); 604 } 605 606 /* Check whether we are the default bridge interface. */ 607 if (strcmp(ifp->name, bridge_get_default_name()) == 0) 608 bridge_set_default(bif); 609 610 return (0); 611 } 612 613 void 614 bridge_ifs_dump(void) 615 { 616 struct bridge_if *bif; 617 618 for (bif = bridge_first_bif(); bif != NULL; 619 bif = bridge_next_bif(bif)) { 620 syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name, 621 bif->sysindex); 622 bridge_ports_dump(bif); 623 bridge_addrs_dump(bif); 624 } 625 } 626 627 /* 628 * RFC4188 specifics. 629 */ 630 int 631 op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value, 632 uint sub, uint iidx __unused, enum snmp_op op) 633 { 634 struct bridge_if *bif; 635 636 if ((bif = bridge_get_default()) == NULL) 637 return (SNMP_ERR_NOSUCHNAME); 638 639 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 640 bridge_update_bif(bif) <= 0) /* It was just deleted. */ 641 return (SNMP_ERR_NOSUCHNAME); 642 643 switch (op) { 644 case SNMP_OP_GET: 645 switch (value->var.subs[sub - 1]) { 646 case LEAF_dot1dBaseBridgeAddress: 647 return (string_get(value, bif->br_addr.octet, 648 ETHER_ADDR_LEN)); 649 case LEAF_dot1dBaseNumPorts: 650 value->v.integer = bif->num_ports; 651 return (SNMP_ERR_NOERROR); 652 case LEAF_dot1dBaseType: 653 value->v.integer = bif->br_type; 654 return (SNMP_ERR_NOERROR); 655 } 656 abort(); 657 658 case SNMP_OP_SET: 659 return (SNMP_ERR_NOT_WRITEABLE); 660 661 case SNMP_OP_GETNEXT: 662 case SNMP_OP_ROLLBACK: 663 case SNMP_OP_COMMIT: 664 break; 665 } 666 667 abort(); 668 } 669 670 int 671 op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub, 672 uint iidx __unused, enum snmp_op op) 673 { 674 struct bridge_if *bif; 675 676 if ((bif = bridge_get_default()) == NULL) 677 return (SNMP_ERR_NOSUCHNAME); 678 679 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 680 bridge_update_bif(bif) <= 0) /* It was just deleted. */ 681 return (SNMP_ERR_NOSUCHNAME); 682 683 switch (op) { 684 case SNMP_OP_GET: 685 switch (val->var.subs[sub - 1]) { 686 case LEAF_dot1dStpProtocolSpecification: 687 val->v.integer = bif->prot_spec; 688 return (SNMP_ERR_NOERROR); 689 690 case LEAF_dot1dStpPriority: 691 val->v.integer = bif->priority; 692 return (SNMP_ERR_NOERROR); 693 694 case LEAF_dot1dStpTimeSinceTopologyChange: 695 if (bridge_get_time_since_tc(bif, 696 &(val->v.uint32)) < 0) 697 return (SNMP_ERR_GENERR); 698 return (SNMP_ERR_NOERROR); 699 700 case LEAF_dot1dStpTopChanges: 701 val->v.uint32 = bif->top_changes; 702 return (SNMP_ERR_NOERROR); 703 704 case LEAF_dot1dStpDesignatedRoot: 705 return (string_get(val, bif->design_root, 706 SNMP_BRIDGE_ID_LEN)); 707 708 case LEAF_dot1dStpRootCost: 709 val->v.integer = bif->root_cost; 710 return (SNMP_ERR_NOERROR); 711 712 case LEAF_dot1dStpRootPort: 713 val->v.integer = bif->root_port; 714 return (SNMP_ERR_NOERROR); 715 716 case LEAF_dot1dStpMaxAge: 717 val->v.integer = bif->max_age; 718 return (SNMP_ERR_NOERROR); 719 720 case LEAF_dot1dStpHelloTime: 721 val->v.integer = bif->hello_time; 722 return (SNMP_ERR_NOERROR); 723 724 case LEAF_dot1dStpHoldTime: 725 val->v.integer = bif->hold_time; 726 return (SNMP_ERR_NOERROR); 727 728 case LEAF_dot1dStpForwardDelay: 729 val->v.integer = bif->fwd_delay; 730 return (SNMP_ERR_NOERROR); 731 732 case LEAF_dot1dStpBridgeMaxAge: 733 val->v.integer = bif->bridge_max_age; 734 return (SNMP_ERR_NOERROR); 735 736 case LEAF_dot1dStpBridgeHelloTime: 737 val->v.integer = bif->bridge_hello_time; 738 return (SNMP_ERR_NOERROR); 739 740 case LEAF_dot1dStpBridgeForwardDelay: 741 val->v.integer = bif->bridge_fwd_delay; 742 return (SNMP_ERR_NOERROR); 743 744 case LEAF_dot1dStpVersion: 745 val->v.integer = bif->stp_version; 746 return (SNMP_ERR_NOERROR); 747 748 case LEAF_dot1dStpTxHoldCount: 749 val->v.integer = bif->tx_hold_count; 750 return (SNMP_ERR_NOERROR); 751 } 752 abort(); 753 754 case SNMP_OP_GETNEXT: 755 abort(); 756 757 case SNMP_OP_SET: 758 switch (val->var.subs[sub - 1]) { 759 case LEAF_dot1dStpPriority: 760 if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY || 761 val->v.integer % 4096 != 0) 762 return (SNMP_ERR_WRONG_VALUE); 763 764 ctx->scratch->int1 = bif->priority; 765 if (bridge_set_priority(bif, val->v.integer) < 0) 766 return (SNMP_ERR_GENERR); 767 return (SNMP_ERR_NOERROR); 768 769 case LEAF_dot1dStpBridgeMaxAge: 770 if (val->v.integer < SNMP_BRIDGE_MIN_MAGE || 771 val->v.integer > SNMP_BRIDGE_MAX_MAGE) 772 return (SNMP_ERR_WRONG_VALUE); 773 774 ctx->scratch->int1 = bif->bridge_max_age; 775 if (bridge_set_maxage(bif, val->v.integer) < 0) 776 return (SNMP_ERR_GENERR); 777 return (SNMP_ERR_NOERROR); 778 779 case LEAF_dot1dStpBridgeHelloTime: 780 if (val->v.integer < SNMP_BRIDGE_MIN_HTIME || 781 val->v.integer > SNMP_BRIDGE_MAX_HTIME) 782 return (SNMP_ERR_WRONG_VALUE); 783 784 ctx->scratch->int1 = bif->bridge_hello_time; 785 if (bridge_set_hello_time(bif, val->v.integer) < 0) 786 return (SNMP_ERR_GENERR); 787 return (SNMP_ERR_NOERROR); 788 789 case LEAF_dot1dStpBridgeForwardDelay: 790 if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY || 791 val->v.integer > SNMP_BRIDGE_MAX_FDELAY) 792 return (SNMP_ERR_WRONG_VALUE); 793 794 ctx->scratch->int1 = bif->bridge_fwd_delay; 795 if (bridge_set_forward_delay(bif, val->v.integer) < 0) 796 return (SNMP_ERR_GENERR); 797 return (SNMP_ERR_NOERROR); 798 799 case LEAF_dot1dStpVersion: 800 if (val->v.integer != dot1dStpVersion_stpCompatible && 801 val->v.integer != dot1dStpVersion_rstp) 802 return (SNMP_ERR_WRONG_VALUE); 803 804 ctx->scratch->int1 = bif->stp_version; 805 if (bridge_set_stp_version(bif, val->v.integer) < 0) 806 return (SNMP_ERR_GENERR); 807 return (SNMP_ERR_NOERROR); 808 809 case LEAF_dot1dStpTxHoldCount: 810 if (val->v.integer < SNMP_BRIDGE_MIN_TXHC || 811 val->v.integer > SNMP_BRIDGE_MAX_TXHC) 812 return (SNMP_ERR_WRONG_VALUE); 813 814 ctx->scratch->int1 = bif->tx_hold_count; 815 if (bridge_set_tx_hold_count(bif, val->v.integer) < 0) 816 return (SNMP_ERR_GENERR); 817 return (SNMP_ERR_NOERROR); 818 819 case LEAF_dot1dStpProtocolSpecification: 820 case LEAF_dot1dStpTimeSinceTopologyChange: 821 case LEAF_dot1dStpTopChanges: 822 case LEAF_dot1dStpDesignatedRoot: 823 case LEAF_dot1dStpRootCost: 824 case LEAF_dot1dStpRootPort: 825 case LEAF_dot1dStpMaxAge: 826 case LEAF_dot1dStpHelloTime: 827 case LEAF_dot1dStpHoldTime: 828 case LEAF_dot1dStpForwardDelay: 829 return (SNMP_ERR_NOT_WRITEABLE); 830 } 831 abort(); 832 833 case SNMP_OP_ROLLBACK: 834 switch (val->var.subs[sub - 1]) { 835 case LEAF_dot1dStpPriority: 836 bridge_set_priority(bif, ctx->scratch->int1); 837 break; 838 case LEAF_dot1dStpBridgeMaxAge: 839 bridge_set_maxage(bif, ctx->scratch->int1); 840 break; 841 case LEAF_dot1dStpBridgeHelloTime: 842 bridge_set_hello_time(bif, ctx->scratch->int1); 843 break; 844 case LEAF_dot1dStpBridgeForwardDelay: 845 bridge_set_forward_delay(bif, ctx->scratch->int1); 846 break; 847 case LEAF_dot1dStpVersion: 848 bridge_set_stp_version(bif, ctx->scratch->int1); 849 break; 850 case LEAF_dot1dStpTxHoldCount: 851 bridge_set_tx_hold_count(bif, ctx->scratch->int1); 852 break; 853 } 854 return (SNMP_ERR_NOERROR); 855 856 case SNMP_OP_COMMIT: 857 return (SNMP_ERR_NOERROR); 858 } 859 860 abort(); 861 } 862 863 int 864 op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value, 865 uint sub, uint iidx __unused, enum snmp_op op) 866 { 867 struct bridge_if *bif; 868 869 if ((bif = bridge_get_default()) == NULL) 870 return (SNMP_ERR_NOSUCHNAME); 871 872 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 873 bridge_update_bif(bif) <= 0) /* It was just deleted. */ 874 return (SNMP_ERR_NOSUCHNAME); 875 876 switch (op) { 877 case SNMP_OP_GET: 878 switch (value->var.subs[sub - 1]) { 879 case LEAF_dot1dTpLearnedEntryDiscards: 880 value->v.uint32 = bif->lrnt_drops; 881 return (SNMP_ERR_NOERROR); 882 case LEAF_dot1dTpAgingTime: 883 value->v.integer = bif->age_time; 884 return (SNMP_ERR_NOERROR); 885 } 886 abort(); 887 888 case SNMP_OP_GETNEXT: 889 abort(); 890 891 case SNMP_OP_SET: 892 switch (value->var.subs[sub - 1]) { 893 case LEAF_dot1dTpLearnedEntryDiscards: 894 return (SNMP_ERR_NOT_WRITEABLE); 895 896 case LEAF_dot1dTpAgingTime: 897 if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME || 898 value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME) 899 return (SNMP_ERR_WRONG_VALUE); 900 901 ctx->scratch->int1 = bif->age_time; 902 if (bridge_set_aging_time(bif, value->v.integer) < 0) 903 return (SNMP_ERR_GENERR); 904 return (SNMP_ERR_NOERROR); 905 } 906 abort(); 907 908 case SNMP_OP_ROLLBACK: 909 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime) 910 bridge_set_aging_time(bif, ctx->scratch->int1); 911 return (SNMP_ERR_NOERROR); 912 913 case SNMP_OP_COMMIT: 914 return (SNMP_ERR_NOERROR); 915 } 916 917 abort(); 918 } 919 920 /* 921 * Private BEGEMOT-BRIDGE-MIB specifics. 922 */ 923 924 /* 925 * Get the bridge name from an OID index. 926 */ 927 static char * 928 bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name) 929 { 930 uint i; 931 932 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 933 return (NULL); 934 935 for (i = 0; i < oid->subs[sub]; i++) 936 b_name[i] = oid->subs[sub + i + 1]; 937 b_name[i] = '\0'; 938 939 return (b_name); 940 } 941 942 static void 943 bridge_if_index_append(struct asn_oid *oid, uint sub, 944 const struct bridge_if *bif) 945 { 946 uint i; 947 948 oid->len = sub + strlen(bif->bif_name) + 1; 949 oid->subs[sub] = strlen(bif->bif_name); 950 951 for (i = 1; i <= strlen(bif->bif_name); i++) 952 oid->subs[sub + i] = bif->bif_name[i - 1]; 953 } 954 955 static struct bridge_if * 956 bridge_if_index_get(const struct asn_oid *oid, uint sub) 957 { 958 uint i; 959 char bif_name[IFNAMSIZ]; 960 961 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 962 return (NULL); 963 964 for (i = 0; i < oid->subs[sub]; i++) 965 bif_name[i] = oid->subs[sub + i + 1]; 966 bif_name[i] = '\0'; 967 968 return (bridge_if_find_ifname(bif_name)); 969 } 970 971 static struct bridge_if * 972 bridge_if_index_getnext(const struct asn_oid *oid, uint sub) 973 { 974 uint i; 975 char bif_name[IFNAMSIZ]; 976 struct bridge_if *bif; 977 978 if (oid->len - sub == 0) 979 return (bridge_first_bif()); 980 981 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 982 return (NULL); 983 984 for (i = 0; i < oid->subs[sub]; i++) 985 bif_name[i] = oid->subs[sub + i + 1]; 986 bif_name[i] = '\0'; 987 988 if ((bif = bridge_if_find_ifname(bif_name)) == NULL) 989 return (NULL); 990 991 return (bridge_next_bif(bif)); 992 } 993 994 static int 995 bridge_set_if_status(struct snmp_context *ctx, 996 struct snmp_value *val, uint sub) 997 { 998 struct bridge_if *bif; 999 char bif_name[IFNAMSIZ]; 1000 1001 bif = bridge_if_index_get(&val->var, sub); 1002 1003 switch (val->v.integer) { 1004 case RowStatus_active: 1005 if (bif == NULL) 1006 return (SNMP_ERR_INCONS_VALUE); 1007 1008 ctx->scratch->int1 = bif->if_status; 1009 1010 switch (bif->if_status) { 1011 case RowStatus_active: 1012 return (SNMP_ERR_NOERROR); 1013 case RowStatus_notInService: 1014 if (bridge_set_if_up(bif->bif_name, 1) < 0) 1015 return (SNMP_ERR_GENERR); 1016 return (SNMP_ERR_NOERROR); 1017 default: 1018 break; 1019 } 1020 return (SNMP_ERR_INCONS_VALUE); 1021 1022 case RowStatus_notInService: 1023 if (bif == NULL) 1024 return (SNMP_ERR_INCONS_VALUE); 1025 1026 ctx->scratch->int1 = bif->if_status; 1027 1028 switch (bif->if_status) { 1029 case RowStatus_active: 1030 if (bridge_set_if_up(bif->bif_name, 1) < 0) 1031 return (SNMP_ERR_GENERR); 1032 return (SNMP_ERR_NOERROR); 1033 case RowStatus_notInService: 1034 return (SNMP_ERR_NOERROR); 1035 default: 1036 break; 1037 } 1038 return (SNMP_ERR_INCONS_VALUE); 1039 1040 case RowStatus_notReady: 1041 return (SNMP_ERR_INCONS_VALUE); 1042 1043 case RowStatus_createAndGo: 1044 if (bif != NULL) 1045 return (SNMP_ERR_INCONS_VALUE); 1046 1047 ctx->scratch->int1 = RowStatus_destroy; 1048 1049 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL) 1050 return (SNMP_ERR_BADVALUE); 1051 if (bridge_if_create(bif_name, 1) < 0) 1052 return (SNMP_ERR_GENERR); 1053 return (SNMP_ERR_NOERROR); 1054 1055 case RowStatus_createAndWait: 1056 if (bif != NULL) 1057 return (SNMP_ERR_INCONS_VALUE); 1058 1059 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL) 1060 return (SNMP_ERR_BADVALUE); 1061 1062 ctx->scratch->int1 = RowStatus_destroy; 1063 1064 if (bridge_if_create(bif_name, 0) < 0) 1065 return (SNMP_ERR_GENERR); 1066 return (SNMP_ERR_NOERROR); 1067 1068 case RowStatus_destroy: 1069 if (bif == NULL) 1070 return (SNMP_ERR_NOSUCHNAME); 1071 1072 ctx->scratch->int1 = bif->if_status; 1073 bif->if_status = RowStatus_destroy; 1074 } 1075 1076 return (SNMP_ERR_NOERROR); 1077 } 1078 1079 static int 1080 bridge_rollback_if_status(struct snmp_context *ctx, 1081 struct snmp_value *val, uint sub) 1082 { 1083 struct bridge_if *bif; 1084 1085 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1086 return (SNMP_ERR_GENERR); 1087 1088 switch (ctx->scratch->int1) { 1089 case RowStatus_destroy: 1090 bridge_if_destroy(bif); 1091 return (SNMP_ERR_NOERROR); 1092 1093 case RowStatus_notInService: 1094 if (bif->if_status != ctx->scratch->int1) 1095 bridge_set_if_up(bif->bif_name, 0); 1096 bif->if_status = RowStatus_notInService; 1097 return (SNMP_ERR_NOERROR); 1098 1099 case RowStatus_active: 1100 if (bif->if_status != ctx->scratch->int1) 1101 bridge_set_if_up(bif->bif_name, 1); 1102 bif->if_status = RowStatus_active; 1103 return (SNMP_ERR_NOERROR); 1104 } 1105 1106 abort(); 1107 } 1108 1109 static int 1110 bridge_commit_if_status(struct snmp_value *val, uint sub) 1111 { 1112 struct bridge_if *bif; 1113 1114 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1115 return (SNMP_ERR_GENERR); 1116 1117 if (bif->if_status == RowStatus_destroy && 1118 bridge_if_destroy(bif) < 0) 1119 return (SNMP_ERR_COMMIT_FAILED); 1120 1121 return (SNMP_ERR_NOERROR); 1122 } 1123 1124 int 1125 op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val, 1126 uint sub, uint iidx __unused, enum snmp_op op) 1127 { 1128 struct bridge_if *bif; 1129 1130 if (time(NULL) - bridge_list_age > bridge_get_data_maxage()) 1131 bridge_update_all_ifs(); 1132 1133 switch (op) { 1134 case SNMP_OP_GET: 1135 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1136 return (SNMP_ERR_NOSUCHNAME); 1137 goto get; 1138 1139 case SNMP_OP_GETNEXT: 1140 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL) 1141 return (SNMP_ERR_NOSUCHNAME); 1142 bridge_if_index_append(&val->var, sub, bif); 1143 goto get; 1144 1145 case SNMP_OP_SET: 1146 switch (val->var.subs[sub - 1]) { 1147 case LEAF_begemotBridgeBaseStatus: 1148 return (bridge_set_if_status(ctx, val, sub)); 1149 case LEAF_begemotBridgeBaseName: 1150 case LEAF_begemotBridgeBaseAddress: 1151 case LEAF_begemotBridgeBaseNumPorts: 1152 case LEAF_begemotBridgeBaseType: 1153 return (SNMP_ERR_NOT_WRITEABLE); 1154 } 1155 abort(); 1156 1157 case SNMP_OP_ROLLBACK: 1158 return (bridge_rollback_if_status(ctx, val, sub)); 1159 1160 case SNMP_OP_COMMIT: 1161 return (bridge_commit_if_status(val, sub)); 1162 } 1163 abort(); 1164 1165 get: 1166 switch (val->var.subs[sub - 1]) { 1167 case LEAF_begemotBridgeBaseName: 1168 return (string_get(val, bif->bif_name, -1)); 1169 1170 case LEAF_begemotBridgeBaseAddress: 1171 return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN)); 1172 1173 case LEAF_begemotBridgeBaseNumPorts: 1174 val->v.integer = bif->num_ports; 1175 return (SNMP_ERR_NOERROR); 1176 1177 case LEAF_begemotBridgeBaseType: 1178 val->v.integer = bif->br_type; 1179 return (SNMP_ERR_NOERROR); 1180 1181 case LEAF_begemotBridgeBaseStatus: 1182 val->v.integer = bif->if_status; 1183 return (SNMP_ERR_NOERROR); 1184 } 1185 1186 abort(); 1187 } 1188 1189 int 1190 op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val, 1191 uint sub, uint iidx __unused, enum snmp_op op) 1192 { 1193 struct bridge_if *bif; 1194 1195 if (time(NULL) - bridge_list_age > bridge_get_data_maxage()) 1196 bridge_update_all_ifs(); 1197 1198 switch (op) { 1199 case SNMP_OP_GET: 1200 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1201 return (SNMP_ERR_NOSUCHNAME); 1202 goto get; 1203 1204 case SNMP_OP_GETNEXT: 1205 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL) 1206 return (SNMP_ERR_NOSUCHNAME); 1207 bridge_if_index_append(&val->var, sub, bif); 1208 goto get; 1209 1210 case SNMP_OP_SET: 1211 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1212 return (SNMP_ERR_NOSUCHNAME); 1213 1214 switch (val->var.subs[sub - 1]) { 1215 case LEAF_begemotBridgeStpPriority: 1216 if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY || 1217 val->v.integer % 4096 != 0) 1218 return (SNMP_ERR_WRONG_VALUE); 1219 1220 ctx->scratch->int1 = bif->priority; 1221 if (bridge_set_priority(bif, val->v.integer) < 0) 1222 return (SNMP_ERR_GENERR); 1223 return (SNMP_ERR_NOERROR); 1224 1225 case LEAF_begemotBridgeStpBridgeMaxAge: 1226 if (val->v.integer < SNMP_BRIDGE_MIN_MAGE || 1227 val->v.integer > SNMP_BRIDGE_MAX_MAGE) 1228 return (SNMP_ERR_WRONG_VALUE); 1229 1230 ctx->scratch->int1 = bif->bridge_max_age; 1231 if (bridge_set_maxage(bif, val->v.integer) < 0) 1232 return (SNMP_ERR_GENERR); 1233 return (SNMP_ERR_NOERROR); 1234 1235 case LEAF_begemotBridgeStpBridgeHelloTime: 1236 if (val->v.integer < SNMP_BRIDGE_MIN_HTIME || 1237 val->v.integer > SNMP_BRIDGE_MAX_HTIME) 1238 return (SNMP_ERR_WRONG_VALUE); 1239 1240 ctx->scratch->int1 = bif->bridge_hello_time; 1241 if (bridge_set_hello_time(bif, val->v.integer) < 0) 1242 return (SNMP_ERR_GENERR); 1243 return (SNMP_ERR_NOERROR); 1244 1245 case LEAF_begemotBridgeStpBridgeForwardDelay: 1246 if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY || 1247 val->v.integer > SNMP_BRIDGE_MAX_FDELAY) 1248 return (SNMP_ERR_WRONG_VALUE); 1249 1250 ctx->scratch->int1 = bif->bridge_fwd_delay; 1251 if (bridge_set_forward_delay(bif, val->v.integer) < 0) 1252 return (SNMP_ERR_GENERR); 1253 return (SNMP_ERR_NOERROR); 1254 1255 case LEAF_begemotBridgeStpVersion: 1256 if (val->v.integer != 1257 begemotBridgeStpVersion_stpCompatible && 1258 val->v.integer != begemotBridgeStpVersion_rstp) 1259 return (SNMP_ERR_WRONG_VALUE); 1260 1261 ctx->scratch->int1 = bif->stp_version; 1262 if (bridge_set_stp_version(bif, val->v.integer) < 0) 1263 return (SNMP_ERR_GENERR); 1264 return (SNMP_ERR_NOERROR); 1265 1266 case LEAF_begemotBridgeStpTxHoldCount: 1267 if (val->v.integer < SNMP_BRIDGE_MIN_TXHC || 1268 val->v.integer > SNMP_BRIDGE_MAX_TXHC) 1269 return (SNMP_ERR_WRONG_VALUE); 1270 1271 ctx->scratch->int1 = bif->tx_hold_count; 1272 if (bridge_set_tx_hold_count(bif, val->v.integer) < 0) 1273 return (SNMP_ERR_GENERR); 1274 return (SNMP_ERR_NOERROR); 1275 1276 case LEAF_begemotBridgeStpProtocolSpecification: 1277 case LEAF_begemotBridgeStpTimeSinceTopologyChange: 1278 case LEAF_begemotBridgeStpTopChanges: 1279 case LEAF_begemotBridgeStpDesignatedRoot: 1280 case LEAF_begemotBridgeStpRootCost: 1281 case LEAF_begemotBridgeStpRootPort: 1282 case LEAF_begemotBridgeStpMaxAge: 1283 case LEAF_begemotBridgeStpHelloTime: 1284 case LEAF_begemotBridgeStpHoldTime: 1285 case LEAF_begemotBridgeStpForwardDelay: 1286 return (SNMP_ERR_NOT_WRITEABLE); 1287 } 1288 abort(); 1289 1290 case SNMP_OP_ROLLBACK: 1291 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1292 return (SNMP_ERR_NOSUCHNAME); 1293 1294 switch (val->var.subs[sub - 1]) { 1295 case LEAF_begemotBridgeStpPriority: 1296 bridge_set_priority(bif, ctx->scratch->int1); 1297 break; 1298 1299 case LEAF_begemotBridgeStpBridgeMaxAge: 1300 bridge_set_maxage(bif, ctx->scratch->int1); 1301 break; 1302 1303 case LEAF_begemotBridgeStpBridgeHelloTime: 1304 bridge_set_hello_time(bif, ctx->scratch->int1); 1305 break; 1306 1307 case LEAF_begemotBridgeStpBridgeForwardDelay: 1308 bridge_set_forward_delay(bif, ctx->scratch->int1); 1309 break; 1310 1311 case LEAF_begemotBridgeStpVersion: 1312 bridge_set_stp_version(bif, ctx->scratch->int1); 1313 break; 1314 1315 case LEAF_begemotBridgeStpTxHoldCount: 1316 bridge_set_tx_hold_count(bif, ctx->scratch->int1); 1317 break; 1318 } 1319 return (SNMP_ERR_NOERROR); 1320 1321 case SNMP_OP_COMMIT: 1322 return (SNMP_ERR_NOERROR); 1323 } 1324 abort(); 1325 1326 get: 1327 switch (val->var.subs[sub - 1]) { 1328 case LEAF_begemotBridgeStpProtocolSpecification: 1329 val->v.integer = bif->prot_spec; 1330 return (SNMP_ERR_NOERROR); 1331 1332 case LEAF_begemotBridgeStpPriority: 1333 val->v.integer = bif->priority; 1334 return (SNMP_ERR_NOERROR); 1335 1336 case LEAF_begemotBridgeStpTimeSinceTopologyChange: 1337 if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0) 1338 return (SNMP_ERR_GENERR); 1339 return (SNMP_ERR_NOERROR); 1340 1341 case LEAF_begemotBridgeStpTopChanges: 1342 val->v.uint32 = bif->top_changes; 1343 return (SNMP_ERR_NOERROR); 1344 1345 case LEAF_begemotBridgeStpDesignatedRoot: 1346 return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN)); 1347 1348 case LEAF_begemotBridgeStpRootCost: 1349 val->v.integer = bif->root_cost; 1350 return (SNMP_ERR_NOERROR); 1351 1352 case LEAF_begemotBridgeStpRootPort: 1353 val->v.integer = bif->root_port; 1354 return (SNMP_ERR_NOERROR); 1355 1356 case LEAF_begemotBridgeStpMaxAge: 1357 val->v.integer = bif->max_age; 1358 return (SNMP_ERR_NOERROR); 1359 1360 case LEAF_begemotBridgeStpHelloTime: 1361 val->v.integer = bif->hello_time; 1362 return (SNMP_ERR_NOERROR); 1363 1364 case LEAF_begemotBridgeStpHoldTime: 1365 val->v.integer = bif->hold_time; 1366 return (SNMP_ERR_NOERROR); 1367 1368 case LEAF_begemotBridgeStpForwardDelay: 1369 val->v.integer = bif->fwd_delay; 1370 return (SNMP_ERR_NOERROR); 1371 1372 case LEAF_begemotBridgeStpBridgeMaxAge: 1373 val->v.integer = bif->bridge_max_age; 1374 return (SNMP_ERR_NOERROR); 1375 1376 case LEAF_begemotBridgeStpBridgeHelloTime: 1377 val->v.integer = bif->bridge_hello_time; 1378 return (SNMP_ERR_NOERROR); 1379 1380 case LEAF_begemotBridgeStpBridgeForwardDelay: 1381 val->v.integer = bif->bridge_fwd_delay; 1382 return (SNMP_ERR_NOERROR); 1383 1384 case LEAF_begemotBridgeStpVersion: 1385 val->v.integer = bif->stp_version; 1386 return (SNMP_ERR_NOERROR); 1387 1388 case LEAF_begemotBridgeStpTxHoldCount: 1389 val->v.integer = bif->tx_hold_count; 1390 return (SNMP_ERR_NOERROR); 1391 } 1392 1393 abort(); 1394 } 1395 1396 int 1397 op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val, 1398 uint sub, uint iidx __unused, enum snmp_op op) 1399 { 1400 struct bridge_if *bif; 1401 1402 if (time(NULL) - bridge_list_age > bridge_get_data_maxage()) 1403 bridge_update_all_ifs(); 1404 1405 switch (op) { 1406 case SNMP_OP_GET: 1407 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1408 return (SNMP_ERR_NOSUCHNAME); 1409 goto get; 1410 1411 case SNMP_OP_GETNEXT: 1412 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL) 1413 return (SNMP_ERR_NOSUCHNAME); 1414 bridge_if_index_append(&val->var, sub, bif); 1415 goto get; 1416 1417 case SNMP_OP_SET: 1418 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1419 return (SNMP_ERR_NOSUCHNAME); 1420 1421 switch (val->var.subs[sub - 1]) { 1422 case LEAF_begemotBridgeTpAgingTime: 1423 if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME || 1424 val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME) 1425 return (SNMP_ERR_WRONG_VALUE); 1426 1427 ctx->scratch->int1 = bif->age_time; 1428 if (bridge_set_aging_time(bif, val->v.integer) < 0) 1429 return (SNMP_ERR_GENERR); 1430 return (SNMP_ERR_NOERROR); 1431 1432 case LEAF_begemotBridgeTpMaxAddresses: 1433 ctx->scratch->int1 = bif->max_addrs; 1434 if (bridge_set_max_cache(bif, val->v.integer) < 0) 1435 return (SNMP_ERR_GENERR); 1436 return (SNMP_ERR_NOERROR); 1437 1438 case LEAF_begemotBridgeTpLearnedEntryDiscards: 1439 return (SNMP_ERR_NOT_WRITEABLE); 1440 } 1441 abort(); 1442 1443 case SNMP_OP_ROLLBACK: 1444 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1445 return (SNMP_ERR_GENERR); 1446 1447 switch (val->var.subs[sub - 1]) { 1448 case LEAF_begemotBridgeTpAgingTime: 1449 bridge_set_aging_time(bif, ctx->scratch->int1); 1450 break; 1451 1452 case LEAF_begemotBridgeTpMaxAddresses: 1453 bridge_set_max_cache(bif, ctx->scratch->int1); 1454 break; 1455 } 1456 return (SNMP_ERR_NOERROR); 1457 1458 case SNMP_OP_COMMIT: 1459 return (SNMP_ERR_NOERROR); 1460 } 1461 abort(); 1462 1463 get: 1464 switch (val->var.subs[sub - 1]) { 1465 case LEAF_begemotBridgeTpLearnedEntryDiscards: 1466 val->v.uint32 = bif->lrnt_drops; 1467 return (SNMP_ERR_NOERROR); 1468 1469 case LEAF_begemotBridgeTpAgingTime: 1470 val->v.integer = bif->age_time; 1471 return (SNMP_ERR_NOERROR); 1472 1473 case LEAF_begemotBridgeTpMaxAddresses: 1474 val->v.integer = bif->max_addrs; 1475 return (SNMP_ERR_NOERROR); 1476 } 1477 1478 abort(); 1479 } 1480