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