Path: blob/main/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c
106842 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2006 Shteryana Shopova <[email protected]>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*27* Bridge MIB implementation for SNMPd.28* Bridge interface objects.29*/3031#include <sys/queue.h>32#include <sys/socket.h>33#include <sys/time.h>34#include <sys/types.h>3536#include <net/ethernet.h>37#include <net/if.h>38#include <net/if_mib.h>39#include <net/if_types.h>4041#include <errno.h>42#include <stdarg.h>43#include <stdlib.h>44#include <string.h>45#include <syslog.h>4647#include <bsnmp/snmpmod.h>48#include <bsnmp/snmp_mibII.h>4950#define SNMPTREE_TYPES51#include "bridge_tree.h"52#include "bridge_snmp.h"53#include "bridge_oid.h"5455static const struct asn_oid oid_newRoot = OIDX_newRoot;56static const struct asn_oid oid_TopologyChange = OIDX_topologyChange;57static const struct asn_oid oid_begemotBrigeName = \58OIDX_begemotBridgeBaseName;59static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;60static const struct asn_oid oid_begemotTopologyChange = \61OIDX_begemotBridgeTopologyChange;6263TAILQ_HEAD(bridge_ifs, bridge_if);6465/*66* Free the bridge interface list.67*/68static void69bridge_ifs_free(struct bridge_ifs *headp)70{71struct bridge_if *b;7273while ((b = TAILQ_FIRST(headp)) != NULL) {74TAILQ_REMOVE(headp, b, b_if);75free(b);76}77}7879/*80* Insert an entry in the bridge interface TAILQ. Keep the81* TAILQ sorted by the bridge's interface name.82*/83static void84bridge_ifs_insert(struct bridge_ifs *headp,85struct bridge_if *b)86{87struct bridge_if *temp;8889if ((temp = TAILQ_FIRST(headp)) == NULL ||90strcmp(b->bif_name, temp->bif_name) < 0) {91TAILQ_INSERT_HEAD(headp, b, b_if);92return;93}9495TAILQ_FOREACH(temp, headp, b_if)96if(strcmp(b->bif_name, temp->bif_name) < 0)97TAILQ_INSERT_BEFORE(temp, b, b_if);9899TAILQ_INSERT_TAIL(headp, b, b_if);100}101102/* The global bridge interface list. */103static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);104static time_t bridge_list_age;105106/*107* Free the global list.108*/109void110bridge_ifs_fini(void)111{112bridge_ifs_free(&bridge_ifs);113}114115/*116* Find a bridge interface entry by the bridge interface system index.117*/118struct bridge_if *119bridge_if_find_ifs(uint32_t sysindex)120{121struct bridge_if *b;122123TAILQ_FOREACH(b, &bridge_ifs, b_if)124if (b->sysindex == sysindex)125return (b);126127return (NULL);128}129130/*131* Find a bridge interface entry by the bridge interface name.132*/133struct bridge_if *134bridge_if_find_ifname(const char *b_name)135{136struct bridge_if *b;137138TAILQ_FOREACH(b, &bridge_ifs, b_if)139if (strcmp(b_name, b->bif_name) == 0)140return (b);141142return (NULL);143}144145/*146* Find a bridge name by the bridge interface system index.147*/148const char *149bridge_if_find_name(uint32_t sysindex)150{151struct bridge_if *b;152153TAILQ_FOREACH(b, &bridge_ifs, b_if)154if (b->sysindex == sysindex)155return (b->bif_name);156157return (NULL);158}159160/*161* Given two bridge interfaces' system indexes, find their162* corresponding names and return the result of the name163* comparison. Returns:164* error : -2165* i1 < i2 : -1166* i1 > i2 : +1167* i1 = i2 : 0168*/169int170bridge_compare_sysidx(uint32_t i1, uint32_t i2)171{172int c;173const char *b1, *b2;174175if (i1 == i2)176return (0);177178if ((b1 = bridge_if_find_name(i1)) == NULL) {179syslog(LOG_ERR, "Bridge interface %d does not exist", i1);180return (-2);181}182183if ((b2 = bridge_if_find_name(i2)) == NULL) {184syslog(LOG_ERR, "Bridge interface %d does not exist", i2);185return (-2);186}187188if ((c = strcmp(b1, b2)) < 0)189return (-1);190else if (c > 0)191return (1);192193return (0);194}195196/*197* Fetch the first bridge interface from the list.198*/199struct bridge_if *200bridge_first_bif(void)201{202return (TAILQ_FIRST(&bridge_ifs));203}204205/*206* Fetch the next bridge interface from the list.207*/208struct bridge_if *209bridge_next_bif(struct bridge_if *b_pr)210{211return (TAILQ_NEXT(b_pr, b_if));212}213214/*215* Create a new entry for a bridge interface and insert216* it in the list.217*/218static struct bridge_if *219bridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr)220{221struct bridge_if *bif;222223if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) {224syslog(LOG_ERR, "bridge new interface failed: %s",225strerror(errno));226return (NULL);227}228229bzero(bif, sizeof(struct bridge_if));230strlcpy(bif->bif_name, bif_n, IFNAMSIZ);231bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);232bif->sysindex = sysindex;233bif->br_type = BaseType_transparent_only;234/* 1 - all bridges default hold time * 100 - centi-seconds */235bif->hold_time = 1 * 100;236bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d;237bridge_ifs_insert(&bridge_ifs, bif);238239return (bif);240}241242/*243* Remove a bridge interface from the list, freeing all it's ports244* and address entries.245*/246void247bridge_remove_bif(struct bridge_if *bif)248{249bridge_members_free(bif);250bridge_addrs_free(bif);251TAILQ_REMOVE(&bridge_ifs, bif, b_if);252free(bif);253}254255256/*257* Prepare the variable (bridge interface name) for the private258* begemot notifications.259*/260static struct snmp_value*261bridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val)262{263uint i;264265b_val->var = oid_begemotBrigeName;266b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name);267268if ((b_val->v.octetstring.octets = (u_char *)269malloc(strlen(bif->bif_name))) == NULL)270return (NULL);271272for (i = 0; i < strlen(bif->bif_name); i++)273b_val->var.subs[b_val->var.len++] = bif->bif_name[i];274275b_val->v.octetstring.len = strlen(bif->bif_name);276bcopy(bif->bif_name, b_val->v.octetstring.octets,277strlen(bif->bif_name));278b_val->syntax = SNMP_SYNTAX_OCTETSTRING;279280return (b_val);281}282283/*284* Compare the values of the old and the new root port and285* send a new root notification, if they are not matching.286*/287static void288bridge_new_root(struct bridge_if *bif)289{290struct snmp_value bif_idx;291292if (bridge_get_default() == bif)293snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL);294295if (bridge_basename_var(bif, &bif_idx) == NULL)296return;297298snmp_send_trap(&oid_begemotTopologyChange,299&bif_idx, (struct snmp_value *) NULL);300}301302/*303* Compare the new and old topology change times and send a304* topology change notification if necessary.305*/306static void307bridge_top_change(struct bridge_if *bif)308{309struct snmp_value bif_idx;310311if (bridge_get_default() == bif)312snmp_send_trap(&oid_TopologyChange,313(struct snmp_value *) NULL);314315if (bridge_basename_var(bif, &bif_idx) == NULL)316return;317318snmp_send_trap(&oid_begemotNewRoot,319&bif_idx, (struct snmp_value *) NULL);320}321322static int323bridge_if_create(const char* b_name, int8_t up)324{325if (bridge_create(b_name) < 0)326return (-1);327328if (up == 1 && (bridge_set_if_up(b_name, 1) < 0))329return (-1);330331/*332* Do not create a new bridge entry here -333* wait until the mibII module notifies us.334*/335return (0);336}337338static int339bridge_if_destroy(struct bridge_if *bif)340{341if (bridge_destroy(bif->bif_name) < 0)342return (-1);343344bridge_remove_bif(bif);345346return (0);347}348349/*350* Calculate the timeticks since the last topology change.351*/352static int353bridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks)354{355struct timeval ct;356357if (gettimeofday(&ct, NULL) < 0) {358syslog(LOG_ERR, "bridge get time since last TC:"359"gettimeofday failed: %s", strerror(errno));360return (-1);361}362363if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) {364ct.tv_sec -= 1;365ct.tv_usec += 1000000;366}367368ct.tv_sec -= bif->last_tc_time.tv_sec;369ct.tv_usec -= bif->last_tc_time.tv_usec;370371*ticks = ct.tv_sec * 100 + ct.tv_usec/10000;372373return (0);374}375376/*377* Update the info we have for a single bridge interface.378* Return:379* 1, if successful380* 0, if the interface was deleted381* -1, error occurred while fetching the info from the kernel.382*/383static int384bridge_update_bif(struct bridge_if *bif)385{386struct mibif *ifp;387388/* Walk through the mibII interface list. */389for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))390if (strcmp(ifp->name, bif->bif_name) == 0)391break;392393if (ifp == NULL) {394/* Ops, we do not exist anymore. */395bridge_remove_bif(bif);396return (0);397}398399if (ifp->physaddr != NULL )400bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);401else402bridge_get_basemac(bif->bif_name, bif->br_addr.octet,403ETHER_ADDR_LEN);404405if (ifp->mib.ifmd_flags & IFF_RUNNING)406bif->if_status = RowStatus_active;407else408bif->if_status = RowStatus_notInService;409410switch (bridge_getinfo_bif(bif)) {411case 2:412bridge_new_root(bif);413break;414case 1:415bridge_top_change(bif);416break;417case -1:418bridge_remove_bif(bif);419return (-1);420default:421break;422}423424/*425* The number of ports is accessible via SNMP -426* update the ports each time the bridge interface data427* is refreshed too.428*/429bif->num_ports = bridge_update_memif(bif);430bif->entry_age = time(NULL);431432return (1);433}434435/*436* Update all bridge interfaces' ports only -437* make sure each bridge interface exists first.438*/439void440bridge_update_all_ports(void)441{442struct mibif *ifp;443struct bridge_if *bif, *t_bif;444445for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {446t_bif = bridge_next_bif(bif);447448for (ifp = mib_first_if(); ifp != NULL;449ifp = mib_next_if(ifp))450if (strcmp(ifp->name, bif->bif_name) == 0)451break;452453if (ifp != NULL)454bif->num_ports = bridge_update_memif(bif);455else /* Ops, we do not exist anymore. */456bridge_remove_bif(bif);457}458459bridge_ports_update_listage();460}461462/*463* Update all addresses only.464*/465void466bridge_update_all_addrs(void)467{468struct mibif *ifp;469struct bridge_if *bif, *t_bif;470471for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {472t_bif = bridge_next_bif(bif);473474for (ifp = mib_first_if(); ifp != NULL;475ifp = mib_next_if(ifp))476if (strcmp(ifp->name, bif->bif_name) == 0)477break;478479if (ifp != NULL)480bif->num_addrs = bridge_update_addrs(bif);481else /* Ops, we don't exist anymore. */482bridge_remove_bif(bif);483}484485bridge_addrs_update_listage();486}487488/*489* Update only the bridge interfaces' data - skip addresses.490*/491void492bridge_update_all_ifs(void)493{494struct bridge_if *bif, *t_bif;495496for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {497t_bif = bridge_next_bif(bif);498bridge_update_bif(bif);499}500501bridge_ports_update_listage();502bridge_list_age = time(NULL);503}504505/*506* Update all info we have for all bridges.507*/508void509bridge_update_all(void *arg __unused)510{511struct bridge_if *bif, *t_bif;512513for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {514t_bif = bridge_next_bif(bif);515if (bridge_update_bif(bif) <= 0)516continue;517518/* Update our learnt addresses. */519bif->num_addrs = bridge_update_addrs(bif);520}521522bridge_list_age = time(NULL);523bridge_ports_update_listage();524bridge_addrs_update_listage();525}526527/*528* Callback for polling our last topology change time -529* check whether we are root or whether a TC was detected once every530* 30 seconds, so that we can send the newRoot and TopologyChange traps531* on time. The rest of the data is polled only once every 5 min.532*/533void534bridge_update_tc_time(void *arg __unused)535{536struct bridge_if *bif;537struct mibif *ifp;538539TAILQ_FOREACH(bif, &bridge_ifs, b_if) {540/* Walk through the mibII interface list. */541for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))542if (strcmp(ifp->name, bif->bif_name) == 0)543break;544545if (ifp == NULL) {546bridge_remove_bif(bif);547continue;548}549550switch (bridge_get_op_param(bif)) {551case 2:552bridge_new_root(bif);553break;554case 1:555bridge_top_change(bif);556break;557}558}559}560561/*562* Callback for handling new bridge interface creation.563*/564int565bridge_attach_newif(struct mibif *ifp)566{567u_char mac[ETHER_ADDR_LEN];568struct bridge_if *bif;569570if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)571return (0);572573/* Make sure it does not exist in our list. */574TAILQ_FOREACH(bif, &bridge_ifs, b_if)575if(strcmp(bif->bif_name, ifp->name) == 0) {576syslog(LOG_ERR, "bridge interface %s already "577"in list", bif->bif_name);578return (-1);579}580581if (ifp->physaddr == NULL) {582if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) {583syslog(LOG_ERR, "bridge attach new %s failed - "584"no bridge mac address", ifp->name);585return (-1);586}587} else588bcopy(ifp->physaddr, &mac, sizeof(mac));589590if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL)591return (-1);592593if (ifp->mib.ifmd_flags & IFF_RUNNING)594bif->if_status = RowStatus_active;595else596bif->if_status = RowStatus_notInService;597598/* Skip sending notifications if the interface was just created. */599if (bridge_getinfo_bif(bif) < 0 ||600(bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||601(bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {602bridge_remove_bif(bif);603return (-1);604}605606/* Check whether we are the default bridge interface. */607if (strcmp(ifp->name, bridge_get_default_name()) == 0)608bridge_set_default(bif);609610return (0);611}612613void614bridge_ifs_dump(void)615{616struct bridge_if *bif;617618for (bif = bridge_first_bif(); bif != NULL;619bif = bridge_next_bif(bif)) {620syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,621bif->sysindex);622bridge_ports_dump(bif);623bridge_addrs_dump(bif);624}625}626627/*628* RFC4188 specifics.629*/630int631op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,632uint sub, uint iidx __unused, enum snmp_op op)633{634struct bridge_if *bif;635636if ((bif = bridge_get_default()) == NULL)637return (SNMP_ERR_NOSUCHNAME);638639if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&640bridge_update_bif(bif) <= 0) /* It was just deleted. */641return (SNMP_ERR_NOSUCHNAME);642643switch (op) {644case SNMP_OP_GET:645switch (value->var.subs[sub - 1]) {646case LEAF_dot1dBaseBridgeAddress:647return (string_get(value, bif->br_addr.octet,648ETHER_ADDR_LEN));649case LEAF_dot1dBaseNumPorts:650value->v.integer = bif->num_ports;651return (SNMP_ERR_NOERROR);652case LEAF_dot1dBaseType:653value->v.integer = bif->br_type;654return (SNMP_ERR_NOERROR);655}656abort();657658case SNMP_OP_SET:659return (SNMP_ERR_NOT_WRITEABLE);660661case SNMP_OP_GETNEXT:662case SNMP_OP_ROLLBACK:663case SNMP_OP_COMMIT:664break;665}666667abort();668}669670int671op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub,672uint iidx __unused, enum snmp_op op)673{674struct bridge_if *bif;675676if ((bif = bridge_get_default()) == NULL)677return (SNMP_ERR_NOSUCHNAME);678679if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&680bridge_update_bif(bif) <= 0) /* It was just deleted. */681return (SNMP_ERR_NOSUCHNAME);682683switch (op) {684case SNMP_OP_GET:685switch (val->var.subs[sub - 1]) {686case LEAF_dot1dStpProtocolSpecification:687val->v.integer = bif->prot_spec;688return (SNMP_ERR_NOERROR);689690case LEAF_dot1dStpPriority:691val->v.integer = bif->priority;692return (SNMP_ERR_NOERROR);693694case LEAF_dot1dStpTimeSinceTopologyChange:695if (bridge_get_time_since_tc(bif,696&(val->v.uint32)) < 0)697return (SNMP_ERR_GENERR);698return (SNMP_ERR_NOERROR);699700case LEAF_dot1dStpTopChanges:701val->v.uint32 = bif->top_changes;702return (SNMP_ERR_NOERROR);703704case LEAF_dot1dStpDesignatedRoot:705return (string_get(val, bif->design_root,706SNMP_BRIDGE_ID_LEN));707708case LEAF_dot1dStpRootCost:709val->v.integer = bif->root_cost;710return (SNMP_ERR_NOERROR);711712case LEAF_dot1dStpRootPort:713val->v.integer = bif->root_port;714return (SNMP_ERR_NOERROR);715716case LEAF_dot1dStpMaxAge:717val->v.integer = bif->max_age;718return (SNMP_ERR_NOERROR);719720case LEAF_dot1dStpHelloTime:721val->v.integer = bif->hello_time;722return (SNMP_ERR_NOERROR);723724case LEAF_dot1dStpHoldTime:725val->v.integer = bif->hold_time;726return (SNMP_ERR_NOERROR);727728case LEAF_dot1dStpForwardDelay:729val->v.integer = bif->fwd_delay;730return (SNMP_ERR_NOERROR);731732case LEAF_dot1dStpBridgeMaxAge:733val->v.integer = bif->bridge_max_age;734return (SNMP_ERR_NOERROR);735736case LEAF_dot1dStpBridgeHelloTime:737val->v.integer = bif->bridge_hello_time;738return (SNMP_ERR_NOERROR);739740case LEAF_dot1dStpBridgeForwardDelay:741val->v.integer = bif->bridge_fwd_delay;742return (SNMP_ERR_NOERROR);743744case LEAF_dot1dStpVersion:745val->v.integer = bif->stp_version;746return (SNMP_ERR_NOERROR);747748case LEAF_dot1dStpTxHoldCount:749val->v.integer = bif->tx_hold_count;750return (SNMP_ERR_NOERROR);751}752abort();753754case SNMP_OP_GETNEXT:755abort();756757case SNMP_OP_SET:758switch (val->var.subs[sub - 1]) {759case LEAF_dot1dStpPriority:760if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||761val->v.integer % 4096 != 0)762return (SNMP_ERR_WRONG_VALUE);763764ctx->scratch->int1 = bif->priority;765if (bridge_set_priority(bif, val->v.integer) < 0)766return (SNMP_ERR_GENERR);767return (SNMP_ERR_NOERROR);768769case LEAF_dot1dStpBridgeMaxAge:770if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||771val->v.integer > SNMP_BRIDGE_MAX_MAGE)772return (SNMP_ERR_WRONG_VALUE);773774ctx->scratch->int1 = bif->bridge_max_age;775if (bridge_set_maxage(bif, val->v.integer) < 0)776return (SNMP_ERR_GENERR);777return (SNMP_ERR_NOERROR);778779case LEAF_dot1dStpBridgeHelloTime:780if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||781val->v.integer > SNMP_BRIDGE_MAX_HTIME)782return (SNMP_ERR_WRONG_VALUE);783784ctx->scratch->int1 = bif->bridge_hello_time;785if (bridge_set_hello_time(bif, val->v.integer) < 0)786return (SNMP_ERR_GENERR);787return (SNMP_ERR_NOERROR);788789case LEAF_dot1dStpBridgeForwardDelay:790if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||791val->v.integer > SNMP_BRIDGE_MAX_FDELAY)792return (SNMP_ERR_WRONG_VALUE);793794ctx->scratch->int1 = bif->bridge_fwd_delay;795if (bridge_set_forward_delay(bif, val->v.integer) < 0)796return (SNMP_ERR_GENERR);797return (SNMP_ERR_NOERROR);798799case LEAF_dot1dStpVersion:800if (val->v.integer != dot1dStpVersion_stpCompatible &&801val->v.integer != dot1dStpVersion_rstp)802return (SNMP_ERR_WRONG_VALUE);803804ctx->scratch->int1 = bif->stp_version;805if (bridge_set_stp_version(bif, val->v.integer) < 0)806return (SNMP_ERR_GENERR);807return (SNMP_ERR_NOERROR);808809case LEAF_dot1dStpTxHoldCount:810if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||811val->v.integer > SNMP_BRIDGE_MAX_TXHC)812return (SNMP_ERR_WRONG_VALUE);813814ctx->scratch->int1 = bif->tx_hold_count;815if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)816return (SNMP_ERR_GENERR);817return (SNMP_ERR_NOERROR);818819case LEAF_dot1dStpProtocolSpecification:820case LEAF_dot1dStpTimeSinceTopologyChange:821case LEAF_dot1dStpTopChanges:822case LEAF_dot1dStpDesignatedRoot:823case LEAF_dot1dStpRootCost:824case LEAF_dot1dStpRootPort:825case LEAF_dot1dStpMaxAge:826case LEAF_dot1dStpHelloTime:827case LEAF_dot1dStpHoldTime:828case LEAF_dot1dStpForwardDelay:829return (SNMP_ERR_NOT_WRITEABLE);830}831abort();832833case SNMP_OP_ROLLBACK:834switch (val->var.subs[sub - 1]) {835case LEAF_dot1dStpPriority:836bridge_set_priority(bif, ctx->scratch->int1);837break;838case LEAF_dot1dStpBridgeMaxAge:839bridge_set_maxage(bif, ctx->scratch->int1);840break;841case LEAF_dot1dStpBridgeHelloTime:842bridge_set_hello_time(bif, ctx->scratch->int1);843break;844case LEAF_dot1dStpBridgeForwardDelay:845bridge_set_forward_delay(bif, ctx->scratch->int1);846break;847case LEAF_dot1dStpVersion:848bridge_set_stp_version(bif, ctx->scratch->int1);849break;850case LEAF_dot1dStpTxHoldCount:851bridge_set_tx_hold_count(bif, ctx->scratch->int1);852break;853}854return (SNMP_ERR_NOERROR);855856case SNMP_OP_COMMIT:857return (SNMP_ERR_NOERROR);858}859860abort();861}862863int864op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,865uint sub, uint iidx __unused, enum snmp_op op)866{867struct bridge_if *bif;868869if ((bif = bridge_get_default()) == NULL)870return (SNMP_ERR_NOSUCHNAME);871872if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&873bridge_update_bif(bif) <= 0) /* It was just deleted. */874return (SNMP_ERR_NOSUCHNAME);875876switch (op) {877case SNMP_OP_GET:878switch (value->var.subs[sub - 1]) {879case LEAF_dot1dTpLearnedEntryDiscards:880value->v.uint32 = bif->lrnt_drops;881return (SNMP_ERR_NOERROR);882case LEAF_dot1dTpAgingTime:883value->v.integer = bif->age_time;884return (SNMP_ERR_NOERROR);885}886abort();887888case SNMP_OP_GETNEXT:889abort();890891case SNMP_OP_SET:892switch (value->var.subs[sub - 1]) {893case LEAF_dot1dTpLearnedEntryDiscards:894return (SNMP_ERR_NOT_WRITEABLE);895896case LEAF_dot1dTpAgingTime:897if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||898value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)899return (SNMP_ERR_WRONG_VALUE);900901ctx->scratch->int1 = bif->age_time;902if (bridge_set_aging_time(bif, value->v.integer) < 0)903return (SNMP_ERR_GENERR);904return (SNMP_ERR_NOERROR);905}906abort();907908case SNMP_OP_ROLLBACK:909if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)910bridge_set_aging_time(bif, ctx->scratch->int1);911return (SNMP_ERR_NOERROR);912913case SNMP_OP_COMMIT:914return (SNMP_ERR_NOERROR);915}916917abort();918}919920/*921* Private BEGEMOT-BRIDGE-MIB specifics.922*/923924/*925* Get the bridge name from an OID index.926*/927static char *928bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)929{930uint i;931932if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)933return (NULL);934935for (i = 0; i < oid->subs[sub]; i++)936b_name[i] = oid->subs[sub + i + 1];937b_name[i] = '\0';938939return (b_name);940}941942static void943bridge_if_index_append(struct asn_oid *oid, uint sub,944const struct bridge_if *bif)945{946uint i;947948oid->len = sub + strlen(bif->bif_name) + 1;949oid->subs[sub] = strlen(bif->bif_name);950951for (i = 1; i <= strlen(bif->bif_name); i++)952oid->subs[sub + i] = bif->bif_name[i - 1];953}954955static struct bridge_if *956bridge_if_index_get(const struct asn_oid *oid, uint sub)957{958uint i;959char bif_name[IFNAMSIZ];960961if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)962return (NULL);963964for (i = 0; i < oid->subs[sub]; i++)965bif_name[i] = oid->subs[sub + i + 1];966bif_name[i] = '\0';967968return (bridge_if_find_ifname(bif_name));969}970971static struct bridge_if *972bridge_if_index_getnext(const struct asn_oid *oid, uint sub)973{974uint i;975char bif_name[IFNAMSIZ];976struct bridge_if *bif;977978if (oid->len - sub == 0)979return (bridge_first_bif());980981if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)982return (NULL);983984for (i = 0; i < oid->subs[sub]; i++)985bif_name[i] = oid->subs[sub + i + 1];986bif_name[i] = '\0';987988if ((bif = bridge_if_find_ifname(bif_name)) == NULL)989return (NULL);990991return (bridge_next_bif(bif));992}993994static int995bridge_set_if_status(struct snmp_context *ctx,996struct snmp_value *val, uint sub)997{998struct bridge_if *bif;999char bif_name[IFNAMSIZ];10001001bif = bridge_if_index_get(&val->var, sub);10021003switch (val->v.integer) {1004case RowStatus_active:1005if (bif == NULL)1006return (SNMP_ERR_INCONS_VALUE);10071008ctx->scratch->int1 = bif->if_status;10091010switch (bif->if_status) {1011case RowStatus_active:1012return (SNMP_ERR_NOERROR);1013case RowStatus_notInService:1014if (bridge_set_if_up(bif->bif_name, 1) < 0)1015return (SNMP_ERR_GENERR);1016return (SNMP_ERR_NOERROR);1017default:1018break;1019}1020return (SNMP_ERR_INCONS_VALUE);10211022case RowStatus_notInService:1023if (bif == NULL)1024return (SNMP_ERR_INCONS_VALUE);10251026ctx->scratch->int1 = bif->if_status;10271028switch (bif->if_status) {1029case RowStatus_active:1030if (bridge_set_if_up(bif->bif_name, 1) < 0)1031return (SNMP_ERR_GENERR);1032return (SNMP_ERR_NOERROR);1033case RowStatus_notInService:1034return (SNMP_ERR_NOERROR);1035default:1036break;1037}1038return (SNMP_ERR_INCONS_VALUE);10391040case RowStatus_notReady:1041return (SNMP_ERR_INCONS_VALUE);10421043case RowStatus_createAndGo:1044if (bif != NULL)1045return (SNMP_ERR_INCONS_VALUE);10461047ctx->scratch->int1 = RowStatus_destroy;10481049if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)1050return (SNMP_ERR_BADVALUE);1051if (bridge_if_create(bif_name, 1) < 0)1052return (SNMP_ERR_GENERR);1053return (SNMP_ERR_NOERROR);10541055case RowStatus_createAndWait:1056if (bif != NULL)1057return (SNMP_ERR_INCONS_VALUE);10581059if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)1060return (SNMP_ERR_BADVALUE);10611062ctx->scratch->int1 = RowStatus_destroy;10631064if (bridge_if_create(bif_name, 0) < 0)1065return (SNMP_ERR_GENERR);1066return (SNMP_ERR_NOERROR);10671068case RowStatus_destroy:1069if (bif == NULL)1070return (SNMP_ERR_NOSUCHNAME);10711072ctx->scratch->int1 = bif->if_status;1073bif->if_status = RowStatus_destroy;1074}10751076return (SNMP_ERR_NOERROR);1077}10781079static int1080bridge_rollback_if_status(struct snmp_context *ctx,1081struct snmp_value *val, uint sub)1082{1083struct bridge_if *bif;10841085if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)1086return (SNMP_ERR_GENERR);10871088switch (ctx->scratch->int1) {1089case RowStatus_destroy:1090bridge_if_destroy(bif);1091return (SNMP_ERR_NOERROR);10921093case RowStatus_notInService:1094if (bif->if_status != ctx->scratch->int1)1095bridge_set_if_up(bif->bif_name, 0);1096bif->if_status = RowStatus_notInService;1097return (SNMP_ERR_NOERROR);10981099case RowStatus_active:1100if (bif->if_status != ctx->scratch->int1)1101bridge_set_if_up(bif->bif_name, 1);1102bif->if_status = RowStatus_active;1103return (SNMP_ERR_NOERROR);1104}11051106abort();1107}11081109static int1110bridge_commit_if_status(struct snmp_value *val, uint sub)1111{1112struct bridge_if *bif;11131114if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)1115return (SNMP_ERR_GENERR);11161117if (bif->if_status == RowStatus_destroy &&1118bridge_if_destroy(bif) < 0)1119return (SNMP_ERR_COMMIT_FAILED);11201121return (SNMP_ERR_NOERROR);1122}11231124int1125op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,1126uint sub, uint iidx __unused, enum snmp_op op)1127{1128struct bridge_if *bif;11291130if (time(NULL) - bridge_list_age > bridge_get_data_maxage())1131bridge_update_all_ifs();11321133switch (op) {1134case SNMP_OP_GET:1135if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)1136return (SNMP_ERR_NOSUCHNAME);1137goto get;11381139case SNMP_OP_GETNEXT:1140if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)1141return (SNMP_ERR_NOSUCHNAME);1142bridge_if_index_append(&val->var, sub, bif);1143goto get;11441145case SNMP_OP_SET:1146switch (val->var.subs[sub - 1]) {1147case LEAF_begemotBridgeBaseStatus:1148return (bridge_set_if_status(ctx, val, sub));1149case LEAF_begemotBridgeBaseName:1150case LEAF_begemotBridgeBaseAddress:1151case LEAF_begemotBridgeBaseNumPorts:1152case LEAF_begemotBridgeBaseType:1153return (SNMP_ERR_NOT_WRITEABLE);1154}1155abort();11561157case SNMP_OP_ROLLBACK:1158return (bridge_rollback_if_status(ctx, val, sub));11591160case SNMP_OP_COMMIT:1161return (bridge_commit_if_status(val, sub));1162}1163abort();11641165get:1166switch (val->var.subs[sub - 1]) {1167case LEAF_begemotBridgeBaseName:1168return (string_get(val, bif->bif_name, -1));11691170case LEAF_begemotBridgeBaseAddress:1171return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN));11721173case LEAF_begemotBridgeBaseNumPorts:1174val->v.integer = bif->num_ports;1175return (SNMP_ERR_NOERROR);11761177case LEAF_begemotBridgeBaseType:1178val->v.integer = bif->br_type;1179return (SNMP_ERR_NOERROR);11801181case LEAF_begemotBridgeBaseStatus:1182val->v.integer = bif->if_status;1183return (SNMP_ERR_NOERROR);1184}11851186abort();1187}11881189int1190op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,1191uint sub, uint iidx __unused, enum snmp_op op)1192{1193struct bridge_if *bif;11941195if (time(NULL) - bridge_list_age > bridge_get_data_maxage())1196bridge_update_all_ifs();11971198switch (op) {1199case SNMP_OP_GET:1200if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)1201return (SNMP_ERR_NOSUCHNAME);1202goto get;12031204case SNMP_OP_GETNEXT:1205if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)1206return (SNMP_ERR_NOSUCHNAME);1207bridge_if_index_append(&val->var, sub, bif);1208goto get;12091210case SNMP_OP_SET:1211if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)1212return (SNMP_ERR_NOSUCHNAME);12131214switch (val->var.subs[sub - 1]) {1215case LEAF_begemotBridgeStpPriority:1216if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||1217val->v.integer % 4096 != 0)1218return (SNMP_ERR_WRONG_VALUE);12191220ctx->scratch->int1 = bif->priority;1221if (bridge_set_priority(bif, val->v.integer) < 0)1222return (SNMP_ERR_GENERR);1223return (SNMP_ERR_NOERROR);12241225case LEAF_begemotBridgeStpBridgeMaxAge:1226if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||1227val->v.integer > SNMP_BRIDGE_MAX_MAGE)1228return (SNMP_ERR_WRONG_VALUE);12291230ctx->scratch->int1 = bif->bridge_max_age;1231if (bridge_set_maxage(bif, val->v.integer) < 0)1232return (SNMP_ERR_GENERR);1233return (SNMP_ERR_NOERROR);12341235case LEAF_begemotBridgeStpBridgeHelloTime:1236if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||1237val->v.integer > SNMP_BRIDGE_MAX_HTIME)1238return (SNMP_ERR_WRONG_VALUE);12391240ctx->scratch->int1 = bif->bridge_hello_time;1241if (bridge_set_hello_time(bif, val->v.integer) < 0)1242return (SNMP_ERR_GENERR);1243return (SNMP_ERR_NOERROR);12441245case LEAF_begemotBridgeStpBridgeForwardDelay:1246if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||1247val->v.integer > SNMP_BRIDGE_MAX_FDELAY)1248return (SNMP_ERR_WRONG_VALUE);12491250ctx->scratch->int1 = bif->bridge_fwd_delay;1251if (bridge_set_forward_delay(bif, val->v.integer) < 0)1252return (SNMP_ERR_GENERR);1253return (SNMP_ERR_NOERROR);12541255case LEAF_begemotBridgeStpVersion:1256if (val->v.integer !=1257begemotBridgeStpVersion_stpCompatible &&1258val->v.integer != begemotBridgeStpVersion_rstp)1259return (SNMP_ERR_WRONG_VALUE);12601261ctx->scratch->int1 = bif->stp_version;1262if (bridge_set_stp_version(bif, val->v.integer) < 0)1263return (SNMP_ERR_GENERR);1264return (SNMP_ERR_NOERROR);12651266case LEAF_begemotBridgeStpTxHoldCount:1267if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||1268val->v.integer > SNMP_BRIDGE_MAX_TXHC)1269return (SNMP_ERR_WRONG_VALUE);12701271ctx->scratch->int1 = bif->tx_hold_count;1272if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)1273return (SNMP_ERR_GENERR);1274return (SNMP_ERR_NOERROR);12751276case LEAF_begemotBridgeStpProtocolSpecification:1277case LEAF_begemotBridgeStpTimeSinceTopologyChange:1278case LEAF_begemotBridgeStpTopChanges:1279case LEAF_begemotBridgeStpDesignatedRoot:1280case LEAF_begemotBridgeStpRootCost:1281case LEAF_begemotBridgeStpRootPort:1282case LEAF_begemotBridgeStpMaxAge:1283case LEAF_begemotBridgeStpHelloTime:1284case LEAF_begemotBridgeStpHoldTime:1285case LEAF_begemotBridgeStpForwardDelay:1286return (SNMP_ERR_NOT_WRITEABLE);1287}1288abort();12891290case SNMP_OP_ROLLBACK:1291if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)1292return (SNMP_ERR_NOSUCHNAME);12931294switch (val->var.subs[sub - 1]) {1295case LEAF_begemotBridgeStpPriority:1296bridge_set_priority(bif, ctx->scratch->int1);1297break;12981299case LEAF_begemotBridgeStpBridgeMaxAge:1300bridge_set_maxage(bif, ctx->scratch->int1);1301break;13021303case LEAF_begemotBridgeStpBridgeHelloTime:1304bridge_set_hello_time(bif, ctx->scratch->int1);1305break;13061307case LEAF_begemotBridgeStpBridgeForwardDelay:1308bridge_set_forward_delay(bif, ctx->scratch->int1);1309break;13101311case LEAF_begemotBridgeStpVersion:1312bridge_set_stp_version(bif, ctx->scratch->int1);1313break;13141315case LEAF_begemotBridgeStpTxHoldCount:1316bridge_set_tx_hold_count(bif, ctx->scratch->int1);1317break;1318}1319return (SNMP_ERR_NOERROR);13201321case SNMP_OP_COMMIT:1322return (SNMP_ERR_NOERROR);1323}1324abort();13251326get:1327switch (val->var.subs[sub - 1]) {1328case LEAF_begemotBridgeStpProtocolSpecification:1329val->v.integer = bif->prot_spec;1330return (SNMP_ERR_NOERROR);13311332case LEAF_begemotBridgeStpPriority:1333val->v.integer = bif->priority;1334return (SNMP_ERR_NOERROR);13351336case LEAF_begemotBridgeStpTimeSinceTopologyChange:1337if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)1338return (SNMP_ERR_GENERR);1339return (SNMP_ERR_NOERROR);13401341case LEAF_begemotBridgeStpTopChanges:1342val->v.uint32 = bif->top_changes;1343return (SNMP_ERR_NOERROR);13441345case LEAF_begemotBridgeStpDesignatedRoot:1346return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN));13471348case LEAF_begemotBridgeStpRootCost:1349val->v.integer = bif->root_cost;1350return (SNMP_ERR_NOERROR);13511352case LEAF_begemotBridgeStpRootPort:1353val->v.integer = bif->root_port;1354return (SNMP_ERR_NOERROR);13551356case LEAF_begemotBridgeStpMaxAge:1357val->v.integer = bif->max_age;1358return (SNMP_ERR_NOERROR);13591360case LEAF_begemotBridgeStpHelloTime:1361val->v.integer = bif->hello_time;1362return (SNMP_ERR_NOERROR);13631364case LEAF_begemotBridgeStpHoldTime:1365val->v.integer = bif->hold_time;1366return (SNMP_ERR_NOERROR);13671368case LEAF_begemotBridgeStpForwardDelay:1369val->v.integer = bif->fwd_delay;1370return (SNMP_ERR_NOERROR);13711372case LEAF_begemotBridgeStpBridgeMaxAge:1373val->v.integer = bif->bridge_max_age;1374return (SNMP_ERR_NOERROR);13751376case LEAF_begemotBridgeStpBridgeHelloTime:1377val->v.integer = bif->bridge_hello_time;1378return (SNMP_ERR_NOERROR);13791380case LEAF_begemotBridgeStpBridgeForwardDelay:1381val->v.integer = bif->bridge_fwd_delay;1382return (SNMP_ERR_NOERROR);13831384case LEAF_begemotBridgeStpVersion:1385val->v.integer = bif->stp_version;1386return (SNMP_ERR_NOERROR);13871388case LEAF_begemotBridgeStpTxHoldCount:1389val->v.integer = bif->tx_hold_count;1390return (SNMP_ERR_NOERROR);1391}13921393abort();1394}13951396int1397op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,1398uint sub, uint iidx __unused, enum snmp_op op)1399{1400struct bridge_if *bif;14011402if (time(NULL) - bridge_list_age > bridge_get_data_maxage())1403bridge_update_all_ifs();14041405switch (op) {1406case SNMP_OP_GET:1407if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)1408return (SNMP_ERR_NOSUCHNAME);1409goto get;14101411case SNMP_OP_GETNEXT:1412if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)1413return (SNMP_ERR_NOSUCHNAME);1414bridge_if_index_append(&val->var, sub, bif);1415goto get;14161417case SNMP_OP_SET:1418if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)1419return (SNMP_ERR_NOSUCHNAME);14201421switch (val->var.subs[sub - 1]) {1422case LEAF_begemotBridgeTpAgingTime:1423if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||1424val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)1425return (SNMP_ERR_WRONG_VALUE);14261427ctx->scratch->int1 = bif->age_time;1428if (bridge_set_aging_time(bif, val->v.integer) < 0)1429return (SNMP_ERR_GENERR);1430return (SNMP_ERR_NOERROR);14311432case LEAF_begemotBridgeTpMaxAddresses:1433ctx->scratch->int1 = bif->max_addrs;1434if (bridge_set_max_cache(bif, val->v.integer) < 0)1435return (SNMP_ERR_GENERR);1436return (SNMP_ERR_NOERROR);14371438case LEAF_begemotBridgeTpLearnedEntryDiscards:1439return (SNMP_ERR_NOT_WRITEABLE);1440}1441abort();14421443case SNMP_OP_ROLLBACK:1444if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)1445return (SNMP_ERR_GENERR);14461447switch (val->var.subs[sub - 1]) {1448case LEAF_begemotBridgeTpAgingTime:1449bridge_set_aging_time(bif, ctx->scratch->int1);1450break;14511452case LEAF_begemotBridgeTpMaxAddresses:1453bridge_set_max_cache(bif, ctx->scratch->int1);1454break;1455}1456return (SNMP_ERR_NOERROR);14571458case SNMP_OP_COMMIT:1459return (SNMP_ERR_NOERROR);1460}1461abort();14621463get:1464switch (val->var.subs[sub - 1]) {1465case LEAF_begemotBridgeTpLearnedEntryDiscards:1466val->v.uint32 = bif->lrnt_drops;1467return (SNMP_ERR_NOERROR);14681469case LEAF_begemotBridgeTpAgingTime:1470val->v.integer = bif->age_time;1471return (SNMP_ERR_NOERROR);14721473case LEAF_begemotBridgeTpMaxAddresses:1474val->v.integer = bif->max_addrs;1475return (SNMP_ERR_NOERROR);1476}14771478abort();1479}148014811482