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