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