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