1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * Bridge MIB implementation for SNMPd. 29 * Bridge ports. 30 */ 31 32 #include <sys/queue.h> 33 #include <sys/socket.h> 34 #include <sys/types.h> 35 36 #include <net/ethernet.h> 37 #include <net/if.h> 38 #include <net/if_mib.h> 39 40 #include <assert.h> 41 #include <errno.h> 42 #include <stdarg.h> 43 #include <string.h> 44 #include <stdlib.h> 45 #include <syslog.h> 46 47 #include <bsnmp/snmpmod.h> 48 #include <bsnmp/snmp_mibII.h> 49 50 #define SNMPTREE_TYPES 51 #include "bridge_tree.h" 52 #include "bridge_snmp.h" 53 54 TAILQ_HEAD(bridge_ports, bridge_port); 55 56 /* 57 * Free the bridge base ports list. 58 */ 59 static void 60 bridge_ports_free(struct bridge_ports *headp) 61 { 62 struct bridge_port *bp; 63 64 while ((bp = TAILQ_FIRST(headp)) != NULL) { 65 TAILQ_REMOVE(headp, bp, b_p); 66 free(bp); 67 } 68 } 69 70 /* 71 * Free the bridge base ports from the base ports list, 72 * members of a specified bridge interface only. 73 */ 74 static void 75 bridge_port_memif_free(struct bridge_ports *headp, 76 struct bridge_if *bif) 77 { 78 struct bridge_port *bp; 79 80 while (bif->f_bp != NULL && bif->sysindex == bif->f_bp->sysindex) { 81 bp = TAILQ_NEXT(bif->f_bp, b_p); 82 TAILQ_REMOVE(headp, bif->f_bp, b_p); 83 free(bif->f_bp); 84 bif->f_bp = bp; 85 } 86 } 87 88 /* 89 * Insert a port entry in the base port TAILQ starting to search 90 * for its place from the position of the first bridge port for the bridge 91 * interface. Update the first bridge port if necessary. 92 */ 93 static void 94 bridge_port_insert_at(struct bridge_ports *headp, 95 struct bridge_port *bp, struct bridge_port **f_bp) 96 { 97 struct bridge_port *t1; 98 99 assert(f_bp != NULL); 100 101 for (t1 = *f_bp; 102 t1 != NULL && bp->sysindex == t1->sysindex; 103 t1 = TAILQ_NEXT(t1, b_p)) { 104 if (bp->if_idx < t1->if_idx) { 105 TAILQ_INSERT_BEFORE(t1, bp, b_p); 106 if (*f_bp == t1) 107 *f_bp = bp; 108 return; 109 } 110 } 111 112 /* 113 * Handle the case when our first port was actually the 114 * last element of the TAILQ. 115 */ 116 if (t1 == NULL) 117 TAILQ_INSERT_TAIL(headp, bp, b_p); 118 else 119 TAILQ_INSERT_BEFORE(t1, bp, b_p); 120 } 121 122 /* 123 * Find a port entry's position in the ports list according 124 * to it's parent bridge interface name. Returns a NULL if 125 * we should be at the TAILQ head, otherwise the entry after 126 * which we should be inserted. 127 */ 128 static struct bridge_port * 129 bridge_port_find_pos(struct bridge_ports *headp, uint32_t b_idx) 130 { 131 uint32_t t_idx; 132 struct bridge_port *t1; 133 134 if ((t1 = TAILQ_FIRST(headp)) == NULL || 135 bridge_compare_sysidx(b_idx, t1->sysindex) < 0) 136 return (NULL); 137 138 t_idx = t1->sysindex; 139 140 for (t1 = TAILQ_NEXT(t1, b_p); t1 != NULL; t1 = TAILQ_NEXT(t1, b_p)) { 141 if (t1->sysindex != t_idx) { 142 if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0) 143 return (TAILQ_PREV(t1, bridge_ports, b_p)); 144 else 145 t_idx = t1->sysindex; 146 } 147 } 148 149 if (t1 == NULL) 150 t1 = TAILQ_LAST(headp, bridge_ports); 151 152 return (t1); 153 } 154 155 /* 156 * Insert a bridge member interface in the ports TAILQ. 157 */ 158 static void 159 bridge_port_memif_insert(struct bridge_ports *headp, 160 struct bridge_port *bp, struct bridge_port **f_bp) 161 { 162 struct bridge_port *temp; 163 164 if (*f_bp != NULL) 165 bridge_port_insert_at(headp, bp, f_bp); 166 else { 167 temp = bridge_port_find_pos(headp, bp->sysindex); 168 169 if (temp == NULL) 170 TAILQ_INSERT_HEAD(headp, bp, b_p); 171 else 172 TAILQ_INSERT_AFTER(headp, temp, bp, b_p); 173 *f_bp = bp; 174 } 175 } 176 177 /* The global ports list. */ 178 static struct bridge_ports bridge_ports = TAILQ_HEAD_INITIALIZER(bridge_ports); 179 static time_t ports_list_age; 180 181 void 182 bridge_ports_update_listage(void) 183 { 184 ports_list_age = time(NULL); 185 } 186 187 void 188 bridge_ports_fini(void) 189 { 190 bridge_ports_free(&bridge_ports); 191 } 192 193 void 194 bridge_members_free(struct bridge_if *bif) 195 { 196 bridge_port_memif_free(&bridge_ports, bif); 197 } 198 199 /* 200 * Find the first port in the ports list. 201 */ 202 static struct bridge_port * 203 bridge_port_first(void) 204 { 205 return (TAILQ_FIRST(&bridge_ports)); 206 } 207 208 /* 209 * Find the next port in the ports list. 210 */ 211 static struct bridge_port * 212 bridge_port_next(struct bridge_port *bp) 213 { 214 return (TAILQ_NEXT(bp, b_p)); 215 } 216 217 /* 218 * Find the first member of the specified bridge interface. 219 */ 220 struct bridge_port * 221 bridge_port_bif_first(struct bridge_if *bif) 222 { 223 return (bif->f_bp); 224 } 225 226 /* 227 * Find the next member of the specified bridge interface. 228 */ 229 struct bridge_port * 230 bridge_port_bif_next(struct bridge_port *bp) 231 { 232 struct bridge_port *bp_next; 233 234 if ((bp_next = TAILQ_NEXT(bp, b_p)) == NULL || 235 bp_next->sysindex != bp->sysindex) 236 return (NULL); 237 238 return (bp_next); 239 } 240 241 /* 242 * Remove a bridge port from the ports list. 243 */ 244 void 245 bridge_port_remove(struct bridge_port *bp, struct bridge_if *bif) 246 { 247 if (bif->f_bp == bp) 248 bif->f_bp = bridge_port_bif_next(bp); 249 250 TAILQ_REMOVE(&bridge_ports, bp, b_p); 251 free(bp); 252 } 253 254 /* 255 * Allocate memory for a new bridge port and insert it 256 * in the base ports list. Return a pointer to the port's 257 * structure in case we want to do anything else with it. 258 */ 259 struct bridge_port * 260 bridge_new_port(struct mibif *mif, struct bridge_if *bif) 261 { 262 struct bridge_port *bp; 263 264 if ((bp = (struct bridge_port *) malloc(sizeof(*bp))) == NULL) { 265 syslog(LOG_ERR, "bridge new member: failed: %s", 266 strerror(errno)); 267 return (NULL); 268 } 269 270 bzero(bp, sizeof(*bp)); 271 272 bp->sysindex = bif->sysindex; 273 bp->if_idx = mif->index; 274 bp->port_no = mif->sysindex; 275 strlcpy(bp->p_name, mif->name, IFNAMSIZ); 276 bp->circuit = oid_zeroDotZero; 277 278 /* 279 * Initialize all rstpMib specific values to false/default. 280 * These will be set to their true values later if the bridge 281 * supports RSTP. 282 */ 283 bp->proto_migr = TruthValue_false; 284 bp->admin_edge = TruthValue_false; 285 bp->oper_edge = TruthValue_false; 286 bp->oper_ptp = TruthValue_false; 287 bp->admin_ptp = StpPortAdminPointToPointType_auto; 288 289 bridge_port_memif_insert(&bridge_ports, bp, &(bif->f_bp)); 290 291 return (bp); 292 } 293 294 /* 295 * Update our info from the corresponding mibII interface info. 296 */ 297 void 298 bridge_port_getinfo_mibif(struct mibif *m_if, struct bridge_port *bp) 299 { 300 bp->max_info = m_if->mib.ifmd_data.ifi_mtu; 301 bp->in_frames = m_if->mib.ifmd_data.ifi_ipackets; 302 bp->out_frames = m_if->mib.ifmd_data.ifi_opackets; 303 bp->in_drops = m_if->mib.ifmd_data.ifi_iqdrops; 304 } 305 306 /* 307 * Find a port, whose SNMP's mibII ifIndex matches one of the ports, 308 * members of the specified bridge interface. 309 */ 310 struct bridge_port * 311 bridge_port_find(int32_t if_idx, struct bridge_if *bif) 312 { 313 struct bridge_port *bp; 314 315 for (bp = bif->f_bp; bp != NULL; bp = TAILQ_NEXT(bp, b_p)) { 316 if (bp->sysindex != bif->sysindex) { 317 bp = NULL; 318 break; 319 } 320 321 if (bp->if_idx == if_idx) 322 break; 323 } 324 325 return (bp); 326 } 327 328 void 329 bridge_ports_dump(struct bridge_if *bif) 330 { 331 struct bridge_port *bp; 332 333 for (bp = bridge_port_bif_first(bif); bp != NULL; 334 bp = bridge_port_bif_next(bp)) { 335 syslog(LOG_ERR, "memif - %s, index - %d", 336 bp->p_name, bp->port_no); 337 } 338 } 339 340 /* 341 * RFC4188 specifics. 342 */ 343 int 344 op_dot1d_base_port(struct snmp_context *c __unused, struct snmp_value *val, 345 uint sub, uint iidx __unused, enum snmp_op op) 346 { 347 struct bridge_if *bif; 348 struct bridge_port *bp; 349 350 if ((bif = bridge_get_default()) == NULL) 351 return (SNMP_ERR_NOSUCHNAME); 352 353 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() && 354 bridge_update_memif(bif) <= 0) 355 return (SNMP_ERR_NOSUCHNAME); 356 357 switch (op) { 358 case SNMP_OP_GET: 359 if (val->var.len - sub != 1) 360 return (SNMP_ERR_NOSUCHNAME); 361 if ((bp = bridge_port_find(val->var.subs[sub], 362 bif)) == NULL) 363 return (SNMP_ERR_NOSUCHNAME); 364 goto get; 365 366 case SNMP_OP_GETNEXT: 367 if (val->var.len - sub == 0) { 368 if ((bp = bridge_port_bif_first(bif)) == NULL) 369 return (SNMP_ERR_NOSUCHNAME); 370 } else { 371 if ((bp = bridge_port_find(val->var.subs[sub], 372 bif)) == NULL || 373 (bp = bridge_port_bif_next(bp)) == NULL) 374 return (SNMP_ERR_NOSUCHNAME); 375 } 376 val->var.len = sub + 1; 377 val->var.subs[sub] = bp->port_no; 378 goto get; 379 380 case SNMP_OP_SET: 381 return (SNMP_ERR_NOT_WRITEABLE); 382 383 case SNMP_OP_ROLLBACK: 384 case SNMP_OP_COMMIT: 385 break; 386 } 387 abort(); 388 389 get: 390 switch (val->var.subs[sub - 1]) { 391 case LEAF_dot1dBasePort: 392 val->v.integer = bp->port_no; 393 return (SNMP_ERR_NOERROR); 394 395 case LEAF_dot1dBasePortIfIndex: 396 val->v.integer = bp->if_idx; 397 return (SNMP_ERR_NOERROR); 398 399 case LEAF_dot1dBasePortCircuit: 400 val->v.oid = bp->circuit; 401 return (SNMP_ERR_NOERROR); 402 403 case LEAF_dot1dBasePortDelayExceededDiscards: 404 val->v.uint32 = bp->dly_ex_drops; 405 return (SNMP_ERR_NOERROR); 406 407 case LEAF_dot1dBasePortMtuExceededDiscards: 408 val->v.uint32 = bp->dly_mtu_drops; 409 return (SNMP_ERR_NOERROR); 410 } 411 412 abort(); 413 } 414 415 int 416 op_dot1d_stp_port(struct snmp_context *ctx, struct snmp_value *val, 417 uint sub, uint iidx __unused, enum snmp_op op) 418 { 419 struct bridge_if *bif; 420 struct bridge_port *bp; 421 422 if ((bif = bridge_get_default()) == NULL) 423 return (SNMP_ERR_NOSUCHNAME); 424 425 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() && 426 bridge_update_memif(bif) <= 0) 427 return (SNMP_ERR_NOSUCHNAME); 428 429 switch (op) { 430 case SNMP_OP_GET: 431 if (val->var.len - sub != 1) 432 return (SNMP_ERR_NOSUCHNAME); 433 if ((bp = bridge_port_find(val->var.subs[sub], 434 bif)) == NULL) 435 return (SNMP_ERR_NOSUCHNAME); 436 goto get; 437 438 case SNMP_OP_GETNEXT: 439 if (val->var.len - sub == 0) { 440 if ((bp = bridge_port_bif_first(bif)) == NULL) 441 return (SNMP_ERR_NOSUCHNAME); 442 } else { 443 if ((bp = bridge_port_find(val->var.subs[sub], 444 bif)) == NULL || 445 (bp = bridge_port_bif_next(bp)) == NULL) 446 return (SNMP_ERR_NOSUCHNAME); 447 } 448 val->var.len = sub + 1; 449 val->var.subs[sub] = bp->port_no; 450 goto get; 451 452 case SNMP_OP_SET: 453 if (val->var.len - sub != 1) 454 return (SNMP_ERR_NOSUCHNAME); 455 if ((bp = bridge_port_find(val->var.subs[sub], 456 bif)) == NULL) 457 return (SNMP_ERR_NOSUCHNAME); 458 459 switch (val->var.subs[sub - 1]) { 460 case LEAF_dot1dStpPortPriority: 461 if (val->v.integer < 0 || val->v.integer > 255) 462 return (SNMP_ERR_WRONG_VALUE); 463 464 ctx->scratch->int1 = bp->priority; 465 if (bridge_port_set_priority(bif->bif_name, bp, 466 val->v.integer) < 0) 467 return (SNMP_ERR_GENERR); 468 return (SNMP_ERR_NOERROR); 469 470 case LEAF_dot1dStpPortEnable: 471 if (val->v.integer != dot1dStpPortEnable_enabled && 472 val->v.integer != dot1dStpPortEnable_disabled) 473 return (SNMP_ERR_WRONG_VALUE); 474 475 ctx->scratch->int1 = bp->enable; 476 if (bridge_port_set_stp_enable(bif->bif_name, 477 bp, val->v.integer) < 0) 478 return (SNMP_ERR_GENERR); 479 return (SNMP_ERR_NOERROR); 480 481 case LEAF_dot1dStpPortPathCost: 482 if (val->v.integer < SNMP_PORT_MIN_PATHCOST || 483 val->v.integer > SNMP_PORT_MAX_PATHCOST) 484 return (SNMP_ERR_WRONG_VALUE); 485 486 ctx->scratch->int1 = bp->path_cost; 487 if (bridge_port_set_path_cost(bif->bif_name, bp, 488 val->v.integer) < 0) 489 return (SNMP_ERR_GENERR); 490 return (SNMP_ERR_NOERROR); 491 492 case LEAF_dot1dStpPort: 493 case LEAF_dot1dStpPortState: 494 case LEAF_dot1dStpPortDesignatedRoot: 495 case LEAF_dot1dStpPortDesignatedCost: 496 case LEAF_dot1dStpPortDesignatedBridge: 497 case LEAF_dot1dStpPortDesignatedPort: 498 case LEAF_dot1dStpPortForwardTransitions: 499 return (SNMP_ERR_NOT_WRITEABLE); 500 } 501 abort(); 502 503 case SNMP_OP_ROLLBACK: 504 if ((bp = bridge_port_find(val->var.subs[sub], 505 bif)) == NULL) 506 return (SNMP_ERR_GENERR); 507 switch (val->var.subs[sub - 1]) { 508 case LEAF_dot1dStpPortPriority: 509 bridge_port_set_priority(bif->bif_name, bp, 510 ctx->scratch->int1); 511 break; 512 case LEAF_dot1dStpPortEnable: 513 bridge_port_set_stp_enable(bif->bif_name, bp, 514 ctx->scratch->int1); 515 break; 516 case LEAF_dot1dStpPortPathCost: 517 bridge_port_set_path_cost(bif->bif_name, bp, 518 ctx->scratch->int1); 519 break; 520 } 521 return (SNMP_ERR_NOERROR); 522 523 case SNMP_OP_COMMIT: 524 return (SNMP_ERR_NOERROR); 525 } 526 abort(); 527 528 get: 529 switch (val->var.subs[sub - 1]) { 530 case LEAF_dot1dStpPort: 531 val->v.integer = bp->port_no; 532 return (SNMP_ERR_NOERROR); 533 534 case LEAF_dot1dStpPortPriority: 535 val->v.integer = bp->priority; 536 return (SNMP_ERR_NOERROR); 537 538 case LEAF_dot1dStpPortState: 539 val->v.integer = bp->state; 540 return (SNMP_ERR_NOERROR); 541 542 case LEAF_dot1dStpPortEnable: 543 val->v.integer = bp->enable; 544 return (SNMP_ERR_NOERROR); 545 546 case LEAF_dot1dStpPortPathCost: 547 val->v.integer = bp->path_cost; 548 return (SNMP_ERR_NOERROR); 549 550 case LEAF_dot1dStpPortDesignatedRoot: 551 return (string_get(val, bp->design_root, 552 SNMP_BRIDGE_ID_LEN)); 553 554 case LEAF_dot1dStpPortDesignatedCost: 555 val->v.integer = bp->design_cost; 556 return (SNMP_ERR_NOERROR); 557 558 case LEAF_dot1dStpPortDesignatedBridge: 559 return (string_get(val, bp->design_bridge, 560 SNMP_BRIDGE_ID_LEN)); 561 562 case LEAF_dot1dStpPortDesignatedPort: 563 return (string_get(val, bp->design_port, 2)); 564 565 case LEAF_dot1dStpPortForwardTransitions: 566 val->v.uint32 = bp->fwd_trans; 567 return (SNMP_ERR_NOERROR); 568 } 569 570 abort(); 571 } 572 573 int 574 op_dot1d_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val, 575 uint sub, uint iidx __unused, enum snmp_op op) 576 { 577 struct bridge_if *bif; 578 struct bridge_port *bp; 579 580 if ((bif = bridge_get_default()) == NULL) 581 return (SNMP_ERR_NOSUCHNAME); 582 583 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() && 584 bridge_update_memif(bif) <= 0) 585 return (SNMP_ERR_NOSUCHNAME); 586 587 switch (op) { 588 case SNMP_OP_GET: 589 if (val->var.len - sub != 1) 590 return (SNMP_ERR_NOSUCHNAME); 591 if ((bp = bridge_port_find(val->var.subs[sub], 592 bif)) == NULL) 593 return (SNMP_ERR_NOSUCHNAME); 594 goto get; 595 596 case SNMP_OP_GETNEXT: 597 if (val->var.len - sub == 0) { 598 if ((bp = bridge_port_bif_first(bif)) == NULL) 599 return (SNMP_ERR_NOSUCHNAME); 600 } else { 601 if ((bp = bridge_port_find(val->var.subs[sub], 602 bif)) == NULL || 603 (bp = bridge_port_bif_next(bp)) == NULL) 604 return (SNMP_ERR_NOSUCHNAME); 605 } 606 val->var.len = sub + 1; 607 val->var.subs[sub] = bp->port_no; 608 goto get; 609 610 case SNMP_OP_SET: 611 if (val->var.len - sub != 1) 612 return (SNMP_ERR_NOSUCHNAME); 613 if ((bp = bridge_port_find(val->var.subs[sub], 614 bif)) == NULL) 615 return (SNMP_ERR_NOSUCHNAME); 616 617 switch (val->var.subs[sub - 1]) { 618 case LEAF_dot1dStpPortAdminEdgePort: 619 if (val->v.integer != TruthValue_true && 620 val->v.integer != TruthValue_false) 621 return (SNMP_ERR_WRONG_VALUE); 622 623 ctx->scratch->int1 = bp->admin_edge; 624 if (bridge_port_set_admin_edge(bif->bif_name, bp, 625 val->v.integer) < 0) 626 return (SNMP_ERR_GENERR); 627 return (SNMP_ERR_NOERROR); 628 629 case LEAF_dot1dStpPortAdminPointToPoint: 630 if (val->v.integer < 0 || val->v.integer > 631 StpPortAdminPointToPointType_auto) 632 return (SNMP_ERR_WRONG_VALUE); 633 634 ctx->scratch->int1 = bp->admin_ptp; 635 if (bridge_port_set_admin_ptp(bif->bif_name, bp, 636 val->v.integer) < 0) 637 return (SNMP_ERR_GENERR); 638 return (SNMP_ERR_NOERROR); 639 640 case LEAF_dot1dStpPortAdminPathCost: 641 if (val->v.integer < SNMP_PORT_MIN_PATHCOST || 642 val->v.integer > SNMP_PORT_MAX_PATHCOST) 643 return (SNMP_ERR_WRONG_VALUE); 644 645 ctx->scratch->int1 = bp->admin_path_cost; 646 if (bridge_port_set_path_cost(bif->bif_name, bp, 647 val->v.integer) < 0) 648 return (SNMP_ERR_GENERR); 649 return (SNMP_ERR_NOERROR); 650 651 case LEAF_dot1dStpPortProtocolMigration: 652 case LEAF_dot1dStpPortOperEdgePort: 653 case LEAF_dot1dStpPortOperPointToPoint: 654 return (SNMP_ERR_NOT_WRITEABLE); 655 } 656 abort(); 657 658 case SNMP_OP_ROLLBACK: 659 if ((bp = bridge_port_find(val->var.subs[sub], 660 bif)) == NULL) 661 return (SNMP_ERR_GENERR); 662 663 switch (val->var.subs[sub - 1]) { 664 case LEAF_dot1dStpPortAdminEdgePort: 665 bridge_port_set_admin_edge(bif->bif_name, bp, 666 ctx->scratch->int1); 667 break; 668 case LEAF_dot1dStpPortAdminPointToPoint: 669 bridge_port_set_admin_ptp(bif->bif_name, bp, 670 ctx->scratch->int1); 671 break; 672 case LEAF_dot1dStpPortAdminPathCost: 673 bridge_port_set_path_cost(bif->bif_name, bp, 674 ctx->scratch->int1); 675 break; 676 } 677 return (SNMP_ERR_NOERROR); 678 679 case SNMP_OP_COMMIT: 680 return (SNMP_ERR_NOERROR); 681 } 682 abort(); 683 684 get: 685 switch (val->var.subs[sub - 1]) { 686 case LEAF_dot1dStpPortProtocolMigration: 687 val->v.integer = bp->proto_migr; 688 return (SNMP_ERR_NOERROR); 689 690 case LEAF_dot1dStpPortAdminEdgePort: 691 val->v.integer = bp->admin_edge; 692 return (SNMP_ERR_NOERROR); 693 694 case LEAF_dot1dStpPortOperEdgePort: 695 val->v.integer = bp->oper_edge; 696 return (SNMP_ERR_NOERROR); 697 698 case LEAF_dot1dStpPortAdminPointToPoint: 699 val->v.integer = bp->admin_ptp; 700 return (SNMP_ERR_NOERROR); 701 702 case LEAF_dot1dStpPortOperPointToPoint: 703 val->v.integer = bp->oper_ptp; 704 return (SNMP_ERR_NOERROR); 705 706 case LEAF_dot1dStpPortAdminPathCost: 707 val->v.integer = bp->admin_path_cost; 708 return (SNMP_ERR_NOERROR); 709 } 710 711 abort(); 712 } 713 714 int 715 op_dot1d_tp_port(struct snmp_context *c __unused, struct snmp_value *val, 716 uint sub, uint iidx __unused, enum snmp_op op) 717 { 718 struct bridge_if *bif; 719 struct bridge_port *bp; 720 721 if ((bif = bridge_get_default()) == NULL) 722 return (SNMP_ERR_NOSUCHNAME); 723 724 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() && 725 bridge_update_memif(bif) <= 0) 726 return (SNMP_ERR_NOSUCHNAME); 727 728 switch (op) { 729 case SNMP_OP_GET: 730 if (val->var.len - sub != 1) 731 return (SNMP_ERR_NOSUCHNAME); 732 if ((bp = bridge_port_find(val->var.subs[sub], 733 bif)) == NULL) 734 return (SNMP_ERR_NOSUCHNAME); 735 goto get; 736 737 case SNMP_OP_GETNEXT: 738 if (val->var.len - sub == 0) { 739 if ((bp = bridge_port_bif_first(bif)) == NULL) 740 return (SNMP_ERR_NOSUCHNAME); 741 } else { 742 if ((bp = bridge_port_find(val->var.subs[sub], 743 bif)) == NULL || 744 (bp = bridge_port_bif_next(bp)) == NULL) 745 return (SNMP_ERR_NOSUCHNAME); 746 } 747 val->var.len = sub + 1; 748 val->var.subs[sub] = bp->port_no; 749 goto get; 750 751 case SNMP_OP_SET: 752 return (SNMP_ERR_NOT_WRITEABLE); 753 754 case SNMP_OP_ROLLBACK: 755 case SNMP_OP_COMMIT: 756 break; 757 } 758 abort(); 759 760 get: 761 switch (val->var.subs[sub - 1]) { 762 case LEAF_dot1dTpPort: 763 val->v.integer = bp->port_no; 764 return (SNMP_ERR_NOERROR); 765 766 case LEAF_dot1dTpPortMaxInfo: 767 val->v.integer = bp->max_info; 768 return (SNMP_ERR_NOERROR); 769 770 case LEAF_dot1dTpPortInFrames: 771 val->v.uint32 = bp->in_frames; 772 return (SNMP_ERR_NOERROR); 773 774 case LEAF_dot1dTpPortOutFrames: 775 val->v.uint32 = bp->out_frames; 776 return (SNMP_ERR_NOERROR); 777 778 case LEAF_dot1dTpPortInDiscards: 779 val->v.uint32 = bp->in_drops; 780 return (SNMP_ERR_NOERROR); 781 } 782 783 abort(); 784 } 785 786 /* 787 * Private BEGEMOT-BRIDGE-MIB specifics. 788 */ 789 790 /* 791 * Construct a bridge port entry index. 792 */ 793 static int 794 bridge_port_index_append(struct asn_oid *oid, uint sub, 795 const struct bridge_port *bp) 796 { 797 uint i; 798 const char *b_name; 799 800 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL) 801 return (-1); 802 803 oid->len = sub + strlen(b_name) + 1 + 1; 804 oid->subs[sub] = strlen(b_name); 805 806 for (i = 1; i <= strlen(b_name); i++) 807 oid->subs[sub + i] = b_name[i - 1]; 808 809 oid->subs[sub + i] = bp->port_no; 810 811 return (0); 812 } 813 814 /* 815 * Get the port entry from an entry's index. 816 */ 817 static struct bridge_port * 818 bridge_port_index_get(const struct asn_oid *oid, uint sub, int8_t status) 819 { 820 uint i; 821 int32_t port_no; 822 char bif_name[IFNAMSIZ]; 823 struct bridge_if *bif; 824 struct bridge_port *bp; 825 826 if (oid->len - sub != oid->subs[sub] + 2 || 827 oid->subs[sub] >= IFNAMSIZ) 828 return (NULL); 829 830 for (i = 0; i < oid->subs[sub]; i++) 831 bif_name[i] = oid->subs[sub + i + 1]; 832 bif_name[i] = '\0'; 833 834 port_no = oid->subs[sub + i + 1]; 835 836 if ((bif = bridge_if_find_ifname(bif_name)) == NULL) 837 return (NULL); 838 839 if ((bp = bridge_port_find(port_no, bif)) == NULL || 840 (status == 0 && bp->status != RowStatus_active)) 841 return (NULL); 842 843 return (bp); 844 } 845 846 /* 847 * Get the next port entry from an entry's index. 848 */ 849 static struct bridge_port * 850 bridge_port_index_getnext(const struct asn_oid *oid, uint sub, int8_t status) 851 { 852 uint i; 853 int32_t port_no; 854 char bif_name[IFNAMSIZ]; 855 struct bridge_if *bif; 856 struct bridge_port *bp; 857 858 if (oid->len - sub == 0) 859 bp = bridge_port_first(); 860 else { 861 if (oid->len - sub != oid->subs[sub] + 2 || 862 oid->subs[sub] >= IFNAMSIZ) 863 return (NULL); 864 865 for (i = 0; i < oid->subs[sub]; i++) 866 bif_name[i] = oid->subs[sub + i + 1]; 867 bif_name[i] = '\0'; 868 869 port_no = oid->subs[sub + i + 1]; 870 871 if ((bif = bridge_if_find_ifname(bif_name)) == NULL || 872 (bp = bridge_port_find(port_no, bif)) == NULL) 873 return (NULL); 874 875 bp = bridge_port_next(bp); 876 } 877 878 if (status == 1) 879 return (bp); 880 881 while (bp != NULL) { 882 if (bp->status == RowStatus_active) 883 break; 884 bp = bridge_port_next(bp); 885 } 886 887 return (bp); 888 } 889 890 /* 891 * Read the bridge name and port index from a ASN OID structure. 892 */ 893 static int 894 bridge_port_index_decode(const struct asn_oid *oid, uint sub, 895 char *b_name, int32_t *idx) 896 { 897 uint i; 898 899 if (oid->len - sub != oid->subs[sub] + 2 || 900 oid->subs[sub] >= IFNAMSIZ) 901 return (-1); 902 903 for (i = 0; i < oid->subs[sub]; i++) 904 b_name[i] = oid->subs[sub + i + 1]; 905 b_name[i] = '\0'; 906 907 *idx = oid->subs[sub + i + 1]; 908 return (0); 909 } 910 911 static int 912 bridge_port_set_status(struct snmp_context *ctx, 913 struct snmp_value *val, uint sub) 914 { 915 int32_t if_idx; 916 char b_name[IFNAMSIZ]; 917 struct bridge_if *bif; 918 struct bridge_port *bp; 919 struct mibif *mif; 920 921 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0) 922 return (SNMP_ERR_INCONS_VALUE); 923 924 if ((bif = bridge_if_find_ifname(b_name)) == NULL || 925 (mif = mib_find_if(if_idx)) == NULL) 926 return (SNMP_ERR_INCONS_VALUE); 927 928 bp = bridge_port_find(if_idx, bif); 929 930 switch (val->v.integer) { 931 case RowStatus_active: 932 if (bp == NULL) 933 return (SNMP_ERR_INCONS_VALUE); 934 935 if (bp->span_enable == 0) 936 return (SNMP_ERR_INCONS_VALUE); 937 938 ctx->scratch->int1 = bp->status; 939 bp->status = RowStatus_active; 940 break; 941 942 case RowStatus_notInService: 943 if (bp == NULL || bp->span_enable == 0 || 944 bp->status == RowStatus_active) 945 return (SNMP_ERR_INCONS_VALUE); 946 947 ctx->scratch->int1 = bp->status; 948 bp->status = RowStatus_notInService; 949 950 case RowStatus_notReady: 951 /* FALLTHROUGH */ 952 case RowStatus_createAndGo: 953 return (SNMP_ERR_INCONS_VALUE); 954 955 case RowStatus_createAndWait: 956 if (bp != NULL) 957 return (SNMP_ERR_INCONS_VALUE); 958 959 if ((bp = bridge_new_port(mif, bif)) == NULL) 960 return (SNMP_ERR_GENERR); 961 962 ctx->scratch->int1 = RowStatus_destroy; 963 bp->status = RowStatus_notReady; 964 break; 965 966 case RowStatus_destroy: 967 if (bp == NULL) 968 return (SNMP_ERR_INCONS_VALUE); 969 970 ctx->scratch->int1 = bp->status; 971 bp->status = RowStatus_destroy; 972 break; 973 } 974 975 return (SNMP_ERR_NOERROR); 976 } 977 978 static int 979 bridge_port_rollback_status(struct snmp_context *ctx, 980 struct snmp_value *val, uint sub) 981 { 982 int32_t if_idx; 983 char b_name[IFNAMSIZ]; 984 struct bridge_if *bif; 985 struct bridge_port *bp; 986 987 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0) 988 return (SNMP_ERR_GENERR); 989 990 if ((bif = bridge_if_find_ifname(b_name)) == NULL || 991 (bp = bridge_port_find(if_idx, bif)) == NULL) 992 return (SNMP_ERR_GENERR); 993 994 if (ctx->scratch->int1 == RowStatus_destroy) 995 bridge_port_remove(bp, bif); 996 else 997 bp->status = ctx->scratch->int1; 998 999 return (SNMP_ERR_NOERROR); 1000 } 1001 1002 static int 1003 bridge_port_commit_status(struct snmp_value *val, uint sub) 1004 { 1005 int32_t if_idx; 1006 char b_name[IFNAMSIZ]; 1007 struct bridge_if *bif; 1008 struct bridge_port *bp; 1009 1010 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0) 1011 return (SNMP_ERR_GENERR); 1012 1013 if ((bif = bridge_if_find_ifname(b_name)) == NULL || 1014 (bp = bridge_port_find(if_idx, bif)) == NULL) 1015 return (SNMP_ERR_GENERR); 1016 1017 switch (bp->status) { 1018 case RowStatus_active: 1019 if (bridge_port_addm(bp, b_name) < 0) 1020 return (SNMP_ERR_COMMIT_FAILED); 1021 break; 1022 1023 case RowStatus_destroy: 1024 if (bridge_port_delm(bp, b_name) < 0) 1025 return (SNMP_ERR_COMMIT_FAILED); 1026 bridge_port_remove(bp, bif); 1027 break; 1028 } 1029 1030 return (SNMP_ERR_NOERROR); 1031 } 1032 1033 static int 1034 bridge_port_set_span_enable(struct snmp_context *ctx, 1035 struct snmp_value *val, uint sub) 1036 { 1037 int32_t if_idx; 1038 char b_name[IFNAMSIZ]; 1039 struct bridge_if *bif; 1040 struct bridge_port *bp; 1041 struct mibif *mif; 1042 1043 if (val->v.integer != begemotBridgeBaseSpanEnabled_enabled && 1044 val->v.integer != begemotBridgeBaseSpanEnabled_disabled) 1045 return (SNMP_ERR_BADVALUE); 1046 1047 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0) 1048 return (SNMP_ERR_INCONS_VALUE); 1049 1050 if ((bif = bridge_if_find_ifname(b_name)) == NULL) 1051 return (SNMP_ERR_INCONS_VALUE); 1052 1053 if ((bp = bridge_port_find(if_idx, bif)) == NULL) { 1054 if ((mif = mib_find_if(if_idx)) == NULL) 1055 return (SNMP_ERR_INCONS_VALUE); 1056 1057 if ((bp = bridge_new_port(mif, bif)) == NULL) 1058 return (SNMP_ERR_GENERR); 1059 1060 ctx->scratch->int1 = RowStatus_destroy; 1061 } else if (bp->status == RowStatus_active) { 1062 return (SNMP_ERR_INCONS_VALUE); 1063 } else { 1064 ctx->scratch->int1 = bp->status; 1065 } 1066 1067 bp->span_enable = val->v.integer; 1068 bp->status = RowStatus_notInService; 1069 1070 return (SNMP_ERR_NOERROR); 1071 } 1072 1073 int 1074 op_begemot_base_port(struct snmp_context *ctx, struct snmp_value *val, 1075 uint sub, uint iidx __unused, enum snmp_op op) 1076 { 1077 int8_t status, which; 1078 const char *bname; 1079 struct bridge_port *bp; 1080 1081 if (time(NULL) - ports_list_age > bridge_get_data_maxage()) 1082 bridge_update_all_ports(); 1083 1084 which = val->var.subs[sub - 1]; 1085 status = 0; 1086 1087 switch (op) { 1088 case SNMP_OP_GET: 1089 if (which == LEAF_begemotBridgeBaseSpanEnabled || 1090 which == LEAF_begemotBridgeBasePortStatus) 1091 status = 1; 1092 if ((bp = bridge_port_index_get(&val->var, sub, 1093 status)) == NULL) 1094 return (SNMP_ERR_NOSUCHNAME); 1095 goto get; 1096 1097 case SNMP_OP_GETNEXT: 1098 if (which == LEAF_begemotBridgeBaseSpanEnabled || 1099 which == LEAF_begemotBridgeBasePortStatus) 1100 status = 1; 1101 if ((bp = bridge_port_index_getnext(&val->var, sub, 1102 status)) == NULL || 1103 bridge_port_index_append(&val->var, sub, bp) < 0) 1104 return (SNMP_ERR_NOSUCHNAME); 1105 goto get; 1106 1107 case SNMP_OP_SET: 1108 switch (which) { 1109 case LEAF_begemotBridgeBaseSpanEnabled: 1110 return (bridge_port_set_span_enable(ctx, val, sub)); 1111 1112 case LEAF_begemotBridgeBasePortStatus: 1113 return (bridge_port_set_status(ctx, val, sub)); 1114 1115 case LEAF_begemotBridgeBasePortPrivate: 1116 if ((bp = bridge_port_index_get(&val->var, sub, 1117 status)) == NULL) 1118 return (SNMP_ERR_NOSUCHNAME); 1119 if ((bname = bridge_if_find_name(bp->sysindex)) == NULL) 1120 return (SNMP_ERR_GENERR); 1121 ctx->scratch->int1 = bp->priv_set; 1122 return (bridge_port_set_private(bname, bp, 1123 val->v.integer)); 1124 1125 case LEAF_begemotBridgeBasePort: 1126 case LEAF_begemotBridgeBasePortIfIndex: 1127 case LEAF_begemotBridgeBasePortDelayExceededDiscards: 1128 case LEAF_begemotBridgeBasePortMtuExceededDiscards: 1129 return (SNMP_ERR_NOT_WRITEABLE); 1130 } 1131 abort(); 1132 1133 case SNMP_OP_ROLLBACK: 1134 switch (which) { 1135 case LEAF_begemotBridgeBaseSpanEnabled: 1136 /* FALLTHROUGH */ 1137 case LEAF_begemotBridgeBasePortStatus: 1138 return (bridge_port_rollback_status(ctx, val, sub)); 1139 case LEAF_begemotBridgeBasePortPrivate: 1140 if ((bp = bridge_port_index_get(&val->var, sub, 1141 status)) == NULL) 1142 return (SNMP_ERR_GENERR); 1143 if ((bname = bridge_if_find_name(bp->sysindex)) == NULL) 1144 return (SNMP_ERR_GENERR); 1145 return (bridge_port_set_private(bname, bp, 1146 ctx->scratch->int1)); 1147 } 1148 return (SNMP_ERR_NOERROR); 1149 1150 case SNMP_OP_COMMIT: 1151 if (which == LEAF_begemotBridgeBasePortStatus) 1152 return (bridge_port_commit_status(val, sub)); 1153 1154 return (SNMP_ERR_NOERROR); 1155 } 1156 abort(); 1157 1158 get: 1159 switch (which) { 1160 case LEAF_begemotBridgeBasePort: 1161 val->v.integer = bp->port_no; 1162 return (SNMP_ERR_NOERROR); 1163 1164 case LEAF_begemotBridgeBasePortIfIndex: 1165 val->v.integer = bp->if_idx; 1166 return (SNMP_ERR_NOERROR); 1167 1168 case LEAF_begemotBridgeBaseSpanEnabled: 1169 val->v.integer = bp->span_enable; 1170 return (SNMP_ERR_NOERROR); 1171 1172 case LEAF_begemotBridgeBasePortDelayExceededDiscards: 1173 val->v.uint32 = bp->dly_ex_drops; 1174 return (SNMP_ERR_NOERROR); 1175 1176 case LEAF_begemotBridgeBasePortMtuExceededDiscards: 1177 val->v.uint32 = bp->dly_mtu_drops; 1178 return (SNMP_ERR_NOERROR); 1179 1180 case LEAF_begemotBridgeBasePortStatus: 1181 val->v.integer = bp->status; 1182 return (SNMP_ERR_NOERROR); 1183 1184 case LEAF_begemotBridgeBasePortPrivate: 1185 val->v.integer = bp->priv_set; 1186 return (SNMP_ERR_NOERROR); 1187 } 1188 1189 abort(); 1190 } 1191 1192 int 1193 op_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val, 1194 uint sub, uint iidx __unused, enum snmp_op op) 1195 { 1196 struct bridge_port *bp; 1197 const char *b_name; 1198 1199 if (time(NULL) - ports_list_age > bridge_get_data_maxage()) 1200 bridge_update_all_ports(); 1201 1202 switch (op) { 1203 case SNMP_OP_GET: 1204 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL) 1205 return (SNMP_ERR_NOSUCHNAME); 1206 goto get; 1207 1208 case SNMP_OP_GETNEXT: 1209 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) == 1210 NULL || bridge_port_index_append(&val->var, sub, bp) < 0) 1211 return (SNMP_ERR_NOSUCHNAME); 1212 goto get; 1213 1214 case SNMP_OP_SET: 1215 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL) 1216 return (SNMP_ERR_NOSUCHNAME); 1217 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL) 1218 return (SNMP_ERR_GENERR); 1219 1220 switch (val->var.subs[sub - 1]) { 1221 case LEAF_begemotBridgeStpPortPriority: 1222 if (val->v.integer < 0 || val->v.integer > 255) 1223 return (SNMP_ERR_WRONG_VALUE); 1224 1225 ctx->scratch->int1 = bp->priority; 1226 if (bridge_port_set_priority(b_name, bp, 1227 val->v.integer) < 0) 1228 return (SNMP_ERR_GENERR); 1229 return (SNMP_ERR_NOERROR); 1230 1231 case LEAF_begemotBridgeStpPortEnable: 1232 if (val->v.integer != 1233 (int32_t)begemotBridgeStpPortEnable_enabled || 1234 val->v.integer != 1235 (int32_t)begemotBridgeStpPortEnable_disabled) 1236 return (SNMP_ERR_WRONG_VALUE); 1237 1238 ctx->scratch->int1 = bp->enable; 1239 if (bridge_port_set_stp_enable(b_name, bp, 1240 val->v.integer) < 0) 1241 return (SNMP_ERR_GENERR); 1242 return (SNMP_ERR_NOERROR); 1243 1244 case LEAF_begemotBridgeStpPortPathCost: 1245 if (val->v.integer < SNMP_PORT_MIN_PATHCOST || 1246 val->v.integer > SNMP_PORT_MAX_PATHCOST) 1247 return (SNMP_ERR_WRONG_VALUE); 1248 1249 ctx->scratch->int1 = bp->path_cost; 1250 if (bridge_port_set_path_cost(b_name, bp, 1251 val->v.integer) < 0) 1252 return (SNMP_ERR_GENERR); 1253 return (SNMP_ERR_NOERROR); 1254 1255 case LEAF_begemotBridgeStpPort: 1256 case LEAF_begemotBridgeStpPortState: 1257 case LEAF_begemotBridgeStpPortDesignatedRoot: 1258 case LEAF_begemotBridgeStpPortDesignatedCost: 1259 case LEAF_begemotBridgeStpPortDesignatedBridge: 1260 case LEAF_begemotBridgeStpPortDesignatedPort: 1261 case LEAF_begemotBridgeStpPortForwardTransitions: 1262 return (SNMP_ERR_NOT_WRITEABLE); 1263 } 1264 abort(); 1265 1266 case SNMP_OP_ROLLBACK: 1267 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL || 1268 (b_name = bridge_if_find_name(bp->sysindex)) == NULL) 1269 return (SNMP_ERR_GENERR); 1270 1271 switch (val->var.subs[sub - 1]) { 1272 case LEAF_begemotBridgeStpPortPriority: 1273 bridge_port_set_priority(b_name, bp, 1274 ctx->scratch->int1); 1275 break; 1276 case LEAF_begemotBridgeStpPortEnable: 1277 bridge_port_set_stp_enable(b_name, bp, 1278 ctx->scratch->int1); 1279 break; 1280 case LEAF_begemotBridgeStpPortPathCost: 1281 bridge_port_set_path_cost(b_name, bp, 1282 ctx->scratch->int1); 1283 break; 1284 } 1285 return (SNMP_ERR_NOERROR); 1286 1287 case SNMP_OP_COMMIT: 1288 return (SNMP_ERR_NOERROR); 1289 } 1290 abort(); 1291 1292 get: 1293 switch (val->var.subs[sub - 1]) { 1294 case LEAF_begemotBridgeStpPort: 1295 val->v.integer = bp->port_no; 1296 return (SNMP_ERR_NOERROR); 1297 1298 case LEAF_begemotBridgeStpPortPriority: 1299 val->v.integer = bp->priority; 1300 return (SNMP_ERR_NOERROR); 1301 1302 case LEAF_begemotBridgeStpPortState: 1303 val->v.integer = bp->state; 1304 return (SNMP_ERR_NOERROR); 1305 1306 case LEAF_begemotBridgeStpPortEnable: 1307 val->v.integer = bp->enable; 1308 return (SNMP_ERR_NOERROR); 1309 1310 case LEAF_begemotBridgeStpPortPathCost: 1311 val->v.integer = bp->path_cost; 1312 return (SNMP_ERR_NOERROR); 1313 1314 case LEAF_begemotBridgeStpPortDesignatedRoot: 1315 return (string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN)); 1316 1317 case LEAF_begemotBridgeStpPortDesignatedCost: 1318 val->v.integer = bp->design_cost; 1319 return (SNMP_ERR_NOERROR); 1320 1321 case LEAF_begemotBridgeStpPortDesignatedBridge: 1322 return (string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN)); 1323 1324 case LEAF_begemotBridgeStpPortDesignatedPort: 1325 return (string_get(val, bp->design_port, 2)); 1326 1327 case LEAF_begemotBridgeStpPortForwardTransitions: 1328 val->v.uint32 = bp->fwd_trans; 1329 return (SNMP_ERR_NOERROR); 1330 } 1331 1332 abort(); 1333 } 1334 1335 int 1336 op_begemot_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val, 1337 uint sub, uint iidx __unused, enum snmp_op op) 1338 { 1339 struct bridge_port *bp; 1340 const char *b_name; 1341 1342 if (time(NULL) - ports_list_age > bridge_get_data_maxage()) 1343 bridge_update_all_ports(); 1344 1345 switch (op) { 1346 case SNMP_OP_GET: 1347 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL) 1348 return (SNMP_ERR_NOSUCHNAME); 1349 goto get; 1350 1351 case SNMP_OP_GETNEXT: 1352 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) == 1353 NULL || bridge_port_index_append(&val->var, sub, bp) < 0) 1354 return (SNMP_ERR_NOSUCHNAME); 1355 goto get; 1356 1357 case SNMP_OP_SET: 1358 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL) 1359 return (SNMP_ERR_NOSUCHNAME); 1360 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL) 1361 return (SNMP_ERR_GENERR); 1362 1363 switch (val->var.subs[sub - 1]) { 1364 case LEAF_begemotBridgeStpPortAdminEdgePort: 1365 if (val->v.integer != TruthValue_true && 1366 val->v.integer != TruthValue_false) 1367 return (SNMP_ERR_WRONG_VALUE); 1368 1369 ctx->scratch->int1 = bp->admin_edge; 1370 if (bridge_port_set_admin_edge(b_name, bp, 1371 val->v.integer) < 0) 1372 return (SNMP_ERR_GENERR); 1373 return (SNMP_ERR_NOERROR); 1374 1375 case LEAF_begemotBridgeStpPortAdminPointToPoint: 1376 if (val->v.integer < 0 || val->v.integer > 1377 StpPortAdminPointToPointType_auto) 1378 return (SNMP_ERR_WRONG_VALUE); 1379 1380 ctx->scratch->int1 = bp->admin_ptp; 1381 if (bridge_port_set_admin_ptp(b_name, bp, 1382 val->v.integer) < 0) 1383 return (SNMP_ERR_GENERR); 1384 return (SNMP_ERR_NOERROR); 1385 1386 case LEAF_begemotBridgeStpPortAdminPathCost: 1387 if (val->v.integer < SNMP_PORT_MIN_PATHCOST || 1388 val->v.integer > SNMP_PORT_MAX_PATHCOST) 1389 return (SNMP_ERR_WRONG_VALUE); 1390 1391 ctx->scratch->int1 = bp->admin_path_cost; 1392 if (bridge_port_set_path_cost(b_name, bp, 1393 val->v.integer) < 0) 1394 return (SNMP_ERR_GENERR); 1395 return (SNMP_ERR_NOERROR); 1396 1397 case LEAF_begemotBridgeStpPortProtocolMigration: 1398 case LEAF_begemotBridgeStpPortOperEdgePort: 1399 case LEAF_begemotBridgeStpPortOperPointToPoint: 1400 return (SNMP_ERR_NOT_WRITEABLE); 1401 } 1402 abort(); 1403 1404 case SNMP_OP_ROLLBACK: 1405 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL || 1406 (b_name = bridge_if_find_name(bp->sysindex)) == NULL) 1407 return (SNMP_ERR_GENERR); 1408 1409 switch (val->var.subs[sub - 1]) { 1410 case LEAF_begemotBridgeStpPortAdminEdgePort: 1411 bridge_port_set_admin_edge(b_name, bp, 1412 ctx->scratch->int1); 1413 break; 1414 case LEAF_begemotBridgeStpPortAdminPointToPoint: 1415 bridge_port_set_admin_ptp(b_name, bp, 1416 ctx->scratch->int1); 1417 break; 1418 case LEAF_begemotBridgeStpPortAdminPathCost: 1419 bridge_port_set_path_cost(b_name, bp, 1420 ctx->scratch->int1); 1421 break; 1422 } 1423 return (SNMP_ERR_NOERROR); 1424 1425 case SNMP_OP_COMMIT: 1426 return (SNMP_ERR_NOERROR); 1427 } 1428 abort(); 1429 1430 get: 1431 switch (val->var.subs[sub - 1]) { 1432 case LEAF_begemotBridgeStpPortProtocolMigration: 1433 val->v.integer = bp->proto_migr; 1434 return (SNMP_ERR_NOERROR); 1435 1436 case LEAF_begemotBridgeStpPortAdminEdgePort: 1437 val->v.integer = bp->admin_edge; 1438 return (SNMP_ERR_NOERROR); 1439 1440 case LEAF_begemotBridgeStpPortOperEdgePort: 1441 val->v.integer = bp->oper_edge; 1442 return (SNMP_ERR_NOERROR); 1443 1444 case LEAF_begemotBridgeStpPortAdminPointToPoint: 1445 val->v.integer = bp->admin_ptp; 1446 return (SNMP_ERR_NOERROR); 1447 1448 case LEAF_begemotBridgeStpPortOperPointToPoint: 1449 val->v.integer = bp->oper_ptp; 1450 return (SNMP_ERR_NOERROR); 1451 1452 case LEAF_begemotBridgeStpPortAdminPathCost: 1453 val->v.integer = bp->admin_path_cost; 1454 return (SNMP_ERR_NOERROR); 1455 } 1456 1457 abort(); 1458 } 1459 1460 int 1461 op_begemot_tp_port(struct snmp_context *c __unused, struct snmp_value *val, 1462 uint sub, uint iidx __unused, enum snmp_op op) 1463 { 1464 struct bridge_port *bp; 1465 1466 if (time(NULL) - ports_list_age > bridge_get_data_maxage()) 1467 bridge_update_all_ports(); 1468 1469 switch (op) { 1470 case SNMP_OP_GET: 1471 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL) 1472 return (SNMP_ERR_NOSUCHNAME); 1473 goto get; 1474 1475 case SNMP_OP_GETNEXT: 1476 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) == 1477 NULL || bridge_port_index_append(&val->var, sub, bp) < 0) 1478 return (SNMP_ERR_NOSUCHNAME); 1479 goto get; 1480 1481 case SNMP_OP_SET: 1482 return (SNMP_ERR_NOT_WRITEABLE); 1483 1484 case SNMP_OP_ROLLBACK: 1485 case SNMP_OP_COMMIT: 1486 break; 1487 } 1488 abort(); 1489 1490 get: 1491 switch (val->var.subs[sub - 1]) { 1492 case LEAF_begemotBridgeTpPort: 1493 val->v.integer = bp->port_no; 1494 return (SNMP_ERR_NOERROR); 1495 1496 case LEAF_begemotBridgeTpPortMaxInfo: 1497 val->v.integer = bp->max_info; 1498 return (SNMP_ERR_NOERROR); 1499 1500 case LEAF_begemotBridgeTpPortInFrames: 1501 val->v.uint32 = bp->in_frames; 1502 return (SNMP_ERR_NOERROR); 1503 1504 case LEAF_begemotBridgeTpPortOutFrames: 1505 val->v.uint32 = bp->out_frames; 1506 return (SNMP_ERR_NOERROR); 1507 1508 case LEAF_begemotBridgeTpPortInDiscards: 1509 val->v.uint32 = bp->in_drops; 1510 return (SNMP_ERR_NOERROR); 1511 } 1512 1513 abort(); 1514 } 1515