summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c')
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c1513
1 files changed, 1513 insertions, 0 deletions
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c
new file mode 100644
index 0000000..0127cea
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c
@@ -0,0 +1,1513 @@
+/*-
+ * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Bridge MIB implementation for SNMPd.
+ * Bridge ports.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_mib.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <bsnmp/snmpmod.h>
+#include <bsnmp/snmp_mibII.h>
+
+#include "bridge_tree.h"
+#include "bridge_snmp.h"
+
+TAILQ_HEAD(bridge_ports, bridge_port);
+
+/*
+ * Free the bridge base ports list.
+ */
+static void
+bridge_ports_free(struct bridge_ports *headp)
+{
+ struct bridge_port *bp;
+
+ while ((bp = TAILQ_FIRST(headp)) != NULL) {
+ TAILQ_REMOVE(headp, bp, b_p);
+ free(bp);
+ }
+}
+
+/*
+ * Free the bridge base ports from the base ports list,
+ * members of a specified bridge interface only.
+ */
+static void
+bridge_port_memif_free(struct bridge_ports *headp,
+ struct bridge_if *bif)
+{
+ struct bridge_port *bp;
+
+ while (bif->f_bp != NULL && bif->sysindex == bif->f_bp->sysindex) {
+ bp = TAILQ_NEXT(bif->f_bp, b_p);
+ TAILQ_REMOVE(headp, bif->f_bp, b_p);
+ free(bif->f_bp);
+ bif->f_bp = bp;
+ }
+}
+
+/*
+ * Insert a port entry in the base port TAILQ starting to search
+ * for its place from the position of the first bridge port for the bridge
+ * interface. Update the first bridge port if necessary.
+ */
+static void
+bridge_port_insert_at(struct bridge_ports *headp,
+ struct bridge_port *bp, struct bridge_port **f_bp)
+{
+ struct bridge_port *t1;
+
+ assert(f_bp != NULL);
+
+ for (t1 = *f_bp;
+ t1 != NULL && bp->sysindex == t1->sysindex;
+ t1 = TAILQ_NEXT(t1, b_p)) {
+ if (bp->if_idx < t1->if_idx) {
+ TAILQ_INSERT_BEFORE(t1, bp, b_p);
+ if (*f_bp == t1)
+ *f_bp = bp;
+ return;
+ }
+ }
+
+ /*
+ * Handle the case when our first port was actually the
+ * last element of the TAILQ.
+ */
+ if (t1 == NULL)
+ TAILQ_INSERT_TAIL(headp, bp, b_p);
+ else
+ TAILQ_INSERT_BEFORE(t1, bp, b_p);
+}
+
+/*
+ * Find a port entry's position in the ports list according
+ * to it's parent bridge interface name. Returns a NULL if
+ * we should be at the TAILQ head, otherwise the entry after
+ * which we should be inserted.
+ */
+static struct bridge_port *
+bridge_port_find_pos(struct bridge_ports *headp, uint32_t b_idx)
+{
+ uint32_t t_idx;
+ struct bridge_port *t1;
+
+ if ((t1 = TAILQ_FIRST(headp)) == NULL ||
+ bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
+ return (NULL);
+
+ t_idx = t1->sysindex;
+
+ for (t1 = TAILQ_NEXT(t1, b_p); t1 != NULL; t1 = TAILQ_NEXT(t1, b_p)) {
+ if (t1->sysindex != t_idx) {
+ if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
+ return (TAILQ_PREV(t1, bridge_ports, b_p));
+ else
+ t_idx = t1->sysindex;
+ }
+ }
+
+ if (t1 == NULL)
+ t1 = TAILQ_LAST(headp, bridge_ports);
+
+ return (t1);
+}
+
+/*
+ * Insert a bridge member interface in the ports TAILQ.
+ */
+static void
+bridge_port_memif_insert(struct bridge_ports *headp,
+ struct bridge_port *bp, struct bridge_port **f_bp)
+{
+ struct bridge_port *temp;
+
+ if (*f_bp != NULL)
+ bridge_port_insert_at(headp, bp, f_bp);
+ else {
+ temp = bridge_port_find_pos(headp, bp->sysindex);
+
+ if (temp == NULL)
+ TAILQ_INSERT_HEAD(headp, bp, b_p);
+ else
+ TAILQ_INSERT_AFTER(headp, temp, bp, b_p);
+ *f_bp = bp;
+ }
+}
+
+/* The global ports list. */
+static struct bridge_ports bridge_ports = TAILQ_HEAD_INITIALIZER(bridge_ports);
+static time_t ports_list_age;
+
+void
+bridge_ports_update_listage(void)
+{
+ ports_list_age = time(NULL);
+}
+
+void
+bridge_ports_fini(void)
+{
+ bridge_ports_free(&bridge_ports);
+}
+
+void
+bridge_members_free(struct bridge_if *bif)
+{
+ bridge_port_memif_free(&bridge_ports, bif);
+}
+
+/*
+ * Find the first port in the ports list.
+ */
+static struct bridge_port *
+bridge_port_first(void)
+{
+ return (TAILQ_FIRST(&bridge_ports));
+}
+
+/*
+ * Find the next port in the ports list.
+ */
+static struct bridge_port *
+bridge_port_next(struct bridge_port *bp)
+{
+ return (TAILQ_NEXT(bp, b_p));
+}
+
+/*
+ * Find the first member of the specified bridge interface.
+ */
+struct bridge_port *
+bridge_port_bif_first(struct bridge_if *bif)
+{
+ return (bif->f_bp);
+}
+
+/*
+ * Find the next member of the specified bridge interface.
+ */
+struct bridge_port *
+bridge_port_bif_next(struct bridge_port *bp)
+{
+ struct bridge_port *bp_next;
+
+ if ((bp_next = TAILQ_NEXT(bp, b_p)) == NULL ||
+ bp_next->sysindex != bp->sysindex)
+ return (NULL);
+
+ return (bp_next);
+}
+
+/*
+ * Remove a bridge port from the ports list.
+ */
+void
+bridge_port_remove(struct bridge_port *bp, struct bridge_if *bif)
+{
+ if (bif->f_bp == bp)
+ bif->f_bp = bridge_port_bif_next(bp);
+
+ TAILQ_REMOVE(&bridge_ports, bp, b_p);
+ free(bp);
+}
+
+/*
+ * Allocate memory for a new bridge port and insert it
+ * in the base ports list. Return a pointer to the port's
+ * structure in case we want to do anything else with it.
+ */
+struct bridge_port *
+bridge_new_port(struct mibif *mif, struct bridge_if *bif)
+{
+ struct bridge_port *bp;
+
+ if ((bp = (struct bridge_port *) malloc(sizeof(*bp))) == NULL) {
+ syslog(LOG_ERR, "bridge new member: failed: %s",
+ strerror(errno));
+ return (NULL);
+ }
+
+ bzero(bp, sizeof(*bp));
+
+ bp->sysindex = bif->sysindex;
+ bp->if_idx = mif->index;
+ bp->port_no = mif->sysindex;
+ strlcpy(bp->p_name, mif->name, IFNAMSIZ);
+ bp->circuit = oid_zeroDotZero;
+
+ /*
+ * Initialize all rstpMib specific values to false/default.
+ * These will be set to their true values later if the bridge
+ * supports RSTP.
+ */
+ bp->proto_migr = TruthValue_false;
+ bp->admin_edge = TruthValue_false;
+ bp->oper_edge = TruthValue_false;
+ bp->oper_ptp = TruthValue_false;
+ bp->admin_ptp = StpPortAdminPointToPointType_auto;
+
+ bridge_port_memif_insert(&bridge_ports, bp, &(bif->f_bp));
+
+ return (bp);
+}
+
+/*
+ * Update our info from the corresponding mibII interface info.
+ */
+void
+bridge_port_getinfo_mibif(struct mibif *m_if, struct bridge_port *bp)
+{
+ bp->max_info = m_if->mib.ifmd_data.ifi_mtu;
+ bp->in_frames = m_if->mib.ifmd_data.ifi_ipackets;
+ bp->out_frames = m_if->mib.ifmd_data.ifi_opackets;
+ bp->in_drops = m_if->mib.ifmd_data.ifi_iqdrops;
+}
+
+/*
+ * Find a port, whose SNMP's mibII ifIndex matches one of the ports,
+ * members of the specified bridge interface.
+ */
+struct bridge_port *
+bridge_port_find(int32_t if_idx, struct bridge_if *bif)
+{
+ struct bridge_port *bp;
+
+ for (bp = bif->f_bp; bp != NULL; bp = TAILQ_NEXT(bp, b_p)) {
+ if (bp->sysindex != bif->sysindex) {
+ bp = NULL;
+ break;
+ }
+
+ if (bp->if_idx == if_idx)
+ break;
+ }
+
+ return (bp);
+}
+
+void
+bridge_ports_dump(struct bridge_if *bif)
+{
+ struct bridge_port *bp;
+
+ for (bp = bridge_port_bif_first(bif); bp != NULL;
+ bp = bridge_port_bif_next(bp)) {
+ syslog(LOG_ERR, "memif - %s, index - %d",
+ bp->p_name, bp->port_no);
+ }
+}
+
+/*
+ * RFC4188 specifics.
+ */
+int
+op_dot1d_base_port(struct snmp_context *c __unused, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
+ bridge_update_memif(bif) <= 0)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if (val->var.len - sub == 0) {
+ if ((bp = bridge_port_bif_first(bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ } else {
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL ||
+ (bp = bridge_port_bif_next(bp)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+ val->var.len = sub + 1;
+ val->var.subs[sub] = bp->port_no;
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ break;
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dBasePort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dBasePortIfIndex:
+ val->v.integer = bp->if_idx;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dBasePortCircuit:
+ val->v.oid = bp->circuit;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dBasePortDelayExceededDiscards:
+ val->v.uint32 = bp->dly_ex_drops;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dBasePortMtuExceededDiscards:
+ val->v.uint32 = bp->dly_mtu_drops;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_dot1d_stp_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
+ bridge_update_memif(bif) <= 0)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if (val->var.len - sub == 0) {
+ if ((bp = bridge_port_bif_first(bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ } else {
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL ||
+ (bp = bridge_port_bif_next(bp)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+ val->var.len = sub + 1;
+ val->var.subs[sub] = bp->port_no;
+ goto get;
+
+ case SNMP_OP_SET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortPriority:
+ if (val->v.integer < 0 || val->v.integer > 255)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->priority;
+ if (bridge_port_set_priority(bif->bif_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortEnable:
+ if (val->v.integer != dot1dStpPortEnable_enabled &&
+ val->v.integer != dot1dStpPortEnable_disabled)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->enable;
+ if (bridge_port_set_stp_enable(bif->bif_name,
+ bp, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortPathCost:
+ if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
+ val->v.integer > SNMP_PORT_MAX_PATHCOST)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->path_cost;
+ if (bridge_port_set_path_cost(bif->bif_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPort:
+ case LEAF_dot1dStpPortState:
+ case LEAF_dot1dStpPortDesignatedRoot:
+ case LEAF_dot1dStpPortDesignatedCost:
+ case LEAF_dot1dStpPortDesignatedBridge:
+ case LEAF_dot1dStpPortDesignatedPort:
+ case LEAF_dot1dStpPortForwardTransitions:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortPriority:
+ bridge_port_set_priority(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpPortEnable:
+ bridge_port_set_stp_enable(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpPortPathCost:
+ bridge_port_set_path_cost(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortPriority:
+ val->v.integer = bp->priority;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortState:
+ val->v.integer = bp->state;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortEnable:
+ val->v.integer = bp->enable;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortPathCost:
+ val->v.integer = bp->path_cost;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortDesignatedRoot:
+ return (string_get(val, bp->design_root,
+ SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_dot1dStpPortDesignatedCost:
+ val->v.integer = bp->design_cost;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortDesignatedBridge:
+ return (string_get(val, bp->design_bridge,
+ SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_dot1dStpPortDesignatedPort:
+ return (string_get(val, bp->design_port, 2));
+
+ case LEAF_dot1dStpPortForwardTransitions:
+ val->v.uint32 = bp->fwd_trans;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_dot1d_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
+ bridge_update_memif(bif) <= 0)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if (val->var.len - sub == 0) {
+ if ((bp = bridge_port_bif_first(bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ } else {
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL ||
+ (bp = bridge_port_bif_next(bp)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+ val->var.len = sub + 1;
+ val->var.subs[sub] = bp->port_no;
+ goto get;
+
+ case SNMP_OP_SET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortAdminEdgePort:
+ if (val->v.integer != TruthValue_true &&
+ val->v.integer != TruthValue_false)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_edge;
+ if (bridge_port_set_admin_edge(bif->bif_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortAdminPointToPoint:
+ if (val->v.integer < 0 || val->v.integer >
+ StpPortAdminPointToPointType_auto)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_ptp;
+ if (bridge_port_set_admin_ptp(bif->bif_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortAdminPathCost:
+ if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
+ val->v.integer > SNMP_PORT_MAX_PATHCOST)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_path_cost;
+ if (bridge_port_set_path_cost(bif->bif_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortProtocolMigration:
+ case LEAF_dot1dStpPortOperEdgePort:
+ case LEAF_dot1dStpPortOperPointToPoint:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortAdminEdgePort:
+ bridge_port_set_admin_edge(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpPortAdminPointToPoint:
+ bridge_port_set_admin_ptp(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpPortAdminPathCost:
+ bridge_port_set_path_cost(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortProtocolMigration:
+ val->v.integer = bp->proto_migr;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortAdminEdgePort:
+ val->v.integer = bp->admin_edge;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortOperEdgePort:
+ val->v.integer = bp->oper_edge;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortAdminPointToPoint:
+ val->v.integer = bp->admin_ptp;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortOperPointToPoint:
+ val->v.integer = bp->oper_ptp;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortAdminPathCost:
+ val->v.integer = bp->admin_path_cost;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_dot1d_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
+ bridge_update_memif(bif) <= 0)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if (val->var.len - sub == 0) {
+ if ((bp = bridge_port_bif_first(bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ } else {
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL ||
+ (bp = bridge_port_bif_next(bp)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+ val->var.len = sub + 1;
+ val->var.subs[sub] = bp->port_no;
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ break;
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dTpPort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dTpPortMaxInfo:
+ val->v.integer = bp->max_info;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dTpPortInFrames:
+ val->v.uint32 = bp->in_frames;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dTpPortOutFrames:
+ val->v.uint32 = bp->out_frames;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dTpPortInDiscards:
+ val->v.uint32 = bp->in_drops;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+/*
+ * Private BEGEMOT-BRIDGE-MIB specifics.
+ */
+
+/*
+ * Construct a bridge port entry index.
+ */
+static int
+bridge_port_index_append(struct asn_oid *oid, uint sub,
+ const struct bridge_port *bp)
+{
+ uint i;
+ const char *b_name;
+
+ if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (-1);
+
+ oid->len = sub + strlen(b_name) + 1 + 1;
+ oid->subs[sub] = strlen(b_name);
+
+ for (i = 1; i <= strlen(b_name); i++)
+ oid->subs[sub + i] = b_name[i - 1];
+
+ oid->subs[sub + i] = bp->port_no;
+
+ return (0);
+}
+
+/*
+ * Get the port entry from an entry's index.
+ */
+static struct bridge_port *
+bridge_port_index_get(const struct asn_oid *oid, uint sub, int8_t status)
+{
+ uint i;
+ int32_t port_no;
+ char bif_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if (oid->len - sub != oid->subs[sub] + 2 ||
+ oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ bif_name[i] = oid->subs[sub + i + 1];
+ bif_name[i] = '\0';
+
+ port_no = oid->subs[sub + i + 1];
+
+ if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
+ return (NULL);
+
+ if ((bp = bridge_port_find(port_no, bif)) == NULL ||
+ (status == 0 && bp->status != RowStatus_active))
+ return (NULL);
+
+ return (bp);
+}
+
+/*
+ * Get the next port entry from an entry's index.
+ */
+static struct bridge_port *
+bridge_port_index_getnext(const struct asn_oid *oid, uint sub, int8_t status)
+{
+ uint i;
+ int32_t port_no;
+ char bif_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if (oid->len - sub == 0)
+ bp = bridge_port_first();
+ else {
+ if (oid->len - sub != oid->subs[sub] + 2 ||
+ oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ bif_name[i] = oid->subs[sub + i + 1];
+ bif_name[i] = '\0';
+
+ port_no = oid->subs[sub + i + 1];
+
+ if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
+ (bp = bridge_port_find(port_no, bif)) == NULL)
+ return (NULL);
+
+ bp = bridge_port_next(bp);
+ }
+
+ if (status == 1)
+ return (bp);
+
+ while (bp != NULL) {
+ if (bp->status == RowStatus_active)
+ break;
+ bp = bridge_port_next(bp);
+ }
+
+ return (bp);
+}
+
+/*
+ * Read the bridge name and port index from a ASN OID structure.
+ */
+static int
+bridge_port_index_decode(const struct asn_oid *oid, uint sub,
+ char *b_name, int32_t *idx)
+{
+ uint i;
+
+ if (oid->len - sub != oid->subs[sub] + 2 ||
+ oid->subs[sub] >= IFNAMSIZ)
+ return (-1);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ b_name[i] = oid->subs[sub + i + 1];
+ b_name[i] = '\0';
+
+ *idx = oid->subs[sub + i + 1];
+ return (0);
+}
+
+static int
+bridge_port_set_status(struct snmp_context *ctx,
+ struct snmp_value *val, uint sub)
+{
+ int32_t if_idx;
+ char b_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+ struct mibif *mif;
+
+ if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
+ (mif = mib_find_if(if_idx)) == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ bp = bridge_port_find(if_idx, bif);
+
+ switch (val->v.integer) {
+ case RowStatus_active:
+ if (bp == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if (bp->span_enable == 0)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ ctx->scratch->int1 = bp->status;
+ bp->status = RowStatus_active;
+ break;
+
+ case RowStatus_notInService:
+ if (bp == NULL || bp->span_enable == 0 ||
+ bp->status == RowStatus_active)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ ctx->scratch->int1 = bp->status;
+ bp->status = RowStatus_notInService;
+
+ case RowStatus_notReady:
+ /* FALLTHROUGH */
+ case RowStatus_createAndGo:
+ return (SNMP_ERR_INCONS_VALUE);
+
+ case RowStatus_createAndWait:
+ if (bp != NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((bp = bridge_new_port(mif, bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ ctx->scratch->int1 = RowStatus_destroy;
+ bp->status = RowStatus_notReady;
+ break;
+
+ case RowStatus_destroy:
+ if (bp == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ ctx->scratch->int1 = bp->status;
+ bp->status = RowStatus_destroy;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+static int
+bridge_port_rollback_status(struct snmp_context *ctx,
+ struct snmp_value *val, uint sub)
+{
+ int32_t if_idx;
+ char b_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
+ return (SNMP_ERR_GENERR);
+
+ if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
+ (bp = bridge_port_find(if_idx, bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ if (ctx->scratch->int1 == RowStatus_destroy)
+ bridge_port_remove(bp, bif);
+ else
+ bp->status = ctx->scratch->int1;
+
+ return (SNMP_ERR_NOERROR);
+}
+
+static int
+bridge_port_commit_status(struct snmp_value *val, uint sub)
+{
+ int32_t if_idx;
+ char b_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
+ return (SNMP_ERR_GENERR);
+
+ if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
+ (bp = bridge_port_find(if_idx, bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (bp->status) {
+ case RowStatus_active:
+ if (bridge_port_addm(bp, b_name) < 0)
+ return (SNMP_ERR_COMMIT_FAILED);
+ break;
+
+ case RowStatus_destroy:
+ if (bridge_port_delm(bp, b_name) < 0)
+ return (SNMP_ERR_COMMIT_FAILED);
+ bridge_port_remove(bp, bif);
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+static int
+bridge_port_set_span_enable(struct snmp_context *ctx,
+ struct snmp_value *val, uint sub)
+{
+ int32_t if_idx;
+ char b_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+ struct mibif *mif;
+
+ if (val->v.integer != begemotBridgeBaseSpanEnabled_enabled &&
+ val->v.integer != begemotBridgeBaseSpanEnabled_disabled)
+ return (SNMP_ERR_BADVALUE);
+
+ if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((bif = bridge_if_find_ifname(b_name)) == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((bp = bridge_port_find(if_idx, bif)) == NULL) {
+ if ((mif = mib_find_if(if_idx)) == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((bp = bridge_new_port(mif, bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ ctx->scratch->int1 = RowStatus_destroy;
+ } else if (bp->status == RowStatus_active) {
+ return (SNMP_ERR_INCONS_VALUE);
+ } else {
+ ctx->scratch->int1 = bp->status;
+ }
+
+ bp->span_enable = val->v.integer;
+ bp->status = RowStatus_notInService;
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_begemot_base_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ int8_t status, which;
+ const char *bname;
+ struct bridge_port *bp;
+
+ if (time(NULL) - ports_list_age > bridge_get_data_maxage())
+ bridge_update_all_ports();
+
+ which = val->var.subs[sub - 1];
+ status = 0;
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (which == LEAF_begemotBridgeBaseSpanEnabled ||
+ which == LEAF_begemotBridgeBasePortStatus)
+ status = 1;
+ if ((bp = bridge_port_index_get(&val->var, sub,
+ status)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if (which == LEAF_begemotBridgeBaseSpanEnabled ||
+ which == LEAF_begemotBridgeBasePortStatus)
+ status = 1;
+ if ((bp = bridge_port_index_getnext(&val->var, sub,
+ status)) == NULL ||
+ bridge_port_index_append(&val->var, sub, bp) < 0)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ switch (which) {
+ case LEAF_begemotBridgeBaseSpanEnabled:
+ return (bridge_port_set_span_enable(ctx, val, sub));
+
+ case LEAF_begemotBridgeBasePortStatus:
+ return (bridge_port_set_status(ctx, val, sub));
+
+ case LEAF_begemotBridgeBasePortPrivate:
+ if ((bp = bridge_port_index_get(&val->var, sub,
+ status)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+ ctx->scratch->int1 = bp->priv_set;
+ return (bridge_port_set_private(bname, bp,
+ val->v.integer));
+
+ case LEAF_begemotBridgeBasePort:
+ case LEAF_begemotBridgeBasePortIfIndex:
+ case LEAF_begemotBridgeBasePortDelayExceededDiscards:
+ case LEAF_begemotBridgeBasePortMtuExceededDiscards:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ switch (which) {
+ case LEAF_begemotBridgeBaseSpanEnabled:
+ /* FALLTHROUGH */
+ case LEAF_begemotBridgeBasePortStatus:
+ return (bridge_port_rollback_status(ctx, val, sub));
+ case LEAF_begemotBridgeBasePortPrivate:
+ if ((bp = bridge_port_index_get(&val->var, sub,
+ status)) == NULL)
+ return (SNMP_ERR_GENERR);
+ if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+ return (bridge_port_set_private(bname, bp,
+ ctx->scratch->int1));
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ if (which == LEAF_begemotBridgeBasePortStatus)
+ return (bridge_port_commit_status(val, sub));
+
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (which) {
+ case LEAF_begemotBridgeBasePort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBasePortIfIndex:
+ val->v.integer = bp->if_idx;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBaseSpanEnabled:
+ val->v.integer = bp->span_enable;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBasePortDelayExceededDiscards:
+ val->v.uint32 = bp->dly_ex_drops;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBasePortMtuExceededDiscards:
+ val->v.uint32 = bp->dly_mtu_drops;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBasePortStatus:
+ val->v.integer = bp->status;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBasePortPrivate:
+ val->v.integer = bp->priv_set;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_port *bp;
+ const char *b_name;
+
+ if (time(NULL) - ports_list_age > bridge_get_data_maxage())
+ bridge_update_all_ports();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
+ NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortPriority:
+ if (val->v.integer < 0 || val->v.integer > 255)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->priority;
+ if (bridge_port_set_priority(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortEnable:
+ if (val->v.integer !=
+ begemotBridgeStpPortEnable_enabled ||
+ val->v.integer !=
+ begemotBridgeStpPortEnable_disabled)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->enable;
+ if (bridge_port_set_stp_enable(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortPathCost:
+ if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
+ val->v.integer > SNMP_PORT_MAX_PATHCOST)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->path_cost;
+ if (bridge_port_set_path_cost(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPort:
+ case LEAF_begemotBridgeStpPortState:
+ case LEAF_begemotBridgeStpPortDesignatedRoot:
+ case LEAF_begemotBridgeStpPortDesignatedCost:
+ case LEAF_begemotBridgeStpPortDesignatedBridge:
+ case LEAF_begemotBridgeStpPortDesignatedPort:
+ case LEAF_begemotBridgeStpPortForwardTransitions:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
+ (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortPriority:
+ bridge_port_set_priority(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_begemotBridgeStpPortEnable:
+ bridge_port_set_stp_enable(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_begemotBridgeStpPortPathCost:
+ bridge_port_set_path_cost(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortPriority:
+ val->v.integer = bp->priority;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortState:
+ val->v.integer = bp->state;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortEnable:
+ val->v.integer = bp->enable;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortPathCost:
+ val->v.integer = bp->path_cost;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortDesignatedRoot:
+ return (string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_begemotBridgeStpPortDesignatedCost:
+ val->v.integer = bp->design_cost;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortDesignatedBridge:
+ return (string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_begemotBridgeStpPortDesignatedPort:
+ return (string_get(val, bp->design_port, 2));
+
+ case LEAF_begemotBridgeStpPortForwardTransitions:
+ val->v.uint32 = bp->fwd_trans;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_begemot_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_port *bp;
+ const char *b_name;
+
+ if (time(NULL) - ports_list_age > bridge_get_data_maxage())
+ bridge_update_all_ports();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
+ NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortAdminEdgePort:
+ if (val->v.integer != TruthValue_true &&
+ val->v.integer != TruthValue_false)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_edge;
+ if (bridge_port_set_admin_edge(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortAdminPointToPoint:
+ if (val->v.integer < 0 || val->v.integer >
+ StpPortAdminPointToPointType_auto)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_ptp;
+ if (bridge_port_set_admin_ptp(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortAdminPathCost:
+ if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
+ val->v.integer > SNMP_PORT_MAX_PATHCOST)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_path_cost;
+ if (bridge_port_set_path_cost(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortProtocolMigration:
+ case LEAF_begemotBridgeStpPortOperEdgePort:
+ case LEAF_begemotBridgeStpPortOperPointToPoint:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
+ (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortAdminEdgePort:
+ bridge_port_set_admin_edge(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_begemotBridgeStpPortAdminPointToPoint:
+ bridge_port_set_admin_ptp(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_begemotBridgeStpPortAdminPathCost:
+ bridge_port_set_path_cost(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortProtocolMigration:
+ val->v.integer = bp->proto_migr;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortAdminEdgePort:
+ val->v.integer = bp->admin_edge;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortOperEdgePort:
+ val->v.integer = bp->oper_edge;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortAdminPointToPoint:
+ val->v.integer = bp->admin_ptp;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortOperPointToPoint:
+ val->v.integer = bp->oper_ptp;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortAdminPathCost:
+ val->v.integer = bp->admin_path_cost;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_begemot_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_port *bp;
+
+ if (time(NULL) - ports_list_age > bridge_get_data_maxage())
+ bridge_update_all_ports();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
+ NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ break;
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeTpPort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpPortMaxInfo:
+ val->v.integer = bp->max_info;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpPortInFrames:
+ val->v.uint32 = bp->in_frames;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpPortOutFrames:
+ val->v.uint32 = bp->out_frames;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpPortInDiscards:
+ val->v.uint32 = bp->in_drops;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
OpenPOWER on IntegriCloud