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