e1d581b289
MFC after: 3 weeks
1480 lines
36 KiB
C
1480 lines
36 KiB
C
/*-
|
|
* 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 interface objects.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include <sys/queue.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <net/ethernet.h>
|
|
#include <net/if.h>
|
|
#include <net/if_mib.h>
|
|
#include <net/if_types.h>
|
|
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
|
|
#include <bsnmp/snmpmod.h>
|
|
#include <bsnmp/snmp_mibII.h>
|
|
|
|
#include "bridge_tree.h"
|
|
#include "bridge_snmp.h"
|
|
#include "bridge_oid.h"
|
|
|
|
static const struct asn_oid oid_newRoot = OIDX_newRoot;
|
|
static const struct asn_oid oid_TopologyChange = OIDX_topologyChange;
|
|
static const struct asn_oid oid_begemotBrigeName = \
|
|
OIDX_begemotBridgeBaseName;
|
|
static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;
|
|
static const struct asn_oid oid_begemotTopologyChange = \
|
|
OIDX_begemotBridgeTopologyChange;
|
|
|
|
TAILQ_HEAD(bridge_ifs, bridge_if);
|
|
|
|
/*
|
|
* Free the bridge interface list.
|
|
*/
|
|
static void
|
|
bridge_ifs_free(struct bridge_ifs *headp)
|
|
{
|
|
struct bridge_if *b;
|
|
|
|
while ((b = TAILQ_FIRST(headp)) != NULL) {
|
|
TAILQ_REMOVE(headp, b, b_if);
|
|
free(b);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Insert an entry in the bridge interface TAILQ. Keep the
|
|
* TAILQ sorted by the bridge's interface name.
|
|
*/
|
|
static void
|
|
bridge_ifs_insert(struct bridge_ifs *headp,
|
|
struct bridge_if *b)
|
|
{
|
|
struct bridge_if *temp;
|
|
|
|
if ((temp = TAILQ_FIRST(headp)) == NULL ||
|
|
strcmp(b->bif_name, temp->bif_name) < 0) {
|
|
TAILQ_INSERT_HEAD(headp, b, b_if);
|
|
return;
|
|
}
|
|
|
|
TAILQ_FOREACH(temp, headp, b_if)
|
|
if(strcmp(b->bif_name, temp->bif_name) < 0)
|
|
TAILQ_INSERT_BEFORE(temp, b, b_if);
|
|
|
|
TAILQ_INSERT_TAIL(headp, b, b_if);
|
|
}
|
|
|
|
/* The global bridge interface list. */
|
|
static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);
|
|
static time_t bridge_list_age;
|
|
|
|
/*
|
|
* Free the global list.
|
|
*/
|
|
void
|
|
bridge_ifs_fini(void)
|
|
{
|
|
bridge_ifs_free(&bridge_ifs);
|
|
}
|
|
|
|
/*
|
|
* Find a bridge interface entry by the bridge interface system index.
|
|
*/
|
|
struct bridge_if *
|
|
bridge_if_find_ifs(uint32_t sysindex)
|
|
{
|
|
struct bridge_if *b;
|
|
|
|
TAILQ_FOREACH(b, &bridge_ifs, b_if)
|
|
if (b->sysindex == sysindex)
|
|
return (b);
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
/*
|
|
* Find a bridge interface entry by the bridge interface name.
|
|
*/
|
|
struct bridge_if *
|
|
bridge_if_find_ifname(const char *b_name)
|
|
{
|
|
struct bridge_if *b;
|
|
|
|
TAILQ_FOREACH(b, &bridge_ifs, b_if)
|
|
if (strcmp(b_name, b->bif_name) == 0)
|
|
return (b);
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
/*
|
|
* Find a bridge name by the bridge interface system index.
|
|
*/
|
|
const char *
|
|
bridge_if_find_name(uint32_t sysindex)
|
|
{
|
|
struct bridge_if *b;
|
|
|
|
TAILQ_FOREACH(b, &bridge_ifs, b_if)
|
|
if (b->sysindex == sysindex)
|
|
return (b->bif_name);
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
/*
|
|
* Given two bridge interfaces' system indexes, find their
|
|
* corresponding names and return the result of the name
|
|
* comparison. Returns:
|
|
* error : -2
|
|
* i1 < i2 : -1
|
|
* i1 > i2 : +1
|
|
* i1 = i2 : 0
|
|
*/
|
|
int
|
|
bridge_compare_sysidx(uint32_t i1, uint32_t i2)
|
|
{
|
|
int c;
|
|
const char *b1, *b2;
|
|
|
|
if (i1 == i2)
|
|
return (0);
|
|
|
|
if ((b1 = bridge_if_find_name(i1)) == NULL) {
|
|
syslog(LOG_ERR, "Bridge interface %d does not exist", i1);
|
|
return (-2);
|
|
}
|
|
|
|
if ((b2 = bridge_if_find_name(i2)) == NULL) {
|
|
syslog(LOG_ERR, "Bridge interface %d does not exist", i2);
|
|
return (-2);
|
|
}
|
|
|
|
if ((c = strcmp(b1, b2)) < 0)
|
|
return (-1);
|
|
else if (c > 0)
|
|
return (1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Fetch the first bridge interface from the list.
|
|
*/
|
|
struct bridge_if *
|
|
bridge_first_bif(void)
|
|
{
|
|
return (TAILQ_FIRST(&bridge_ifs));
|
|
}
|
|
|
|
/*
|
|
* Fetch the next bridge interface from the list.
|
|
*/
|
|
struct bridge_if *
|
|
bridge_next_bif(struct bridge_if *b_pr)
|
|
{
|
|
return (TAILQ_NEXT(b_pr, b_if));
|
|
}
|
|
|
|
/*
|
|
* Create a new entry for a bridge interface and insert
|
|
* it in the list.
|
|
*/
|
|
static struct bridge_if *
|
|
bridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr)
|
|
{
|
|
struct bridge_if *bif;
|
|
|
|
if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) {
|
|
syslog(LOG_ERR, "bridge new interface failed: %s",
|
|
strerror(errno));
|
|
return (NULL);
|
|
}
|
|
|
|
bzero(bif, sizeof(struct bridge_if));
|
|
strlcpy(bif->bif_name, bif_n, IFNAMSIZ);
|
|
bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
|
|
bif->sysindex = sysindex;
|
|
bif->br_type = BaseType_transparent_only;
|
|
/* 1 - all bridges default hold time * 100 - centi-seconds */
|
|
bif->hold_time = 1 * 100;
|
|
bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d;
|
|
bridge_ifs_insert(&bridge_ifs, bif);
|
|
|
|
return (bif);
|
|
}
|
|
|
|
/*
|
|
* Remove a bridge interface from the list, freeing all it's ports
|
|
* and address entries.
|
|
*/
|
|
void
|
|
bridge_remove_bif(struct bridge_if *bif)
|
|
{
|
|
bridge_members_free(bif);
|
|
bridge_addrs_free(bif);
|
|
TAILQ_REMOVE(&bridge_ifs, bif, b_if);
|
|
free(bif);
|
|
}
|
|
|
|
|
|
/*
|
|
* Prepare the variable (bridge interface name) for the private
|
|
* begemot notifications.
|
|
*/
|
|
static struct snmp_value*
|
|
bridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val)
|
|
{
|
|
uint i;
|
|
|
|
b_val->var = oid_begemotBrigeName;
|
|
b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name);
|
|
|
|
if ((b_val->v.octetstring.octets = (u_char *)
|
|
malloc(strlen(bif->bif_name))) == NULL)
|
|
return (NULL);
|
|
|
|
for (i = 0; i < strlen(bif->bif_name); i++)
|
|
b_val->var.subs[b_val->var.len++] = bif->bif_name[i];
|
|
|
|
b_val->v.octetstring.len = strlen(bif->bif_name);
|
|
bcopy(bif->bif_name, b_val->v.octetstring.octets,
|
|
strlen(bif->bif_name));
|
|
b_val->syntax = SNMP_SYNTAX_OCTETSTRING;
|
|
|
|
return (b_val);
|
|
}
|
|
|
|
/*
|
|
* Compare the values of the old and the new root port and
|
|
* send a new root notification, if they are not matching.
|
|
*/
|
|
static void
|
|
bridge_new_root(struct bridge_if *bif)
|
|
{
|
|
struct snmp_value bif_idx;
|
|
|
|
if (bridge_get_default() == bif)
|
|
snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL);
|
|
|
|
if (bridge_basename_var(bif, &bif_idx) == NULL)
|
|
return;
|
|
|
|
snmp_send_trap(&oid_begemotTopologyChange,
|
|
&bif_idx, (struct snmp_value *) NULL);
|
|
}
|
|
|
|
/*
|
|
* Compare the new and old topology change times and send a
|
|
* topology change notification if necessary.
|
|
*/
|
|
static void
|
|
bridge_top_change(struct bridge_if *bif)
|
|
{
|
|
struct snmp_value bif_idx;
|
|
|
|
if (bridge_get_default() == bif)
|
|
snmp_send_trap(&oid_TopologyChange,
|
|
(struct snmp_value *) NULL);
|
|
|
|
if (bridge_basename_var(bif, &bif_idx) == NULL)
|
|
return;
|
|
|
|
snmp_send_trap(&oid_begemotNewRoot,
|
|
&bif_idx, (struct snmp_value *) NULL);
|
|
}
|
|
|
|
static int
|
|
bridge_if_create(const char* b_name, int8_t up)
|
|
{
|
|
if (bridge_create(b_name) < 0)
|
|
return (-1);
|
|
|
|
if (up == 1 && (bridge_set_if_up(b_name, 1) < 0))
|
|
return (-1);
|
|
|
|
/*
|
|
* Do not create a new bridge entry here -
|
|
* wait until the mibII module notifies us.
|
|
*/
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
bridge_if_destroy(struct bridge_if *bif)
|
|
{
|
|
if (bridge_destroy(bif->bif_name) < 0)
|
|
return (-1);
|
|
|
|
bridge_remove_bif(bif);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Calculate the timeticks since the last topology change.
|
|
*/
|
|
static int
|
|
bridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks)
|
|
{
|
|
struct timeval ct;
|
|
|
|
if (gettimeofday(&ct, NULL) < 0) {
|
|
syslog(LOG_ERR, "bridge get time since last TC:"
|
|
"gettimeofday failed: %s", strerror(errno));
|
|
return (-1);
|
|
}
|
|
|
|
if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) {
|
|
ct.tv_sec -= 1;
|
|
ct.tv_usec += 1000000;
|
|
}
|
|
|
|
ct.tv_sec -= bif->last_tc_time.tv_sec;
|
|
ct.tv_usec -= bif->last_tc_time.tv_usec;
|
|
|
|
*ticks = ct.tv_sec * 100 + ct.tv_usec/10000;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Update the info we have for a single bridge interface.
|
|
* Return:
|
|
* 1, if successful
|
|
* 0, if the interface was deleted
|
|
* -1, error occurred while fetching the info from the kernel.
|
|
*/
|
|
static int
|
|
bridge_update_bif(struct bridge_if *bif)
|
|
{
|
|
struct mibif *ifp;
|
|
|
|
/* Walk through the mibII interface list. */
|
|
for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
|
|
if (strcmp(ifp->name, bif->bif_name) == 0)
|
|
break;
|
|
|
|
if (ifp == NULL) {
|
|
/* Ops, we do not exist anymore. */
|
|
bridge_remove_bif(bif);
|
|
return (0);
|
|
}
|
|
|
|
if (ifp->physaddr != NULL )
|
|
bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
|
|
else
|
|
bridge_get_basemac(bif->bif_name, bif->br_addr.octet,
|
|
ETHER_ADDR_LEN);
|
|
|
|
if (ifp->mib.ifmd_flags & IFF_RUNNING)
|
|
bif->if_status = RowStatus_active;
|
|
else
|
|
bif->if_status = RowStatus_notInService;
|
|
|
|
switch (bridge_getinfo_bif(bif)) {
|
|
case 2:
|
|
bridge_new_root(bif);
|
|
break;
|
|
case 1:
|
|
bridge_top_change(bif);
|
|
break;
|
|
case -1:
|
|
bridge_remove_bif(bif);
|
|
return (-1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* The number of ports is accessible via SNMP -
|
|
* update the ports each time the bridge interface data
|
|
* is refreshed too.
|
|
*/
|
|
bif->num_ports = bridge_update_memif(bif);
|
|
bif->entry_age = time(NULL);
|
|
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Update all bridge interfaces' ports only -
|
|
* make sure each bridge interface exists first.
|
|
*/
|
|
void
|
|
bridge_update_all_ports(void)
|
|
{
|
|
struct mibif *ifp;
|
|
struct bridge_if *bif, *t_bif;
|
|
|
|
for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
|
|
t_bif = bridge_next_bif(bif);
|
|
|
|
for (ifp = mib_first_if(); ifp != NULL;
|
|
ifp = mib_next_if(ifp))
|
|
if (strcmp(ifp->name, bif->bif_name) == 0)
|
|
break;
|
|
|
|
if (ifp != NULL)
|
|
bif->num_ports = bridge_update_memif(bif);
|
|
else /* Ops, we do not exist anymore. */
|
|
bridge_remove_bif(bif);
|
|
}
|
|
|
|
bridge_ports_update_listage();
|
|
}
|
|
|
|
/*
|
|
* Update all addresses only.
|
|
*/
|
|
void
|
|
bridge_update_all_addrs(void)
|
|
{
|
|
struct mibif *ifp;
|
|
struct bridge_if *bif, *t_bif;
|
|
|
|
for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
|
|
t_bif = bridge_next_bif(bif);
|
|
|
|
for (ifp = mib_first_if(); ifp != NULL;
|
|
ifp = mib_next_if(ifp))
|
|
if (strcmp(ifp->name, bif->bif_name) == 0)
|
|
break;
|
|
|
|
if (ifp != NULL)
|
|
bif->num_addrs = bridge_update_addrs(bif);
|
|
else /* Ops, we don't exist anymore. */
|
|
bridge_remove_bif(bif);
|
|
}
|
|
|
|
bridge_addrs_update_listage();
|
|
}
|
|
|
|
/*
|
|
* Update only the bridge interfaces' data - skip addresses.
|
|
*/
|
|
void
|
|
bridge_update_all_ifs(void)
|
|
{
|
|
struct bridge_if *bif, *t_bif;
|
|
|
|
for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
|
|
t_bif = bridge_next_bif(bif);
|
|
bridge_update_bif(bif);
|
|
}
|
|
|
|
bridge_ports_update_listage();
|
|
bridge_list_age = time(NULL);
|
|
}
|
|
|
|
/*
|
|
* Update all info we have for all bridges.
|
|
*/
|
|
void
|
|
bridge_update_all(void *arg __unused)
|
|
{
|
|
struct bridge_if *bif, *t_bif;
|
|
|
|
for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
|
|
t_bif = bridge_next_bif(bif);
|
|
if (bridge_update_bif(bif) <= 0)
|
|
continue;
|
|
|
|
/* Update our learnt addresses. */
|
|
bif->num_addrs = bridge_update_addrs(bif);
|
|
}
|
|
|
|
bridge_list_age = time(NULL);
|
|
bridge_ports_update_listage();
|
|
bridge_addrs_update_listage();
|
|
}
|
|
|
|
/*
|
|
* Callback for polling our last topology change time -
|
|
* check whether we are root or whether a TC was detected once every
|
|
* 30 seconds, so that we can send the newRoot and TopologyChange traps
|
|
* on time. The rest of the data is polled only once every 5 min.
|
|
*/
|
|
void
|
|
bridge_update_tc_time(void *arg __unused)
|
|
{
|
|
struct bridge_if *bif;
|
|
struct mibif *ifp;
|
|
|
|
TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
|
|
/* Walk through the mibII interface list. */
|
|
for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
|
|
if (strcmp(ifp->name, bif->bif_name) == 0)
|
|
break;
|
|
|
|
if (ifp == NULL) {
|
|
bridge_remove_bif(bif);
|
|
continue;
|
|
}
|
|
|
|
switch (bridge_get_op_param(bif)) {
|
|
case 2:
|
|
bridge_new_root(bif);
|
|
break;
|
|
case 1:
|
|
bridge_top_change(bif);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Callback for handling new bridge interface creation.
|
|
*/
|
|
int
|
|
bridge_attach_newif(struct mibif *ifp)
|
|
{
|
|
u_char mac[ETHER_ADDR_LEN];
|
|
struct bridge_if *bif;
|
|
|
|
if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
|
|
return (0);
|
|
|
|
/* Make sure it does not exist in our list. */
|
|
TAILQ_FOREACH(bif, &bridge_ifs, b_if)
|
|
if(strcmp(bif->bif_name, ifp->name) == 0) {
|
|
syslog(LOG_ERR, "bridge interface %s already "
|
|
"in list", bif->bif_name);
|
|
return (-1);
|
|
}
|
|
|
|
if (ifp->physaddr == NULL) {
|
|
if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) {
|
|
syslog(LOG_ERR, "bridge attach new %s failed - "
|
|
"no bridge mac address", ifp->name);
|
|
return (-1);
|
|
}
|
|
} else
|
|
bcopy(ifp->physaddr, &mac, sizeof(mac));
|
|
|
|
if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL)
|
|
return (-1);
|
|
|
|
if (ifp->mib.ifmd_flags & IFF_RUNNING)
|
|
bif->if_status = RowStatus_active;
|
|
else
|
|
bif->if_status = RowStatus_notInService;
|
|
|
|
/* Skip sending notifications if the interface was just created. */
|
|
if (bridge_getinfo_bif(bif) < 0 ||
|
|
(bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
|
|
(bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
|
|
bridge_remove_bif(bif);
|
|
return (-1);
|
|
}
|
|
|
|
/* Check whether we are the default bridge interface. */
|
|
if (strcmp(ifp->name, bridge_get_default_name()) == 0)
|
|
bridge_set_default(bif);
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
bridge_ifs_dump(void)
|
|
{
|
|
struct bridge_if *bif;
|
|
|
|
for (bif = bridge_first_bif(); bif != NULL;
|
|
bif = bridge_next_bif(bif)) {
|
|
syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
|
|
bif->sysindex);
|
|
bridge_ports_dump(bif);
|
|
bridge_addrs_dump(bif);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* RFC4188 specifics.
|
|
*/
|
|
int
|
|
op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
|
|
uint sub, uint iidx __unused, enum snmp_op op)
|
|
{
|
|
struct bridge_if *bif;
|
|
|
|
if ((bif = bridge_get_default()) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
|
|
bridge_update_bif(bif) <= 0) /* It was just deleted. */
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
switch (op) {
|
|
case SNMP_OP_GET:
|
|
switch (value->var.subs[sub - 1]) {
|
|
case LEAF_dot1dBaseBridgeAddress:
|
|
return (string_get(value, bif->br_addr.octet,
|
|
ETHER_ADDR_LEN));
|
|
case LEAF_dot1dBaseNumPorts:
|
|
value->v.integer = bif->num_ports;
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_dot1dBaseType:
|
|
value->v.integer = bif->br_type;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_SET:
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
case SNMP_OP_ROLLBACK:
|
|
case SNMP_OP_COMMIT:
|
|
break;
|
|
}
|
|
|
|
abort();
|
|
}
|
|
|
|
int
|
|
op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub,
|
|
uint iidx __unused, enum snmp_op op)
|
|
{
|
|
struct bridge_if *bif;
|
|
|
|
if ((bif = bridge_get_default()) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
|
|
bridge_update_bif(bif) <= 0) /* It was just deleted. */
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
switch (op) {
|
|
case SNMP_OP_GET:
|
|
switch (val->var.subs[sub - 1]) {
|
|
case LEAF_dot1dStpProtocolSpecification:
|
|
val->v.integer = bif->prot_spec;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpPriority:
|
|
val->v.integer = bif->priority;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpTimeSinceTopologyChange:
|
|
if (bridge_get_time_since_tc(bif,
|
|
&(val->v.uint32)) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpTopChanges:
|
|
val->v.uint32 = bif->top_changes;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpDesignatedRoot:
|
|
return (string_get(val, bif->design_root,
|
|
SNMP_BRIDGE_ID_LEN));
|
|
|
|
case LEAF_dot1dStpRootCost:
|
|
val->v.integer = bif->root_cost;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpRootPort:
|
|
val->v.integer = bif->root_port;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpMaxAge:
|
|
val->v.integer = bif->max_age;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpHelloTime:
|
|
val->v.integer = bif->hello_time;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpHoldTime:
|
|
val->v.integer = bif->hold_time;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpForwardDelay:
|
|
val->v.integer = bif->fwd_delay;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpBridgeMaxAge:
|
|
val->v.integer = bif->bridge_max_age;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpBridgeHelloTime:
|
|
val->v.integer = bif->bridge_hello_time;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpBridgeForwardDelay:
|
|
val->v.integer = bif->bridge_fwd_delay;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpVersion:
|
|
val->v.integer = bif->stp_version;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpTxHoldCount:
|
|
val->v.integer = bif->tx_hold_count;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
abort();
|
|
|
|
case SNMP_OP_SET:
|
|
switch (val->var.subs[sub - 1]) {
|
|
case LEAF_dot1dStpPriority:
|
|
if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
|
|
val->v.integer % 4096 != 0)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->priority;
|
|
if (bridge_set_priority(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpBridgeMaxAge:
|
|
if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
|
|
val->v.integer > SNMP_BRIDGE_MAX_MAGE)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->bridge_max_age;
|
|
if (bridge_set_maxage(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpBridgeHelloTime:
|
|
if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
|
|
val->v.integer > SNMP_BRIDGE_MAX_HTIME)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->bridge_hello_time;
|
|
if (bridge_set_hello_time(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpBridgeForwardDelay:
|
|
if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
|
|
val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->bridge_fwd_delay;
|
|
if (bridge_set_forward_delay(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpVersion:
|
|
if (val->v.integer != dot1dStpVersion_stpCompatible &&
|
|
val->v.integer != dot1dStpVersion_rstp)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->stp_version;
|
|
if (bridge_set_stp_version(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpTxHoldCount:
|
|
if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
|
|
val->v.integer > SNMP_BRIDGE_MAX_TXHC)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->tx_hold_count;
|
|
if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_dot1dStpProtocolSpecification:
|
|
case LEAF_dot1dStpTimeSinceTopologyChange:
|
|
case LEAF_dot1dStpTopChanges:
|
|
case LEAF_dot1dStpDesignatedRoot:
|
|
case LEAF_dot1dStpRootCost:
|
|
case LEAF_dot1dStpRootPort:
|
|
case LEAF_dot1dStpMaxAge:
|
|
case LEAF_dot1dStpHelloTime:
|
|
case LEAF_dot1dStpHoldTime:
|
|
case LEAF_dot1dStpForwardDelay:
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
switch (val->var.subs[sub - 1]) {
|
|
case LEAF_dot1dStpPriority:
|
|
bridge_set_priority(bif, ctx->scratch->int1);
|
|
break;
|
|
case LEAF_dot1dStpBridgeMaxAge:
|
|
bridge_set_maxage(bif, ctx->scratch->int1);
|
|
break;
|
|
case LEAF_dot1dStpBridgeHelloTime:
|
|
bridge_set_hello_time(bif, ctx->scratch->int1);
|
|
break;
|
|
case LEAF_dot1dStpBridgeForwardDelay:
|
|
bridge_set_forward_delay(bif, ctx->scratch->int1);
|
|
break;
|
|
case LEAF_dot1dStpVersion:
|
|
bridge_set_stp_version(bif, ctx->scratch->int1);
|
|
break;
|
|
case LEAF_dot1dStpTxHoldCount:
|
|
bridge_set_tx_hold_count(bif, ctx->scratch->int1);
|
|
break;
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_COMMIT:
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
abort();
|
|
}
|
|
|
|
int
|
|
op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
|
|
uint sub, uint iidx __unused, enum snmp_op op)
|
|
{
|
|
struct bridge_if *bif;
|
|
|
|
if ((bif = bridge_get_default()) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
|
|
bridge_update_bif(bif) <= 0) /* It was just deleted. */
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
switch (op) {
|
|
case SNMP_OP_GET:
|
|
switch (value->var.subs[sub - 1]) {
|
|
case LEAF_dot1dTpLearnedEntryDiscards:
|
|
value->v.uint32 = bif->lrnt_drops;
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_dot1dTpAgingTime:
|
|
value->v.integer = bif->age_time;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
abort();
|
|
|
|
case SNMP_OP_SET:
|
|
switch (value->var.subs[sub - 1]) {
|
|
case LEAF_dot1dTpLearnedEntryDiscards:
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
|
|
case LEAF_dot1dTpAgingTime:
|
|
if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
|
|
value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->age_time;
|
|
if (bridge_set_aging_time(bif, value->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
|
|
bridge_set_aging_time(bif, ctx->scratch->int1);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_COMMIT:
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
* Private BEGEMOT-BRIDGE-MIB specifics.
|
|
*/
|
|
|
|
/*
|
|
* Get the bridge name from an OID index.
|
|
*/
|
|
static char *
|
|
bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
|
|
{
|
|
uint i;
|
|
|
|
if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
|
|
return (NULL);
|
|
|
|
for (i = 0; i < oid->subs[sub]; i++)
|
|
b_name[i] = oid->subs[sub + i + 1];
|
|
b_name[i] = '\0';
|
|
|
|
return (b_name);
|
|
}
|
|
|
|
static void
|
|
bridge_if_index_append(struct asn_oid *oid, uint sub,
|
|
const struct bridge_if *bif)
|
|
{
|
|
uint i;
|
|
|
|
oid->len = sub + strlen(bif->bif_name) + 1;
|
|
oid->subs[sub] = strlen(bif->bif_name);
|
|
|
|
for (i = 1; i <= strlen(bif->bif_name); i++)
|
|
oid->subs[sub + i] = bif->bif_name[i - 1];
|
|
}
|
|
|
|
static struct bridge_if *
|
|
bridge_if_index_get(const struct asn_oid *oid, uint sub)
|
|
{
|
|
uint i;
|
|
char bif_name[IFNAMSIZ];
|
|
|
|
if (oid->len - sub != oid->subs[sub] + 1 || 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';
|
|
|
|
return (bridge_if_find_ifname(bif_name));
|
|
}
|
|
|
|
static struct bridge_if *
|
|
bridge_if_index_getnext(const struct asn_oid *oid, uint sub)
|
|
{
|
|
uint i;
|
|
char bif_name[IFNAMSIZ];
|
|
struct bridge_if *bif;
|
|
|
|
if (oid->len - sub == 0)
|
|
return (bridge_first_bif());
|
|
|
|
if (oid->len - sub != oid->subs[sub] + 1 || 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';
|
|
|
|
if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
|
|
return (NULL);
|
|
|
|
return (bridge_next_bif(bif));
|
|
}
|
|
|
|
static int
|
|
bridge_set_if_status(struct snmp_context *ctx,
|
|
struct snmp_value *val, uint sub)
|
|
{
|
|
struct bridge_if *bif;
|
|
char bif_name[IFNAMSIZ];
|
|
|
|
bif = bridge_if_index_get(&val->var, sub);
|
|
|
|
switch (val->v.integer) {
|
|
case RowStatus_active:
|
|
if (bif == NULL)
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->if_status;
|
|
|
|
switch (bif->if_status) {
|
|
case RowStatus_active:
|
|
return (SNMP_ERR_NOERROR);
|
|
case RowStatus_notInService:
|
|
if (bridge_set_if_up(bif->bif_name, 1) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
default:
|
|
break;
|
|
}
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
|
|
case RowStatus_notInService:
|
|
if (bif == NULL)
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->if_status;
|
|
|
|
switch (bif->if_status) {
|
|
case RowStatus_active:
|
|
if (bridge_set_if_up(bif->bif_name, 1) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
case RowStatus_notInService:
|
|
return (SNMP_ERR_NOERROR);
|
|
default:
|
|
break;
|
|
}
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
|
|
case RowStatus_notReady:
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
|
|
case RowStatus_createAndGo:
|
|
if (bif != NULL)
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
|
|
ctx->scratch->int1 = RowStatus_destroy;
|
|
|
|
if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
|
|
return (SNMP_ERR_BADVALUE);
|
|
if (bridge_if_create(bif_name, 1) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case RowStatus_createAndWait:
|
|
if (bif != NULL)
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
|
|
if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
|
|
return (SNMP_ERR_BADVALUE);
|
|
|
|
ctx->scratch->int1 = RowStatus_destroy;
|
|
|
|
if (bridge_if_create(bif_name, 0) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case RowStatus_destroy:
|
|
if (bif == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
ctx->scratch->int1 = bif->if_status;
|
|
bif->if_status = RowStatus_destroy;
|
|
}
|
|
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
static int
|
|
bridge_rollback_if_status(struct snmp_context *ctx,
|
|
struct snmp_value *val, uint sub)
|
|
{
|
|
struct bridge_if *bif;
|
|
|
|
if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_GENERR);
|
|
|
|
switch (ctx->scratch->int1) {
|
|
case RowStatus_destroy:
|
|
bridge_if_destroy(bif);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case RowStatus_notInService:
|
|
if (bif->if_status != ctx->scratch->int1)
|
|
bridge_set_if_up(bif->bif_name, 0);
|
|
bif->if_status = RowStatus_notInService;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case RowStatus_active:
|
|
if (bif->if_status != ctx->scratch->int1)
|
|
bridge_set_if_up(bif->bif_name, 1);
|
|
bif->if_status = RowStatus_active;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
abort();
|
|
}
|
|
|
|
static int
|
|
bridge_commit_if_status(struct snmp_value *val, uint sub)
|
|
{
|
|
struct bridge_if *bif;
|
|
|
|
if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_GENERR);
|
|
|
|
if (bif->if_status == RowStatus_destroy &&
|
|
bridge_if_destroy(bif) < 0)
|
|
return (SNMP_ERR_COMMIT_FAILED);
|
|
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
int
|
|
op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
|
|
uint sub, uint iidx __unused, enum snmp_op op)
|
|
{
|
|
struct bridge_if *bif;
|
|
|
|
if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
|
|
bridge_update_all_ifs();
|
|
|
|
switch (op) {
|
|
case SNMP_OP_GET:
|
|
if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
goto get;
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
bridge_if_index_append(&val->var, sub, bif);
|
|
goto get;
|
|
|
|
case SNMP_OP_SET:
|
|
switch (val->var.subs[sub - 1]) {
|
|
case LEAF_begemotBridgeBaseStatus:
|
|
return (bridge_set_if_status(ctx, val, sub));
|
|
case LEAF_begemotBridgeBaseName:
|
|
case LEAF_begemotBridgeBaseAddress:
|
|
case LEAF_begemotBridgeBaseNumPorts:
|
|
case LEAF_begemotBridgeBaseType:
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
return (bridge_rollback_if_status(ctx, val, sub));
|
|
|
|
case SNMP_OP_COMMIT:
|
|
return (bridge_commit_if_status(val, sub));
|
|
}
|
|
abort();
|
|
|
|
get:
|
|
switch (val->var.subs[sub - 1]) {
|
|
case LEAF_begemotBridgeBaseName:
|
|
return (string_get(val, bif->bif_name, -1));
|
|
|
|
case LEAF_begemotBridgeBaseAddress:
|
|
return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN));
|
|
|
|
case LEAF_begemotBridgeBaseNumPorts:
|
|
val->v.integer = bif->num_ports;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeBaseType:
|
|
val->v.integer = bif->br_type;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeBaseStatus:
|
|
val->v.integer = bif->if_status;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
abort();
|
|
}
|
|
|
|
int
|
|
op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
|
|
uint sub, uint iidx __unused, enum snmp_op op)
|
|
{
|
|
struct bridge_if *bif;
|
|
|
|
if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
|
|
bridge_update_all_ifs();
|
|
|
|
switch (op) {
|
|
case SNMP_OP_GET:
|
|
if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
goto get;
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
bridge_if_index_append(&val->var, sub, bif);
|
|
goto get;
|
|
|
|
case SNMP_OP_SET:
|
|
if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
switch (val->var.subs[sub - 1]) {
|
|
case LEAF_begemotBridgeStpPriority:
|
|
if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
|
|
val->v.integer % 4096 != 0)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->priority;
|
|
if (bridge_set_priority(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpBridgeMaxAge:
|
|
if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
|
|
val->v.integer > SNMP_BRIDGE_MAX_MAGE)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->bridge_max_age;
|
|
if (bridge_set_maxage(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpBridgeHelloTime:
|
|
if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
|
|
val->v.integer > SNMP_BRIDGE_MAX_HTIME)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->bridge_hello_time;
|
|
if (bridge_set_hello_time(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpBridgeForwardDelay:
|
|
if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
|
|
val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->bridge_fwd_delay;
|
|
if (bridge_set_forward_delay(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpVersion:
|
|
if (val->v.integer !=
|
|
begemotBridgeStpVersion_stpCompatible &&
|
|
val->v.integer != begemotBridgeStpVersion_rstp)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->stp_version;
|
|
if (bridge_set_stp_version(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpTxHoldCount:
|
|
if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
|
|
val->v.integer > SNMP_BRIDGE_MAX_TXHC)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->tx_hold_count;
|
|
if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpProtocolSpecification:
|
|
case LEAF_begemotBridgeStpTimeSinceTopologyChange:
|
|
case LEAF_begemotBridgeStpTopChanges:
|
|
case LEAF_begemotBridgeStpDesignatedRoot:
|
|
case LEAF_begemotBridgeStpRootCost:
|
|
case LEAF_begemotBridgeStpRootPort:
|
|
case LEAF_begemotBridgeStpMaxAge:
|
|
case LEAF_begemotBridgeStpHelloTime:
|
|
case LEAF_begemotBridgeStpHoldTime:
|
|
case LEAF_begemotBridgeStpForwardDelay:
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
switch (val->var.subs[sub - 1]) {
|
|
case LEAF_begemotBridgeStpPriority:
|
|
bridge_set_priority(bif, ctx->scratch->int1);
|
|
break;
|
|
|
|
case LEAF_begemotBridgeStpBridgeMaxAge:
|
|
bridge_set_maxage(bif, ctx->scratch->int1);
|
|
break;
|
|
|
|
case LEAF_begemotBridgeStpBridgeHelloTime:
|
|
bridge_set_hello_time(bif, ctx->scratch->int1);
|
|
break;
|
|
|
|
case LEAF_begemotBridgeStpBridgeForwardDelay:
|
|
bridge_set_forward_delay(bif, ctx->scratch->int1);
|
|
break;
|
|
|
|
case LEAF_begemotBridgeStpVersion:
|
|
bridge_set_stp_version(bif, ctx->scratch->int1);
|
|
break;
|
|
|
|
case LEAF_begemotBridgeStpTxHoldCount:
|
|
bridge_set_tx_hold_count(bif, 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_begemotBridgeStpProtocolSpecification:
|
|
val->v.integer = bif->prot_spec;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpPriority:
|
|
val->v.integer = bif->priority;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpTimeSinceTopologyChange:
|
|
if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpTopChanges:
|
|
val->v.uint32 = bif->top_changes;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpDesignatedRoot:
|
|
return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN));
|
|
|
|
case LEAF_begemotBridgeStpRootCost:
|
|
val->v.integer = bif->root_cost;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpRootPort:
|
|
val->v.integer = bif->root_port;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpMaxAge:
|
|
val->v.integer = bif->max_age;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpHelloTime:
|
|
val->v.integer = bif->hello_time;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpHoldTime:
|
|
val->v.integer = bif->hold_time;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpForwardDelay:
|
|
val->v.integer = bif->fwd_delay;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpBridgeMaxAge:
|
|
val->v.integer = bif->bridge_max_age;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpBridgeHelloTime:
|
|
val->v.integer = bif->bridge_hello_time;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpBridgeForwardDelay:
|
|
val->v.integer = bif->bridge_fwd_delay;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpVersion:
|
|
val->v.integer = bif->stp_version;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeStpTxHoldCount:
|
|
val->v.integer = bif->tx_hold_count;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
abort();
|
|
}
|
|
|
|
int
|
|
op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
|
|
uint sub, uint iidx __unused, enum snmp_op op)
|
|
{
|
|
struct bridge_if *bif;
|
|
|
|
if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
|
|
bridge_update_all_ifs();
|
|
|
|
switch (op) {
|
|
case SNMP_OP_GET:
|
|
if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
goto get;
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
bridge_if_index_append(&val->var, sub, bif);
|
|
goto get;
|
|
|
|
case SNMP_OP_SET:
|
|
if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
switch (val->var.subs[sub - 1]) {
|
|
case LEAF_begemotBridgeTpAgingTime:
|
|
if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
|
|
val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int1 = bif->age_time;
|
|
if (bridge_set_aging_time(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeTpMaxAddresses:
|
|
ctx->scratch->int1 = bif->max_addrs;
|
|
if (bridge_set_max_cache(bif, val->v.integer) < 0)
|
|
return (SNMP_ERR_GENERR);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeTpLearnedEntryDiscards:
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
|
|
return (SNMP_ERR_GENERR);
|
|
|
|
switch (val->var.subs[sub - 1]) {
|
|
case LEAF_begemotBridgeTpAgingTime:
|
|
bridge_set_aging_time(bif, ctx->scratch->int1);
|
|
break;
|
|
|
|
case LEAF_begemotBridgeTpMaxAddresses:
|
|
bridge_set_max_cache(bif, 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_begemotBridgeTpLearnedEntryDiscards:
|
|
val->v.uint32 = bif->lrnt_drops;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeTpAgingTime:
|
|
val->v.integer = bif->age_time;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotBridgeTpMaxAddresses:
|
|
val->v.integer = bif->max_addrs;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
abort();
|
|
}
|