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