summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsnmpd
diff options
context:
space:
mode:
authorsyrinx <syrinx@FreeBSD.org>2006-11-19 15:42:48 +0000
committersyrinx <syrinx@FreeBSD.org>2006-11-19 15:42:48 +0000
commit2b14cadbaf5d2b420ab83271176821eda38aa302 (patch)
tree53dc45659d9c24255eac36127cb8f2501bc1b4de /usr.sbin/bsnmpd
parenta6852e6ab69a2171d499ab704c1fff41bfcf12d1 (diff)
downloadFreeBSD-src-2b14cadbaf5d2b420ab83271176821eda38aa302.zip
FreeBSD-src-2b14cadbaf5d2b420ab83271176821eda38aa302.tar.gz
Bring in a SNMP module to support monitoring if_bridge(4) interfaces
via bsnmpd(1). The module implements IETF BRIDGE-MIB as defined in RFC4188 and a private BEGEMOT-BRIDGE-MIB. Sponsored by: Google Summer of Code 2006 Reviewed by: bz Approved by: bz (mentor)
Diffstat (limited to 'usr.sbin/bsnmpd')
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/BEGEMOT-BRIDGE-MIB.txt965
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/BRIDGE-MIB.txt1483
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/Makefile19
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c592
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c1369
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_pf.c117
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c1152
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.c327
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.h307
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c1293
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_tree.def242
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.3113
12 files changed, 7979 insertions, 0 deletions
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/BEGEMOT-BRIDGE-MIB.txt b/usr.sbin/bsnmpd/modules/snmp_bridge/BEGEMOT-BRIDGE-MIB.txt
new file mode 100644
index 0000000..fdba57b
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/BEGEMOT-BRIDGE-MIB.txt
@@ -0,0 +1,965 @@
+--
+-- 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 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 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.
+--
+-- $FreeBSD$
+--
+
+BEGEMOT-BRIDGE-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ Counter32, Integer32, TimeTicks, mib-2
+ FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION, MacAddress, TruthValue, RowStatus
+ FROM SNMPv2-TC
+ BridgeId, Timeout
+ FROM BRIDGE-MIB
+ InterfaceIndex FROM IF-MIB
+ begemot
+ FROM BEGEMOT-MIB;
+
+begemotBridge MODULE-IDENTITY
+ LAST-UPDATED "200608100000Z"
+ ORGANIZATION "Sofia University St. Kliment Ohridski"
+ CONTACT-INFO
+ " Shteryana Shopova
+
+ Postal: Faculty of Mathematics and Informatics
+ 5 James Bourchier Blvd.
+ 1164 Sofia
+ Bulgaria
+
+ Fax: +359 2 687 180
+
+ E-Mail: syrinx@FreeBSD.org"
+ DESCRIPTION
+ "The Begemot MIB for managing bridge interfaces."
+
+ ::= { begemot 205 }
+
+-- ---------------------------------------------------------- --
+BridgeIfName ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "16a"
+ STATUS current
+ DESCRIPTION
+ "Name of a bridge interface."
+ SYNTAX OCTET STRING (SIZE(1..16))
+
+BridgeIfNameOrEmpty ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "16a"
+ STATUS current
+ DESCRIPTION
+ "Name of a bridge interface."
+ SYNTAX OCTET STRING (SIZE(0..16))
+
+BridgePortId ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1x.1x"
+ STATUS current
+ DESCRIPTION
+ "A port identifier that contains a bridge port's STP priority
+ in the first octet and the port number in the second octet."
+ SYNTAX OCTET STRING (SIZE(2))
+
+-- ---------------------------------------------------------- --
+-- subtrees in the Begemot Bridge MIB
+-- ---------------------------------------------------------- --
+begemotBridgeNotifications OBJECT IDENTIFIER ::= { begemotBridge 0 }
+
+begemotBridgeBase OBJECT IDENTIFIER ::= { begemotBridge 1 }
+
+begemotBridgeStp OBJECT IDENTIFIER ::= { begemotBridge 2 }
+
+begemotBridgeTp OBJECT IDENTIFIER ::= { begemotBridge 3 }
+
+begemotBridgePf OBJECT IDENTIFIER ::= { begemotBridge 4 }
+
+begemotBridgeConfigObjects OBJECT IDENTIFIER ::= { begemotBridge 5 }
+
+-- ---------------------------------------------------------- --
+-- the base Bridge interface table
+-- ---------------------------------------------------------- --
+
+begemotBridgeBaseTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotBridgeBaseEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains generic information for each
+ bridge interface on the managed device."
+ ::= { begemotBridgeBase 1 }
+
+begemotBridgeBaseEntry OBJECT-TYPE
+ SYNTAX BegemotBridgeBaseEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of information for the bridge interfaces on
+ the managed device."
+ INDEX { begemotBridgeBaseName }
+ ::= { begemotBridgeBaseTable 1 }
+
+BegemotBridgeBaseEntry ::= SEQUENCE {
+ begemotBridgeBaseName BridgeIfName,
+ begemotBridgeBaseAddress MacAddress,
+ begemotBridgeBaseNumPorts Integer32,
+ begemotBridgeBaseType INTEGER,
+ begemotBridgeBaseStatus RowStatus
+}
+
+begemotBridgeBaseName OBJECT-TYPE
+ SYNTAX BridgeIfName
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the bridge interface for which this
+ entry contains management information."
+ ::= { begemotBridgeBaseEntry 1 }
+
+begemotBridgeBaseAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The MAC address of the bridge interface."
+ ::= { begemotBridgeBaseEntry 2 }
+
+begemotBridgeBaseNumPorts OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of ports, members of this bridge."
+ ::= { begemotBridgeBaseEntry 3 }
+
+begemotBridgeBaseType OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(1),
+ transparent-only(2),
+ sourceroute-only(3),
+ srt(4)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates what type of bridging this bridge can
+ perform."
+ ::= { begemotBridgeBaseEntry 4 }
+
+begemotBridgeBaseStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "Used to create/destroy bridge interfaces on the
+ managed device."
+ ::= { begemotBridgeBaseEntry 5 }
+
+-- ---------------------------------------------------------- --
+-- the base Bridge ports table
+-- ---------------------------------------------------------- --
+
+begemotBridgeBasePortTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotBridgeBasePortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table containing generic information about ports,
+ members of each bridge interface."
+ ::= { begemotBridgeBase 2 }
+
+begemotBridgeBasePortEntry OBJECT-TYPE
+ SYNTAX BegemotBridgeBasePortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of information about a specific port, member of
+ a bridge interface."
+ INDEX { begemotBridgeBaseName, begemotBridgeBasePortIfIndex }
+ ::= { begemotBridgeBasePortTable 1 }
+
+BegemotBridgeBasePortEntry ::= SEQUENCE {
+ begemotBridgeBasePort Integer32,
+ begemotBridgeBasePortIfIndex InterfaceIndex,
+ begemotBridgeBaseSpanEnabled INTEGER,
+ begemotBridgeBasePortDelayExceededDiscards Counter32,
+ begemotBridgeBasePortMtuExceededDiscards Counter32,
+ begemotBridgeBasePortStatus RowStatus
+}
+
+begemotBridgeBasePort OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The system interface index of the interface corresponding
+ to this port."
+ ::= { begemotBridgeBasePortEntry 1 }
+
+begemotBridgeBasePortIfIndex OBJECT-TYPE
+ SYNTAX InterfaceIndex
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of the instance of the ifIndex object,
+ defined in IF-MIB, for the interface corresponding
+ to this port."
+ ::= { begemotBridgeBasePortEntry 2 }
+
+begemotBridgeBaseSpanEnabled OBJECT-TYPE
+ SYNTAX INTEGER {
+ enabled(1),
+ disabled(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this objects reflects whether the port
+ is a span port on the specified bridge interface."
+ ::= { begemotBridgeBasePortEntry 3 }
+
+begemotBridgeBasePortDelayExceededDiscards OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames discarded by this port due
+ to excessive transit delay through the bridge."
+ ::= { begemotBridgeBasePortEntry 4 }
+
+begemotBridgeBasePortMtuExceededDiscards OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames discarded by this port due
+ to an excessive size."
+ ::= { begemotBridgeBasePortEntry 5 }
+
+begemotBridgeBasePortStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "Used to control addition of member ports to or
+ removal of member ports from a specified bridge."
+ ::= { begemotBridgeBasePortEntry 6 }
+
+-- ---------------------------------------------------------- --
+-- the Bridge interface STP table
+-- ---------------------------------------------------------- --
+
+begemotBridgeStpTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotBridgeStpEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains Spanning Tree Protocol information
+ for each bridge interface on the managed device."
+ ::= { begemotBridgeStp 1 }
+
+begemotBridgeStpEntry OBJECT-TYPE
+ SYNTAX BegemotBridgeStpEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of information about the Spanning Tree Protocol
+ operation on a bridge interface."
+ AUGMENTS { begemotBridgeBaseEntry }
+ ::= { begemotBridgeStpTable 1 }
+
+BegemotBridgeStpEntry ::= SEQUENCE {
+ begemotBridgeStpProtocolSpecification INTEGER,
+ begemotBridgeStpPriority Integer32,
+ begemotBridgeStpTimeSinceTopologyChange TimeTicks,
+ begemotBridgeStpTopChanges Counter32,
+ begemotBridgeStpDesignatedRoot BridgeId,
+ begemotBridgeStpRootCost Integer32,
+ begemotBridgeStpRootPort Integer32,
+ begemotBridgeStpMaxAge Timeout,
+ begemotBridgeStpHelloTime Timeout,
+ begemotBridgeStpHoldTime Integer32,
+ begemotBridgeStpForwardDelay Timeout,
+ begemotBridgeStpBridgeMaxAge Timeout,
+ begemotBridgeStpBridgeHelloTime Timeout,
+ begemotBridgeStpBridgeForwardDelay Timeout
+}
+
+begemotBridgeStpProtocolSpecification OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(1),
+ decLb100(2),
+ ieee8021d(3)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The Spanning Tree Protocol version being run on the
+ bridge interface. The value 'decLb100(2)' indicates the
+ DEC LANbridge 100 Spanning Tree protocol, 'ieee8021d(3)'
+ indicates the bridge is running IEEE 802.1D STP
+ implementation."
+ ::= { begemotBridgeStpEntry 1 }
+
+begemotBridgeStpPriority OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The priority value of the bridge interface forming the
+ first two octets of the bridge identifier. Acceptable
+ values are 0-61440, in steps of 4096."
+ ::= { begemotBridgeStpEntry 2 }
+
+begemotBridgeStpTimeSinceTopologyChange OBJECT-TYPE
+ SYNTAX TimeTicks
+ UNITS "centi-seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The time (in hundreds of a second) since a topology change
+ was last detected by this bridge."
+ ::= { begemotBridgeStpEntry 3 }
+
+begemotBridgeStpTopChanges OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times a topology change was detected by the
+ bridge interface since the management entity was initialized
+ or reset."
+ ::= { begemotBridgeStpEntry 4 }
+
+begemotBridgeStpDesignatedRoot OBJECT-TYPE
+ SYNTAX BridgeId
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The bridge identifier of the root of the spanning tree as
+ calculated by the Spanning Tree Protocol."
+ ::= { begemotBridgeStpEntry 5 }
+
+begemotBridgeStpRootCost OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The cost of the path from this bridge to the root bridge."
+ ::= { begemotBridgeStpEntry 6 }
+
+begemotBridgeStpRootPort OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The port number of the port that offers the lowest
+ cost path from this bridge to the root bridge of
+ the spanning tree. If this bridge is the root bridge,
+ this object shall have a value of zero."
+ ::= { begemotBridgeStpEntry 7 }
+
+begemotBridgeStpMaxAge OBJECT-TYPE
+ SYNTAX Timeout
+ UNITS "centi-seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum age of Spanning Tree Protocol information
+ received from the network on any port, before that
+ information is discarded. This is the actual value that
+ the bridge is currently using."
+ ::= { begemotBridgeStpEntry 8 }
+
+begemotBridgeStpHelloTime OBJECT-TYPE
+ SYNTAX Timeout
+ UNITS "centi-seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The amount of time between transmission of
+ Configuration BPDUs by this bridge on any port,
+ when it is the root of the spanning tree or is
+ trying to become so. This is the actual value that
+ this bridge is currently using."
+ ::= { begemotBridgeStpEntry 9 }
+
+begemotBridgeStpHoldTime OBJECT-TYPE
+ SYNTAX Integer32
+ UNITS "centi-seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This time value determines the interval length
+ during which no more than two Configuration BPDUs
+ shall be transmitted by this node, in units of
+ hundredths of a second."
+ ::= { begemotBridgeStpEntry 10 }
+
+begemotBridgeStpForwardDelay OBJECT-TYPE
+ SYNTAX Timeout
+ UNITS "centi-seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This value, measured in units of hundredths of a second
+ determines how long a port will stay consecutively in the
+ Listening and Learning states before transitioning to
+ Forwarding state.
+ This is the actual value currently used by the bridge
+ as opposed to begemotBridgeStpBridgeForwardDelay, which
+ is the value this and all bridges participating in the
+ spanning tree were to use, if this was the root bridge."
+ ::= { begemotBridgeStpEntry 11 }
+
+begemotBridgeStpBridgeMaxAge OBJECT-TYPE
+ SYNTAX Timeout (600..4000)
+ UNITS "centi-seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value that all bridges participating in the
+ spanning tree would use for MaxAge if this bridge
+ was the root of the spanning tree."
+ ::= { begemotBridgeStpEntry 12 }
+
+begemotBridgeStpBridgeHelloTime OBJECT-TYPE
+ SYNTAX Timeout (100..1000)
+ UNITS "centi-seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value that all bridges participating in the
+ spanning tree would use for HelloTime if this
+ bridge was the root of the spanning tree."
+ ::= { begemotBridgeStpEntry 13 }
+
+begemotBridgeStpBridgeForwardDelay OBJECT-TYPE
+ SYNTAX Timeout (400..3000)
+ UNITS "centi-seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value that all bridges participating in the
+ spanning tree would use for ForwardDelay if this
+ bridge was the root of the spanning tree."
+ ::= { begemotBridgeStpEntry 14 }
+
+-- ---------------------------------------------------------- --
+-- the Bridge STP ports table
+-- ---------------------------------------------------------- --
+
+begemotBridgeStpPortTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotBridgeStpPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table containing Spanning Tree Protocol information
+ about the members of each bridge interface."
+ ::= { begemotBridgeStp 2 }
+
+begemotBridgeStpPortEntry OBJECT-TYPE
+ SYNTAX BegemotBridgeStpPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of Spanning Tree Protocol information about
+ a specific member of a bridge interface."
+ INDEX { begemotBridgeBaseName, begemotBridgeBasePortIfIndex }
+ ::= { begemotBridgeStpPortTable 1 }
+
+BegemotBridgeStpPortEntry ::= SEQUENCE {
+ begemotBridgeStpPort Integer32,
+ begemotBridgeStpPortPriority Integer32,
+ begemotBridgeStpPortState INTEGER,
+ begemotBridgeStpPortEnable INTEGER,
+ begemotBridgeStpPortPathCost Integer32,
+ begemotBridgeStpPortDesignatedRoot BridgeId,
+ begemotBridgeStpPortDesignatedCost Integer32,
+ begemotBridgeStpPortDesignatedBridge BridgeId,
+ begemotBridgeStpPortDesignatedPort BridgePortId,
+ begemotBridgeStpPortForwardTransitions Counter32
+}
+
+begemotBridgeStpPort OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The system interface index of the interface corresponding
+ to this port, for which the management entity has Spanning
+ Tree Protocol information."
+ ::= { begemotBridgeStpPortEntry 1 }
+
+begemotBridgeStpPortPriority OBJECT-TYPE
+ SYNTAX Integer32 (0..255)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The STP priority of this port that is contained in the first
+ octet of its Port Identifier. The second octet contains the
+ value of begemotBridgeStpPort."
+ ::= { begemotBridgeStpPortEntry 2 }
+
+begemotBridgeStpPortState OBJECT-TYPE
+ SYNTAX INTEGER {
+ disabled(1),
+ blocking(2),
+ listening(3),
+ learning(4),
+ forwarding(5),
+ broken(6)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The current state of the port as defined by the operation
+ of the Spanning Tree Protocol. If the Spanning Tree Protocol
+ is administratively disabled on the port, this object shall
+ have value disabled(1). A value of broken(6) does not correspond
+ to any legal state of a port, and if present should indicate
+ error in the operation of either the Spanning Tree Protocol
+ implementation running on the device or the management entity."
+ ::= { begemotBridgeStpPortEntry 3 }
+
+begemotBridgeStpPortEnable OBJECT-TYPE
+ SYNTAX INTEGER {
+ enabled(1),
+ disabled(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The administrative Spanning Tree Protocol state of the
+ port - value of enabled(1) indicates that the port is
+ participating in the Spanning Tree Protocol operation."
+ ::= { begemotBridgeStpPortEntry 4 }
+
+begemotBridgeStpPortPathCost OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The contribution of the path through this port, when the port
+ is the Root Port, to the total cost of the path to the root
+ bridge for this bridge."
+ ::= { begemotBridgeStpPortEntry 5 }
+
+begemotBridgeStpPortDesignatedRoot OBJECT-TYPE
+ SYNTAX BridgeId
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The unique Bridge Identifier of the bridge recorded as the
+ root in the Root Identifier parameter of Configuration BPDUs
+ transmitted by the Designated Bridge for the LAN to which
+ the port is attached."
+ ::= { begemotBridgeStpPortEntry 6 }
+
+begemotBridgeStpPortDesignatedCost OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "For a Designated port, the path cost (equal to the Root
+ Path Cost of the bridge) offered to the LAN to which the
+ port is attached otherwise the cost of the path to the Root
+ offered by the Designated Port on the LAN to which this
+ Port is attached."
+ ::= { begemotBridgeStpPortEntry 7 }
+
+begemotBridgeStpPortDesignatedBridge OBJECT-TYPE
+ SYNTAX BridgeId
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The unique Bridge Identifier of the bridge to which the
+ port belongs, in the case when the port is a designated
+ port, otherwise the bridge believed to be the Designated
+ Bridge for the LAN to which this port is attached."
+ ::= { begemotBridgeStpPortEntry 8 }
+
+begemotBridgeStpPortDesignatedPort OBJECT-TYPE
+ SYNTAX BridgePortId
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The Port Identifier of the Bridge port, on the Designated
+ Bridge, through which the Designated Bridge transmits the
+ Configuration Message information stored by this port."
+ ::= { begemotBridgeStpPortEntry 9 }
+
+begemotBridgeStpPortForwardTransitions OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times this port has transitioned
+ from the Learning state to the Forwarding state."
+ ::= { begemotBridgeStpPortEntry 10 }
+
+-- ---------------------------------------------------------- --
+-- the Bridge interface Transparent bridging table
+-- ---------------------------------------------------------- --
+
+begemotBridgeTpTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotBridgeTpEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information regarding transparent
+ bridging for each bridge interface on the managed device."
+ ::= { begemotBridgeTp 1 }
+
+begemotBridgeTpEntry OBJECT-TYPE
+ SYNTAX BegemotBridgeTpEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of information regarding transparent bridging
+ on a bridge interface."
+ AUGMENTS { begemotBridgeBaseEntry }
+ ::= { begemotBridgeTpTable 1 }
+
+BegemotBridgeTpEntry ::= SEQUENCE {
+ begemotBridgeTpLearnedEntryDiscards Counter32,
+ begemotBridgeTpAgingTime Integer32,
+ begemotBridgeTpMaxAddresses Integer32
+}
+
+begemotBridgeTpLearnedEntryDiscards OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of Forwarding Database entries that would
+ have been learnt, but have been discarded due to Forwarding
+ Address Table having reached it's maximum entries limit."
+ ::= { begemotBridgeTpEntry 1 }
+
+begemotBridgeTpAgingTime OBJECT-TYPE
+ SYNTAX Integer32 (10..1000000)
+ UNITS "seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The timeout period in seconds before aging out
+ dynamically learnt forwarding entries."
+ ::= { begemotBridgeTpEntry 2 }
+
+begemotBridgeTpMaxAddresses OBJECT-TYPE
+ SYNTAX Integer32 (1..10000)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of entires that this bridge can
+ learn in it's Forwarding Address Table and use for
+ making forwarding decisions."
+ ::= { begemotBridgeTpEntry 3 }
+
+-- ---------------------------------------------------------- --
+-- The Forwarding Database for Transparent Bridging interfaces
+-- ---------------------------------------------------------- --
+
+begemotBridgeTpFdbTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotBridgeTpFdbEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information about unicast entries
+ for which the bridge interfaces have forwarding and/or
+ filtering information. This information is used by the
+ bridge interfaces to make forwarding decisions."
+ ::= { begemotBridgeTp 2 }
+
+begemotBridgeTpFdbEntry OBJECT-TYPE
+ SYNTAX BegemotBridgeTpFdbEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information about a specific unicast MAC address
+ for which the bridge interface has some forwarding
+ and/or filtering information."
+ INDEX { begemotBridgeBaseName, begemotBridgeTpFdbAddress }
+ ::= { begemotBridgeTpFdbTable 1 }
+
+BegemotBridgeTpFdbEntry ::= SEQUENCE {
+ begemotBridgeTpFdbAddress MacAddress,
+ begemotBridgeTpFdbPort Integer32,
+ begemotBridgeTpFdbStatus INTEGER
+}
+
+begemotBridgeTpFdbAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A unicast MAC address for which the bridge has which the
+ bridge interface has some forwarding and/or filtering
+ information."
+ ::= { begemotBridgeTpFdbEntry 1 }
+
+begemotBridgeTpFdbPort OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The port number of the bridge port on which a frame having
+ a source address equal to the value of the corresponding
+ instance of begemotBridgeTpFdbAddress has been seen."
+ ::= { begemotBridgeTpFdbEntry 2 }
+
+begemotBridgeTpFdbStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1),
+ invalid(2),
+ learned(3),
+ self(4),
+ mgmt(5)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The status of this entry. The meanings of the
+ values are:
+ other(1) - none of the following.
+ invalid(2) - this entry is no longer valid (e.g.,
+ it was learned but has since aged out), but has
+ not yet been flushed from the table.
+ learned(3) - the value of the corresponding instance
+ of begemotBridgeTpFdbPort was learned, and is being
+ used.
+ self(4) - the value of the corresponding instance of
+ begemotBridgeTpFdbAddress represents one of the
+ bridge's addresses. The corresponding instance of
+ begemotBridgeTpFdbPort indicates which of the bridge's
+ ports has this address.
+ mgmt(5) - the value of the corresponding instance of
+ begemotBridgeTpFdbAddress has been added to the
+ bridge's Forwarding Database by some management
+ means."
+ ::= { begemotBridgeTpFdbEntry 3 }
+
+-- ---------------------------------------------------------- --
+-- Ports table for Transparent Bridging interfaces
+-- ---------------------------------------------------------- --
+
+begemotBridgeTpPortTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotBridgeTpPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information about every bridge port,
+ member of a bridge interface, associated with the transparent
+ bridging function of the bridge."
+ ::= { begemotBridgeTp 3 }
+
+begemotBridgeTpPortEntry OBJECT-TYPE
+ SYNTAX BegemotBridgeTpPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of information about every bridge port, member of a
+ bridge interface, associated with the bridge's transparent
+ bridging function."
+ INDEX { begemotBridgeBaseName, begemotBridgeBasePortIfIndex }
+ ::= { begemotBridgeTpPortTable 1 }
+
+BegemotBridgeTpPortEntry ::= SEQUENCE {
+ begemotBridgeTpPort Integer32,
+ begemotBridgeTpPortMaxInfo Integer32,
+ begemotBridgeTpPortInFrames Counter32,
+ begemotBridgeTpPortOutFrames Counter32,
+ begemotBridgeTpPortInDiscards Counter32
+}
+
+begemotBridgeTpPort OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The system interface index of the port for which this entry
+ contains Transparent bridging management information."
+ ::= { begemotBridgeTpPortEntry 1 }
+
+begemotBridgeTpPortMaxInfo OBJECT-TYPE
+ SYNTAX Integer32
+ UNITS "bytes"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum size of the INFO (non-MAC) field that this port
+ will receive or transmit."
+ ::= { begemotBridgeTpPortEntry 2 }
+
+begemotBridgeTpPortInFrames OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that have been received by this
+ port from its segment. Note that a frame received on the
+ interface corresponding to this port is only counted by
+ this object if and only if it is for a protocol being
+ processed by the local bridging function, including
+ bridge management frames."
+ ::= { begemotBridgeTpPortEntry 3 }
+
+begemotBridgeTpPortOutFrames OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that have been transmitted by this
+ port to its segment. Note that a frame transmitted on
+ the interface corresponding to this port is only counted
+ by this object if and only if it is for a protocol being
+ processed by the local bridging function, including
+ bridge management frames."
+ ::= { begemotBridgeTpPortEntry 4 }
+
+begemotBridgeTpPortInDiscards OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Count of received valid frames that were discarded
+ (i.e., filtered) by the Forwarding Process."
+ ::= { begemotBridgeTpPortEntry 5 }
+
+-- ---------------------------------------------------------- --
+-- the begemotBridgePf objects
+-- ---------------------------------------------------------- --
+
+begemotBridgePfilStatus OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Indicates whether packet filtering by some firewall
+ package is enabled on the bridge interface."
+ ::= { begemotBridgePf 1 }
+
+begemotBridgePfilMembers OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "A value of true(1) indicates that packet filtering is
+ enabled on both incoming and outgoing bridge member
+ interfaces."
+ ::= { begemotBridgePf 2 }
+
+begemotBridgePfilIpOnly OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This value controls the handling of non-IP packets which
+ are not passed on for further processing to a firewall
+ package. A value of false(0) indicates that all non-IP
+ Ethernet frames are passed unconditionally."
+ ::= { begemotBridgePf 3 }
+
+begemotBridgeLayer2PfStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ enabled(1),
+ disabled(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This value indicates whether layer2 filtering by a
+ firewall package is enabled for bridge interfaces."
+ ::= { begemotBridgePf 4 }
+
+-- ---------------------------------------------------------- --
+-- the begemotBridgeConfigObjects objects
+-- ---------------------------------------------------------- --
+
+begemotBridgeDefaultBridgeIf OBJECT-TYPE
+
+ SYNTAX BridgeIfNameOrEmpty
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The name of the bridge interface that will be managed
+ via objects in IETF BRIDGE-MIB (RFC4188). If the
+ object's value is set to an empty string, bridge interfaces
+ will only be managed via objects in this MIB module."
+ DEFVAL { "bridge0" }
+ ::= { begemotBridgeConfigObjects 1 }
+
+begemotBridgeDataUpdate OBJECT-TYPE
+
+ SYNTAX Timeout (1..300)
+ UNITS "seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum age in seconds of the cached data."
+ DEFVAL { 10 }
+ ::= { begemotBridgeConfigObjects 2 }
+
+begemotBridgeDataPoll OBJECT-TYPE
+
+ SYNTAX Timeout (1..3600)
+ UNITS "seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The polling rate of data when the module is idle."
+ DEFVAL { 300 }
+ ::= { begemotBridgeConfigObjects 3 }
+
+-- ---------------------------------------------------------- --
+-- Notifications for the Spanning Tree Protocol
+-- ---------------------------------------------------------- --
+
+begemotBridgeNewRoot NOTIFICATION-TYPE
+ OBJECTS { begemotBridgeBaseName }
+ STATUS current
+ DESCRIPTION
+ "The begemotBridgeNewRoot trap indicates that one of the
+ bridge interfaces on the sending agent's device has
+ become the new root of the spanning tree topology it is
+ participating in."
+ ::= { begemotBridgeNotifications 1 }
+
+begemotBridgeTopologyChange NOTIFICATION-TYPE
+ OBJECTS { begemotBridgeBaseName }
+ STATUS current
+ DESCRIPTION
+ "A begemotBridgeTopologyChange trap is send when a member
+ port on one of the bridge interfaces, monitored by the agent,
+ transitions from the Learning state to the Forwarding state,
+ or from the Forwarding state to the Blocking state. The trap
+ is not sent if a begemotBridgeNewRoot trap is sent for the
+ same transition."
+ ::= { begemotBridgeNotifications 2 }
+
+END
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/BRIDGE-MIB.txt b/usr.sbin/bsnmpd/modules/snmp_bridge/BRIDGE-MIB.txt
new file mode 100644
index 0000000..9f87b65
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/BRIDGE-MIB.txt
@@ -0,0 +1,1483 @@
+--
+-- Copyright (C) The Internet Society (2005).
+--
+-- This document is subject to the rights, licenses and restrictions
+-- contained in BCP 78, and except as set forth therein, the authors
+-- retain all their rights.
+--
+-- This document and the information contained herein are provided on an
+-- "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+-- OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+-- ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+-- INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+-- INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+-- WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+--
+-- $FreeBSD$
+--
+
+BRIDGE-MIB DEFINITIONS ::= BEGIN
+
+-- ---------------------------------------------------------- --
+-- MIB for IEEE 802.1D devices
+-- ---------------------------------------------------------- --
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ Counter32, Integer32, TimeTicks, mib-2
+ FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION, MacAddress
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF
+ InterfaceIndex FROM IF-MIB
+ ;
+
+dot1dBridge MODULE-IDENTITY
+ LAST-UPDATED "200509190000Z"
+ ORGANIZATION "IETF Bridge MIB Working Group"
+ CONTACT-INFO
+ "Email: bridge-mib@ietf.org
+
+ K.C. Norseth (Editor)
+ L-3 Communications
+ Tel: +1 801-594-2809
+ Email: kenyon.c.norseth@L-3com.com
+ Postal: 640 N. 2200 West.
+ Salt Lake City, Utah 84116-0850
+ Les Bell (Editor)
+ 3Com Europe Limited
+ Phone: +44 1442 438025
+ Email: elbell@ntlworld.com
+ Postal: 3Com Centre, Boundary Way
+ Hemel Hempstead
+ Herts. HP2 7YU
+ UK
+
+ Send comments to <bridge-mib@ietf.org>"
+ DESCRIPTION
+ "The Bridge MIB module for managing devices that support
+ IEEE 802.1D.
+
+ Copyright (C) The Internet Society (2005). This version of
+ this MIB module is part of RFC 4188; see the RFC itself for
+ full legal notices."
+ REVISION "200509190000Z"
+ DESCRIPTION
+ "Third revision, published as part of RFC 4188.
+
+ The MIB module has been converted to SMIv2 format.
+ Conformance statements have been added and some
+ description and reference clauses have been updated.
+
+ The object dot1dStpPortPathCost32 was added to
+ support IEEE 802.1t and the permissible values of
+ dot1dStpPriority and dot1dStpPortPriority have been
+ clarified for bridges supporting IEEE 802.1t or
+ IEEE 802.1w.
+
+ The interpretation of dot1dStpTimeSinceTopologyChange
+ has been clarified for bridges supporting the Rapid
+ Spanning Tree Protocol (RSTP)."
+ REVISION "199307310000Z"
+ DESCRIPTION
+ "Second revision, published as part of RFC 1493."
+ REVISION "199112310000Z"
+ DESCRIPTION
+ "Initial revision, published as part of RFC 1286."
+ ::= { mib-2 17 }
+
+
+-- ---------------------------------------------------------- --
+-- Textual Conventions
+-- ---------------------------------------------------------- --
+
+BridgeId ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "The Bridge-Identifier, as used in the Spanning Tree
+ Protocol, to uniquely identify a bridge. Its first two
+ octets (in network byte order) contain a priority value,
+ and its last 6 octets contain the MAC address used to
+ refer to a bridge in a unique fashion (typically, the
+ numerically smallest MAC address of all ports on the
+ bridge)."
+ SYNTAX OCTET STRING (SIZE (8))
+
+Timeout ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "d"
+ STATUS current
+ DESCRIPTION
+ "A Spanning Tree Protocol (STP) timer in units of 1/100
+ seconds. Several objects in this MIB module represent
+ values of timers used by the Spanning Tree Protocol.
+ In this MIB, these timers have values in units of
+ hundredths of a second (i.e., 1/100 secs).
+
+ These timers, when stored in a Spanning Tree Protocol's
+ BPDU, are in units of 1/256 seconds. Note, however, that
+ 802.1D-1998 specifies a settable granularity of no more
+ than one second for these timers. To avoid ambiguity,
+ a conversion algorithm is defined below for converting
+ between the different units, which ensures a timer's
+ value is not distorted by multiple conversions.
+
+ To convert a Timeout value into a value in units of
+ 1/256 seconds, the following algorithm should be used:
+
+ b = floor( (n * 256) / 100)
+
+ where:
+ floor = quotient [ignore remainder]
+ n is the value in 1/100 second units
+ b is the value in 1/256 second units
+
+ To convert the value from 1/256 second units back to
+ 1/100 seconds, the following algorithm should be used:
+
+ n = ceiling( (b * 100) / 256)
+
+ where:
+ ceiling = quotient [if remainder is 0], or
+ quotient + 1 [if remainder is nonzero]
+ n is the value in 1/100 second units
+ b is the value in 1/256 second units
+
+ Note: it is important that the arithmetic operations are
+ done in the order specified (i.e., multiply first,
+ divide second)."
+ SYNTAX Integer32
+
+-- ---------------------------------------------------------- --
+-- subtrees in the Bridge MIB
+-- ---------------------------------------------------------- --
+
+dot1dNotifications OBJECT IDENTIFIER ::= { dot1dBridge 0 }
+
+dot1dBase OBJECT IDENTIFIER ::= { dot1dBridge 1 }
+dot1dStp OBJECT IDENTIFIER ::= { dot1dBridge 2 }
+
+dot1dSr OBJECT IDENTIFIER ::= { dot1dBridge 3 }
+-- documented in RFC 1525
+
+dot1dTp OBJECT IDENTIFIER ::= { dot1dBridge 4 }
+dot1dStatic OBJECT IDENTIFIER ::= { dot1dBridge 5 }
+
+-- Subtrees used by Bridge MIB Extensions:
+-- pBridgeMIB MODULE-IDENTITY ::= { dot1dBridge 6 }
+-- qBridgeMIB MODULE-IDENTITY ::= { dot1dBridge 7 }
+-- Note that the practice of registering related MIB modules
+-- below dot1dBridge has been discouraged since there is no
+-- robust mechanism to track such registrations.
+
+dot1dConformance OBJECT IDENTIFIER ::= { dot1dBridge 8 }
+
+-- ---------------------------------------------------------- --
+-- the dot1dBase subtree
+-- ---------------------------------------------------------- --
+-- Implementation of the dot1dBase subtree is mandatory for all
+-- bridges.
+-- ---------------------------------------------------------- --
+
+dot1dBaseBridgeAddress OBJECT-TYPE
+
+ SYNTAX MacAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The MAC address used by this bridge when it must be
+ referred to in a unique fashion. It is recommended
+ that this be the numerically smallest MAC address of
+ all ports that belong to this bridge. However, it is only
+ required to be unique. When concatenated with
+ dot1dStpPriority, a unique BridgeIdentifier is formed,
+ which is used in the Spanning Tree Protocol."
+ REFERENCE
+ "IEEE 802.1D-1998: clauses 14.4.1.1.3 and 7.12.5"
+ ::= { dot1dBase 1 }
+
+dot1dBaseNumPorts OBJECT-TYPE
+ SYNTAX Integer32
+ UNITS "ports"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of ports controlled by this bridging
+ entity."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.4.1.1.3"
+ ::= { dot1dBase 2 }
+
+dot1dBaseType OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(1),
+ transparent-only(2),
+ sourceroute-only(3),
+ srt(4)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates what type of bridging this bridge can
+ perform. If a bridge is actually performing a
+ certain type of bridging, this will be indicated by
+ entries in the port table for the given type."
+ ::= { dot1dBase 3 }
+
+-- ---------------------------------------------------------- --
+-- The Generic Bridge Port Table
+-- ---------------------------------------------------------- --
+dot1dBasePortTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF Dot1dBasePortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains generic information about every
+ port that is associated with this bridge. Transparent,
+ source-route, and srt ports are included."
+ ::= { dot1dBase 4 }
+
+dot1dBasePortEntry OBJECT-TYPE
+ SYNTAX Dot1dBasePortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+
+ DESCRIPTION
+ "A list of information for each port of the bridge."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.4.2, 14.6.1"
+ INDEX { dot1dBasePort }
+ ::= { dot1dBasePortTable 1 }
+
+Dot1dBasePortEntry ::=
+ SEQUENCE {
+ dot1dBasePort
+ Integer32,
+ dot1dBasePortIfIndex
+ InterfaceIndex,
+ dot1dBasePortCircuit
+ OBJECT IDENTIFIER,
+ dot1dBasePortDelayExceededDiscards
+ Counter32,
+ dot1dBasePortMtuExceededDiscards
+ Counter32
+ }
+
+dot1dBasePort OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The port number of the port for which this entry
+ contains bridge management information."
+ ::= { dot1dBasePortEntry 1 }
+
+dot1dBasePortIfIndex OBJECT-TYPE
+ SYNTAX InterfaceIndex
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of the instance of the ifIndex object,
+ defined in IF-MIB, for the interface corresponding
+ to this port."
+ ::= { dot1dBasePortEntry 2 }
+
+dot1dBasePortCircuit OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "For a port that (potentially) has the same value of
+ dot1dBasePortIfIndex as another port on the same bridge.
+ This object contains the name of an object instance
+ unique to this port. For example, in the case where
+ multiple ports correspond one-to-one with multiple X.25
+ virtual circuits, this value might identify an (e.g.,
+ the first) object instance associated with the X.25
+ virtual circuit corresponding to this port.
+
+ For a port which has a unique value of
+ dot1dBasePortIfIndex, this object can have the value
+ { 0 0 }."
+ ::= { dot1dBasePortEntry 3 }
+
+dot1dBasePortDelayExceededDiscards OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames discarded by this port due
+ to excessive transit delay through the bridge. It
+ is incremented by both transparent and source
+ route bridges."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.6.1.1.3"
+ ::= { dot1dBasePortEntry 4 }
+
+dot1dBasePortMtuExceededDiscards OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames discarded by this port due
+ to an excessive size. It is incremented by both
+ transparent and source route bridges."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.6.1.1.3"
+ ::= { dot1dBasePortEntry 5 }
+
+-- ---------------------------------------------------------- --
+-- the dot1dStp subtree
+-- ---------------------------------------------------------- --
+-- Implementation of the dot1dStp subtree is optional. It is
+-- implemented by those bridges that support the Spanning Tree
+-- Protocol.
+-- ---------------------------------------------------------- --
+dot1dStpProtocolSpecification OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(1),
+ decLb100(2),
+ ieee8021d(3)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An indication of what version of the Spanning Tree
+ Protocol is being run. The value 'decLb100(2)'
+ indicates the DEC LANbridge 100 Spanning Tree protocol.
+ IEEE 802.1D implementations will return 'ieee8021d(3)'.
+ If future versions of the IEEE Spanning Tree Protocol
+ that are incompatible with the current version
+ are released a new value will be defined."
+ ::= { dot1dStp 1 }
+
+dot1dStpPriority OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of the write-able portion of the Bridge ID
+ (i.e., the first two octets of the (8 octet long) Bridge
+ ID). The other (last) 6 octets of the Bridge ID are
+ given by the value of dot1dBaseBridgeAddress.
+ On bridges supporting IEEE 802.1t or IEEE 802.1w,
+ permissible values are 0-61440, in steps of 4096."
+ REFERENCE
+ "IEEE 802.1D-1998 clause 8.10.2, Table 8-4,
+ IEEE 802.1t clause 8.10.2, Table 8-4, clause 14.3."
+ ::= { dot1dStp 2 }
+
+dot1dStpTimeSinceTopologyChange OBJECT-TYPE
+ SYNTAX TimeTicks
+ UNITS "centi-seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The time (in hundredths of a second) since the
+ last time a topology change was detected by the
+ bridge entity.
+ For RSTP, this reports the time since the tcWhile
+ timer for any port on this Bridge was nonzero."
+ REFERENCE
+ "IEEE 802.1D-1998 clause 14.8.1.1.,
+ IEEE 802.1w clause 14.8.1.1."
+ ::= { dot1dStp 3 }
+
+dot1dStpTopChanges OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of topology changes detected by
+ this bridge since the management entity was last
+ reset or initialized."
+ REFERENCE
+ "IEEE 802.1D-1998 clause 14.8.1.1."
+ ::= { dot1dStp 4 }
+
+dot1dStpDesignatedRoot OBJECT-TYPE
+ SYNTAX BridgeId
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The bridge identifier of the root of the spanning
+ tree, as determined by the Spanning Tree Protocol,
+ as executed by this node. This value is used as
+ the Root Identifier parameter in all Configuration
+ Bridge PDUs originated by this node."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.3.1"
+ ::= { dot1dStp 5 }
+
+dot1dStpRootCost OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The cost of the path to the root as seen from
+ this bridge."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.3.2"
+ ::= { dot1dStp 6 }
+
+dot1dStpRootPort OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The port number of the port that offers the lowest
+ cost path from this bridge to the root bridge."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.3.3"
+ ::= { dot1dStp 7 }
+
+dot1dStpMaxAge OBJECT-TYPE
+ SYNTAX Timeout
+ UNITS "centi-seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum age of Spanning Tree Protocol information
+ learned from the network on any port before it is
+ discarded, in units of hundredths of a second. This is
+ the actual value that this bridge is currently using."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.3.4"
+ ::= { dot1dStp 8 }
+
+dot1dStpHelloTime OBJECT-TYPE
+ SYNTAX Timeout
+ UNITS "centi-seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The amount of time between the transmission of
+ Configuration bridge PDUs by this node on any port when
+ it is the root of the spanning tree, or trying to become
+ so, in units of hundredths of a second. This is the
+ actual value that this bridge is currently using."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.3.5"
+ ::= { dot1dStp 9 }
+
+dot1dStpHoldTime OBJECT-TYPE
+ SYNTAX Integer32
+ UNITS "centi-seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This time value determines the interval length
+ during which no more than two Configuration bridge
+ PDUs shall be transmitted by this node, in units
+ of hundredths of a second."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.3.14"
+ ::= { dot1dStp 10 }
+
+dot1dStpForwardDelay OBJECT-TYPE
+ SYNTAX Timeout
+ UNITS "centi-seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This time value, measured in units of hundredths of a
+ second, controls how fast a port changes its spanning
+ state when moving towards the Forwarding state. The
+ value determines how long the port stays in each of the
+ Listening and Learning states, which precede the
+ Forwarding state. This value is also used when a
+ topology change has been detected and is underway, to
+ age all dynamic entries in the Forwarding Database.
+ [Note that this value is the one that this bridge is
+ currently using, in contrast to
+ dot1dStpBridgeForwardDelay, which is the value that this
+ bridge and all others would start using if/when this
+ bridge were to become the root.]"
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.3.6"
+ ::= { dot1dStp 11 }
+
+dot1dStpBridgeMaxAge OBJECT-TYPE
+ SYNTAX Timeout (600..4000)
+ UNITS "centi-seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value that all bridges use for MaxAge when this
+ bridge is acting as the root. Note that 802.1D-1998
+ specifies that the range for this parameter is related
+ to the value of dot1dStpBridgeHelloTime. The
+ granularity of this timer is specified by 802.1D-1998 to
+ be 1 second. An agent may return a badValue error if a
+ set is attempted to a value that is not a whole number
+ of seconds."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.3.8"
+ ::= { dot1dStp 12 }
+
+dot1dStpBridgeHelloTime OBJECT-TYPE
+ SYNTAX Timeout (100..1000)
+ UNITS "centi-seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value that all bridges use for HelloTime when this
+ bridge is acting as the root. The granularity of this
+ timer is specified by 802.1D-1998 to be 1 second. An
+ agent may return a badValue error if a set is attempted
+ to a value that is not a whole number of seconds."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.3.9"
+ ::= { dot1dStp 13 }
+
+dot1dStpBridgeForwardDelay OBJECT-TYPE
+ SYNTAX Timeout (400..3000)
+ UNITS "centi-seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value that all bridges use for ForwardDelay when
+ this bridge is acting as the root. Note that
+ 802.1D-1998 specifies that the range for this parameter
+ is related to the value of dot1dStpBridgeMaxAge. The
+ granularity of this timer is specified by 802.1D-1998 to
+ be 1 second. An agent may return a badValue error if a
+ set is attempted to a value that is not a whole number
+ of seconds."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.3.10"
+ ::= { dot1dStp 14 }
+
+-- ---------------------------------------------------------- --
+-- The Spanning Tree Port Table
+-- ---------------------------------------------------------- --
+
+dot1dStpPortTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF Dot1dStpPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains port-specific information
+ for the Spanning Tree Protocol."
+ ::= { dot1dStp 15 }
+
+dot1dStpPortEntry OBJECT-TYPE
+ SYNTAX Dot1dStpPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of information maintained by every port about
+ the Spanning Tree Protocol state for that port."
+ INDEX { dot1dStpPort }
+ ::= { dot1dStpPortTable 1 }
+
+Dot1dStpPortEntry ::=
+ SEQUENCE {
+ dot1dStpPort
+ Integer32,
+ dot1dStpPortPriority
+ Integer32,
+ dot1dStpPortState
+ INTEGER,
+ dot1dStpPortEnable
+ INTEGER,
+ dot1dStpPortPathCost
+ Integer32,
+ dot1dStpPortDesignatedRoot
+ BridgeId,
+ dot1dStpPortDesignatedCost
+ Integer32,
+ dot1dStpPortDesignatedBridge
+ BridgeId,
+ dot1dStpPortDesignatedPort
+ OCTET STRING,
+ dot1dStpPortForwardTransitions
+ Counter32,
+ dot1dStpPortPathCost32
+ Integer32
+ }
+
+dot1dStpPort OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The port number of the port for which this entry
+ contains Spanning Tree Protocol management information."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.8.2.1.2"
+ ::= { dot1dStpPortEntry 1 }
+
+dot1dStpPortPriority OBJECT-TYPE
+ SYNTAX Integer32 (0..255)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of the priority field that is contained in
+ the first (in network byte order) octet of the (2 octet
+ long) Port ID. The other octet of the Port ID is given
+ by the value of dot1dStpPort.
+ On bridges supporting IEEE 802.1t or IEEE 802.1w,
+ permissible values are 0-240, in steps of 16."
+ REFERENCE
+ "IEEE 802.1D-1998 clause 8.10.2, Table 8-4,
+ IEEE 802.1t clause 8.10.2, Table 8-4, clause 14.3."
+ ::= { dot1dStpPortEntry 2 }
+
+dot1dStpPortState OBJECT-TYPE
+ SYNTAX INTEGER {
+ disabled(1),
+ blocking(2),
+ listening(3),
+ learning(4),
+ forwarding(5),
+ broken(6)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The port's current state, as defined by application of
+ the Spanning Tree Protocol. This state controls what
+ action a port takes on reception of a frame. If the
+ bridge has detected a port that is malfunctioning, it
+ will place that port into the broken(6) state. For
+ ports that are disabled (see dot1dStpPortEnable), this
+ object will have a value of disabled(1)."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.5.2"
+ ::= { dot1dStpPortEntry 3 }
+
+dot1dStpPortEnable OBJECT-TYPE
+ SYNTAX INTEGER {
+ enabled(1),
+ disabled(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The enabled/disabled status of the port."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.5.2"
+ ::= { dot1dStpPortEntry 4 }
+
+dot1dStpPortPathCost OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The contribution of this port to the path cost of
+ paths towards the spanning tree root which include
+ this port. 802.1D-1998 recommends that the default
+ value of this parameter be in inverse proportion to
+ the speed of the attached LAN.
+
+ New implementations should support dot1dStpPortPathCost32.
+ If the port path costs exceeds the maximum value of this
+ object then this object should report the maximum value,
+ namely 65535. Applications should try to read the
+ dot1dStpPortPathCost32 object if this object reports
+ the maximum value."
+ REFERENCE "IEEE 802.1D-1998: clause 8.5.5.3"
+ ::= { dot1dStpPortEntry 5 }
+
+dot1dStpPortDesignatedRoot OBJECT-TYPE
+ SYNTAX BridgeId
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The unique Bridge Identifier of the Bridge
+ recorded as the Root in the Configuration BPDUs
+ transmitted by the Designated Bridge for the
+ segment to which the port is attached."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.5.4"
+ ::= { dot1dStpPortEntry 6 }
+
+dot1dStpPortDesignatedCost OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The path cost of the Designated Port of the segment
+ connected to this port. This value is compared to the
+ Root Path Cost field in received bridge PDUs."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.5.5"
+ ::= { dot1dStpPortEntry 7 }
+
+dot1dStpPortDesignatedBridge OBJECT-TYPE
+ SYNTAX BridgeId
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The Bridge Identifier of the bridge that this
+ port considers to be the Designated Bridge for
+ this port's segment."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.5.6"
+ ::= { dot1dStpPortEntry 8 }
+
+dot1dStpPortDesignatedPort OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (2))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The Port Identifier of the port on the Designated
+ Bridge for this port's segment."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 8.5.5.7"
+ ::= { dot1dStpPortEntry 9 }
+
+dot1dStpPortForwardTransitions OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times this port has transitioned
+ from the Learning state to the Forwarding state."
+ ::= { dot1dStpPortEntry 10 }
+
+dot1dStpPortPathCost32 OBJECT-TYPE
+ SYNTAX Integer32 (1..200000000)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The contribution of this port to the path cost of
+ paths towards the spanning tree root which include
+ this port. 802.1D-1998 recommends that the default
+ value of this parameter be in inverse proportion to
+ the speed of the attached LAN.
+
+ This object replaces dot1dStpPortPathCost to support
+ IEEE 802.1t."
+ REFERENCE
+ "IEEE 802.1t clause 8.10.2, Table 8-5."
+ ::= { dot1dStpPortEntry 11 }
+
+-- ---------------------------------------------------------- --
+-- the dot1dTp subtree
+-- ---------------------------------------------------------- --
+-- Implementation of the dot1dTp subtree is optional. It is
+-- implemented by those bridges that support the transparent
+-- bridging mode. A transparent or SRT bridge will implement
+-- this subtree.
+-- ---------------------------------------------------------- --
+
+dot1dTpLearnedEntryDiscards OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of Forwarding Database entries that
+ have been or would have been learned, but have been
+ discarded due to a lack of storage space in the
+ Forwarding Database. If this counter is increasing, it
+ indicates that the Forwarding Database is regularly
+ becoming full (a condition that has unpleasant
+ performance effects on the subnetwork). If this counter
+ has a significant value but is not presently increasing,
+ it indicates that the problem has been occurring but is
+ not persistent."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.7.1.1.3"
+ ::= { dot1dTp 1 }
+
+dot1dTpAgingTime OBJECT-TYPE
+ SYNTAX Integer32 (10..1000000)
+ UNITS "seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The timeout period in seconds for aging out
+ dynamically-learned forwarding information.
+ 802.1D-1998 recommends a default of 300 seconds."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.7.1.1.3"
+ ::= { dot1dTp 2 }
+
+
+-- ---------------------------------------------------------- --
+-- The Forwarding Database for Transparent Bridges
+-- ---------------------------------------------------------- --
+
+dot1dTpFdbTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF Dot1dTpFdbEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information about unicast
+ entries for which the bridge has forwarding and/or
+ filtering information. This information is used
+ by the transparent bridging function in
+ determining how to propagate a received frame."
+ ::= { dot1dTp 3 }
+
+dot1dTpFdbEntry OBJECT-TYPE
+ SYNTAX Dot1dTpFdbEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information about a specific unicast MAC address
+ for which the bridge has some forwarding and/or
+ filtering information."
+ INDEX { dot1dTpFdbAddress }
+ ::= { dot1dTpFdbTable 1 }
+
+Dot1dTpFdbEntry ::=
+ SEQUENCE {
+ dot1dTpFdbAddress
+ MacAddress,
+ dot1dTpFdbPort
+ Integer32,
+ dot1dTpFdbStatus
+ INTEGER
+ }
+
+dot1dTpFdbAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A unicast MAC address for which the bridge has
+ forwarding and/or filtering information."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 7.9.1, 7.9.2"
+ ::= { dot1dTpFdbEntry 1 }
+
+dot1dTpFdbPort OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Either the value '0', or the port number of the port on
+ which a frame having a source address equal to the value
+ of the corresponding instance of dot1dTpFdbAddress has
+ been seen. A value of '0' indicates that the port
+ number has not been learned, but that the bridge does
+ have some forwarding/filtering information about this
+ address (e.g., in the dot1dStaticTable). Implementors
+ are encouraged to assign the port value to this object
+ whenever it is learned, even for addresses for which the
+ corresponding value of dot1dTpFdbStatus is not
+ learned(3)."
+ ::= { dot1dTpFdbEntry 2 }
+dot1dTpFdbStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1),
+ invalid(2),
+ learned(3),
+ self(4),
+ mgmt(5)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The status of this entry. The meanings of the
+ values are:
+ other(1) - none of the following. This would
+ include the case where some other MIB object
+ (not the corresponding instance of
+ dot1dTpFdbPort, nor an entry in the
+ dot1dStaticTable) is being used to determine if
+ and how frames addressed to the value of the
+ corresponding instance of dot1dTpFdbAddress are
+ being forwarded.
+ invalid(2) - this entry is no longer valid (e.g.,
+ it was learned but has since aged out), but has
+ not yet been flushed from the table.
+ learned(3) - the value of the corresponding instance
+ of dot1dTpFdbPort was learned, and is being
+ used.
+ self(4) - the value of the corresponding instance of
+ dot1dTpFdbAddress represents one of the bridge's
+ addresses. The corresponding instance of
+ dot1dTpFdbPort indicates which of the bridge's
+ ports has this address.
+ mgmt(5) - the value of the corresponding instance of
+ dot1dTpFdbAddress is also the value of an
+ existing instance of dot1dStaticAddress."
+ ::= { dot1dTpFdbEntry 3 }
+
+-- ---------------------------------------------------------- --
+-- Port Table for Transparent Bridges
+-- ---------------------------------------------------------- --
+
+dot1dTpPortTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF Dot1dTpPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information about every port that
+ is associated with this transparent bridge."
+ ::= { dot1dTp 4 }
+
+dot1dTpPortEntry OBJECT-TYPE
+ SYNTAX Dot1dTpPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of information for each port of a transparent
+ bridge."
+ INDEX { dot1dTpPort }
+ ::= { dot1dTpPortTable 1 }
+
+Dot1dTpPortEntry ::=
+ SEQUENCE {
+ dot1dTpPort
+ Integer32,
+ dot1dTpPortMaxInfo
+ Integer32,
+ dot1dTpPortInFrames
+ Counter32,
+ dot1dTpPortOutFrames
+ Counter32,
+ dot1dTpPortInDiscards
+ Counter32
+ }
+
+dot1dTpPort OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The port number of the port for which this entry
+ contains Transparent bridging management information."
+ ::= { dot1dTpPortEntry 1 }
+
+-- It would be nice if we could use ifMtu as the size of the
+-- largest INFO field, but we can't because ifMtu is defined
+-- to be the size that the (inter-)network layer can use, which
+-- can differ from the MAC layer (especially if several layers
+-- of encapsulation are used).
+
+dot1dTpPortMaxInfo OBJECT-TYPE
+ SYNTAX Integer32
+ UNITS "bytes"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum size of the INFO (non-MAC) field that
+ this port will receive or transmit."
+ ::= { dot1dTpPortEntry 2 }
+
+dot1dTpPortInFrames OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that have been received by this
+ port from its segment. Note that a frame received on the
+ interface corresponding to this port is only counted by
+ this object if and only if it is for a protocol being
+ processed by the local bridging function, including
+ bridge management frames."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.6.1.1.3"
+ ::= { dot1dTpPortEntry 3 }
+
+dot1dTpPortOutFrames OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that have been transmitted by this
+ port to its segment. Note that a frame transmitted on
+ the interface corresponding to this port is only counted
+ by this object if and only if it is for a protocol being
+ processed by the local bridging function, including
+ bridge management frames."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.6.1.1.3"
+ ::= { dot1dTpPortEntry 4 }
+
+dot1dTpPortInDiscards OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Count of received valid frames that were discarded
+ (i.e., filtered) by the Forwarding Process."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.6.1.1.3"
+ ::= { dot1dTpPortEntry 5 }
+
+-- ---------------------------------------------------------- --
+-- The Static (Destination-Address Filtering) Database
+-- ---------------------------------------------------------- --
+-- Implementation of this subtree is optional.
+-- ---------------------------------------------------------- --
+
+dot1dStaticTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF Dot1dStaticEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table containing filtering information configured
+ into the bridge by (local or network) management
+ specifying the set of ports to which frames received
+ from specific ports and containing specific destination
+ addresses are allowed to be forwarded. The value of
+ zero in this table, as the port number from which frames
+ with a specific destination address are received, is
+ used to specify all ports for which there is no specific
+ entry in this table for that particular destination
+ address. Entries are valid for unicast and for
+ group/broadcast addresses."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.7.2"
+ ::= { dot1dStatic 1 }
+
+dot1dStaticEntry OBJECT-TYPE
+ SYNTAX Dot1dStaticEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Filtering information configured into the bridge by
+ (local or network) management specifying the set of
+ ports to which frames received from a specific port and
+ containing a specific destination address are allowed to
+ be forwarded."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 14.7.2"
+ INDEX { dot1dStaticAddress, dot1dStaticReceivePort }
+ ::= { dot1dStaticTable 1 }
+
+Dot1dStaticEntry ::=
+ SEQUENCE {
+ dot1dStaticAddress MacAddress,
+ dot1dStaticReceivePort Integer32,
+ dot1dStaticAllowedToGoTo OCTET STRING,
+ dot1dStaticStatus INTEGER
+ }
+
+dot1dStaticAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The destination MAC address in a frame to which this
+ entry's filtering information applies. This object can
+ take the value of a unicast address, a group address, or
+ the broadcast address."
+ REFERENCE
+ "IEEE 802.1D-1998: clause 7.9.1, 7.9.2"
+ ::= { dot1dStaticEntry 1 }
+
+dot1dStaticReceivePort OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "Either the value '0', or the port number of the port
+ from which a frame must be received in order for this
+ entry's filtering information to apply. A value of zero
+ indicates that this entry applies on all ports of the
+ bridge for which there is no other applicable entry."
+ ::= { dot1dStaticEntry 2 }
+
+dot1dStaticAllowedToGoTo OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..512))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The set of ports to which frames received from a
+ specific port and destined for a specific MAC address,
+ are allowed to be forwarded. Each octet within the
+ value of this object specifies a set of eight ports,
+ with the first octet specifying ports 1 through 8, the
+ second octet specifying ports 9 through 16, etc. Within
+ each octet, the most significant bit represents the
+ lowest numbered port, and the least significant bit
+ represents the highest numbered port. Thus, each port
+ of the bridge is represented by a single bit within the
+ value of this object. If that bit has a value of '1',
+ then that port is included in the set of ports; the port
+ is not included if its bit has a value of '0'. (Note
+ that the setting of the bit corresponding to the port
+ from which a frame is received is irrelevant.) The
+ default value of this object is a string of ones of
+ appropriate length.
+
+ The value of this object may exceed the required minimum
+ maximum message size of some SNMP transport (484 bytes,
+ in the case of SNMP over UDP, see RFC 3417, section 3.2).
+ SNMP engines on bridges supporting a large number of
+ ports must support appropriate maximum message sizes."
+ ::= { dot1dStaticEntry 3 }
+
+dot1dStaticStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1),
+ invalid(2),
+ permanent(3),
+ deleteOnReset(4),
+ deleteOnTimeout(5)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object indicates the status of this entry.
+ The default value is permanent(3).
+ other(1) - this entry is currently in use but the
+ conditions under which it will remain so are
+ different from each of the following values.
+ invalid(2) - writing this value to the object
+ removes the corresponding entry.
+ permanent(3) - this entry is currently in use and
+ will remain so after the next reset of the
+ bridge.
+ deleteOnReset(4) - this entry is currently in use
+ and will remain so until the next reset of the
+ bridge.
+ deleteOnTimeout(5) - this entry is currently in use
+ and will remain so until it is aged out."
+ ::= { dot1dStaticEntry 4 }
+
+-- ---------------------------------------------------------- --
+-- Notifications for use by Bridges
+-- ---------------------------------------------------------- --
+-- Notifications for the Spanning Tree Protocol
+-- ---------------------------------------------------------- --
+
+newRoot NOTIFICATION-TYPE
+ -- OBJECTS { }
+ STATUS current
+ DESCRIPTION
+ "The newRoot trap indicates that the sending agent has
+ become the new root of the Spanning Tree; the trap is
+ sent by a bridge soon after its election as the new
+ root, e.g., upon expiration of the Topology Change Timer,
+ immediately subsequent to its election. Implementation
+ of this trap is optional."
+ ::= { dot1dNotifications 1 }
+
+topologyChange NOTIFICATION-TYPE
+ -- OBJECTS { }
+ STATUS current
+ DESCRIPTION
+ "A topologyChange trap is sent by a bridge when any of
+ its configured ports transitions from the Learning state
+ to the Forwarding state, or from the Forwarding state to
+ the Blocking state. The trap is not sent if a newRoot
+ trap is sent for the same transition. Implementation of
+ this trap is optional."
+ ::= { dot1dNotifications 2 }
+
+-- ---------------------------------------------------------- --
+-- IEEE 802.1D MIB - Conformance Information
+-- ---------------------------------------------------------- --
+
+dot1dGroups OBJECT IDENTIFIER ::= { dot1dConformance 1 }
+dot1dCompliances OBJECT IDENTIFIER ::= { dot1dConformance 2 }
+
+-- ---------------------------------------------------------- --
+-- units of conformance
+-- ---------------------------------------------------------- --
+
+-- ---------------------------------------------------------- --
+-- the dot1dBase group
+-- ---------------------------------------------------------- --
+
+dot1dBaseBridgeGroup OBJECT-GROUP
+ OBJECTS {
+ dot1dBaseBridgeAddress,
+ dot1dBaseNumPorts,
+ dot1dBaseType
+ }
+ STATUS current
+ DESCRIPTION
+ "Bridge level information for this device."
+ ::= { dot1dGroups 1 }
+
+dot1dBasePortGroup OBJECT-GROUP
+ OBJECTS {
+ dot1dBasePort,
+ dot1dBasePortIfIndex,
+ dot1dBasePortCircuit,
+ dot1dBasePortDelayExceededDiscards,
+ dot1dBasePortMtuExceededDiscards
+ }
+ STATUS current
+ DESCRIPTION
+ "Information for each port on this device."
+ ::= { dot1dGroups 2 }
+
+-- ---------------------------------------------------------- --
+-- the dot1dStp group
+-- ---------------------------------------------------------- --
+
+dot1dStpBridgeGroup OBJECT-GROUP
+ OBJECTS {
+ dot1dStpProtocolSpecification,
+ dot1dStpPriority,
+ dot1dStpTimeSinceTopologyChange,
+ dot1dStpTopChanges,
+ dot1dStpDesignatedRoot,
+ dot1dStpRootCost,
+ dot1dStpRootPort,
+ dot1dStpMaxAge,
+ dot1dStpHelloTime,
+ dot1dStpHoldTime,
+ dot1dStpForwardDelay,
+ dot1dStpBridgeMaxAge,
+ dot1dStpBridgeHelloTime,
+ dot1dStpBridgeForwardDelay
+ }
+ STATUS current
+ DESCRIPTION
+ "Bridge level Spanning Tree data for this device."
+ ::= { dot1dGroups 3 }
+
+dot1dStpPortGroup OBJECT-GROUP
+ OBJECTS {
+ dot1dStpPort,
+ dot1dStpPortPriority,
+ dot1dStpPortState,
+ dot1dStpPortEnable,
+ dot1dStpPortPathCost,
+ dot1dStpPortDesignatedRoot,
+ dot1dStpPortDesignatedCost,
+ dot1dStpPortDesignatedBridge,
+ dot1dStpPortDesignatedPort,
+ dot1dStpPortForwardTransitions
+ }
+ STATUS current
+ DESCRIPTION
+ "Spanning Tree data for each port on this device."
+ ::= { dot1dGroups 4 }
+
+dot1dStpPortGroup2 OBJECT-GROUP
+ OBJECTS {
+ dot1dStpPort,
+ dot1dStpPortPriority,
+ dot1dStpPortState,
+ dot1dStpPortEnable,
+ dot1dStpPortDesignatedRoot,
+ dot1dStpPortDesignatedCost,
+ dot1dStpPortDesignatedBridge,
+ dot1dStpPortDesignatedPort,
+ dot1dStpPortForwardTransitions,
+ dot1dStpPortPathCost32
+ }
+ STATUS current
+ DESCRIPTION
+ "Spanning Tree data for each port on this device."
+ ::= { dot1dGroups 5 }
+
+dot1dStpPortGroup3 OBJECT-GROUP
+ OBJECTS {
+ dot1dStpPortPathCost32
+ }
+ STATUS current
+ DESCRIPTION
+ "Spanning Tree data for devices supporting 32-bit
+ path costs."
+ ::= { dot1dGroups 6 }
+
+-- ---------------------------------------------------------- --
+-- the dot1dTp group
+-- ---------------------------------------------------------- --
+
+dot1dTpBridgeGroup OBJECT-GROUP
+ OBJECTS {
+ dot1dTpLearnedEntryDiscards,
+ dot1dTpAgingTime
+ }
+ STATUS current
+ DESCRIPTION
+ "Bridge level Transparent Bridging data."
+ ::= { dot1dGroups 7 }
+
+dot1dTpFdbGroup OBJECT-GROUP
+ OBJECTS {
+ dot1dTpFdbAddress,
+ dot1dTpFdbPort,
+ dot1dTpFdbStatus
+ }
+
+ STATUS current
+ DESCRIPTION
+ "Filtering Database information for the Bridge."
+ ::= { dot1dGroups 8 }
+
+dot1dTpGroup OBJECT-GROUP
+ OBJECTS {
+ dot1dTpPort,
+ dot1dTpPortMaxInfo,
+ dot1dTpPortInFrames,
+ dot1dTpPortOutFrames,
+ dot1dTpPortInDiscards
+ }
+ STATUS current
+ DESCRIPTION
+ "Dynamic Filtering Database information for each port of
+ the Bridge."
+ ::= { dot1dGroups 9 }
+
+-- ---------------------------------------------------------- --
+-- The Static (Destination-Address Filtering) Database
+-- ---------------------------------------------------------- --
+
+dot1dStaticGroup OBJECT-GROUP
+ OBJECTS {
+ dot1dStaticAddress,
+ dot1dStaticReceivePort,
+ dot1dStaticAllowedToGoTo,
+ dot1dStaticStatus
+ }
+ STATUS current
+ DESCRIPTION
+ "Static Filtering Database information for each port of
+ the Bridge."
+ ::= { dot1dGroups 10 }
+
+-- ---------------------------------------------------------- --
+-- The Trap Notification Group
+-- ---------------------------------------------------------- --
+
+dot1dNotificationGroup NOTIFICATION-GROUP
+ NOTIFICATIONS {
+ newRoot,
+ topologyChange
+ }
+ STATUS current
+ DESCRIPTION
+ "Group of objects describing notifications (traps)."
+ ::= { dot1dGroups 11 }
+
+-- ---------------------------------------------------------- --
+-- compliance statements
+-- ---------------------------------------------------------- --
+
+bridgeCompliance1493 MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for device support of bridging
+ services, as per RFC1493."
+
+ MODULE
+ MANDATORY-GROUPS {
+ dot1dBaseBridgeGroup,
+ dot1dBasePortGroup
+ }
+
+ GROUP dot1dStpBridgeGroup
+ DESCRIPTION
+ "Implementation of this group is mandatory for bridges
+ that support the Spanning Tree Protocol."
+
+ GROUP dot1dStpPortGroup
+ DESCRIPTION
+ "Implementation of this group is mandatory for bridges
+ that support the Spanning Tree Protocol."
+
+ GROUP dot1dTpBridgeGroup
+ DESCRIPTION
+ "Implementation of this group is mandatory for bridges
+ that support the transparent bridging mode. A
+ transparent or SRT bridge will implement this group."
+
+ GROUP dot1dTpFdbGroup
+ DESCRIPTION
+ "Implementation of this group is mandatory for bridges
+ that support the transparent bridging mode. A
+ transparent or SRT bridge will implement this group."
+
+ GROUP dot1dTpGroup
+ DESCRIPTION
+ "Implementation of this group is mandatory for bridges
+ that support the transparent bridging mode. A
+ transparent or SRT bridge will implement this group."
+
+ GROUP dot1dStaticGroup
+ DESCRIPTION
+ "Implementation of this group is optional."
+
+ GROUP dot1dNotificationGroup
+ DESCRIPTION
+ "Implementation of this group is optional."
+ ::= { dot1dCompliances 1 }
+
+bridgeCompliance4188 MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for device support of bridging
+ services. This supports 32-bit Path Cost values and the
+ more restricted bridge and port priorities, as per IEEE
+ 802.1t.
+
+ Full support for the 802.1D management objects requires that
+ the SNMPv2-MIB [RFC3418] objects sysDescr, and sysUpTime, as
+ well as the IF-MIB [RFC2863] objects ifIndex, ifType,
+ ifDescr, ifPhysAddress, and ifLastChange are implemented."
+
+ MODULE
+ MANDATORY-GROUPS {
+ dot1dBaseBridgeGroup,
+ dot1dBasePortGroup
+ }
+
+ GROUP dot1dStpBridgeGroup
+ DESCRIPTION
+ "Implementation of this group is mandatory for
+ bridges that support the Spanning Tree Protocol."
+
+ OBJECT dot1dStpPriority
+ SYNTAX Integer32 (0|4096|8192|12288|16384|20480|24576
+ |28672|32768|36864|40960|45056|49152
+ |53248|57344|61440)
+ DESCRIPTION
+ "The possible values defined by IEEE 802.1t."
+
+ GROUP dot1dStpPortGroup2
+ DESCRIPTION
+ "Implementation of this group is mandatory for
+ bridges that support the Spanning Tree Protocol."
+
+ GROUP dot1dStpPortGroup3
+ DESCRIPTION
+ "Implementation of this group is mandatory for bridges
+ that support the Spanning Tree Protocol and 32-bit path
+ costs. In particular, this includes devices supporting
+ IEEE 802.1t and IEEE 802.1w."
+
+ OBJECT dot1dStpPortPriority
+ SYNTAX Integer32 (0|16|32|48|64|80|96|112|128
+ |144|160|176|192|208|224|240)
+ DESCRIPTION
+ "The possible values defined by IEEE 802.1t."
+
+ GROUP dot1dTpBridgeGroup
+ DESCRIPTION
+ "Implementation of this group is mandatory for
+ bridges that support the transparent bridging
+ mode. A transparent or SRT bridge will implement
+ this group."
+
+ GROUP dot1dTpFdbGroup
+ DESCRIPTION
+ "Implementation of this group is mandatory for
+ bridges that support the transparent bridging
+ mode. A transparent or SRT bridge will implement
+ this group."
+
+ GROUP dot1dTpGroup
+ DESCRIPTION
+ "Implementation of this group is mandatory for
+ bridges that support the transparent bridging
+ mode. A transparent or SRT bridge will implement
+ this group."
+
+ GROUP dot1dStaticGroup
+ DESCRIPTION
+ "Implementation of this group is optional."
+
+ GROUP dot1dNotificationGroup
+ DESCRIPTION
+ "Implementation of this group is optional."
+
+ ::= { dot1dCompliances 2 }
+
+END
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/Makefile b/usr.sbin/bsnmpd/modules/snmp_bridge/Makefile
new file mode 100644
index 0000000..873151c
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/Makefile
@@ -0,0 +1,19 @@
+#
+# $FreeBSD$
+#
+
+MOD= bridge
+SRCS= bridge_snmp.c bridge_if.c bridge_port.c bridge_addrs.c \
+ bridge_pf.c bridge_sys.c
+CFLAGS+= -DSNMPTREE_TYPES
+
+XSYM= dot1dBridge newRoot topologyChange begemotBridgeNewRoot \
+ begemotBridgeTopologyChange begemotBridgeBaseName
+
+MAN= snmp_bridge.3
+
+BMIBS= BRIDGE-MIB.txt BEGEMOT-BRIDGE-MIB.txt
+DEFS= ${MOD}_tree.def
+INCS= ${MOD}_snmp.h
+
+.include <bsd.snmpmod.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c
new file mode 100644
index 0000000..fdb0fa3
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c
@@ -0,0 +1,592 @@
+/*-
+ * 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 addresses.
+ *
+ * $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(tp_entries, tp_entry);
+
+/*
+ * Free the bridge address list.
+ */
+static void
+bridge_tpe_free(struct tp_entries *headp)
+{
+ struct tp_entry *t;
+
+ while ((t = TAILQ_FIRST(headp)) != NULL) {
+ TAILQ_REMOVE(headp, t, tp_e);
+ free(t);
+ }
+}
+
+/*
+ * Free the bridge address entries from the address list,
+ * for the specified bridge interface only.
+ */
+static void
+bridge_tpe_bif_free(struct tp_entries *headp,
+ struct bridge_if *bif)
+{
+ struct tp_entry *tp;
+
+ while (bif->f_tpa != NULL && bif->sysindex == bif->f_tpa->sysindex) {
+ tp = TAILQ_NEXT(bif->f_tpa, tp_e);
+ TAILQ_REMOVE(headp, bif->f_tpa, tp_e);
+ free(bif->f_tpa);
+ bif->f_tpa = tp;
+ }
+}
+
+/*
+ * Compare two mac addresses.
+ * m1 < m2 : -1
+ * m1 > m2 : +1
+ * m1 = m2 : 0
+ */
+static int
+bridge_compare_macs(const uint8_t *m1, const uint8_t *m2)
+{
+ int i;
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ if (m1[i] < m2[i])
+ return (-1);
+ if (m1[i] > m2[i])
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Insert an address entry in the bridge address TAILQ starting to search
+ * for its place from the position of the first bridge address for the bridge
+ * interface. Update the first bridge address if neccessary.
+ */
+static void
+bridge_addrs_insert_at(struct tp_entries *headp,
+ struct tp_entry *ta, struct tp_entry **f_tpa)
+{
+ struct tp_entry *t1;
+
+ assert(f_tpa != NULL);
+
+ for (t1 = *f_tpa;
+ t1 != NULL && ta->sysindex == t1->sysindex;
+ t1 = TAILQ_NEXT(t1, tp_e)) {
+ if (bridge_compare_macs(ta->tp_addr, t1->tp_addr) < 0) {
+ TAILQ_INSERT_BEFORE(t1, ta, tp_e);
+ if (*f_tpa == t1)
+ (*f_tpa) = ta;
+ return;
+ }
+ }
+
+ if (t1 == NULL)
+ TAILQ_INSERT_TAIL(headp, ta, tp_e);
+ else
+ TAILQ_INSERT_BEFORE(t1, ta, tp_e);
+}
+
+/*
+ * Find an address entry's possition in the address list
+ * according to bridge interface name.
+ */
+static struct tp_entry *
+bridge_addrs_find_pos(struct tp_entries *headp, uint32_t b_idx)
+{
+ uint32_t t_idx;
+ struct tp_entry *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, tp_e); t1 != NULL; t1 = TAILQ_NEXT(t1, tp_e)) {
+
+ if (t1->sysindex != t_idx) {
+ if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
+ return (TAILQ_PREV(t1, tp_entries, tp_e));
+ else
+ t_idx = t1->sysindex;
+ }
+ }
+
+ if (t1 == NULL)
+ t1 = TAILQ_LAST(headp, tp_entries);
+
+ return (t1);
+}
+
+/*
+ * Insert a bridge address in the bridge addresses list.
+ */
+static void
+bridge_addrs_bif_insert(struct tp_entries *headp, struct tp_entry *te,
+ struct tp_entry **f_tpa)
+{
+ struct tp_entry *temp;
+
+ if (*f_tpa != NULL)
+ bridge_addrs_insert_at(headp, te, f_tpa);
+ else {
+ temp = bridge_addrs_find_pos(headp, te->sysindex);
+
+ if (temp == NULL)
+ TAILQ_INSERT_HEAD(headp, te, tp_e);
+ else
+ TAILQ_INSERT_AFTER(headp, temp, te, tp_e);
+ *f_tpa = te;
+ }
+}
+
+static struct tp_entries tp_entries = TAILQ_HEAD_INITIALIZER(tp_entries);
+static time_t address_list_age;
+
+void
+bridge_addrs_update_listage(void)
+{
+ address_list_age = time(NULL);
+}
+
+void
+bridge_addrs_fini(void)
+{
+ bridge_tpe_free(&tp_entries);
+}
+
+void
+bridge_addrs_free(struct bridge_if *bif)
+{
+ bridge_tpe_bif_free(&tp_entries, bif);
+}
+
+/*
+ * Find the first address in the list.
+ */
+static struct tp_entry *
+bridge_addrs_first(void)
+{
+ return (TAILQ_FIRST(&tp_entries));
+}
+
+/*
+ * Find the next address in the list.
+ */
+static struct tp_entry *
+bridge_addrs_next(struct tp_entry *te)
+{
+ return (TAILQ_NEXT(te, tp_e));
+}
+
+/*
+ * Find the first address, learnt by the specified bridge interface.
+ */
+struct tp_entry *
+bridge_addrs_bif_first(struct bridge_if *bif)
+{
+ return (bif->f_tpa);
+}
+
+/*
+ * Find the next address, learnt by the specified bridge interface.
+ */
+struct tp_entry *
+bridge_addrs_bif_next(struct tp_entry *te)
+{
+ struct tp_entry *te_next;
+
+ if ((te_next = TAILQ_NEXT(te, tp_e)) == NULL ||
+ te_next->sysindex != te->sysindex)
+ return (NULL);
+
+ return (te_next);
+}
+
+/*
+ * Remove a bridge address from the list.
+ */
+void
+bridge_addrs_remove(struct tp_entry *te, struct bridge_if *bif)
+{
+ if (bif->f_tpa == te)
+ bif->f_tpa = bridge_addrs_bif_next(te);
+
+ TAILQ_REMOVE(&tp_entries, te, tp_e);
+ free(te);
+}
+
+/*
+ * Allocate memory for a new bridge address and insert it in the list.
+ */
+struct tp_entry *
+bridge_new_addrs(uint8_t *mac, struct bridge_if *bif)
+{
+ struct tp_entry *te;
+
+ if ((te = (struct tp_entry *) malloc(sizeof(*te))) == NULL) {
+ syslog(LOG_ERR, "bridge new address: failed: %s",
+ strerror(errno));
+ return (NULL);
+ }
+
+ bzero(te, sizeof(*te));
+
+ te->sysindex = bif->sysindex;
+ bcopy(mac, te->tp_addr, ETHER_ADDR_LEN);
+ bridge_addrs_bif_insert(&tp_entries, te, &(bif->f_tpa));
+
+ return (te);
+}
+
+/*
+ * Given a mac address, learnt on a bridge,
+ * find the corrsponding TP entry for it.
+ */
+struct tp_entry *
+bridge_addrs_find(uint8_t *mac, struct bridge_if *bif)
+{
+ struct tp_entry *te;
+
+ for (te = bif->f_tpa; te != NULL; te = TAILQ_NEXT(te, tp_e)) {
+ if (te->sysindex != bif->sysindex) {
+ te = NULL;
+ break;
+ }
+
+ if (bridge_compare_macs(te->tp_addr, mac) == 0)
+ break;
+ }
+
+ return (te);
+}
+
+void
+bridge_addrs_dump(struct bridge_if *bif)
+{
+ struct tp_entry *te;
+
+ syslog(LOG_ERR, "Addresses count - %d", bif->num_addrs);
+ for (te = bridge_addrs_bif_first(bif); te != NULL;
+ te = bridge_addrs_bif_next(te)) {
+ syslog(LOG_ERR, "address %x:%x:%x:%x:%x:%x on port %d.%d",
+ te->tp_addr[0], te->tp_addr[1], te->tp_addr[2],
+ te->tp_addr[3], te->tp_addr[4], te->tp_addr[5],
+ te->sysindex, te->port_no);
+ }
+}
+
+/*
+ * RFC4188 specifics.
+ */
+
+/*
+ * Construct the SNMP index from the address DST Mac.
+ */
+static void
+bridge_addrs_index_append(struct asn_oid *oid, uint sub,
+ const struct tp_entry *te)
+{
+ int i;
+
+ oid->len = sub + ETHER_ADDR_LEN + 1;
+ oid->subs[sub] = ETHER_ADDR_LEN;
+
+ for (i = 1; i <= ETHER_ADDR_LEN; i++)
+ oid->subs[sub + i] = te->tp_addr[i - 1];
+}
+
+/*
+ * Find the address entry for the SNMP index from the default bridge only.
+ */
+static struct tp_entry *
+bridge_addrs_get(const struct asn_oid *oid, uint sub,
+ struct bridge_if *bif)
+{
+ int i;
+ uint8_t tp_addr[ETHER_ADDR_LEN];
+
+ if (oid->len - sub != ETHER_ADDR_LEN + 1 ||
+ oid->subs[sub] != ETHER_ADDR_LEN)
+ return (NULL);
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ tp_addr[i] = oid->subs[sub + i + 1];
+
+ return (bridge_addrs_find(tp_addr, bif));
+}
+
+/*
+ * Find the next address entry for the SNMP index
+ * from the default bridge only.
+ */
+static struct tp_entry *
+bridge_addrs_getnext(const struct asn_oid *oid, uint sub,
+ struct bridge_if *bif)
+{
+ int i;
+ uint8_t tp_addr[ETHER_ADDR_LEN];
+ static struct tp_entry *te;
+
+ if (oid->len - sub == 0)
+ return (bridge_addrs_bif_first(bif));
+
+ if (oid->len - sub != ETHER_ADDR_LEN + 1 ||
+ oid->subs[sub] != ETHER_ADDR_LEN)
+ return (NULL);
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ tp_addr[i] = oid->subs[sub + i + 1];
+
+ if ((te = bridge_addrs_find(tp_addr, bif)) == NULL)
+ return (NULL);
+
+ return (bridge_addrs_bif_next(te));
+}
+
+int
+op_dot1d_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ int ret;
+ struct bridge_if *bif;
+ struct tp_entry *te;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->addrs_age > bridge_get_data_maxage() &&
+ bridge_update_addrs(bif) <= 0)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ te = NULL; /* Make the compiler happy. */
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((te = bridge_addrs_get(&val->var, sub, bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ if ((te = bridge_addrs_getnext(&val->var, sub, bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ bridge_addrs_index_append(&val->var, sub, te);
+ break;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+
+ ret = SNMP_ERR_NOERROR;
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dTpFdbAddress:
+ ret = string_get(val, te->tp_addr, ETHER_ADDR_LEN);
+ break;
+ case LEAF_dot1dTpFdbPort :
+ val->v.integer = te->port_no;
+ break;
+ case LEAF_dot1dTpFdbStatus:
+ val->v.integer = te->status;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * Private BEGEMOT-BRIDGE-MIB specifics.
+ */
+
+/*
+ * Construct the SNMP index from the bridge interface name
+ * and the address DST Mac.
+ */
+static int
+bridge_addrs_begemot_index_append(struct asn_oid *oid, uint sub,
+ const struct tp_entry *te)
+{
+ uint i, n_len;
+ const char *b_name;
+
+ if ((b_name = bridge_if_find_name(te->sysindex)) == NULL)
+ return (-1);
+
+ n_len = strlen(b_name);
+ oid->len = sub++;
+ oid->subs[oid->len++] = n_len;
+
+ for (i = 1; i <= n_len; i++)
+ oid->subs[oid->len++] = b_name[i - 1];
+
+ oid->subs[oid->len++] = ETHER_ADDR_LEN;
+ for (i = 1 ; i <= ETHER_ADDR_LEN; i++)
+ oid->subs[oid->len++] = te->tp_addr[i - 1];
+
+ return (0);
+}
+
+/*
+ * Find a bridge address entry by the bridge interface name
+ * and the address DST Mac.
+ */
+static struct tp_entry *
+bridge_addrs_begemot_get(const struct asn_oid *oid, uint sub)
+{
+ uint i, n_len;
+ uint8_t tp_addr[ETHER_ADDR_LEN];
+ char bif_name[IFNAMSIZ];
+ struct bridge_if *bif;
+
+ n_len = oid->subs[sub];
+ if (oid->len - sub != n_len + ETHER_ADDR_LEN + 3 ||
+ n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN)
+ return (NULL);
+
+ for (i = 0; i < n_len; i++)
+ bif_name[i] = oid->subs[n_len + i + 1];
+ bif_name[i] = '\0';
+
+ for (i = 1; i <= ETHER_ADDR_LEN; i++)
+ tp_addr[i - 1] = oid->subs[n_len + i + 1];
+
+ if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
+ return (NULL);
+
+ return (bridge_addrs_find(tp_addr, bif));
+}
+
+/*
+ * Find the next bridge address entry by the bridge interface name
+ * and the address DST Mac.
+ */
+static struct tp_entry *
+bridge_addrs_begemot_getnext(const struct asn_oid *oid, uint sub)
+{
+ uint i, n_len;
+ uint8_t tp_addr[ETHER_ADDR_LEN];
+ char bif_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct tp_entry *tp;
+
+ if (oid->len - sub == 0)
+ return (bridge_addrs_first());
+
+ n_len = oid->subs[sub];
+ if (oid->len - sub != n_len + ETHER_ADDR_LEN + 2 ||
+ n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN)
+ return (NULL);
+
+ for (i = 1; i <= n_len; i++)
+ bif_name[i - 1] = oid->subs[sub + i];
+
+ bif_name[i - 1] = '\0';
+
+ for (i = 1; i <= ETHER_ADDR_LEN; i++)
+ tp_addr[i - 1] = oid->subs[sub + n_len + i + 1];
+
+ if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
+ (tp = bridge_addrs_find(tp_addr, bif)) == NULL)
+ return (NULL);
+
+ return (bridge_addrs_next(tp));
+}
+
+int
+op_begemot_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ int ret;
+ struct tp_entry *te = NULL;
+
+ if (time(NULL) - address_list_age > bridge_get_data_maxage())
+ bridge_update_all_addrs();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((te = bridge_addrs_begemot_get(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ if ((te = bridge_addrs_begemot_getnext(&val->var,
+ sub)) == NULL ||
+ bridge_addrs_begemot_index_append(&val->var,
+ sub, te) < 0)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+
+ ret = SNMP_ERR_NOERROR;
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeTpFdbAddress:
+ ret = string_get(val, te->tp_addr, ETHER_ADDR_LEN);
+ break;
+ case LEAF_begemotBridgeTpFdbPort:
+ val->v.integer = te->port_no;
+ break;
+ case LEAF_begemotBridgeTpFdbStatus:
+ val->v.integer = te->status;
+ break;
+ }
+
+ return (ret);
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c
new file mode 100644
index 0000000..d188ab5
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c
@@ -0,0 +1,1369 @@
+/*-
+ * 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:"
+ "getttimeofday 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 occured 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);
+
+ 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 *p_mac, 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 ((p_mac = ifp->physaddr) == NULL &&
+ (p_mac = bridge_get_basemac(ifp->name, mac)) == NULL) {
+ syslog(LOG_ERR, "bridge attach new %s failed - "
+ "no bridge mac address", ifp->name);
+ return (-1);
+ }
+
+ if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, p_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)
+{
+ int ret;
+ 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);
+
+ ret = SNMP_ERR_NOERROR;
+
+ switch (op) {
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+ case LEAF_dot1dBaseBridgeAddress:
+ ret = string_get(value, bif->br_addr.octet,
+ ETHER_ADDR_LEN);
+ break;
+ case LEAF_dot1dBaseNumPorts:
+ value->v.integer = bif->num_ports;
+ break;
+ case LEAF_dot1dBaseType:
+ value->v.integer = bif->br_type;
+ break;
+ abort();
+ }
+ break;
+
+ case SNMP_OP_SET:
+ ret = SNMP_ERR_NOT_WRITEABLE;
+ break;
+
+ case SNMP_OP_GETNEXT:
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+
+ return (ret);
+}
+
+int
+op_dot1d_stp(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_dot1dStpProtocolSpecification:
+ value->v.integer = bif->prot_spec;
+ break;
+
+ case LEAF_dot1dStpPriority:
+ value->v.integer = bif->priority;
+ break;
+
+ case LEAF_dot1dStpTimeSinceTopologyChange:
+ if (bridge_get_time_since_tc(bif,
+ &(value->v.uint32)) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+
+ case LEAF_dot1dStpTopChanges:
+ value->v.uint32 = bif->top_changes;
+ break;
+
+ case LEAF_dot1dStpDesignatedRoot:
+ return (string_get(value, bif->design_root,
+ SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_dot1dStpRootCost:
+ value->v.integer = bif->root_cost;
+ break;
+
+ case LEAF_dot1dStpRootPort:
+ value->v.integer = bif->root_port;
+ break;
+
+ case LEAF_dot1dStpMaxAge:
+ value->v.integer = bif->max_age;
+ break;
+
+ case LEAF_dot1dStpHelloTime:
+ value->v.integer = bif->hello_time;
+ break;
+
+ case LEAF_dot1dStpHoldTime:
+ value->v.integer = bif->hold_time;
+ break;
+
+ case LEAF_dot1dStpForwardDelay:
+ value->v.integer = bif->fwd_delay;
+ break;
+
+ case LEAF_dot1dStpBridgeMaxAge:
+ value->v.integer = bif->bridge_max_age;
+ break;
+
+ case LEAF_dot1dStpBridgeHelloTime:
+ value->v.integer = bif->bridge_hello_time;
+ break;
+
+ case LEAF_dot1dStpBridgeForwardDelay:
+ value->v.integer = bif->bridge_fwd_delay;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_SET:
+ switch (value->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPriority:
+ ctx->scratch->int1 = bif->priority;
+ if (bridge_set_priority(bif, value->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+
+ case LEAF_dot1dStpBridgeMaxAge:
+ ctx->scratch->int1 = bif->bridge_max_age;
+ if (bridge_set_maxage(bif, value->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+
+ case LEAF_dot1dStpBridgeHelloTime:
+ ctx->scratch->int1 = bif->bridge_hello_time;
+ if (bridge_set_hello_time(bif, value->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+
+ case LEAF_dot1dStpBridgeForwardDelay:
+ ctx->scratch->int1 = bif->bridge_fwd_delay;
+ if (bridge_set_forward_delay(bif, value->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+
+ 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);
+ }
+
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ switch (value->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPriority:
+ (void) bridge_set_priority(bif, ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpBridgeMaxAge:
+ (void) bridge_set_maxage(bif, ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpBridgeHelloTime:
+ (void) bridge_set_hello_time(bif, ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpBridgeForwardDelay:
+ (void) bridge_set_forward_delay(bif,
+ ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+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;
+ break;
+ case LEAF_dot1dTpAgingTime:
+ value->v.integer = bif->age_time;
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_SET:
+ if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime) {
+ ctx->scratch->int1 = bif->age_time;
+ if (bridge_set_aging_time(bif, value->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
+ (void) bridge_set_aging_time(bif, ctx->scratch->int1);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * 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)
+{
+ int ret;
+ struct bridge_if *bif = NULL;
+
+ 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);
+ break;
+
+ 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);
+ break;
+
+ 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));
+ }
+
+ ret = SNMP_ERR_NOERROR;
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeBaseName:
+ ret = string_get(val, bif->bif_name, -1);
+ break;
+
+ case LEAF_begemotBridgeBaseAddress:
+ ret = string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN);
+ break;
+
+ case LEAF_begemotBridgeBaseNumPorts:
+ val->v.integer = bif->num_ports;
+ break;
+
+ case LEAF_begemotBridgeBaseType:
+ val->v.integer = bif->br_type;
+ break;
+
+ case LEAF_begemotBridgeBaseStatus:
+ val->v.integer = bif->if_status;
+ break;
+ }
+
+ return (ret);
+}
+
+int
+op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ int ret = SNMP_ERR_NOERROR; /* Make the compiler happy. */
+ struct bridge_if *bif = NULL;
+
+ 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);
+ break;
+
+ 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);
+ break;
+
+ 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:
+ ctx->scratch->int1 = bif->priority;
+ ret = bridge_set_priority(bif, val->v.integer);
+ break;
+
+ case LEAF_begemotBridgeStpBridgeMaxAge:
+ ctx->scratch->int1 = bif->bridge_max_age;
+ ret = bridge_set_maxage(bif, val->v.integer);
+ break;
+
+ case LEAF_begemotBridgeStpBridgeHelloTime:
+ ctx->scratch->int1 = bif->bridge_hello_time;
+ ret = bridge_set_hello_time(bif, val->v.integer);
+ break;
+
+ case LEAF_begemotBridgeStpBridgeForwardDelay:
+ ctx->scratch->int1 = bif->bridge_fwd_delay;
+ ret = bridge_set_forward_delay(bif, val->v.integer);
+ break;
+
+ 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);
+ }
+
+ if (ret == 0)
+ return (SNMP_ERR_NOERROR);
+ else if (ret == -2)
+ return (SNMP_ERR_WRONG_VALUE);
+ return (SNMP_ERR_GENERR);
+
+ 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;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpProtocolSpecification:
+ val->v.integer = bif->prot_spec;
+ break;
+
+ case LEAF_begemotBridgeStpPriority:
+ val->v.integer = bif->priority;
+ break;
+
+ case LEAF_begemotBridgeStpTimeSinceTopologyChange:
+ if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+
+ case LEAF_begemotBridgeStpTopChanges:
+ val->v.uint32 = bif->top_changes;
+ break;
+
+ case LEAF_begemotBridgeStpDesignatedRoot:
+ ret = string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN);
+ break;
+
+ case LEAF_begemotBridgeStpRootCost:
+ val->v.integer = bif->root_cost;
+ break;
+
+ case LEAF_begemotBridgeStpRootPort:
+ val->v.integer = bif->root_port;
+ break;
+
+ case LEAF_begemotBridgeStpMaxAge:
+ val->v.integer = bif->max_age;
+ break;
+
+ case LEAF_begemotBridgeStpHelloTime:
+ val->v.integer = bif->hello_time;
+ break;
+
+ case LEAF_begemotBridgeStpHoldTime:
+ val->v.integer = bif->hold_time;
+ break;
+
+ case LEAF_begemotBridgeStpForwardDelay:
+ val->v.integer = bif->fwd_delay;
+ break;
+
+ case LEAF_begemotBridgeStpBridgeMaxAge:
+ val->v.integer = bif->bridge_max_age;
+ break;
+
+ case LEAF_begemotBridgeStpBridgeHelloTime:
+ val->v.integer = bif->bridge_hello_time;
+ break;
+
+ case LEAF_begemotBridgeStpBridgeForwardDelay:
+ val->v.integer = bif->bridge_fwd_delay;
+ break;
+ }
+
+ return (ret);
+}
+
+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 = NULL;
+
+ 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);
+ break;
+
+ 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);
+ break;
+
+ 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:
+ 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);
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeTpLearnedEntryDiscards:
+ val->v.uint32 = bif->lrnt_drops;
+ break;
+
+ case LEAF_begemotBridgeTpAgingTime:
+ val->v.integer = bif->age_time;
+ break;
+
+ case LEAF_begemotBridgeTpMaxAddresses:
+ val->v.integer = bif->max_addrs;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_pf.c b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_pf.c
new file mode 100644
index 0000000..f6e17fd
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_pf.c
@@ -0,0 +1,117 @@
+/*-
+ * 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 pfil controls.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+
+#include <errno.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"
+
+static int
+val2snmp_truth(uint8_t val)
+{
+ if (val == 0)
+ return (2);
+
+ return (1);
+}
+
+static int
+snmp_truth2val(int32_t truth)
+{
+ if (truth == 2)
+ return (0);
+ else if (truth == 1)
+ return (1);
+
+ return (-1);
+}
+
+int
+op_begemot_bridge_pf(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ int k_val;
+
+ if (val->var.subs[sub - 1] > LEAF_begemotBridgeLayer2PfStatus)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GETNEXT:
+ abort();
+ case SNMP_OP_ROLLBACK:
+ bridge_do_pfctl(val->var.subs[sub - 1] - 1,
+ op, &(ctx->scratch->int1));
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_SET:
+ ctx->scratch->int1 =
+ bridge_get_pfval(val->var.subs[sub - 1]);
+
+ if ((k_val = snmp_truth2val(val->v.integer)) < 0)
+ return (SNMP_ERR_BADVALUE);
+
+ case SNMP_OP_GET:
+ break;
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgePfilStatus:
+ case LEAF_begemotBridgePfilMembers:
+ case LEAF_begemotBridgePfilIpOnly:
+ case LEAF_begemotBridgeLayer2PfStatus:
+ if (bridge_do_pfctl(val->var.subs[sub - 1] - 1,
+ op, &k_val) < 0)
+ return (SNMP_ERR_GENERR);
+ val->v.integer = val2snmp_truth(k_val);
+ break;
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
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..35b2100
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c
@@ -0,0 +1,1152 @@
+/*-
+ * 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 neccessary.
+ */
+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 possition 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;
+
+ 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);
+
+ bp = NULL; /* Make the compiler happy. */
+ 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);
+ break;
+
+ 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;
+ break;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dBasePort:
+ val->v.integer = bp->port_no;
+ break;
+ case LEAF_dot1dBasePortIfIndex:
+ val->v.integer = bp->if_idx;
+ break;
+ case LEAF_dot1dBasePortCircuit:
+ val->v.oid = bp->circuit;
+ break;
+ case LEAF_dot1dBasePortDelayExceededDiscards:
+ val->v.uint32 = bp->dly_ex_drops;
+ break;
+ case LEAF_dot1dBasePortMtuExceededDiscards:
+ val->v.uint32 = bp->dly_mtu_drops;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_dot1d_stp_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ int ret;
+ 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);
+
+ bp = NULL; /* Make the compiler happy. */
+ ret = SNMP_ERR_NOERROR;
+
+ 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);
+ break;
+
+ 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;
+ break;
+
+ case SNMP_OP_SET:
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortPriority:
+ ctx->scratch->int1 = bp->priority;
+ ret = bridge_port_set_priority(bif->bif_name, bp,
+ val->v.integer);
+ break;
+ case LEAF_dot1dStpPortEnable:
+ ctx->scratch->int1 = bp->enable;
+ ret = bridge_port_set_stp_enable(bif->bif_name,
+ bp, val->v.integer);
+ break;
+ case LEAF_dot1dStpPortPathCost:
+ ctx->scratch->int1 = bp->path_cost;
+ ret = bridge_port_set_path_cost(bif->bif_name, bp,
+ val->v.integer);
+ break;
+ 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);
+ }
+ if (ret == 0)
+ return (SNMP_ERR_NOERROR);
+ else if (ret == -2)
+ return (SNMP_ERR_WRONG_VALUE);
+ return (SNMP_ERR_GENERR);
+
+ 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);
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPort:
+ val->v.integer = bp->port_no;
+ break;
+ case LEAF_dot1dStpPortPriority:
+ val->v.integer = bp->priority;
+ break;
+ case LEAF_dot1dStpPortState:
+ val->v.integer = bp->state;
+ break;
+ case LEAF_dot1dStpPortEnable:
+ val->v.integer = bp->enable;
+ break;
+ case LEAF_dot1dStpPortPathCost:
+ val->v.integer = bp->path_cost;
+ break;
+ case LEAF_dot1dStpPortDesignatedRoot:
+ ret = string_get(val, bp->design_root,
+ SNMP_BRIDGE_ID_LEN);
+ break;
+ case LEAF_dot1dStpPortDesignatedCost:
+ val->v.integer = bp->design_cost;
+ break;
+ case LEAF_dot1dStpPortDesignatedBridge:
+ ret = string_get(val, bp->design_bridge,
+ SNMP_BRIDGE_ID_LEN);
+ break;
+ case LEAF_dot1dStpPortDesignatedPort:
+ ret = string_get(val, bp->design_port, 2);
+ break;
+ case LEAF_dot1dStpPortForwardTransitions:
+ val->v.uint32 = bp->fwd_trans;
+ break;
+ }
+
+ return (ret);
+}
+
+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);
+
+ bp = NULL; /* Make the compiler happy. */
+ 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);
+ break;
+
+ 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;
+ break;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dTpPort:
+ val->v.integer = bp->port_no;
+ break;
+ case LEAF_dot1dTpPortMaxInfo:
+ val->v.integer = bp->max_info;
+ break;
+ case LEAF_dot1dTpPortInFrames:
+ val->v.uint32 = bp->in_frames;
+ break;
+ case LEAF_dot1dTpPortOutFrames:
+ val->v.uint32 = bp->out_frames;
+ break;
+ case LEAF_dot1dTpPortInDiscards:
+ val->v.uint32 = bp->in_drops;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * 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;
+ struct bridge_port *bp = NULL;
+
+ 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);
+ break;
+
+ 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);
+ break;
+
+ 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_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));
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ if (which == LEAF_begemotBridgeBasePortStatus)
+ return (bridge_port_commit_status(val, sub));
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ switch (which) {
+ case LEAF_begemotBridgeBasePort:
+ val->v.integer = bp->port_no;
+ break;
+ case LEAF_begemotBridgeBasePortIfIndex:
+ val->v.integer = bp->if_idx;
+ break;
+ case LEAF_begemotBridgeBaseSpanEnabled:
+ val->v.integer = bp->span_enable;
+ break;
+ case LEAF_begemotBridgeBasePortDelayExceededDiscards:
+ val->v.uint32 = bp->dly_ex_drops;
+ break;
+ case LEAF_begemotBridgeBasePortMtuExceededDiscards:
+ val->v.uint32 = bp->dly_mtu_drops;
+ break;
+ case LEAF_begemotBridgeBasePortStatus:
+ val->v.integer = bp->status;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ int ret;
+ struct bridge_port *bp = NULL;
+ 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);
+ break;
+
+ 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);
+ break;
+
+ 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);
+
+ ret = SNMP_ERR_NOERROR;
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortPriority:
+ ctx->scratch->int1 = bp->priority;
+ ret = bridge_port_set_priority(b_name, bp,
+ val->v.integer);
+ break;
+ case LEAF_begemotBridgeStpPortEnable:
+ ctx->scratch->int1 = bp->enable;
+ ret = bridge_port_set_stp_enable(b_name, bp,
+ val->v.integer);
+ break;
+ case LEAF_begemotBridgeStpPortPathCost:
+ ctx->scratch->int1 = bp->path_cost;
+ ret = bridge_port_set_path_cost(b_name, bp,
+ val->v.integer);
+ break;
+ 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);
+ }
+ if (ret == 0)
+ return (SNMP_ERR_NOERROR);
+ else if (ret == -2)
+ return (SNMP_ERR_WRONG_VALUE);
+ return (SNMP_ERR_GENERR);
+
+ 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);
+ }
+
+ ret = SNMP_ERR_NOERROR;
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPort:
+ val->v.integer = bp->port_no;
+ break;
+ case LEAF_begemotBridgeStpPortPriority:
+ val->v.integer = bp->priority;
+ break;
+ case LEAF_begemotBridgeStpPortState:
+ val->v.integer = bp->state;
+ break;
+ case LEAF_begemotBridgeStpPortEnable:
+ val->v.integer = bp->enable;
+ break;
+ case LEAF_begemotBridgeStpPortPathCost:
+ val->v.integer = bp->path_cost;
+ break;
+ case LEAF_begemotBridgeStpPortDesignatedRoot:
+ ret = string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN);
+ break;
+ case LEAF_begemotBridgeStpPortDesignatedCost:
+ val->v.integer = bp->design_cost;
+ break;
+ case LEAF_begemotBridgeStpPortDesignatedBridge:
+ ret = string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN);
+ break;
+ case LEAF_begemotBridgeStpPortDesignatedPort:
+ ret = string_get(val, bp->design_port, 2);
+ break;
+ case LEAF_begemotBridgeStpPortForwardTransitions:
+ val->v.uint32 = bp->fwd_trans;
+ break;
+ }
+
+ return (ret);
+}
+
+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 = NULL;
+
+ 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);
+ break;
+
+ 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);
+ break;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeTpPort:
+ val->v.integer = bp->port_no;
+ break;
+ case LEAF_begemotBridgeTpPortMaxInfo:
+ val->v.integer = bp->max_info;
+ break;
+ case LEAF_begemotBridgeTpPortInFrames:
+ val->v.uint32 = bp->in_frames;
+ break;
+ case LEAF_begemotBridgeTpPortOutFrames:
+ val->v.uint32 = bp->out_frames;
+ break;
+ case LEAF_begemotBridgeTpPortInDiscards:
+ val->v.uint32 = bp->in_drops;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.c b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.c
new file mode 100644
index 0000000..dfcd1f9
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.c
@@ -0,0 +1,327 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#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 <net/if_types.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.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 struct lmodule *bridge_module;
+
+/* For the registration. */
+static const struct asn_oid oid_dot1Bridge = OIDX_dot1dBridge;
+/* The registration. */
+static uint reg_bridge;
+
+/* Periodic timer for polling all bridges' data. */
+static void *bridge_data_timer;
+static void *bridge_tc_timer;
+
+static int bridge_data_maxage = SNMP_BRIDGE_DATA_MAXAGE;
+static int bridge_poll_ticks = SNMP_BRIDGE_POLL_INTERVAL * 100;
+static int bridge_tc_poll_ticks = SNMP_BRIDGE_TC_POLL_INTERVAL * 100;
+
+/*
+ * Our default bridge, whose info will be visible under
+ * the dot1dBridge subtree and functions to set/fetch it.
+ */
+static char bif_default_name[IFNAMSIZ] = "bridge0";
+static struct bridge_if *bif_default;
+
+struct bridge_if *
+bridge_get_default(void)
+{
+ struct mibif *ifp;
+
+ if (bif_default != NULL) {
+
+ /* Walk through the mibII interface list. */
+ for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
+ if (strcmp(ifp->name, bif_default->bif_name) == 0)
+ break;
+
+ if (ifp == NULL)
+ bif_default = NULL;
+ }
+
+ return (bif_default);
+}
+
+void
+bridge_set_default(struct bridge_if *bif)
+{
+ bif_default = bif;
+
+ syslog(LOG_ERR, "Set default bridge interface to: %s",
+ bif == NULL ? "(none)" : bif->bif_name);
+}
+
+const char *
+bridge_get_default_name(void)
+{
+ return (bif_default_name);
+}
+
+static int
+bridge_set_default_name(const char *bif_name, uint len)
+{
+ struct bridge_if *bif;
+
+ if (len >= IFNAMSIZ)
+ return (-1);
+
+ bcopy(bif_name, bif_default_name, len);
+ bif_default_name[len] = '\0';
+
+ if ((bif = bridge_if_find_ifname(bif_default_name)) == NULL)
+ return (0);
+
+ bif_default = bif;
+ return (1);
+}
+
+int
+bridge_get_data_maxage(void)
+{
+ return (bridge_data_maxage);
+}
+
+static void
+bridge_set_poll_ticks(int poll_ticks)
+{
+ if (bridge_data_timer != NULL)
+ timer_stop(bridge_data_timer);
+
+ bridge_poll_ticks = poll_ticks;
+ bridge_data_timer = timer_start_repeat(bridge_poll_ticks,
+ bridge_poll_ticks, bridge_update_all, NULL, bridge_module);
+}
+/*
+ * The bridge module configuration via SNMP.
+ */
+static int
+bridge_default_name_save(struct snmp_context *ctx, const char *bridge_default)
+{
+ if ((ctx->scratch->int1 = strlen(bridge_default)) >= IFNAMSIZ)
+ return (-1);
+
+ if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL)
+ return (-1);
+
+ strncpy(ctx->scratch->ptr1, bridge_default, ctx->scratch->int1);
+ return (0);
+}
+
+int
+op_begemot_bridge_config(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ switch (op) {
+ case SNMP_OP_GET:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeDefaultBridgeIf:
+ string_get(val, bridge_get_default_name(), -1);
+ break;
+ case LEAF_begemotBridgeDataUpdate:
+ val->v.integer = bridge_data_maxage;
+ break;
+ case LEAF_begemotBridgeDataPoll:
+ val->v.integer = bridge_poll_ticks / 100;
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_SET:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeDefaultBridgeIf:
+ /*
+ * Cannot use string_save() here - requires either
+ * a fixed-sized or var-length string - not less
+ * than or equal.
+ */
+ if (bridge_default_name_save(ctx,
+ bridge_get_default_name()) < 0)
+ return (SNMP_ERR_RES_UNAVAIL);
+
+ if (bridge_set_default_name(val->v.octetstring.octets,
+ val->v.octetstring.len) < 0)
+ return (SNMP_ERR_BADVALUE);
+ break;
+ case LEAF_begemotBridgeDataUpdate:
+ ctx->scratch->int1 = bridge_data_maxage;
+ bridge_data_maxage = val->v.integer;
+ break;
+ case LEAF_begemotBridgeDataPoll:
+ ctx->scratch->int1 = val->v.integer;
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeDefaultBridgeIf:
+ bridge_set_default_name(ctx->scratch->ptr1,
+ ctx->scratch->int1);
+ free(ctx->scratch->ptr1);
+ break;
+ case LEAF_begemotBridgeDataUpdate:
+ bridge_data_maxage = ctx->scratch->int1;
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeDefaultBridgeIf:
+ free(ctx->scratch->ptr1);
+ break;
+ case LEAF_begemotBridgeDataPoll:
+ bridge_set_poll_ticks(ctx->scratch->int1 * 100);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Bridge mib module initialization hook.
+ * Returns 0 on success, < 0 on error.
+ */
+static int
+bridge_init(struct lmodule * mod, int argc __unused, char *argv[] __unused)
+{
+ bridge_module = mod;
+
+ if (bridge_kmod_load() < 0)
+ return (-1);
+
+ if (bridge_ioctl_init() < 0)
+ return (-1);
+
+ /* Register to get creation messages for bridge interfaces. */
+ if (mib_register_newif(bridge_attach_newif, bridge_module)) {
+ syslog(LOG_ERR, "Cannot register newif function: %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Bridge mib module finalization hook.
+ */
+static int
+bridge_fini(void)
+{
+ mib_unregister_newif(bridge_module);
+ or_unregister(reg_bridge);
+
+ if (bridge_data_timer != NULL) {
+ timer_stop(bridge_data_timer);
+ bridge_data_timer = NULL;
+ }
+
+ if (bridge_tc_timer != NULL) {
+ timer_stop(bridge_tc_timer);
+ bridge_tc_timer = NULL;
+ }
+
+ bridge_ifs_fini();
+ bridge_ports_fini();
+ bridge_addrs_fini();
+
+ return (0);
+}
+
+/*
+ * Bridge mib module start operation.
+ */
+static void
+bridge_start(void)
+{
+ reg_bridge = or_register(&oid_dot1Bridge,
+ "The IETF MIB for Bridges (RFC 4188).", bridge_module);
+
+ bridge_data_timer = timer_start_repeat(bridge_poll_ticks,
+ bridge_poll_ticks, bridge_update_all, NULL, bridge_module);
+
+ bridge_tc_timer = timer_start_repeat(bridge_tc_poll_ticks,
+ bridge_tc_poll_ticks, bridge_update_tc_time, NULL, bridge_module);
+}
+
+static void
+bridge_dump(void)
+{
+ struct bridge_if *bif;
+
+ if ((bif = bridge_get_default()) == NULL)
+ syslog(LOG_ERR, "Dump: no default bridge interface");
+ else
+ syslog(LOG_ERR, "Dump: default bridge interface %s",
+ bif->bif_name);
+
+ bridge_ifs_dump();
+ bridge_pf_dump();
+}
+
+const struct snmp_module config = {
+ .comment = "This module implements the bridge mib (RFC 4188).",
+ .init = bridge_init,
+ .fini = bridge_fini,
+ .start = bridge_start,
+ .tree = bridge_ctree,
+ .dump = bridge_dump,
+ .tree_size = bridge_CTREE_SIZE,
+};
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.h b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.h
new file mode 100644
index 0000000..75d4096
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.h
@@ -0,0 +1,307 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef SNMP_BRIDGE_H
+#define SNMP_BRIDGE_H
+
+#define SNMP_BRIDGE_ID_LEN 8
+
+typedef uint8_t port_id[2];
+typedef u_char bridge_id[SNMP_BRIDGE_ID_LEN];
+
+#define SNMP_BRIDGE_MAX_PRIORITY 65535
+
+#define SNMP_BRIDGE_MIN_AGE_TIME 10
+#define SNMP_BRIDGE_MAX_AGE_TIME 1000000
+
+#define SNMP_PORT_PATHCOST_OBSOLETE 65535
+
+#define SNMP_BRIDGE_DATA_MAXAGE 10
+/* By default poll kernel data every 5 minutes. */
+#define SNMP_BRIDGE_POLL_INTERVAL (5 * 60)
+/* Poll for a topology change once every 30 seconds. */
+#define SNMP_BRIDGE_TC_POLL_INTERVAL 30
+
+struct bridge_if *bridge_get_default(void);
+
+void bridge_set_default(struct bridge_if *bif);
+
+const char *bridge_get_default_name(void);
+
+int bridge_get_data_maxage(void);
+
+/*
+ * Bridge Addresses Table.
+ */
+struct tp_entry {
+ uint32_t sysindex; /* The bridge if sysindex. */
+ int32_t port_no;
+ enum TpFdbStatus status;
+ uint8_t tp_addr[ETHER_ADDR_LEN];
+ uint8_t flags;
+ TAILQ_ENTRY(tp_entry) tp_e;
+};
+
+/*
+ * Bridge ports.
+ * The bridge port system interface index is used for a
+ * port number. Transparent bridging statistics and STP
+ * information for a port are also contained here.
+ */
+struct bridge_port {
+ /* dot1dBase subtree objects. */
+ uint32_t sysindex; /* The bridge interface sysindex. */
+ int32_t port_no; /* The bridge member system index. */
+ int32_t if_idx; /* SNMP ifIndex from mibII. */
+ int8_t span_enable; /* Span flag set - private MIB. */
+ struct asn_oid circuit; /* Unused. */
+ uint32_t dly_ex_drops; /* Drops on output. */
+ uint32_t dly_mtu_drops; /* MTU exceeded drops. */
+ int32_t status; /* The entry status. */
+
+ /* dot1dStp subtree objects. */
+ int32_t path_cost;
+ int32_t priority;
+ int32_t design_cost;
+ uint32_t fwd_trans;
+ char p_name[IFNAMSIZ]; /* Not in BRIDGE-MIB. */
+ enum StpPortState state;
+ enum dot1dStpPortEnable enable;
+ port_id design_port;
+ bridge_id design_root;
+ bridge_id design_bridge;
+
+ /* dot1dTp subtree objects. */
+ int32_t max_info;
+ int32_t in_frames;
+ int32_t out_frames;
+ int32_t in_drops;
+
+ uint8_t flags;
+ TAILQ_ENTRY(bridge_port) b_p;
+};
+
+/*
+ * A bridge interface.
+ * The system interface index of the bridge is not required neither by the
+ * standard BRIDGE-MIB nor by the private BEGEMOT-BRIDGE-MIB, but is used
+ * as key for looking up the other info for this bridge.
+ */
+struct bridge_if {
+ /* dot1dBase subtree objects. */
+ uint32_t sysindex; /* The system interface index. */
+ int32_t num_ports; /* Number of ports. */
+ enum BaseType br_type; /* Bridge type. */
+ enum RowStatus if_status; /* Bridge status. */
+ char bif_name[IFNAMSIZ]; /* Bridge interface name. */
+ struct ether_addr br_addr; /* Bridge address. */
+ struct bridge_port *f_bp; /* This bridge's first entry
+ * in the base ports TAILQ. */
+ /* dot1dStp subtree objects. */
+ int32_t priority;
+ int32_t root_cost;
+ int32_t root_port;
+ int32_t max_age; /* Current max age. */
+ int32_t hello_time; /* Current hello time. */
+ int32_t fwd_delay; /* Current forward delay. */
+ int32_t hold_time;
+ int32_t bridge_max_age; /* Configured max age. */
+ int32_t bridge_hello_time; /* Configured hello time. */
+ int32_t bridge_fwd_delay; /* Configured forward delay. */
+ uint32_t top_changes;
+ enum dot1dStpProtocolSpecification prot_spec;
+ struct timeval last_tc_time;
+ bridge_id design_root;
+
+ /* dot1dTp subtree objects. */
+ int32_t lrnt_drops; /* Dropped addresses. */
+ int32_t age_time; /* Address entry timeout. */
+ int32_t num_addrs; /* Current # of addresses in cache. */
+ int32_t max_addrs; /* Max # of addresses in cache. */
+ struct tp_entry *f_tpa; /* This bridge's first entry in
+ * the tp addresses TAILQ. */
+
+ time_t entry_age;
+ time_t ports_age;
+ time_t addrs_age;
+ TAILQ_ENTRY(bridge_if) b_if;
+};
+
+void bridge_ifs_fini(void);
+
+struct bridge_if *bridge_if_find_ifs(uint32_t sysindex);
+
+struct bridge_if *bridge_if_find_ifname(const char *b_name);
+
+const char *bridge_if_find_name(uint32_t sysindex);
+
+int bridge_compare_sysidx(uint32_t i1, uint32_t i2);
+
+int bridge_attach_newif(struct mibif *ifp);
+
+struct bridge_if *bridge_first_bif(void);
+
+struct bridge_if *bridge_next_bif(struct bridge_if *b_pr);
+
+void bridge_remove_bif(struct bridge_if *bif);
+
+void bridge_update_all_ports(void);
+
+void bridge_update_all_addrs(void);
+
+void bridge_update_all_ifs(void);
+
+void bridge_update_all(void *arg);
+
+void bridge_update_tc_time(void *arg);
+
+void bridge_ifs_dump(void);
+
+/* Bridge ports. */
+void bridge_ports_update_listage(void);
+
+void bridge_ports_fini(void);
+
+void bridge_members_free(struct bridge_if *bif);
+
+struct bridge_port *bridge_new_port(struct mibif *mif, struct bridge_if *bif);
+
+void bridge_port_remove(struct bridge_port *bp, struct bridge_if *bif);
+
+struct bridge_port *bridge_port_bif_first(struct bridge_if *bif);
+
+struct bridge_port *bridge_port_bif_next(struct bridge_port *bp);
+
+struct bridge_port *bridge_port_find(int32_t if_idx, struct bridge_if *bif);
+
+void bridge_port_getinfo_mibif(struct mibif *m_if, struct bridge_port *bp);
+
+int bridge_getinfo_bif_ports(struct bridge_if *bif);
+
+int bridge_update_memif(struct bridge_if *bif);
+
+void bridge_ports_dump(struct bridge_if *bif);
+
+/* Bridge addresses. */
+void bridge_addrs_update_listage(void);
+
+void bridge_addrs_fini(void);
+
+void bridge_addrs_free(struct bridge_if *bif);
+
+struct tp_entry *bridge_new_addrs(uint8_t *mac, struct bridge_if *bif);
+
+void bridge_addrs_remove(struct tp_entry *te, struct bridge_if *bif);
+
+struct tp_entry *bridge_addrs_find(uint8_t *mac, struct bridge_if *bif);
+
+struct tp_entry *bridge_addrs_bif_first(struct bridge_if *bif);
+
+struct tp_entry *bridge_addrs_bif_next(struct tp_entry *te);
+
+int bridge_getinfo_bif_addrs(struct bridge_if *bif);
+
+int bridge_update_addrs(struct bridge_if *bif);
+
+void bridge_addrs_dump(struct bridge_if *bif);
+
+/* Bridge PF. */
+
+void bridge_pf_dump(void);
+
+/* System specific. */
+
+/* Open the socket for the ioctls. */
+int bridge_ioctl_init(void);
+
+/* Load bridge kernel module. */
+int bridge_kmod_load(void);
+
+/* Get the bridge interface information. */
+int bridge_getinfo_bif(struct bridge_if *bif);
+
+/* Get the bridge interface STP parameters. */
+int bridge_get_op_param(struct bridge_if *bif);
+
+/* Set the bridge priority. */
+int bridge_set_priority(struct bridge_if *bif, int32_t priority);
+
+/* Set the bridge max age. */
+int bridge_set_maxage(struct bridge_if *bif, int32_t max_age);
+
+/* Set the bridge hello time.*/
+int bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time);
+
+/* Set the bridge forward delay.*/
+int bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay);
+
+/* Set the bridge address cache max age. */
+int bridge_set_aging_time(struct bridge_if *bif, int32_t age_time);
+
+/* Set the max number of entries in the bridge address cache. */
+int bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache);
+
+/* Set the bridge interface status to up/down. */
+int bridge_set_if_up(const char* b_name, int8_t up);
+
+/* Create a bridge interface. */
+int bridge_create(const char *b_name);
+
+/* Destroy a bridge interface. */
+int bridge_destroy(const char *b_name);
+
+/* Fetch the bridge mac address. */
+u_char *bridge_get_basemac(const char *bif_name, u_char *mac);
+
+/* Set a bridge member priority. */
+int bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
+ int32_t priority);
+
+/* Set a bridge member STP-enabled flag. */
+int bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
+ uint32_t enable);
+
+/* Set a bridge member STP path cost. */
+int bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
+ int32_t path_cost);
+
+/* Add a bridge member port. */
+int bridge_port_addm(struct bridge_port *bp, const char *b_name);
+
+/* Delete a bridge member port. */
+int bridge_port_delm(struct bridge_port *bp, const char *b_name);
+
+/* Get the current value from the module for bridge PF control. */
+int32_t bridge_get_pfval(uint8_t which);
+
+/* Get/Set a bridge PF control. */
+int32_t bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val);
+
+#endif /* SNMP_BRIDGE_H */
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c
new file mode 100644
index 0000000..13b3007
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c
@@ -0,0 +1,1293 @@
+/*-
+ * 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 OS specific ioctls.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/linker.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#if __FreeBSD_version > 700018
+#include <net/bridgestp.h>
+#endif
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_bridgevar.h>
+#include <net/if_dl.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <bsnmp/snmpmod.h>
+#include <bsnmp/snmp_mibII.h>
+
+#include "bridge_tree.h"
+#include "bridge_snmp.h"
+
+int sock = -1;
+
+int
+bridge_ioctl_init(void)
+{
+ if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Load the if_bridge.ko module in kernel if not already there.
+ */
+int
+bridge_kmod_load(void)
+{
+ int fileid, modid;
+ const char mod_name[] = "if_bridge";
+ struct module_stat mstat;
+
+ /* Scan files in kernel. */
+ mstat.version = sizeof(struct module_stat);
+ for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
+ /* Scan modules in file. */
+ for (modid = kldfirstmod(fileid); modid > 0;
+ modid = modfnext(modid)) {
+
+ if (modstat(modid, &mstat) < 0)
+ continue;
+
+ if (strcmp(mod_name, mstat.name) == 0)
+ return (0);
+ }
+ }
+
+ /* Not present - load it. */
+ if (kldload(mod_name) < 0) {
+ syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
+ return (-1);
+ }
+
+ return (1);
+}
+
+/************************************************************************
+ * Bridge interfaces.
+ */
+
+/*
+ * Convert the kernel uint64_t value for a bridge id
+ */
+static void
+snmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id)
+{
+ int i;
+ u_char *o;
+
+ o = (u_char *) &id;
+
+ for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++)
+ b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o;
+}
+
+/*
+ * Fetch the bridge configuration parameters from the kernel excluding
+ * it's base MAC address.
+ */
+static int
+bridge_get_conf_param(struct bridge_if *bif)
+{
+ struct ifdrv ifd;
+ struct ifbrparam b_param;
+
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_len = sizeof(b_param);
+ ifd.ifd_data = &b_param;
+
+ /* Bridge priority. */
+ ifd.ifd_cmd = BRDGGPRI;
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ bif->priority = b_param.ifbrp_prio;
+
+ /* Configured max age. */
+ ifd.ifd_cmd = BRDGGMA;
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ /* Centi-seconds. */
+ bif->bridge_max_age = 100 * b_param.ifbrp_maxage;
+
+ /* Configured hello time. */
+ ifd.ifd_cmd = BRDGGHT;
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s",
+ strerror(errno));
+ return (-1);
+ }
+ bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime;
+
+ /* Forward delay. */
+ ifd.ifd_cmd = BRDGGFD;
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s",
+ strerror(errno));
+ return (-1);
+ }
+ bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay;
+
+ /* Number of dropped addresses. */
+ ifd.ifd_cmd = BRDGGRTE;
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s",
+ strerror(errno));
+ return (-1);
+ }
+ bif->lrnt_drops = b_param.ifbrp_cexceeded;
+
+ /* Address table timeout. */
+ ifd.ifd_cmd = BRDGGTO;
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s",
+ strerror(errno));
+ return (-1);
+ }
+ bif->age_time = b_param.ifbrp_ctime;
+
+ /* Address table size. */
+ ifd.ifd_cmd = BRDGGCACHE;
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+ bif->max_addrs = b_param.ifbrp_csize;
+
+ return (0);
+}
+
+/*
+ * Fetch the current bridge STP operational parameters.
+ * Returns: -1 - on error;
+ * 0 - old TC time and Root Port values are same;
+ * 1 - topologyChange notification should be sent;
+ * 2 - newRoot notification should be sent.
+ */
+int
+bridge_get_op_param(struct bridge_if *bif)
+{
+ int new_root_send;
+ struct ifdrv ifd;
+ struct ifbropreq b_req;
+
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_len = sizeof(b_req);
+ ifd.ifd_data = &b_req;
+ ifd.ifd_cmd = BRDGPARAM;
+
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ bif->max_age = 100 * b_req.ifbop_maxage;
+ bif->hello_time = 100 * b_req.ifbop_hellotime;
+ bif->fwd_delay = 100 * b_req.ifbop_fwddelay;
+
+ if (b_req.ifbop_root_port == 0 &&
+ bif->root_port != b_req.ifbop_root_port)
+ new_root_send = 2;
+ else
+ new_root_send = 0;
+
+ bif->root_port = b_req.ifbop_root_port;
+ bif->root_cost = b_req.ifbop_root_path_cost;
+ snmp_uint64_to_bridgeid(b_req.ifbop_designated_root,
+ bif->design_root);
+
+ if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) {
+ bif->top_changes++;
+ bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec;
+ bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec;
+
+ /*
+ * "The trap is not sent if a (begemotBridge)NewRoot
+ * trap is sent for the same transition."
+ */
+ if (new_root_send == 0)
+ return (1);
+ }
+
+ return (new_root_send);
+}
+
+int
+bridge_getinfo_bif(struct bridge_if *bif)
+{
+ if (bridge_get_conf_param(bif) < 0)
+ return (-1);
+
+ return (bridge_get_op_param(bif));
+}
+
+int
+bridge_set_priority(struct bridge_if *bif, int32_t priority)
+{
+ struct ifdrv ifd;
+ struct ifbrparam b_param;
+
+ /* Sanity check. */
+ if (priority > SNMP_BRIDGE_MAX_PRIORITY || priority % 4096 != 0)
+ return (-1);
+
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_len = sizeof(b_param);
+ ifd.ifd_data = &b_param;
+ b_param.ifbrp_prio = (uint32_t) priority;
+ ifd.ifd_cmd = BRDGSPRI;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ /*
+ * Re-fetching the data from the driver after that might be a good
+ * idea, since changing our bridge's priority should invoke
+ * recalculation of the active spanning tree topology in the network.
+ */
+ bif->priority = priority;
+ return (0);
+}
+
+/*
+ * Convert 1/100 of seconds to 1/256 of seconds.
+ * Timeout ::= TEXTUAL-CONVENTION.
+ * To convert a Timeout value into a value in units of
+ * 1/256 seconds, the following algorithm should be used:
+ * b = floor( (n * 256) / 100)
+ */
+static uint32_t
+snmp_hundred_secs2_256(int32_t h_secs)
+{
+ return ((h_secs * 256) / 100);
+}
+
+int
+bridge_set_maxage(struct bridge_if *bif, int32_t max_age)
+{
+ struct ifdrv ifd;
+ struct ifbrparam b_param;
+
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_len = sizeof(b_param);
+ ifd.ifd_data = &b_param;
+ b_param.ifbrp_maxage = (uint32_t) max_age;
+ ifd.ifd_cmd = BRDGSMA;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ bif->bridge_max_age = max_age;
+ return (0);
+}
+
+int
+bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
+{
+ struct ifdrv ifd;
+ struct ifbrparam b_param;
+
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_len = sizeof(b_param);
+ ifd.ifd_data = &b_param;
+ b_param.ifbrp_hellotime = snmp_hundred_secs2_256(hello_time);
+ ifd.ifd_cmd = BRDGSHT;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ bif->bridge_hello_time = b_param.ifbrp_hellotime;
+ return (0);
+}
+
+int
+bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
+{
+ struct ifdrv ifd;
+ struct ifbrparam b_param;
+
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_len = sizeof(b_param);
+ ifd.ifd_data = &b_param;
+ b_param.ifbrp_fwddelay = snmp_hundred_secs2_256(fwd_delay);
+ ifd.ifd_cmd = BRDGSFD;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
+ return (0);
+}
+
+int
+bridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
+{
+ struct ifdrv ifd;
+ struct ifbrparam b_param;
+
+ /* Sanity check. */
+ if (age_time < SNMP_BRIDGE_MIN_AGE_TIME ||
+ age_time > SNMP_BRIDGE_MAX_AGE_TIME)
+ return (-1);
+
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_len = sizeof(b_param);
+ ifd.ifd_data = &b_param;
+ b_param.ifbrp_ctime = (uint32_t) age_time;
+ ifd.ifd_cmd = BRDGSTO;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ bif->age_time = age_time;
+ return (0);
+}
+
+int
+bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
+{
+ struct ifdrv ifd;
+ struct ifbrparam b_param;
+
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_len = sizeof(b_param);
+ ifd.ifd_data = &b_param;
+ b_param.ifbrp_csize = max_cache;
+ ifd.ifd_cmd = BRDGSCACHE;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ bif->max_addrs = b_param.ifbrp_csize;
+ return (0);
+}
+
+/*
+ * Set the bridge interface status to up/down.
+ */
+int
+bridge_set_if_up(const char* b_name, int8_t up)
+{
+ int flags;
+ struct ifreq ifr;
+
+ bzero(&ifr, sizeof(ifr));
+ strcpy(ifr.ifr_name, b_name);
+ if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
+ if (up == 1)
+ flags |= IFF_UP;
+ else
+ flags &= ~IFF_UP;
+
+ ifr.ifr_flags = flags & 0xffff;
+ ifr.ifr_flagshigh = flags >> 16;
+ if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+bridge_create(const char *b_name)
+{
+ char *new_name;
+ struct ifreq ifr;
+
+ bzero(&ifr, sizeof(ifr));
+ strcpy(ifr.ifr_name, b_name);
+
+ if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) {
+ syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ if (strcmp(b_name, ifr.ifr_name) == 0)
+ return (0);
+
+ if ((new_name = strdup(b_name)) == NULL) {
+ syslog(LOG_ERR, "create bridge: strdup() failed");
+ return (-1);
+ }
+
+ ifr.ifr_data = new_name;
+ if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) "
+ "failed: %s", strerror(errno));
+ free(new_name);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+bridge_destroy(const char *b_name)
+{
+ struct ifreq ifr;
+
+ bzero(&ifr, sizeof(ifr));
+ strcpy(ifr.ifr_name, b_name);
+
+ if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
+ syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Fetch the bridge base MAC address. Return pointer to the
+ * buffer containing the mac address, NULL on failure.
+ */
+u_char *
+bridge_get_basemac(const char *bif_name, u_char *mac)
+{
+ int len;
+ char if_name[IFNAMSIZ];
+ struct ifaddrs *ifap, *tmp;
+ struct sockaddr_dl *sdl;
+
+ if (getifaddrs(&ifap) < 0) {
+ syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
+ strerror(errno));
+ return (NULL);
+ }
+
+ for (tmp = ifap; tmp != NULL; tmp = tmp->ifa_next) {
+ sdl = (struct sockaddr_dl *) tmp->ifa_addr;
+
+ if ((len = sdl->sdl_nlen) >= IFNAMSIZ)
+ len = IFNAMSIZ - 1;
+
+ bcopy(sdl->sdl_data, if_name, len);
+ if_name[len] = '\0';
+
+ if (sdl->sdl_family == AF_LINK && !strncmp(bif_name,
+ if_name, strlen(bif_name))) {
+ bcopy(sdl->sdl_data + sdl->sdl_nlen, mac,
+ ETHER_ADDR_LEN);
+ freeifaddrs(ifap);
+ return (mac);
+ }
+ }
+
+ freeifaddrs(ifap);
+ return (NULL);
+}
+
+/************************************************************************
+ * Bridge ports.
+ */
+
+/*
+ * Convert the kernel STP port state into
+ * the corresopnding enumerated type from SNMP Bridge MIB.
+ */
+static int
+state2snmp_st(uint8_t ifbr_state)
+{
+ switch (ifbr_state) {
+ case BSTP_IFSTATE_DISABLED:
+ return (StpPortState_disabled);
+ case BSTP_IFSTATE_LISTENING:
+ return (StpPortState_listening);
+ case BSTP_IFSTATE_LEARNING:
+ return (StpPortState_learning);
+ case BSTP_IFSTATE_FORWARDING:
+ return (StpPortState_forwarding);
+ case BSTP_IFSTATE_BLOCKING:
+ return (StpPortState_blocking);
+ }
+
+ return (StpPortState_broken);
+}
+
+/*
+ * Fill in a bridge member information according to data polled from kernel.
+ */
+static void
+bridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp)
+{
+ bp->state = state2snmp_st(k_info->ifbr_state);
+ bp->priority = k_info->ifbr_priority;
+
+ /*
+ * RFC 4188:
+ * "New implementations should support dot1dStpPortPathCost32.
+ * If the port path costs exceeds the maximum value of this
+ * object then this object should report the maximum value,
+ * namely 65535. Applications should try to read the
+ * dot1dStpPortPathCost32 object if this object reports
+ * the maximum value."
+ */
+
+#if 0
+ /*
+ * Kernel variable is a 32-bit integer but the ioctl supports
+ * only getting/setting a 8-bit value.
+ */
+
+ if (k_info->ifbr_path_cost > SNMP_PORT_PATHCOST_OBSOLETE) {
+ bp->path_cost = SNMP_PORT_PATHCOST_OBSOLETE;
+ bp->path_cost32 = k_info->ifbr_path_cost;
+ } else
+
+ bp->path_cost = bp->path_cost32 = k_info->ifbr_path_cost;
+#endif
+
+ bp->path_cost = k_info->ifbr_path_cost;
+
+ if (k_info->ifbr_ifsflags & IFBIF_STP)
+ bp->enable = dot1dStpPortEnable_enabled;
+ else
+ bp->enable = dot1dStpPortEnable_disabled;
+
+ /* Begemot Bridge MIB only. */
+ if (k_info->ifbr_ifsflags & IFBIF_SPAN)
+ bp->span_enable = begemotBridgeBaseSpanEnabled_enabled;
+ else
+ bp->span_enable = begemotBridgeBaseSpanEnabled_disabled;
+}
+
+/*
+ * Fill in a bridge interface STP information according to
+ * data polled from kernel.
+ */
+static void
+bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
+{
+ bp->enable = dot1dStpPortEnable_enabled;
+ bp->fwd_trans = bp_stp->ifbp_fwd_trans;
+ bp->design_cost = bp_stp->ifbp_design_cost;
+ snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root);
+ snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge);
+ bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port),
+ sizeof(uint16_t));
+}
+
+/*
+ * Clear a bridge interface STP information.
+ */
+static void
+bridge_port_clearinfo_opstp(struct bridge_port *bp)
+{
+ if (bp->enable == dot1dStpPortEnable_enabled) {
+ bp->design_cost = 0;
+ bzero(&(bp->design_root), sizeof(bridge_id));
+ bzero(&(bp->design_bridge), sizeof(bridge_id));
+ bzero(&(bp->design_port), sizeof(port_id));
+ bp->fwd_trans = 0;
+ }
+
+ bp->enable = dot1dStpPortEnable_disabled;
+}
+
+/*
+ * Set a bridge member priority.
+ */
+int
+bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
+ int32_t priority)
+{
+ struct ifdrv ifd;
+ struct ifbreq b_req;
+
+ if (priority < 0 || priority > 255)
+ return (-2);
+
+ strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
+ ifd.ifd_len = sizeof(b_req);
+ ifd.ifd_data = &b_req;
+ strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
+
+ b_req.ifbr_priority = (uint8_t) priority;
+ ifd.ifd_cmd = BRDGSIFPRIO;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) "
+ "failed: %s", bp->p_name, strerror(errno));
+ return (-1);
+ }
+
+ bp->priority = priority;
+ return (0);
+}
+
+/*
+ * Set a bridge member STP-enabled flag.
+ */
+int
+bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
+ uint32_t enable)
+{
+ struct ifdrv ifd;
+ struct ifbreq b_req;
+
+ if (bp->enable == enable)
+ return (0);
+
+ if (enable != dot1dStpPortEnable_enabled &&
+ enable != dot1dStpPortEnable_disabled)
+ return (-2);
+
+ bzero(&b_req, sizeof(b_req));
+ strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
+ ifd.ifd_len = sizeof(b_req);
+ ifd.ifd_data = &b_req;
+ strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
+ ifd.ifd_cmd = BRDGGIFFLGS;
+
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
+ "failed: %s", bp->p_name, strerror(errno));
+ return (-1);
+ }
+
+ if (enable == dot1dStpPortEnable_enabled)
+ b_req.ifbr_ifsflags |= IFBIF_STP;
+ else
+ b_req.ifbr_ifsflags &= ~IFBIF_STP;
+
+ ifd.ifd_cmd = BRDGSIFFLGS;
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
+ "failed: %s", bp->p_name, strerror(errno));
+ return (-1);
+ }
+
+ bp->enable = enable;
+ return (0);
+}
+
+/*
+ * Set a bridge member STP path cost.
+ */
+int
+bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
+ int32_t path_cost)
+{
+ struct ifdrv ifd;
+ struct ifbreq b_req;
+
+ if (path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
+ return (-2);
+
+ strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
+ ifd.ifd_len = sizeof(b_req);
+ ifd.ifd_data = &b_req;
+ strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
+
+ b_req.ifbr_path_cost = (uint16_t) path_cost;
+ ifd.ifd_cmd = BRDGSIFCOST;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) "
+ "failed: %s", bp->p_name, strerror(errno));
+ return (-1);
+ }
+
+ bp->path_cost = path_cost;
+ return (0);
+}
+
+/*
+ * Add a bridge member port.
+ */
+int
+bridge_port_addm(struct bridge_port *bp, const char *b_name)
+{
+ struct ifdrv ifd;
+ struct ifbreq b_req;
+
+ bzero(&ifd, sizeof(ifd));
+ bzero(&b_req, sizeof(b_req));
+
+ strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
+ ifd.ifd_len = sizeof(b_req);
+ ifd.ifd_data = &b_req;
+ strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
+
+ if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
+ ifd.ifd_cmd = BRDGADDS;
+ else
+ ifd.ifd_cmd = BRDGADD;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
+ bp->p_name,
+ (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
+ strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Delete a bridge member port.
+ */
+int
+bridge_port_delm(struct bridge_port *bp, const char *b_name)
+{
+ struct ifdrv ifd;
+ struct ifbreq b_req;
+
+ bzero(&ifd, sizeof(ifd));
+ bzero(&b_req, sizeof(b_req));
+
+ strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
+ ifd.ifd_len = sizeof(b_req);
+ ifd.ifd_data = &b_req;
+ strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
+
+ if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
+ ifd.ifd_cmd = BRDGDELS;
+ else
+ ifd.ifd_cmd = BRDGDEL;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
+ bp->p_name,
+ (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
+ strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Fetch the bridge member list from kernel.
+ * Return -1 on error, or buffer len if successful.
+ */
+static int32_t
+bridge_port_get_iflist(struct bridge_if *bif, char **buf)
+{
+ uint32_t len = 8192; /* ??? */
+ char *ninbuf;
+ struct ifbifconf ifbc;
+ struct ifdrv ifd;
+
+ *buf = NULL;
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_cmd = BRDGGIFS;
+ ifd.ifd_len = sizeof(ifbc);
+ ifd.ifd_data = &ifbc;
+
+ for ( ; ; ) {
+ if ((ninbuf = realloc(*buf, len) /* ??? */) == NULL) {
+ syslog(LOG_ERR, "get bridge member list: "
+ "realloc failed: %s", strerror(errno));
+ free(*buf);
+ *buf = NULL;
+ return (-1);
+ }
+
+ ifbc.ifbic_len = len;
+ ifbc.ifbic_buf = *buf = ninbuf;
+
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "get bridge member list: ioctl "
+ "(BRDGGIFS) failed: %s", strerror(errno));
+ free(*buf);
+ buf = NULL;
+ return (-1);
+ }
+
+ if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
+ break;
+
+ len += 8192;
+ }
+
+ return (ifbc.ifbic_len);
+}
+
+/*
+ * Fetch the bridge STP member list from kernel.
+ * Return -1 on error, or buffer len if successful.
+ */
+static int32_t
+bridge_port_get_ifstplist(struct bridge_if *bif, char **buf)
+{
+ uint32_t len = 8192; /* ??? */
+ char *ninbuf;
+ struct ifbpstpconf ifbstp;
+ struct ifdrv ifd;
+
+ *buf = NULL;
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_cmd = BRDGGIFSSTP;
+ ifd.ifd_len = sizeof(ifbstp);
+ ifd.ifd_data = &ifbstp;
+
+ for ( ; ; ) {
+ if ((ninbuf = realloc(*buf, len) /* ??? */) == NULL) {
+ syslog(LOG_ERR, "get bridge STP ports list: "
+ "realloc failed: %s", strerror(errno));
+ free(*buf);
+ *buf = NULL;
+ return (-1);
+ }
+
+ ifbstp.ifbpstp_len = len;
+ ifbstp.ifbpstp_buf = *buf = ninbuf;
+
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "get bridge STP ports list: ioctl "
+ "(BRDGGIFSSTP) failed: %s", strerror(errno));
+ free(*buf);
+ buf = NULL;
+ return (-1);
+ }
+
+ if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
+ break;
+
+ len += 8192;
+ }
+
+ return (ifbstp.ifbpstp_len);
+}
+
+/*
+ * Locate a bridge if STP params structure in a buffer.
+ */
+static struct ifbpstpreq *
+bridge_port_find_ifstplist(uint8_t port_no, char *buf, uint32_t buf_len)
+{
+ uint32_t i;
+ struct ifbpstpreq *bstp;
+
+ for (i = 0; i < buf_len / sizeof(*bstp); i++) {
+ bstp = (struct ifbpstpreq *) buf + i;
+ if (bstp->ifbp_portno == port_no)
+ return (bstp);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Read the initial info for all members of a bridge interface.
+ * Returns the number of ports, 0 - if none, otherwise
+ * -1 if some other error occured.
+ */
+int
+bridge_getinfo_bif_ports(struct bridge_if *bif)
+{
+ uint32_t i;
+ int32_t buf_len;
+ char *mem_buf;
+ struct ifbreq *b_req;
+ struct ifbpstpreq *bs_req;
+ struct bridge_port *bp;
+ struct mibif *m_if;
+
+ if ((buf_len = bridge_port_get_iflist(bif, &mem_buf)) < 0)
+ return (-1);
+
+ for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
+ b_req = (struct ifbreq *) mem_buf + i;
+
+ if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) {
+ /* Hopefully we will not fail here. */
+ if ((bp = bridge_new_port(m_if, bif)) != NULL) {
+ bp->status = RowStatus_active;
+ bridge_port_getinfo_conf(b_req, bp);
+ bridge_port_getinfo_mibif(m_if, bp);
+ }
+ } else {
+ syslog(LOG_ERR, "bridge member %s not present "
+ "in mibII ifTable", b_req->ifbr_ifsname);
+ }
+ }
+ free(mem_buf);
+
+ if ((buf_len = bridge_port_get_ifstplist(bif, &mem_buf)) < 0)
+ return (-1);
+
+ for (bp = bridge_port_bif_first(bif); bp != NULL;
+ bp = bridge_port_bif_next(bp)) {
+ if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
+ mem_buf, buf_len)) == NULL)
+ bridge_port_clearinfo_opstp(bp);
+ else
+ bridge_port_getinfo_opstp(bs_req, bp);
+ }
+ free(mem_buf);
+
+ return (i);
+}
+
+/*
+ * Update the information for the bridge interface members.
+ */
+int
+bridge_update_memif(struct bridge_if *bif)
+{
+ int added, updated;
+ uint32_t i;
+ int32_t buf_len;
+ char *if_buf;
+ struct ifbreq *b_req;
+ struct ifbpstpreq *bs_req;
+ struct bridge_port *bp, *bp_next;
+ struct mibif *m_if;
+
+ if ((buf_len = bridge_port_get_iflist(bif, &if_buf)) < 0)
+ return (-1);
+
+ added = updated = 0;
+
+#define BP_FOUND 0x01
+ for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
+ b_req = (struct ifbreq *) if_buf + i;
+
+ if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) {
+ syslog(LOG_ERR, "bridge member %s not present "
+ "in mibII ifTable", b_req->ifbr_ifsname);
+ continue;
+ }
+
+ if ((bp = bridge_port_find(m_if->index, bif)) == NULL &&
+ (bp = bridge_new_port(m_if, bif)) != NULL) {
+ bp->status = RowStatus_active;
+ added++;
+ }
+
+ if (bp != NULL) {
+ updated++;
+ bridge_port_getinfo_conf(b_req, bp);
+ bridge_port_getinfo_mibif(m_if, bp);
+ bp->flags |= BP_FOUND;
+ }
+ }
+ free(if_buf);
+
+ /* Clean up list. */
+ for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
+ bp_next = bridge_port_bif_next(bp);
+
+ if ((bp->flags & BP_FOUND) == 0 &&
+ bp->status == RowStatus_active)
+ bridge_port_remove(bp, bif);
+ else
+ bp->flags |= ~BP_FOUND;
+ }
+#undef BP_FOUND
+
+ if ((buf_len = bridge_port_get_ifstplist(bif, &if_buf)) < 0)
+ return (-1);
+
+ for (bp = bridge_port_bif_first(bif); bp != NULL;
+ bp = bridge_port_bif_next(bp)) {
+ if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
+ if_buf, buf_len)) == NULL)
+ bridge_port_clearinfo_opstp(bp);
+ else
+ bridge_port_getinfo_opstp(bs_req, bp);
+ }
+ free(if_buf);
+ bif->ports_age = time(NULL);
+
+ return (updated);
+}
+
+/************************************************************************
+ * Bridge addresses.
+ */
+
+/*
+ * Update the bridge address info according to the polled data.
+ */
+static void
+bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
+{
+ tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
+
+ if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
+ tpe->status = TpFdbStatus_mgmt;
+ else
+ tpe->status = TpFdbStatus_learned;
+}
+
+/*
+ * Read the bridge addresses from kernel.
+ * Return -1 on error, or buffer len if successful.
+ */
+static int32_t
+bridge_addrs_getinfo_ifalist(struct bridge_if *bif, char **buf)
+{
+ uint32_t len = 8192; /* ??? */
+ char *ninbuf;
+ struct ifbaconf bac;
+ struct ifdrv ifd;
+
+ *buf = NULL;
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_cmd = BRDGRTS;
+ ifd.ifd_len = sizeof(bac);
+ ifd.ifd_data = &bac;
+
+ for ( ; ; ) {
+ if ((ninbuf = realloc(*buf, len) /* ??? */) == NULL) {
+ syslog(LOG_ERR, "get bridge address list: "
+ " realloc failed: %s", strerror(errno));
+ free(*buf);
+ *buf = NULL;
+ return (-1);
+ }
+
+ bac.ifbac_len = len;
+ bac.ifbac_buf = *buf = ninbuf;
+
+ if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "get bridge address list: "
+ "ioctl(BRDGRTS) failed: %s", strerror(errno));
+ free(*buf);
+ buf = NULL;
+ return (-1);
+ }
+
+ if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
+ break;
+
+ len += 8192;
+ }
+
+ return (bac.ifbac_len);
+}
+
+/*
+ * Read the initial info for all addresses on a bridge interface.
+ * Returns the number of addresses, 0 - if none, otherwise
+ * -1 if some other error occured.
+ */
+int
+bridge_getinfo_bif_addrs(struct bridge_if *bif)
+{
+ uint32_t i;
+ int32_t buf_len;
+ char *addr_buf;
+ struct ifbareq *addr_req;
+ struct tp_entry *te;
+
+ if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_buf)) < 0)
+ return (-1);
+
+ for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
+ addr_req = (struct ifbareq *) addr_buf + i;
+
+ if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
+ bridge_addrs_info_ifaddrlist(addr_req, te);
+ }
+
+ free(addr_buf);
+ return (i);
+}
+
+/*
+ * Update the addresses for the bridge interface.
+ */
+int
+bridge_update_addrs(struct bridge_if *bif)
+{
+ int added, updated;
+ uint32_t i;
+ int32_t buf_len;
+ char *ifbad_buf;
+ struct tp_entry *te, *te_next;
+ struct ifbareq *a_req;
+
+ if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &ifbad_buf)) < 0)
+ return (-1);
+
+ added = updated = 0;
+
+#define BA_FOUND 0x01
+ for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
+ a_req = (struct ifbareq *) ifbad_buf + i;
+
+ if ((te = bridge_addrs_find(a_req->ifba_dst, bif)) == NULL) {
+ added++;
+
+ if ((te = bridge_new_addrs(a_req->ifba_dst, bif))
+ == NULL)
+ continue;
+ } else
+ updated++;
+
+ bridge_addrs_info_ifaddrlist(a_req, te);
+ te-> flags |= BA_FOUND;
+ }
+ free(ifbad_buf);
+
+ for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
+ te_next = bridge_addrs_bif_next(te);
+
+ if ((te-> flags & BA_FOUND) == 0)
+ bridge_addrs_remove(te, bif);
+ else
+ te-> flags &= ~BA_FOUND;
+ }
+#undef BA_FOUND
+
+ bif->addrs_age = time(NULL);
+ return (updated + added);
+}
+
+/************************************************************************
+ * Bridge packet filtering.
+ */
+const char bridge_sysctl[] = "net.link.bridge.";
+
+static struct {
+ int32_t val;
+ const char *name;
+} bridge_pf_sysctl[] = {
+ { 1, "pfil_bridge" },
+ { 1, "pfil_member" },
+ { 1, "pfil_onlyip" },
+ { 0, "ipfw" },
+};
+
+int32_t
+bridge_get_pfval(uint8_t which)
+{
+ if (which > sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0])
+ || which < 1)
+ return (-1);
+
+ return (bridge_pf_sysctl[which - 1].val);
+}
+
+int32_t
+bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
+{
+ char mib_name[100];
+ int32_t i, s_i;
+ size_t len, s_len;
+
+ if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
+ return (-2);
+
+ if (op == SNMP_OP_SET) {
+ s_i = *val;
+ s_len = sizeof(s_i);
+ } else
+ s_len = 0;
+
+ len = sizeof(i);
+
+ strcpy(mib_name, bridge_sysctl);
+
+ if (sysctlbyname(strcat(mib_name,
+ bridge_pf_sysctl[bridge_ctl].name), &i, &len,
+ (op == SNMP_OP_SET ? &s_i : NULL), s_len) == -1) {
+ syslog(LOG_ERR, "sysctl(%s%s) failed - %s", bridge_sysctl,
+ bridge_pf_sysctl[bridge_ctl].name, strerror(errno));
+ return (-1);
+ }
+
+ bridge_pf_sysctl[bridge_ctl].val = i;
+ *val = i;
+
+ return (i);
+}
+
+void
+bridge_pf_dump(void)
+{
+ uint8_t i;
+
+ for (i = 0; i < sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0]);
+ i++) {
+ syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
+ bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);
+ }
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_tree.def b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_tree.def
new file mode 100644
index 0000000..892615b
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_tree.def
@@ -0,0 +1,242 @@
+#-
+# 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.
+#
+# $FreeBSD$
+#
+
+#include "tc.def"
+
+typedef TruthValue ENUM (
+ 1 true
+ 2 false
+)
+
+typedef RowStatus ENUM (
+ 1 active
+ 2 notInService
+ 3 notReady
+ 4 createAndGo
+ 5 createAndWait
+ 6 destroy
+)
+
+typedef StpPortState ENUM (
+ 1 disabled
+ 2 blocking
+ 3 listening
+ 4 learning
+ 5 forwarding
+ 6 broken
+)
+
+typedef BaseType ENUM (
+ 1 unknown
+ 2 transparent-only
+ 3 sourceroute-only
+ 4 srt
+)
+
+typedef TpFdbStatus ENUM (
+ 1 other
+ 2 invalid
+ 3 learned
+ 4 self
+ 5 mgmt
+)
+
+(1 internet
+ (2 mgmt
+ (1 mib_2
+ (17 dot1dBridge
+ (0 dot1dNotifications
+ (1 newRoot OID op_snmp_trap)
+ (2 topologyChange OID op_snmp_trap)
+ )
+ (1 dot1dBase
+ (1 dot1dBaseBridgeAddress OCTETSTRING | MacAddress op_dot1d_base GET)
+ (2 dot1dBaseNumPorts INTEGER32 op_dot1d_base GET)
+ (3 dot1dBaseType BaseType op_dot1d_base GET)
+ (4 dot1dBasePortTable
+ (1 dot1dBasePortEntry : INTEGER op_dot1d_base_port
+ (1 dot1dBasePort INTEGER GET)
+ (2 dot1dBasePortIfIndex INTEGER GET)
+ (3 dot1dBasePortCircuit OID GET)
+ (4 dot1dBasePortDelayExceededDiscards COUNTER GET)
+ (5 dot1dBasePortMtuExceededDiscards COUNTER GET)
+ ))
+ )
+ (2 dot1dStp
+ (1 dot1dStpProtocolSpecification ENUM ( 1 unknown 2 decLb100 3 ieee8021d ) op_dot1d_stp GET)
+ (2 dot1dStpPriority INTEGER op_dot1d_stp GET SET)
+ (3 dot1dStpTimeSinceTopologyChange TIMETICKS op_dot1d_stp GET)
+ (4 dot1dStpTopChanges COUNTER op_dot1d_stp GET)
+ (5 dot1dStpDesignatedRoot OCTETSTRING | BridgeId op_dot1d_stp GET)
+ (6 dot1dStpRootCost INTEGER32 op_dot1d_stp GET)
+ (7 dot1dStpRootPort INTEGER32 op_dot1d_stp GET)
+ (8 dot1dStpMaxAge INTEGER op_dot1d_stp GET)
+ (9 dot1dStpHelloTime INTEGER op_dot1d_stp GET)
+ (10 dot1dStpHoldTime INTEGER32 op_dot1d_stp GET)
+ (11 dot1dStpForwardDelay INTEGER op_dot1d_stp GET)
+ (12 dot1dStpBridgeMaxAge INTEGER op_dot1d_stp GET SET)
+ (13 dot1dStpBridgeHelloTime INTEGER op_dot1d_stp GET SET)
+ (14 dot1dStpBridgeForwardDelay INTEGER op_dot1d_stp GET SET)
+ (15 dot1dStpPortTable
+ (1 dot1dStpPortEntry : INTEGER op_dot1d_stp_port
+ (1 dot1dStpPort INTEGER GET)
+ (2 dot1dStpPortPriority INTEGER GET SET)
+ (3 dot1dStpPortState StpPortState GET)
+ (4 dot1dStpPortEnable ENUM ( 1 enabled 2 disabled ) GET SET)
+ (5 dot1dStpPortPathCost INTEGER GET SET)
+ (6 dot1dStpPortDesignatedRoot OCTETSTRING | BridgeId GET)
+ (7 dot1dStpPortDesignatedCost INTEGER32 GET)
+ (8 dot1dStpPortDesignatedBridge OCTETSTRING | BridgeId GET)
+ (9 dot1dStpPortDesignatedPort OCTETSTRING | BridgePortId GET)
+ (10 dot1dStpPortForwardTransitions COUNTER GET)
+ ))
+ )
+ (3 dot1dSr
+ )
+ (4 dot1dTp
+ (1 dot1dTpLearnedEntryDiscards COUNTER op_dot1d_tp GET)
+ (2 dot1dTpAgingTime INTEGER op_dot1d_tp GET SET)
+ (3 dot1dTpFdbTable
+ (1 dot1dTpFdbEntry : OCTETSTRING | MacAddress op_dot1d_tp_fdb
+ (1 dot1dTpFdbAddress OCTETSTRING | MacAddress GET)
+ (2 dot1dTpFdbPort INTEGER32 GET)
+ (3 dot1dTpFdbStatus TpFdbStatus GET)
+ ))
+ (4 dot1dTpPortTable
+ (1 dot1dTpPortEntry : INTEGER op_dot1d_tp_port
+ (1 dot1dTpPort INTEGER GET)
+ (2 dot1dTpPortMaxInfo INTEGER32 GET)
+ (3 dot1dTpPortInFrames COUNTER GET)
+ (4 dot1dTpPortOutFrames COUNTER GET)
+ (5 dot1dTpPortInDiscards COUNTER GET)
+ ))
+ )
+ (5 dot1dStatic
+ )
+ (8 dot1dConformance
+ (1 dot1dGroups
+ )
+ (2 dot1dCompliances
+ )
+ )
+ )))
+ (4 private
+ (1 enterprises
+ (12325 fokus
+ (1 begemot
+ (205 begemotBridge
+ (0 begemotBridgeNotifications
+ (1 begemotBridgeNewRoot OID op_snmp_trap)
+ (2 begemotBridgeTopologyChange OID op_snmp_trap)
+ )
+ (1 begemotBridgeBase
+ (1 begemotBridgeBaseTable
+ (1 begemotBridgeBaseEntry : OCTETSTRING | BridgeIfName op_begemot_base_bridge
+ (1 begemotBridgeBaseName OCTETSTRING | BridgeIfName GET)
+ (2 begemotBridgeBaseAddress OCTETSTRING | MacAddress GET)
+ (3 begemotBridgeBaseNumPorts INTEGER32 GET)
+ (4 begemotBridgeBaseType BaseType GET)
+ (5 begemotBridgeBaseStatus RowStatus GET SET)
+ ))
+ (2 begemotBridgeBasePortTable
+ (1 begemotBridgeBasePortEntry : OCTETSTRING | BridgeIfName INTEGER op_begemot_base_port
+ (1 begemotBridgeBasePort INTEGER GET)
+ (2 begemotBridgeBasePortIfIndex INTEGER GET)
+ (3 begemotBridgeBaseSpanEnabled ENUM ( 1 enabled 2 disabled ) GET SET)
+ (4 begemotBridgeBasePortDelayExceededDiscards COUNTER GET)
+ (5 begemotBridgeBasePortMtuExceededDiscards COUNTER GET)
+ (6 begemotBridgeBasePortStatus RowStatus GET SET)
+ ))
+ )
+ (2 begemotBridgeStp
+ (1 begemotBridgeStpTable
+ (1 begemotBridgeStpEntry : OCTETSTRING | BridgeIfName op_begemot_stp
+ (1 begemotBridgeStpProtocolSpecification ENUM ( 1 unknown 2 decLb100 3 ieee8021d ) GET)
+ (2 begemotBridgeStpPriority INTEGER GET SET)
+ (3 begemotBridgeStpTimeSinceTopologyChange TIMETICKS GET)
+ (4 begemotBridgeStpTopChanges COUNTER GET)
+ (5 begemotBridgeStpDesignatedRoot OCTETSTRING | BridgeId GET)
+ (6 begemotBridgeStpRootCost INTEGER32 GET)
+ (7 begemotBridgeStpRootPort INTEGER32 GET)
+ (8 begemotBridgeStpMaxAge INTEGER GET)
+ (9 begemotBridgeStpHelloTime INTEGER GET)
+ (10 begemotBridgeStpHoldTime INTEGER32 GET)
+ (11 begemotBridgeStpForwardDelay INTEGER GET)
+ (12 begemotBridgeStpBridgeMaxAge INTEGER GET SET)
+ (13 begemotBridgeStpBridgeHelloTime INTEGER GET SET)
+ (14 begemotBridgeStpBridgeForwardDelay INTEGER GET SET)
+ ))
+ (2 begemotBridgeStpPortTable
+ (1 begemotBridgeStpPortEntry : OCTETSTRING | BridgeIfName INTEGER op_begemot_stp_port
+ (1 begemotBridgeStpPort INTEGER GET)
+ (2 begemotBridgeStpPortPriority INTEGER GET SET)
+ (3 begemotBridgeStpPortState StpPortState GET)
+ (4 begemotBridgeStpPortEnable ENUM ( 1 enabled 2 disabled ) GET SET)
+ (5 begemotBridgeStpPortPathCost INTEGER GET SET)
+ (6 begemotBridgeStpPortDesignatedRoot OCTETSTRING | BridgeId GET)
+ (7 begemotBridgeStpPortDesignatedCost INTEGER32 GET)
+ (8 begemotBridgeStpPortDesignatedBridge OCTETSTRING | BridgeId GET)
+ (9 begemotBridgeStpPortDesignatedPort OCTETSTRING | BridgePortId GET)
+ (10 begemotBridgeStpPortForwardTransitions COUNTER GET)
+ ))
+ )
+ (3 begemotBridgeTp
+ (1 begemotBridgeTpTable
+ (1 begemotBridgeTpEntry : OCTETSTRING | BridgeIfName op_begemot_tp
+ (1 begemotBridgeTpLearnedEntryDiscards COUNTER GET)
+ (2 begemotBridgeTpAgingTime INTEGER GET SET)
+ (3 begemotBridgeTpMaxAddresses INTEGER GET SET)
+ ))
+ (2 begemotBridgeTpFdbTable
+ (1 begemotBridgeTpFdbEntry : OCTETSTRING | BridgeIfName OCTETSTRING | MacAddress op_begemot_tp_fdb
+ (1 begemotBridgeTpFdbAddress OCTETSTRING | MacAddress GET)
+ (2 begemotBridgeTpFdbPort INTEGER32 GET)
+ (3 begemotBridgeTpFdbStatus TpFdbStatus GET)
+ ))
+ (3 begemotBridgeTpPortTable
+ (1 begemotBridgeTpPortEntry : OCTETSTRING | BridgeIfName INTEGER op_begemot_tp_port
+ (1 begemotBridgeTpPort INTEGER GET)
+ (2 begemotBridgeTpPortMaxInfo INTEGER32 GET)
+ (3 begemotBridgeTpPortInFrames COUNTER GET)
+ (4 begemotBridgeTpPortOutFrames COUNTER GET)
+ (5 begemotBridgeTpPortInDiscards COUNTER GET)
+ ))
+ )
+ (4 begemotBridgePf
+ (1 begemotBridgePfilStatus TruthValue op_begemot_bridge_pf GET SET)
+ (2 begemotBridgePfilMembers TruthValue op_begemot_bridge_pf GET SET)
+ (3 begemotBridgePfilIpOnly TruthValue op_begemot_bridge_pf GET SET)
+ (4 begemotBridgeLayer2PfStatus ENUM ( 1 enabled 2 disabled ) op_begemot_bridge_pf GET SET)
+ )
+ (5 begemotBridgeConfigObjects
+ (1 begemotBridgeDefaultBridgeIf OCTETSTRING | BridgeIfNameOrEmpty op_begemot_bridge_config GET SET)
+ (2 begemotBridgeDataUpdate INTEGER op_begemot_bridge_config GET SET)
+ (3 begemotBridgeDataPoll INTEGER op_begemot_bridge_config GET SET)
+ )
+ )))))
+)
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.3 b/usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.3
new file mode 100644
index 0000000..cc942b4
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.3
@@ -0,0 +1,113 @@
+.\"-
+.\" 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 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 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 18, 2006
+.Dt snmp_bridge 3
+.Os
+.Sh NAME
+.Nm snmp_bridge
+.Nd "bridge module for snmpd.
+.Sh LIBRARY
+.Pq begemotSnmpdModulePath."bridge" = "/usr/lib/snmp_bridge.so"
+.Sh DESCRIPTION
+The
+.Nm snmp_bridge
+module implements the BRIDGE-MIB as standardized in RFC 4188 and a private
+BEGEMOT-BRIDGE-MIB, which allows management of multiple bridge interfaces.
+Most of the objects defined in the private BEGEMOT-BRIDGE-MIB are duplicates
+of the original objects defined by the standard BRIDGE-MIB, but the private
+MIB also defines additional objects which make the functionality of
+.Nm
+similar to
+.Xr ifconfig 8
+for configuring bridge interfaces.
+Therefore one should consider adding write comminities or loading the
+.Nm
+module on systems where security is crucial.
+.Sh IMPLEMENTATION NOTES
+The additional objects to configure a bridge are:
+.Bl -tag -width "XXXXXXXXX"
+.It Va begemotBridgeBaseStatus
+Bridge interfaces can be created and destroyed via this object.
+SNMP SET operations with the following values are allowed:
+.Bl -tag -width ".It Va createAndWait"
+.It Va createAndWait
+will attempt to create a bridge interface with the name given by the table
+index.
+.It Va createAndGo
+will attempt to create a bridge interface with the name given by the table
+index and set the status of the interface to "active/up".
+.It Va destroy
+will attempt to destory the bridge interface.
+.El
+.It Va begemotBridgeBaseSpanEnabled
+A SNMP SET operation on this object is only successfull if the corresponding
+port has not been added as member of the bridge interface on the system.
+.It Va begemotBridgeBasePortStatus
+SNMP SET operations with the following values are allowed:
+.Bl -tag -width ".It Va createAndWait"
+.It Va createAndWait
+will create a new row for the bridge member in the SNMP
+.Va begemotBridgeBasePortTable
+but will not try to commit the information to the system.
+.It Va active
+will attempt to commit the information to the system and will be successful
+only if a value for
+.Va begemotBridgeBaseSpanEnabled
+has been SET already.
+.It Va destroy
+will attempt to remove the interface from the system bridge interface.
+.El
+.El
+.Sh RESTRICTIONS
+Not all information in the MIBs is currently available in FreeBSD.
+The following variables carry no information:
+.Bl -tag -width "XXXXXXXXX"
+.It Va dot1dBasePortCircuit
+.It Va dot1dBasePortDelayExceededDiscards
+.It Va dot1dBasePortMtuExceededDiscards
+.It Va begemotBridgeBasePortDelayExceededDiscards
+.It Va begemotBridgeBasePortMtuExceededDiscards
+.El
+.Sh FILES
+.Bl -tag -width "XXXXXXXXX"
+.It Pa /usr/share/snmp/defs/bridge_tree.def
+The description of the MIB tree implemented by
+.Nm .
+.It Pa /usr/share/snmp/mibs/BRIDGE-MIB.txt
+This is the BRIDGE-MIB that is implemented by this module.
+.It Pa /usr/share/snmp/mibs/BEGEMOT-BRIDGE-MIB.txt
+This is the private BEGEMOT-BRIDGE-MIB that is implemented by this module.
+.El
+.Sh SEE ALSO
+.Xr bsnmpd 1 ,
+.Xr gensnmptree 1 ,
+.Xr if_bridge 4 ,
+.Xr ifconfig 8 ,
+.Xr snmpmod 3
+.Sh AUTHORS
+.An Shteryana Shopova Aq syrinx@FreeBSD.org
OpenPOWER on IntegriCloud