summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsnmpd
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bsnmpd')
-rw-r--r--usr.sbin/bsnmpd/Makefile8
-rw-r--r--usr.sbin/bsnmpd/Makefile.inc3
-rw-r--r--usr.sbin/bsnmpd/bsnmpd/Makefile52
-rw-r--r--usr.sbin/bsnmpd/gensnmptree/Makefile15
-rw-r--r--usr.sbin/bsnmpd/modules/Makefile28
-rw-r--r--usr.sbin/bsnmpd/modules/Makefile.inc9
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_atm/BEGEMOT-ATM-FREEBSD-MIB.txt99
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_atm/Makefile21
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_atm/atm_freebsd.def56
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_atm/atm_sys.c301
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/BEGEMOT-BRIDGE-MIB.txt1166
-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/RSTP-MIB.txt325
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c589
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c1479
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_pf.c116
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c1513
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.c338
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.h357
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c1503
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/bridge_tree.def283
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.3119
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt125
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/Makefile82
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c171
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c684
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c647
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c473
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c302
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_partition_tbl.c630
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c398
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c431
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c492
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c208
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h324
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_storage_tbl.c668
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c555
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c792
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_tree.def292
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.388
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_mibII/Makefile29
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_netgraph/BEGEMOT-NETGRAPH.txt398
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_netgraph/Makefile17
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_netgraph/netgraph_tree.def78
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.3436
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.c1690
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.h91
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_pf/BEGEMOT-PF-MIB.txt1347
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_pf/Makefile13
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c1800
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def210
-rwxr-xr-xusr.sbin/bsnmpd/modules/snmp_target/Makefile20
-rwxr-xr-xusr.sbin/bsnmpd/modules/snmp_usm/Makefile22
-rwxr-xr-xusr.sbin/bsnmpd/modules/snmp_vacm/Makefile20
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/BEGEMOT-WIRELESS-MIB.txt3898
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/Makefile15
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/snmp_wlan.3160
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c4513
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.h286
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/wlan_sys.c3145
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/wlan_tree.def677
-rw-r--r--usr.sbin/bsnmpd/tools/Makefile7
-rw-r--r--usr.sbin/bsnmpd/tools/Makefile.inc13
-rw-r--r--usr.sbin/bsnmpd/tools/bsnmptools/Makefile28
-rw-r--r--usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1426
-rw-r--r--usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c1289
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/Makefile13
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c971
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpmap.c1018
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c1287
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.h95
-rwxr-xr-xusr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c2132
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h333
74 files changed, 43721 insertions, 0 deletions
diff --git a/usr.sbin/bsnmpd/Makefile b/usr.sbin/bsnmpd/Makefile
new file mode 100644
index 0000000..632753d
--- /dev/null
+++ b/usr.sbin/bsnmpd/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+SUBDIR= gensnmptree \
+ bsnmpd \
+ modules \
+ tools
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/bsnmpd/Makefile.inc b/usr.sbin/bsnmpd/Makefile.inc
new file mode 100644
index 0000000..265f86d
--- /dev/null
+++ b/usr.sbin/bsnmpd/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include "../Makefile.inc"
diff --git a/usr.sbin/bsnmpd/bsnmpd/Makefile b/usr.sbin/bsnmpd/bsnmpd/Makefile
new file mode 100644
index 0000000..3e6df47
--- /dev/null
+++ b/usr.sbin/bsnmpd/bsnmpd/Makefile
@@ -0,0 +1,52 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+
+.include <bsd.own.mk>
+
+CONTRIB=${.CURDIR}/../../../contrib/bsnmp
+.PATH: ${CONTRIB}/snmpd
+
+PROG= bsnmpd
+SRCS= main.c action.c config.c export.c trap.c trans_udp.c trans_lsock.c
+SRCS+= oid.h tree.c tree.h
+XSYM= snmpMIB begemotSnmpdModuleTable begemotSnmpd begemotTrapSinkTable \
+ sysUpTime snmpTrapOID coldStart authenticationFailure \
+ begemotSnmpdTransUdp begemotSnmpdTransLsock begemotSnmpdLocalPortTable \
+ freeBSD freeBSDVersion
+CLEANFILES= oid.h tree.c tree.h
+MAN= bsnmpd.1 snmpmod.3
+NO_WERROR=
+
+FILESGROUPS= BMIBS DEFS
+
+BMIBS= FOKUS-MIB.txt BEGEMOT-MIB.txt BEGEMOT-SNMPD.txt
+BMIBSDIR= ${SHAREDIR}/snmp/mibs
+DEFS= tree.def
+DEFSDIR= ${SHAREDIR}/snmp/defs
+
+CFLAGS+= -DSNMPTREE_TYPES
+CFLAGS+= -I${CONTRIB}/lib -I${CONTRIB}/snmpd -I. -DUSE_LIBBEGEMOT
+CFLAGS+= -DUSE_TCPWRAPPERS -DQUADFMT='"llu"' -DQUADXFMT='"llx"'
+CFLAGS+= -DHAVE_STDINT_H -DHAVE_INTTYPES_H -DHAVE_ERR_H -DHAVE_STRLCPY
+DPADD= ${LIBBEGEMOT} ${LIBBSNMP} ${LIBWRAP}
+LDADD= -lbegemot -lbsnmp -lwrap
+
+LDFLAGS= -Wl,-export-dynamic
+
+.if ${MK_OPENSSL} != "no"
+CFLAGS+= -DHAVE_LIBCRYPTO
+.endif
+
+oid.h: tree.def Makefile
+ gensnmptree -e ${XSYM} < ${.ALLSRC:M*.def} > ${.TARGET}
+
+.ORDER: tree.c tree.h
+tree.c tree.h: tree.def
+ gensnmptree -l < ${.ALLSRC}
+
+MANFILTER= sed -e 's%@MODPATH@%${LIBDIR}/%g' \
+ -e 's%@DEFPATH@%${DEFSDIR}/%g' \
+ -e 's%@MIBSPATH@%${BMIBSDIR}/%g'
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsnmpd/gensnmptree/Makefile b/usr.sbin/bsnmpd/gensnmptree/Makefile
new file mode 100644
index 0000000..a92f4eb
--- /dev/null
+++ b/usr.sbin/bsnmpd/gensnmptree/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+
+CONTRIB=${.CURDIR}/../../../contrib/bsnmp
+.PATH: ${CONTRIB}/gensnmptree
+
+PROG= gensnmptree
+CFLAGS+= -I${CONTRIB}/lib
+CFLAGS+= -DQUADFMT='"llu"' -DQUADXFMT='"llx"' -DHAVE_STDINT_H
+CFLAGS+= -DHAVE_INTTYPES_H
+
+WARNS?= 5
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsnmpd/modules/Makefile b/usr.sbin/bsnmpd/modules/Makefile
new file mode 100644
index 0000000..ab378f0
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/Makefile
@@ -0,0 +1,28 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+.PATH: ${.CURDIR}/../../../contrib/bsnmp/snmpd
+
+.if ${MK_ATM} != "no"
+_snmp_atm= snmp_atm
+.endif
+
+SUBDIR= ${_snmp_atm} \
+ snmp_bridge \
+ snmp_hostres \
+ snmp_mibII \
+ snmp_pf \
+ snmp_target \
+ snmp_usm \
+ snmp_vacm \
+ snmp_wlan
+
+.if ${MK_NETGRAPH_SUPPORT} != "no"
+SUBDIR+=snmp_netgraph
+.endif
+
+INCS= snmpmod.h
+INCSDIR= ${INCLUDEDIR}/bsnmp
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsnmpd/modules/Makefile.inc b/usr.sbin/bsnmpd/modules/Makefile.inc
new file mode 100644
index 0000000..b5dad56
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+SHLIB_MAJOR= 6
+
+MANFILTER= sed -e 's%@MODPATH@%${LIBDIR}/%g' \
+ -e 's%@DEFPATH@%${DEFSDIR}/%g' \
+ -e 's%@MIBSPATH@%${BMIBSDIR}/%g'
+
+.include "../Makefile.inc"
diff --git a/usr.sbin/bsnmpd/modules/snmp_atm/BEGEMOT-ATM-FREEBSD-MIB.txt b/usr.sbin/bsnmpd/modules/snmp_atm/BEGEMOT-ATM-FREEBSD-MIB.txt
new file mode 100644
index 0000000..83c4e5c
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_atm/BEGEMOT-ATM-FREEBSD-MIB.txt
@@ -0,0 +1,99 @@
+--
+-- Copyright (c) 2004
+-- Hartmut Brandt.
+-- All rights reserved.
+--
+-- Author: Hartmut Brandt <harti@freebsd.org>
+--
+-- 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$
+--
+-- Private Begemot MIB for ATM interfaces on FreeBSD
+--
+BEGEMOT-ATM-FREEBSD-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE
+ FROM SNMPv2-SMI
+ NgNodeIdOrZero
+ FROM BEGEMOT-NETGRAPH-MIB
+ begemotAtmSysGroup, begemotAtmIfEntry
+ FROM BEGEMOT-ATM-MIB;
+
+begemotAtmFreeBSDGroup MODULE-IDENTITY
+ LAST-UPDATED "200408060000Z"
+ ORGANIZATION "German Aerospace Centre"
+ CONTACT-INFO
+ " Hartmut Brandt
+
+ Postal: German Aerospace Centre (DLR)
+ Institute of Communications and Navigation
+ 82234 Wessling
+ Germany
+
+ Fax: +49 8153 28 2844
+
+ E-mail: harti@freebsd.org"
+ DESCRIPTION
+ "The FreeBSD specific Begemot MIB for ATM interfaces."
+
+ ::= { begemotAtmSysGroup 1 }
+
+-- Netgraph
+begemotAtmNgGroup OBJECT IDENTIFIER ::= { begemotAtmFreeBSDGroup 1 }
+
+--
+-- Interfaces table
+--
+begemotAtmNgIfTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotAtmNgIfEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table contains an entry for each hardware ATM
+ interface. The table is indexed by the interface index."
+ ::= { begemotAtmNgGroup 1 }
+
+begemotAtmNgIfEntry OBJECT-TYPE
+ SYNTAX BegemotAtmNgIfEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This is a table entry describing one ATM hardware interface."
+ AUGMENTS { begemotAtmIfEntry }
+ ::= { begemotAtmNgIfTable 1 }
+
+BegemotAtmNgIfEntry ::= SEQUENCE {
+ begemotAtmNgIfNodeId NgNodeIdOrZero
+}
+
+begemotAtmNgIfNodeId OBJECT-TYPE
+ SYNTAX NgNodeIdOrZero
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The netgraph node id of the interface. If there is no
+ node corresponding to the interface, this is 0."
+ ::= { begemotAtmNgIfEntry 1 }
+
+END
diff --git a/usr.sbin/bsnmpd/modules/snmp_atm/Makefile b/usr.sbin/bsnmpd/modules/snmp_atm/Makefile
new file mode 100644
index 0000000..4bba7cb
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_atm/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+
+CONTRIB= ${.CURDIR}/../../../../contrib/ngatm
+.PATH: ${CONTRIB}/snmp_atm
+
+MOD= atm
+SRCS= snmp_atm.c atm_sys.c
+XSYM= begemotAtm
+MAN= snmp_atm.3
+
+BMIBS= BEGEMOT-ATM.txt BEGEMOT-ATM-FREEBSD-MIB.txt
+DEFS= ${MOD}_tree.def atm_freebsd.def
+INCS= snmp_${MOD}.h
+
+EXTRAMIBDEFS= atm_freebsd.def
+
+CFLAGS+= -I${CONTRIB}/snmp_atm
+
+.include <bsd.snmpmod.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_atm/atm_freebsd.def b/usr.sbin/bsnmpd/modules/snmp_atm/atm_freebsd.def
new file mode 100644
index 0000000..6cc61d0
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_atm/atm_freebsd.def
@@ -0,0 +1,56 @@
+#
+# Copyright (c) 2004
+# Hartmut Brandt.
+# All rights reserved.
+#
+# Author: Hartmut Brandt <harti@freebsd.org>
+#
+# 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$
+#
+# SNMP module for ATM hardware interfaces.
+#
+# $Begemot: libunimsg/snmp_atm/atm_tree.def,v 1.2 2004/08/05 07:14:22 brandt Exp $
+#
+(1 internet
+ (4 private
+ (1 enterprises
+ (12325 fokus
+ (1 begemot
+ (101 begemotAtm
+ (1 begemotAtmObjects
+ (4 begemotAtmSysGroup
+ (1 begemotAtmFreeBSDGroup
+ (1 begemotAtmNgGroup
+ (1 begemotAtmNgIfTable
+ (1 begemotAtmNgIfEntry : INTEGER op_atmif_ng
+ (1 begemotAtmIfNodeId UNSIGNED32 GET)
+ ))
+ )
+ )
+ )
+ )
+ ))
+ )
+ )
+))
diff --git a/usr.sbin/bsnmpd/modules/snmp_atm/atm_sys.c b/usr.sbin/bsnmpd/modules/snmp_atm/atm_sys.c
new file mode 100644
index 0000000..525e805
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_atm/atm_sys.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2001-2002
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ * Copyright (c) 2003-2004
+ * Hartmut Brandt.
+ * All rights reserved.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * 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$
+ *
+ * SNMP module for ATM hardware interfaces - FreeBSD/Ng specific part.
+ */
+
+#include "atm.h"
+#include "atm_tree.h"
+#include "atm_oid.h"
+
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+
+#include <net/if_atm.h>
+
+#include <bsnmp/snmp_netgraph.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/atm/ng_atm.h>
+
+static const struct hwinfo {
+ const char *device;
+ const char *vendor;
+} hwinfo[] = {
+ ATM_DEVICE_NAMES
+};
+
+struct atmif_sys {
+ ng_ID_t atm_node;
+ void *regc; /* cookie registration */
+};
+
+/*
+ * Find the interface for a given node
+ */
+struct atmif *
+atm_node2if(u_int node)
+{
+ struct atmif_priv *aif;
+
+ if (node != 0)
+ TAILQ_FOREACH(aif, &atmif_list, link)
+ if (aif->sys->atm_node == node)
+ return (&aif->pub);
+ return (NULL);
+}
+
+u_int
+atm_if2node(struct atmif *pub)
+{
+ struct atmif_priv *aif = (struct atmif_priv *)pub;
+
+ return (aif->sys->atm_node);
+}
+
+/*
+ * Destroy system dependend stuff.
+ */
+void
+atmif_sys_destroy(struct atmif_priv *aif)
+{
+
+ ng_unregister_cookie(aif->sys->regc);
+ free(aif->sys);
+ free(aif->pub.mib);
+}
+
+/*
+ * Handle a message from the ATM node
+ */
+static void
+handle_atm_message(const struct ng_mesg *mesg, const char *path __unused,
+ ng_ID_t node, void *uarg)
+{
+ struct atmif_priv *aif = uarg;
+ enum atmif_carrier_state ost;
+
+ switch (mesg->header.cmd) {
+
+ case NGM_ATM_IF_CHANGE:
+ {
+ const struct ngm_atm_if_change *arg;
+
+ ost = aif->pub.carrier;
+ if (mesg->header.arglen != sizeof(*arg)) {
+ syslog(LOG_ERR, "ATM_IF_CHANGE: wrong size");
+ atmif_check_carrier(aif);
+ return;
+ }
+ arg = (const struct ngm_atm_if_change *)
+ (const void *)mesg->data;
+
+ if (arg->carrier)
+ aif->pub.carrier = ATMIF_CARRIER_ON;
+ else
+ aif->pub.carrier = ATMIF_CARRIER_OFF;
+
+ if (ost != aif->pub.carrier)
+ atmif_send_notification(aif, ATMIF_NOTIFY_CARRIER,
+ (uintptr_t)ost);
+ return;
+ }
+
+ case NGM_ATM_VCC_CHANGE:
+ {
+ const struct ngm_atm_vcc_change *arg;
+
+ if (mesg->header.arglen != sizeof(*arg)) {
+ syslog(LOG_ERR, "ATM_VCC_CHANGE: wrong size");
+ return;
+ }
+ arg = (const struct ngm_atm_vcc_change *)
+ (const void *)mesg->data;
+ atmif_send_notification(aif, ATMIF_NOTIFY_VCC,
+ (uintptr_t)(((arg->vpi & 0xff) << 24) |
+ ((arg->vci & 0xffff) << 8) | (arg->state & 1)));
+ return;
+ }
+ }
+ syslog(LOG_WARNING, "spurious message %u from node [%x]",
+ mesg->header.cmd, node);
+}
+
+/*
+ * Attach to an ATM interface
+ */
+int
+atmif_sys_attach_if(struct atmif_priv *aif)
+{
+ struct ng_mesg *resp, *resp1;
+ struct namelist *list;
+ u_int i;
+
+ if ((aif->sys = malloc(sizeof(*aif->sys))) == NULL) {
+ syslog(LOG_CRIT, "out of memory");
+ return (-1);
+ }
+ memset(aif->sys, 0, sizeof(*aif->sys));
+
+ if ((aif->pub.mib = malloc(sizeof(*aif->pub.mib))) == NULL) {
+ free(aif->sys);
+ syslog(LOG_CRIT, "out of memory");
+ return (-1);
+ }
+
+ atmif_sys_fill_mib(aif);
+
+ /*
+ * Get ATM node Id. Must do it the hard way by scanning all nodes
+ * because the name may be wrong.
+ */
+ if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, NGM_LISTNODES,
+ NULL, 0)) == NULL) {
+ syslog(LOG_ERR, "cannot fetch node list: %m");
+ free(aif->sys);
+ return (-1);
+ }
+ list = (struct namelist *)(void *)resp->data;
+
+ for (i = 0; i < list->numnames; i++) {
+ if (strcmp(list->nodeinfo[i].type, NG_ATM_NODE_TYPE) != 0)
+ continue;
+ if ((resp1 = ng_dialog_id(list->nodeinfo[i].id,
+ NGM_ATM_COOKIE, NGM_ATM_GET_IFNAME, NULL, 0)) == NULL)
+ continue;
+ if (strcmp(resp1->data, aif->pub.ifp->name) == 0) {
+ free(resp1);
+ break;
+ }
+ free(resp1);
+ }
+ if (i == list->numnames)
+ aif->sys->atm_node = 0;
+ else
+ aif->sys->atm_node = list->nodeinfo[i].id;
+
+ free(resp);
+
+ if ((aif->sys->regc = ng_register_cookie(module, NGM_ATM_COOKIE,
+ aif->sys->atm_node, handle_atm_message, aif)) == NULL) {
+ syslog(LOG_ERR, "cannot register cookie: %m");
+ free(aif->sys);
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Table of all ATM interfaces - Ng part
+ */
+int
+op_atmif_ng(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int vindex __unused, enum snmp_op op)
+{
+ struct atmif_priv *aif;
+ int err;
+
+ if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR)
+ return (err);
+
+ if (op == SNMP_OP_SET) {
+ switch (value->var.subs[sub - 1]) {
+
+ default:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ }
+
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotAtmIfNodeId:
+ value->v.uint32 = aif->sys->atm_node;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
+
+/*
+ * Get vendor string
+ */
+int
+atm_sys_get_hw_vendor(struct atmif_priv *aif, struct snmp_value *value)
+{
+
+ if (aif->pub.mib->device >= sizeof(hwinfo) / sizeof(hwinfo[0]))
+ return (string_get(value, "unknown", -1));
+ return (string_get(value, hwinfo[aif->pub.mib->device].vendor, -1));
+}
+
+/*
+ * Get device string
+ */
+int
+atm_sys_get_hw_device(struct atmif_priv *aif, struct snmp_value *value)
+{
+
+ if (aif->pub.mib->device >= sizeof(hwinfo) / sizeof(hwinfo[0]))
+ return (string_get(value, "unknown", -1));
+ return (string_get(value, hwinfo[aif->pub.mib->device].device, -1));
+}
+
+/*
+ * Extract the ATM MIB from the interface's private MIB
+ */
+void
+atmif_sys_fill_mib(struct atmif_priv *aif)
+{
+ struct ifatm_mib *mib;
+
+ if (aif->pub.ifp->specmiblen != sizeof(struct ifatm_mib)) {
+ syslog(LOG_ERR, "atmif MIB has wrong size %zu",
+ aif->pub.ifp->specmiblen);
+ memset(aif->pub.mib, 0, sizeof(*aif->pub.mib));
+ aif->pub.mib->version = 0;
+ return;
+ }
+ mib = (struct ifatm_mib *)aif->pub.ifp->specmib;
+
+ aif->pub.mib->device = mib->device;
+ aif->pub.mib->serial = mib->serial;
+ aif->pub.mib->hw_version = mib->hw_version;
+ aif->pub.mib->sw_version = mib->sw_version;
+ aif->pub.mib->media = mib->media;
+
+ memcpy(aif->pub.mib->esi, mib->esi, 6);
+ aif->pub.mib->pcr = mib->pcr;
+ aif->pub.mib->vpi_bits = mib->vpi_bits;
+ aif->pub.mib->vci_bits = mib->vci_bits;
+ aif->pub.mib->max_vpcs = mib->max_vpcs;
+ aif->pub.mib->max_vccs = mib->max_vccs;
+}
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..d55ea3c
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/BEGEMOT-BRIDGE-MIB.txt
@@ -0,0 +1,1166 @@
+--
+-- 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 "200708060000Z"
+ 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."
+ REVISION "200708060000Z"
+ DESCRIPTION
+ "Third revision adds begemotBridgeBasePortPrivate
+ object."
+ REVISION "200611210000Z"
+ DESCRIPTION
+ "Second revision adds support for monitoring RSTP
+ specific variables."
+ REVISION "200607270000Z"
+ DESCRIPTION
+ "Initial revision."
+ ::= { 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,
+ begemotBridgeBasePortPrivate TruthValue
+}
+
+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 }
+
+begemotBridgeBasePortPrivate OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this objects reflects whether the port
+ has a PRIVATE flag set. A port with this flags set
+ can only communicate with ports not having the
+ PRIVATE flag set."
+ ::= { begemotBridgeBasePortEntry 7 }
+
+-- ---------------------------------------------------------- --
+-- 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,
+ begemotBridgeStpVersion INTEGER,
+ begemotBridgeStpTxHoldCount Integer32
+}
+
+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 }
+
+begemotBridgeStpVersion OBJECT-TYPE
+ SYNTAX INTEGER {
+ stpCompatible(0),
+ rstp(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The version of Spanning Tree Protocol the bridge is
+ currently running. The value 'stpCompatible(0)'
+ indicates the Spanning Tree Protocol specified in
+ IEEE 802.1D-1998 and 'rstp(2)' indicates the Rapid
+ Spanning Tree Protocol specified in IEEE 802.1w and
+ clause 17 of 802.1D-2004. The values are directly from
+ the IEEE standard. New values may be defined as future
+ versions of the protocol become available.
+
+ The value of this object MUST be retained across
+ reinitializations of the management system."
+ DEFVAL { rstp }
+ ::= { begemotBridgeStpEntry 15 }
+
+begemotBridgeStpTxHoldCount OBJECT-TYPE
+ SYNTAX Integer32 (1..10)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value used by the Port Transmit state machine to limit
+ the maximum transmission rate of BPDUs on the bridge interface.
+
+ The value of this object MUST be retained across
+ reinitializations of the management system."
+ DEFVAL { 3 }
+ ::= { begemotBridgeStpEntry 16 }
+
+-- ---------------------------------------------------------- --
+-- 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 STP extended ports table
+-- ---------------------------------------------------------- --
+
+begemotBridgeStpExtPortTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotBridgeStpExtPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains port-specific Rapid Spanning Tree
+ information for the bridge interface members."
+ ::= { begemotBridgeStp 3 }
+
+begemotBridgeStpExtPortEntry OBJECT-TYPE
+ SYNTAX BegemotBridgeStpExtPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of Rapid Spanning Tree information maintained by
+ each bridge interface member."
+ AUGMENTS { begemotBridgeStpPortEntry }
+ ::= { begemotBridgeStpExtPortTable 1 }
+
+BegemotBridgeStpExtPortEntry ::= SEQUENCE {
+ begemotBridgeStpPortProtocolMigration TruthValue,
+ begemotBridgeStpPortAdminEdgePort TruthValue,
+ begemotBridgeStpPortOperEdgePort TruthValue,
+ begemotBridgeStpPortAdminPointToPoint INTEGER,
+ begemotBridgeStpPortOperPointToPoint TruthValue,
+ begemotBridgeStpPortAdminPathCost Integer32
+}
+
+begemotBridgeStpPortProtocolMigration OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "When operating in RSTP (version 2) mode, writing true(1)
+ to this object forces this port to transmit RSTP BPDUs.
+ Any other operation on this object has no effect and
+ it always returns false(2) when read."
+ ::= { begemotBridgeStpExtPortEntry 1 }
+
+begemotBridgeStpPortAdminEdgePort OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The administrative value of the Edge Port parameter. A
+ value of true(1) indicates that this port should be
+ assumed as an edge-port, and a value of false(2) indicates
+ that this port should be assumed as a non-edge-port.
+ Setting this object will also cause the corresponding
+ instance of begemotBridgeStpPortOperEdgePort to change to
+ the same value. Note that even when this object's value
+ is true, the value of the corresponding instance of
+ begemotBridgeStpPortOperEdgePort can be false if a BPDU
+ has been received.
+
+ The value of this object MUST be retained across
+ reinitializations of the management system."
+ ::= { begemotBridgeStpExtPortEntry 2 }
+
+begemotBridgeStpPortOperEdgePort OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The operational value of the Edge Port parameter. The
+ object is initialized to the value of the corresponding
+ instance of begemotBridgeStpPortAdminEdgePort. When the
+ corresponding instance of begemotBridgeStpPortAdminEdgePort
+ is set, this object will be changed as well. This object
+ will also be changed to false on reception of a BPDU."
+ ::= { begemotBridgeStpExtPortEntry 3 }
+
+begemotBridgeStpPortAdminPointToPoint OBJECT-TYPE
+ SYNTAX INTEGER {
+ forceTrue(0),
+ forceFalse(1),
+ auto(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The administrative point-to-point status of the LAN segment
+ attached to this port, using the enumeration values of the
+ IEEE 802.1w clause. A value of forceTrue(0) indicates
+ that this port should always be treated as if it is
+ connected to a point-to-point link. A value of
+ forceFalse(1) indicates that this port should be treated as
+ having a shared media connection. A value of auto(2)
+ indicates that this port is considered to have a
+ point-to-point link if it is an Aggregator and all of its
+ members are aggregatable, or if the MAC entity
+ is configured for full duplex operation, either through
+ auto-negotiation or by management means. Manipulating this
+ object changes the underlying adminPortToPortMAC.
+
+ The value of this object MUST be retained across
+ reinitializations of the management system."
+ ::= { begemotBridgeStpExtPortEntry 4 }
+
+begemotBridgeStpPortOperPointToPoint OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The operational point-to-point status of the LAN segment
+ attached to this port. It indicates whether a port is
+ considered to have a point-to-point connection.
+ If adminPointToPointMAC is set to auto(2), then the value
+ of operPointToPointMAC is determined in accordance with the
+ specific procedures defined for the MAC entity concerned,
+ as defined in IEEE 802.1w, clause 6.5. The value is
+ determined dynamically; that is, it is re-evaluated whenever
+ the value of adminPointToPointMAC changes, and whenever
+ the specific procedures defined for the MAC entity evaluates
+ a change in its point-to-point status."
+ ::= { begemotBridgeStpExtPortEntry 5 }
+
+begemotBridgeStpPortAdminPathCost OBJECT-TYPE
+ SYNTAX Integer32 (0..200000000)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The administratively assigned value for the contribution
+ of this port to the path cost of paths toward the spanning
+ tree root.
+
+ Writing a value of '0' assigns the automatically calculated
+ default Path Cost value to the port. If the default Path
+ Cost is being used, this object returns '0' when read.
+
+ This complements the object begemotBridgeStpPortPathCost or
+ begemotBridgeStpPortPathCost32, which returns the operational
+ value of the path cost.
+
+ The value of this object MUST be retained across
+ reinitializations of the management system."
+ ::= { begemotBridgeStpExtPortEntry 6 }
+
+-- ---------------------------------------------------------- --
+-- 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..5d0afec
--- /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 RSTP-MIB.txt
+DEFS= ${MOD}_tree.def
+INCS= ${MOD}_snmp.h
+
+.include <bsd.snmpmod.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/RSTP-MIB.txt b/usr.sbin/bsnmpd/modules/snmp_bridge/RSTP-MIB.txt
new file mode 100644
index 0000000..ea6648e
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/RSTP-MIB.txt
@@ -0,0 +1,325 @@
+--
+-- 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$
+--
+
+RSTP-MIB DEFINITIONS ::= BEGIN
+
+-- -------------------------------------------------------------
+-- MIB for IEEE 802.1w Rapid Spanning Tree Protocol
+-- -------------------------------------------------------------
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, Integer32, mib-2
+ FROM SNMPv2-SMI
+ TruthValue
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP
+ FROM SNMPv2-CONF
+ dot1dStp, dot1dStpPortEntry
+ FROM BRIDGE-MIB;
+
+rstpMIB MODULE-IDENTITY
+ LAST-UPDATED "200512070000Z"
+ ORGANIZATION "IETF Bridge MIB Working Group"
+ CONTACT-INFO
+ "Email: Bridge-mib@ietf.org"
+ DESCRIPTION
+ "The Bridge MIB Extension module for managing devices
+ that support the Rapid Spanning Tree Protocol defined
+ by IEEE 802.1w.
+
+ Copyright (C) The Internet Society (2005). This version of
+ this MIB module is part of RFC 4318; See the RFC itself for
+ full legal notices."
+
+ REVISION "200512070000Z"
+ DESCRIPTION
+ "The initial version of this MIB module as published in
+ RFC 4318."
+ ::= { mib-2 134 }
+
+-- ---------------------------------------------------------- --
+-- subtrees in the RSTP-MIB
+-- ---------------------------------------------------------- --
+
+rstpNotifications OBJECT IDENTIFIER ::= { rstpMIB 0 }
+rstpObjects OBJECT IDENTIFIER ::= { rstpMIB 1 }
+rstpConformance OBJECT IDENTIFIER ::= { rstpMIB 2 }
+
+-- -------------------------------------------------------------
+-- Addition to the dot1dStp group
+-- -------------------------------------------------------------
+
+dot1dStpVersion OBJECT-TYPE
+ SYNTAX INTEGER {
+ stpCompatible(0),
+ rstp(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The version of Spanning Tree Protocol the bridge is
+ currently running. The value 'stpCompatible(0)'
+ indicates the Spanning Tree Protocol specified in
+ IEEE 802.1D-1998 and 'rstp(2)' indicates the Rapid
+ Spanning Tree Protocol specified in IEEE 802.1w and
+ clause 17 of 802.1D-2004. The values are directly from
+ the IEEE standard. New values may be defined as future
+ versions of the protocol become available.
+
+ The value of this object MUST be retained across
+ reinitializations of the management system."
+ REFERENCE
+ "IEEE 802.1w clause 14.8.1, 17.12, 17.16.1"
+ DEFVAL { rstp }
+ ::= { dot1dStp 16 }
+
+dot1dStpTxHoldCount OBJECT-TYPE
+ SYNTAX Integer32 (1..10)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value used by the Port Transmit state machine to limit
+ the maximum transmission rate.
+
+ The value of this object MUST be retained across
+ reinitializations of the management system."
+
+ REFERENCE
+ "IEEE 802.1w clause 17.16.6"
+ DEFVAL { 3 }
+ ::= { dot1dStp 17 }
+
+--
+-- { dot1dStp 18 } was used to represent dot1dStpPathCostDefault
+-- in an earlier version of this MIB. It has since been
+-- obsoleted, and should not be used.
+--
+
+dot1dStpExtPortTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF Dot1dStpExtPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains port-specific Rapid Spanning Tree
+ information."
+ ::= { dot1dStp 19 }
+
+dot1dStpExtPortEntry OBJECT-TYPE
+ SYNTAX Dot1dStpExtPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of Rapid Spanning Tree information maintained by
+ each port."
+ AUGMENTS { dot1dStpPortEntry }
+ ::= { dot1dStpExtPortTable 1 }
+
+Dot1dStpExtPortEntry ::=
+ SEQUENCE {
+ dot1dStpPortProtocolMigration
+ TruthValue,
+ dot1dStpPortAdminEdgePort
+ TruthValue,
+ dot1dStpPortOperEdgePort
+ TruthValue,
+ dot1dStpPortAdminPointToPoint
+ INTEGER,
+ dot1dStpPortOperPointToPoint
+ TruthValue,
+ dot1dStpPortAdminPathCost
+ Integer32
+ }
+
+dot1dStpPortProtocolMigration OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "When operating in RSTP (version 2) mode, writing true(1)
+ to this object forces this port to transmit RSTP BPDUs.
+ Any other operation on this object has no effect and
+ it always returns false(2) when read."
+ REFERENCE
+ "IEEE 802.1w clause 14.8.2.4, 17.18.10, 17.26"
+ ::= { dot1dStpExtPortEntry 1 }
+
+dot1dStpPortAdminEdgePort OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The administrative value of the Edge Port parameter. A
+ value of true(1) indicates that this port should be
+ assumed as an edge-port, and a value of false(2) indicates
+ that this port should be assumed as a non-edge-port.
+ Setting this object will also cause the corresponding
+ instance of dot1dStpPortOperEdgePort to change to the
+ same value. Note that even when this object's value
+ is true, the value of the corresponding instance of
+ dot1dStpPortOperEdgePort can be false if a BPDU has
+ been received.
+
+ The value of this object MUST be retained across
+ reinitializations of the management system."
+
+ REFERENCE
+ "IEEE 802.1t clause 14.8.2, 18.3.3"
+ ::= { dot1dStpExtPortEntry 2 }
+
+dot1dStpPortOperEdgePort OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The operational value of the Edge Port parameter. The
+ object is initialized to the value of the corresponding
+ instance of dot1dStpPortAdminEdgePort. When the
+ corresponding instance of dot1dStpPortAdminEdgePort is
+ set, this object will be changed as well. This object
+ will also be changed to false on reception of a BPDU."
+
+ REFERENCE
+ "IEEE 802.1t clause 14.8.2, 18.3.4"
+ ::= { dot1dStpExtPortEntry 3 }
+
+dot1dStpPortAdminPointToPoint OBJECT-TYPE
+ SYNTAX INTEGER {
+ forceTrue(0),
+ forceFalse(1),
+ auto(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The administrative point-to-point status of the LAN segment
+ attached to this port, using the enumeration values of the
+ IEEE 802.1w clause. A value of forceTrue(0) indicates
+ that this port should always be treated as if it is
+ connected to a point-to-point link. A value of
+ forceFalse(1) indicates that this port should be treated as
+ having a shared media connection. A value of auto(2)
+ indicates that this port is considered to have a
+ point-to-point link if it is an Aggregator and all of its
+ members are aggregatable, or if the MAC entity
+ is configured for full duplex operation, either through
+ auto-negotiation or by management means. Manipulating this
+ object changes the underlying adminPortToPortMAC.
+
+ The value of this object MUST be retained across
+ reinitializations of the management system."
+
+ REFERENCE
+ "IEEE 802.1w clause 6.4.3, 6.5, 14.8.2"
+ ::= { dot1dStpExtPortEntry 4 }
+
+dot1dStpPortOperPointToPoint OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The operational point-to-point status of the LAN segment
+ attached to this port. It indicates whether a port is
+ considered to have a point-to-point connection.
+ If adminPointToPointMAC is set to auto(2), then the value
+ of operPointToPointMAC is determined in accordance with the
+ specific procedures defined for the MAC entity concerned,
+ as defined in IEEE 802.1w, clause 6.5. The value is
+ determined dynamically; that is, it is re-evaluated whenever
+ the value of adminPointToPointMAC changes, and whenever
+ the specific procedures defined for the MAC entity evaluate
+ a change in its point-to-point status."
+ REFERENCE
+ "IEEE 802.1w clause 6.4.3, 6.5, 14.8.2"
+ ::= { dot1dStpExtPortEntry 5 }
+
+dot1dStpPortAdminPathCost OBJECT-TYPE
+ SYNTAX Integer32 (0..200000000)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The administratively assigned value for the contribution
+ of this port to the path cost of paths toward the spanning
+ tree root.
+
+ Writing a value of '0' assigns the automatically calculated
+ default Path Cost value to the port. If the default Path
+ Cost is being used, this object returns '0' when read.
+
+ This complements the object dot1dStpPortPathCost or
+ dot1dStpPortPathCost32, which returns the operational value
+ of the path cost.
+
+ The value of this object MUST be retained across
+ reinitializations of the management system."
+ REFERENCE
+ "IEEE 802.1D-1998: Section 8.5.5.3"
+ ::= { dot1dStpExtPortEntry 6 }
+
+-- -------------------------------------------------------------
+-- rstpMIB - Conformance Information
+-- -------------------------------------------------------------
+
+rstpGroups OBJECT IDENTIFIER ::= { rstpConformance 1 }
+
+rstpCompliances OBJECT IDENTIFIER ::= { rstpConformance 2 }
+
+-- -------------------------------------------------------------
+-- Units of conformance
+-- -------------------------------------------------------------
+
+rstpBridgeGroup OBJECT-GROUP
+ OBJECTS {
+ dot1dStpVersion,
+ dot1dStpTxHoldCount
+ }
+ STATUS current
+ DESCRIPTION
+ "Rapid Spanning Tree information for the bridge."
+ ::= { rstpGroups 1 }
+
+rstpPortGroup OBJECT-GROUP
+ OBJECTS {
+ dot1dStpPortProtocolMigration,
+ dot1dStpPortAdminEdgePort,
+ dot1dStpPortOperEdgePort,
+ dot1dStpPortAdminPointToPoint,
+ dot1dStpPortOperPointToPoint,
+ dot1dStpPortAdminPathCost
+ }
+ STATUS current
+ DESCRIPTION
+ "Rapid Spanning Tree information for individual ports."
+ ::= { rstpGroups 2 }
+
+-- -------------------------------------------------------------
+-- Compliance statements
+-- -------------------------------------------------------------
+
+rstpCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for device support of Rapid
+ Spanning Tree Protocol (RSTP) bridging services."
+ MODULE
+ MANDATORY-GROUPS {
+ rstpBridgeGroup,
+ rstpPortGroup
+ }
+ ::= { rstpCompliances 1 }
+
+END
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..0daceec
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c
@@ -0,0 +1,589 @@
+/*-
+ * 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 necessary.
+ */
+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 position 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)
+{
+ 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);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((te = bridge_addrs_get(&val->var, sub, bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ 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);
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ break;
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dTpFdbAddress:
+ return (string_get(val, te->tp_addr, ETHER_ADDR_LEN));
+ case LEAF_dot1dTpFdbPort :
+ val->v.integer = te->port_no;
+ return (SNMP_ERR_NOERROR);
+ case LEAF_dot1dTpFdbStatus:
+ val->v.integer = te->status;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+/*
+ * 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)
+{
+ struct tp_entry *te;
+
+ 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);
+ goto get;
+
+ 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);
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ break;
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeTpFdbAddress:
+ return (string_get(val, te->tp_addr, ETHER_ADDR_LEN));
+ case LEAF_begemotBridgeTpFdbPort:
+ val->v.integer = te->port_no;
+ return (SNMP_ERR_NOERROR);
+ case LEAF_begemotBridgeTpFdbStatus:
+ val->v.integer = te->status;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
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..e5f5c50
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c
@@ -0,0 +1,1479 @@
+/*-
+ * 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 occurred while fetching the info from the kernel.
+ */
+static int
+bridge_update_bif(struct bridge_if *bif)
+{
+ struct mibif *ifp;
+
+ /* Walk through the mibII interface list. */
+ for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
+ if (strcmp(ifp->name, bif->bif_name) == 0)
+ break;
+
+ if (ifp == NULL) {
+ /* Ops, we do not exist anymore. */
+ bridge_remove_bif(bif);
+ return (0);
+ }
+
+ if (ifp->physaddr != NULL )
+ bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
+ else
+ bridge_get_basemac(bif->bif_name, bif->br_addr.octet,
+ ETHER_ADDR_LEN);
+
+ if (ifp->mib.ifmd_flags & IFF_RUNNING)
+ bif->if_status = RowStatus_active;
+ else
+ bif->if_status = RowStatus_notInService;
+
+ switch (bridge_getinfo_bif(bif)) {
+ case 2:
+ bridge_new_root(bif);
+ break;
+ case 1:
+ bridge_top_change(bif);
+ break;
+ case -1:
+ bridge_remove_bif(bif);
+ return (-1);
+ default:
+ break;
+ }
+
+ /*
+ * The number of ports is accessible via SNMP -
+ * update the ports each time the bridge interface data
+ * is refreshed too.
+ */
+ bif->num_ports = bridge_update_memif(bif);
+ bif->entry_age = time(NULL);
+
+ return (1);
+}
+
+/*
+ * Update all bridge interfaces' ports only -
+ * make sure each bridge interface exists first.
+ */
+void
+bridge_update_all_ports(void)
+{
+ struct mibif *ifp;
+ struct bridge_if *bif, *t_bif;
+
+ for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
+ t_bif = bridge_next_bif(bif);
+
+ for (ifp = mib_first_if(); ifp != NULL;
+ ifp = mib_next_if(ifp))
+ if (strcmp(ifp->name, bif->bif_name) == 0)
+ break;
+
+ if (ifp != NULL)
+ bif->num_ports = bridge_update_memif(bif);
+ else /* Ops, we do not exist anymore. */
+ bridge_remove_bif(bif);
+ }
+
+ bridge_ports_update_listage();
+}
+
+/*
+ * Update all addresses only.
+ */
+void
+bridge_update_all_addrs(void)
+{
+ struct mibif *ifp;
+ struct bridge_if *bif, *t_bif;
+
+ for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
+ t_bif = bridge_next_bif(bif);
+
+ for (ifp = mib_first_if(); ifp != NULL;
+ ifp = mib_next_if(ifp))
+ if (strcmp(ifp->name, bif->bif_name) == 0)
+ break;
+
+ if (ifp != NULL)
+ bif->num_addrs = bridge_update_addrs(bif);
+ else /* Ops, we don't exist anymore. */
+ bridge_remove_bif(bif);
+ }
+
+ bridge_addrs_update_listage();
+}
+
+/*
+ * Update only the bridge interfaces' data - skip addresses.
+ */
+void
+bridge_update_all_ifs(void)
+{
+ struct bridge_if *bif, *t_bif;
+
+ for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
+ t_bif = bridge_next_bif(bif);
+ bridge_update_bif(bif);
+ }
+
+ bridge_ports_update_listage();
+ bridge_list_age = time(NULL);
+}
+
+/*
+ * Update all info we have for all bridges.
+ */
+void
+bridge_update_all(void *arg __unused)
+{
+ struct bridge_if *bif, *t_bif;
+
+ for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
+ t_bif = bridge_next_bif(bif);
+ if (bridge_update_bif(bif) <= 0)
+ continue;
+
+ /* Update our learnt addresses. */
+ bif->num_addrs = bridge_update_addrs(bif);
+ }
+
+ bridge_list_age = time(NULL);
+ bridge_ports_update_listage();
+ bridge_addrs_update_listage();
+}
+
+/*
+ * Callback for polling our last topology change time -
+ * check whether we are root or whether a TC was detected once every
+ * 30 seconds, so that we can send the newRoot and TopologyChange traps
+ * on time. The rest of the data is polled only once every 5 min.
+ */
+void
+bridge_update_tc_time(void *arg __unused)
+{
+ struct bridge_if *bif;
+ struct mibif *ifp;
+
+ TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
+ /* Walk through the mibII interface list. */
+ for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
+ if (strcmp(ifp->name, bif->bif_name) == 0)
+ break;
+
+ if (ifp == NULL) {
+ bridge_remove_bif(bif);
+ continue;
+ }
+
+ switch (bridge_get_op_param(bif)) {
+ case 2:
+ bridge_new_root(bif);
+ break;
+ case 1:
+ bridge_top_change(bif);
+ break;
+ }
+ }
+}
+
+/*
+ * Callback for handling new bridge interface creation.
+ */
+int
+bridge_attach_newif(struct mibif *ifp)
+{
+ u_char mac[ETHER_ADDR_LEN];
+ struct bridge_if *bif;
+
+ if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
+ return (0);
+
+ /* Make sure it does not exist in our list. */
+ TAILQ_FOREACH(bif, &bridge_ifs, b_if)
+ if(strcmp(bif->bif_name, ifp->name) == 0) {
+ syslog(LOG_ERR, "bridge interface %s already "
+ "in list", bif->bif_name);
+ return (-1);
+ }
+
+ if (ifp->physaddr == NULL) {
+ if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) {
+ syslog(LOG_ERR, "bridge attach new %s failed - "
+ "no bridge mac address", ifp->name);
+ return (-1);
+ }
+ } else
+ bcopy(ifp->physaddr, &mac, sizeof(mac));
+
+ if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL)
+ return (-1);
+
+ if (ifp->mib.ifmd_flags & IFF_RUNNING)
+ bif->if_status = RowStatus_active;
+ else
+ bif->if_status = RowStatus_notInService;
+
+ /* Skip sending notifications if the interface was just created. */
+ if (bridge_getinfo_bif(bif) < 0 ||
+ (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
+ (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
+ bridge_remove_bif(bif);
+ return (-1);
+ }
+
+ /* Check whether we are the default bridge interface. */
+ if (strcmp(ifp->name, bridge_get_default_name()) == 0)
+ bridge_set_default(bif);
+
+ return (0);
+}
+
+void
+bridge_ifs_dump(void)
+{
+ struct bridge_if *bif;
+
+ for (bif = bridge_first_bif(); bif != NULL;
+ bif = bridge_next_bif(bif)) {
+ syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
+ bif->sysindex);
+ bridge_ports_dump(bif);
+ bridge_addrs_dump(bif);
+ }
+}
+
+/*
+ * RFC4188 specifics.
+ */
+int
+op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
+ bridge_update_bif(bif) <= 0) /* It was just deleted. */
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+ case LEAF_dot1dBaseBridgeAddress:
+ return (string_get(value, bif->br_addr.octet,
+ ETHER_ADDR_LEN));
+ case LEAF_dot1dBaseNumPorts:
+ value->v.integer = bif->num_ports;
+ return (SNMP_ERR_NOERROR);
+ case LEAF_dot1dBaseType:
+ value->v.integer = bif->br_type;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_GETNEXT:
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ break;
+ }
+
+ abort();
+}
+
+int
+op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub,
+ uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
+ bridge_update_bif(bif) <= 0) /* It was just deleted. */
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpProtocolSpecification:
+ val->v.integer = bif->prot_spec;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPriority:
+ val->v.integer = bif->priority;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpTimeSinceTopologyChange:
+ if (bridge_get_time_since_tc(bif,
+ &(val->v.uint32)) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpTopChanges:
+ val->v.uint32 = bif->top_changes;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpDesignatedRoot:
+ return (string_get(val, bif->design_root,
+ SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_dot1dStpRootCost:
+ val->v.integer = bif->root_cost;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpRootPort:
+ val->v.integer = bif->root_port;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpMaxAge:
+ val->v.integer = bif->max_age;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpHelloTime:
+ val->v.integer = bif->hello_time;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpHoldTime:
+ val->v.integer = bif->hold_time;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpForwardDelay:
+ val->v.integer = bif->fwd_delay;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpBridgeMaxAge:
+ val->v.integer = bif->bridge_max_age;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpBridgeHelloTime:
+ val->v.integer = bif->bridge_hello_time;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpBridgeForwardDelay:
+ val->v.integer = bif->bridge_fwd_delay;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpVersion:
+ val->v.integer = bif->stp_version;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpTxHoldCount:
+ val->v.integer = bif->tx_hold_count;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_SET:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPriority:
+ if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
+ val->v.integer % 4096 != 0)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->priority;
+ if (bridge_set_priority(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpBridgeMaxAge:
+ if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
+ val->v.integer > SNMP_BRIDGE_MAX_MAGE)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->bridge_max_age;
+ if (bridge_set_maxage(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpBridgeHelloTime:
+ if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
+ val->v.integer > SNMP_BRIDGE_MAX_HTIME)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->bridge_hello_time;
+ if (bridge_set_hello_time(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpBridgeForwardDelay:
+ if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
+ val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->bridge_fwd_delay;
+ if (bridge_set_forward_delay(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpVersion:
+ if (val->v.integer != dot1dStpVersion_stpCompatible &&
+ val->v.integer != dot1dStpVersion_rstp)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->stp_version;
+ if (bridge_set_stp_version(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpTxHoldCount:
+ if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
+ val->v.integer > SNMP_BRIDGE_MAX_TXHC)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->tx_hold_count;
+ if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpProtocolSpecification:
+ case LEAF_dot1dStpTimeSinceTopologyChange:
+ case LEAF_dot1dStpTopChanges:
+ case LEAF_dot1dStpDesignatedRoot:
+ case LEAF_dot1dStpRootCost:
+ case LEAF_dot1dStpRootPort:
+ case LEAF_dot1dStpMaxAge:
+ case LEAF_dot1dStpHelloTime:
+ case LEAF_dot1dStpHoldTime:
+ case LEAF_dot1dStpForwardDelay:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPriority:
+ bridge_set_priority(bif, ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpBridgeMaxAge:
+ bridge_set_maxage(bif, ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpBridgeHelloTime:
+ bridge_set_hello_time(bif, ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpBridgeForwardDelay:
+ bridge_set_forward_delay(bif, ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpVersion:
+ bridge_set_stp_version(bif, ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpTxHoldCount:
+ bridge_set_tx_hold_count(bif, ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
+ bridge_update_bif(bif) <= 0) /* It was just deleted. */
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+ case LEAF_dot1dTpLearnedEntryDiscards:
+ value->v.uint32 = bif->lrnt_drops;
+ return (SNMP_ERR_NOERROR);
+ case LEAF_dot1dTpAgingTime:
+ value->v.integer = bif->age_time;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_SET:
+ switch (value->var.subs[sub - 1]) {
+ case LEAF_dot1dTpLearnedEntryDiscards:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case LEAF_dot1dTpAgingTime:
+ if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
+ value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->age_time;
+ if (bridge_set_aging_time(bif, value->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
+ bridge_set_aging_time(bif, ctx->scratch->int1);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+/*
+ * Private BEGEMOT-BRIDGE-MIB specifics.
+ */
+
+/*
+ * Get the bridge name from an OID index.
+ */
+static char *
+bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
+{
+ uint i;
+
+ if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ b_name[i] = oid->subs[sub + i + 1];
+ b_name[i] = '\0';
+
+ return (b_name);
+}
+
+static void
+bridge_if_index_append(struct asn_oid *oid, uint sub,
+ const struct bridge_if *bif)
+{
+ uint i;
+
+ oid->len = sub + strlen(bif->bif_name) + 1;
+ oid->subs[sub] = strlen(bif->bif_name);
+
+ for (i = 1; i <= strlen(bif->bif_name); i++)
+ oid->subs[sub + i] = bif->bif_name[i - 1];
+}
+
+static struct bridge_if *
+bridge_if_index_get(const struct asn_oid *oid, uint sub)
+{
+ uint i;
+ char bif_name[IFNAMSIZ];
+
+ if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ bif_name[i] = oid->subs[sub + i + 1];
+ bif_name[i] = '\0';
+
+ return (bridge_if_find_ifname(bif_name));
+}
+
+static struct bridge_if *
+bridge_if_index_getnext(const struct asn_oid *oid, uint sub)
+{
+ uint i;
+ char bif_name[IFNAMSIZ];
+ struct bridge_if *bif;
+
+ if (oid->len - sub == 0)
+ return (bridge_first_bif());
+
+ if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ bif_name[i] = oid->subs[sub + i + 1];
+ bif_name[i] = '\0';
+
+ if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
+ return (NULL);
+
+ return (bridge_next_bif(bif));
+}
+
+static int
+bridge_set_if_status(struct snmp_context *ctx,
+ struct snmp_value *val, uint sub)
+{
+ struct bridge_if *bif;
+ char bif_name[IFNAMSIZ];
+
+ bif = bridge_if_index_get(&val->var, sub);
+
+ switch (val->v.integer) {
+ case RowStatus_active:
+ if (bif == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ ctx->scratch->int1 = bif->if_status;
+
+ switch (bif->if_status) {
+ case RowStatus_active:
+ return (SNMP_ERR_NOERROR);
+ case RowStatus_notInService:
+ if (bridge_set_if_up(bif->bif_name, 1) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+ default:
+ break;
+ }
+ return (SNMP_ERR_INCONS_VALUE);
+
+ case RowStatus_notInService:
+ if (bif == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ ctx->scratch->int1 = bif->if_status;
+
+ switch (bif->if_status) {
+ case RowStatus_active:
+ if (bridge_set_if_up(bif->bif_name, 1) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+ case RowStatus_notInService:
+ return (SNMP_ERR_NOERROR);
+ default:
+ break;
+ }
+ return (SNMP_ERR_INCONS_VALUE);
+
+ case RowStatus_notReady:
+ return (SNMP_ERR_INCONS_VALUE);
+
+ case RowStatus_createAndGo:
+ if (bif != NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ ctx->scratch->int1 = RowStatus_destroy;
+
+ if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
+ return (SNMP_ERR_BADVALUE);
+ if (bridge_if_create(bif_name, 1) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case RowStatus_createAndWait:
+ if (bif != NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
+ return (SNMP_ERR_BADVALUE);
+
+ ctx->scratch->int1 = RowStatus_destroy;
+
+ if (bridge_if_create(bif_name, 0) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case RowStatus_destroy:
+ if (bif == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ ctx->scratch->int1 = bif->if_status;
+ bif->if_status = RowStatus_destroy;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+static int
+bridge_rollback_if_status(struct snmp_context *ctx,
+ struct snmp_value *val, uint sub)
+{
+ struct bridge_if *bif;
+
+ if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (ctx->scratch->int1) {
+ case RowStatus_destroy:
+ bridge_if_destroy(bif);
+ return (SNMP_ERR_NOERROR);
+
+ case RowStatus_notInService:
+ if (bif->if_status != ctx->scratch->int1)
+ bridge_set_if_up(bif->bif_name, 0);
+ bif->if_status = RowStatus_notInService;
+ return (SNMP_ERR_NOERROR);
+
+ case RowStatus_active:
+ if (bif->if_status != ctx->scratch->int1)
+ bridge_set_if_up(bif->bif_name, 1);
+ bif->if_status = RowStatus_active;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+static int
+bridge_commit_if_status(struct snmp_value *val, uint sub)
+{
+ struct bridge_if *bif;
+
+ if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ if (bif->if_status == RowStatus_destroy &&
+ bridge_if_destroy(bif) < 0)
+ return (SNMP_ERR_COMMIT_FAILED);
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+
+ if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
+ bridge_update_all_ifs();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ bridge_if_index_append(&val->var, sub, bif);
+ goto get;
+
+ case SNMP_OP_SET:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeBaseStatus:
+ return (bridge_set_if_status(ctx, val, sub));
+ case LEAF_begemotBridgeBaseName:
+ case LEAF_begemotBridgeBaseAddress:
+ case LEAF_begemotBridgeBaseNumPorts:
+ case LEAF_begemotBridgeBaseType:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ return (bridge_rollback_if_status(ctx, val, sub));
+
+ case SNMP_OP_COMMIT:
+ return (bridge_commit_if_status(val, sub));
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeBaseName:
+ return (string_get(val, bif->bif_name, -1));
+
+ case LEAF_begemotBridgeBaseAddress:
+ return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN));
+
+ case LEAF_begemotBridgeBaseNumPorts:
+ val->v.integer = bif->num_ports;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBaseType:
+ val->v.integer = bif->br_type;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBaseStatus:
+ val->v.integer = bif->if_status;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+
+ if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
+ bridge_update_all_ifs();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ bridge_if_index_append(&val->var, sub, bif);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPriority:
+ if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
+ val->v.integer % 4096 != 0)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->priority;
+ if (bridge_set_priority(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpBridgeMaxAge:
+ if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
+ val->v.integer > SNMP_BRIDGE_MAX_MAGE)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->bridge_max_age;
+ if (bridge_set_maxage(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpBridgeHelloTime:
+ if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
+ val->v.integer > SNMP_BRIDGE_MAX_HTIME)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->bridge_hello_time;
+ if (bridge_set_hello_time(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpBridgeForwardDelay:
+ if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
+ val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->bridge_fwd_delay;
+ if (bridge_set_forward_delay(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpVersion:
+ if (val->v.integer !=
+ begemotBridgeStpVersion_stpCompatible &&
+ val->v.integer != begemotBridgeStpVersion_rstp)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->stp_version;
+ if (bridge_set_stp_version(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpTxHoldCount:
+ if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
+ val->v.integer > SNMP_BRIDGE_MAX_TXHC)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->tx_hold_count;
+ if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpProtocolSpecification:
+ case LEAF_begemotBridgeStpTimeSinceTopologyChange:
+ case LEAF_begemotBridgeStpTopChanges:
+ case LEAF_begemotBridgeStpDesignatedRoot:
+ case LEAF_begemotBridgeStpRootCost:
+ case LEAF_begemotBridgeStpRootPort:
+ case LEAF_begemotBridgeStpMaxAge:
+ case LEAF_begemotBridgeStpHelloTime:
+ case LEAF_begemotBridgeStpHoldTime:
+ case LEAF_begemotBridgeStpForwardDelay:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPriority:
+ bridge_set_priority(bif, ctx->scratch->int1);
+ break;
+
+ case LEAF_begemotBridgeStpBridgeMaxAge:
+ bridge_set_maxage(bif, ctx->scratch->int1);
+ break;
+
+ case LEAF_begemotBridgeStpBridgeHelloTime:
+ bridge_set_hello_time(bif, ctx->scratch->int1);
+ break;
+
+ case LEAF_begemotBridgeStpBridgeForwardDelay:
+ bridge_set_forward_delay(bif, ctx->scratch->int1);
+ break;
+
+ case LEAF_begemotBridgeStpVersion:
+ bridge_set_stp_version(bif, ctx->scratch->int1);
+ break;
+
+ case LEAF_begemotBridgeStpTxHoldCount:
+ bridge_set_tx_hold_count(bif, ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpProtocolSpecification:
+ val->v.integer = bif->prot_spec;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPriority:
+ val->v.integer = bif->priority;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpTimeSinceTopologyChange:
+ if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpTopChanges:
+ val->v.uint32 = bif->top_changes;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpDesignatedRoot:
+ return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_begemotBridgeStpRootCost:
+ val->v.integer = bif->root_cost;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpRootPort:
+ val->v.integer = bif->root_port;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpMaxAge:
+ val->v.integer = bif->max_age;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpHelloTime:
+ val->v.integer = bif->hello_time;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpHoldTime:
+ val->v.integer = bif->hold_time;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpForwardDelay:
+ val->v.integer = bif->fwd_delay;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpBridgeMaxAge:
+ val->v.integer = bif->bridge_max_age;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpBridgeHelloTime:
+ val->v.integer = bif->bridge_hello_time;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpBridgeForwardDelay:
+ val->v.integer = bif->bridge_fwd_delay;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpVersion:
+ val->v.integer = bif->stp_version;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpTxHoldCount:
+ val->v.integer = bif->tx_hold_count;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+
+ if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
+ bridge_update_all_ifs();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ bridge_if_index_append(&val->var, sub, bif);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeTpAgingTime:
+ if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
+ val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bif->age_time;
+ if (bridge_set_aging_time(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpMaxAddresses:
+ ctx->scratch->int1 = bif->max_addrs;
+ if (bridge_set_max_cache(bif, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpLearnedEntryDiscards:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeTpAgingTime:
+ bridge_set_aging_time(bif, ctx->scratch->int1);
+ break;
+
+ case LEAF_begemotBridgeTpMaxAddresses:
+ bridge_set_max_cache(bif, ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeTpLearnedEntryDiscards:
+ val->v.uint32 = bif->lrnt_drops;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpAgingTime:
+ val->v.integer = bif->age_time;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpMaxAddresses:
+ val->v.integer = bif->max_addrs;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
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..0ad8cbf
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_pf.c
@@ -0,0 +1,116 @@
+/*-
+ * 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);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_GET:
+ 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);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+ }
+
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c
new file mode 100644
index 0000000..0127cea
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c
@@ -0,0 +1,1513 @@
+/*-
+ * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Bridge MIB implementation for SNMPd.
+ * Bridge ports.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_mib.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <bsnmp/snmpmod.h>
+#include <bsnmp/snmp_mibII.h>
+
+#include "bridge_tree.h"
+#include "bridge_snmp.h"
+
+TAILQ_HEAD(bridge_ports, bridge_port);
+
+/*
+ * Free the bridge base ports list.
+ */
+static void
+bridge_ports_free(struct bridge_ports *headp)
+{
+ struct bridge_port *bp;
+
+ while ((bp = TAILQ_FIRST(headp)) != NULL) {
+ TAILQ_REMOVE(headp, bp, b_p);
+ free(bp);
+ }
+}
+
+/*
+ * Free the bridge base ports from the base ports list,
+ * members of a specified bridge interface only.
+ */
+static void
+bridge_port_memif_free(struct bridge_ports *headp,
+ struct bridge_if *bif)
+{
+ struct bridge_port *bp;
+
+ while (bif->f_bp != NULL && bif->sysindex == bif->f_bp->sysindex) {
+ bp = TAILQ_NEXT(bif->f_bp, b_p);
+ TAILQ_REMOVE(headp, bif->f_bp, b_p);
+ free(bif->f_bp);
+ bif->f_bp = bp;
+ }
+}
+
+/*
+ * Insert a port entry in the base port TAILQ starting to search
+ * for its place from the position of the first bridge port for the bridge
+ * interface. Update the first bridge port if necessary.
+ */
+static void
+bridge_port_insert_at(struct bridge_ports *headp,
+ struct bridge_port *bp, struct bridge_port **f_bp)
+{
+ struct bridge_port *t1;
+
+ assert(f_bp != NULL);
+
+ for (t1 = *f_bp;
+ t1 != NULL && bp->sysindex == t1->sysindex;
+ t1 = TAILQ_NEXT(t1, b_p)) {
+ if (bp->if_idx < t1->if_idx) {
+ TAILQ_INSERT_BEFORE(t1, bp, b_p);
+ if (*f_bp == t1)
+ *f_bp = bp;
+ return;
+ }
+ }
+
+ /*
+ * Handle the case when our first port was actually the
+ * last element of the TAILQ.
+ */
+ if (t1 == NULL)
+ TAILQ_INSERT_TAIL(headp, bp, b_p);
+ else
+ TAILQ_INSERT_BEFORE(t1, bp, b_p);
+}
+
+/*
+ * Find a port entry's position in the ports list according
+ * to it's parent bridge interface name. Returns a NULL if
+ * we should be at the TAILQ head, otherwise the entry after
+ * which we should be inserted.
+ */
+static struct bridge_port *
+bridge_port_find_pos(struct bridge_ports *headp, uint32_t b_idx)
+{
+ uint32_t t_idx;
+ struct bridge_port *t1;
+
+ if ((t1 = TAILQ_FIRST(headp)) == NULL ||
+ bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
+ return (NULL);
+
+ t_idx = t1->sysindex;
+
+ for (t1 = TAILQ_NEXT(t1, b_p); t1 != NULL; t1 = TAILQ_NEXT(t1, b_p)) {
+ if (t1->sysindex != t_idx) {
+ if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
+ return (TAILQ_PREV(t1, bridge_ports, b_p));
+ else
+ t_idx = t1->sysindex;
+ }
+ }
+
+ if (t1 == NULL)
+ t1 = TAILQ_LAST(headp, bridge_ports);
+
+ return (t1);
+}
+
+/*
+ * Insert a bridge member interface in the ports TAILQ.
+ */
+static void
+bridge_port_memif_insert(struct bridge_ports *headp,
+ struct bridge_port *bp, struct bridge_port **f_bp)
+{
+ struct bridge_port *temp;
+
+ if (*f_bp != NULL)
+ bridge_port_insert_at(headp, bp, f_bp);
+ else {
+ temp = bridge_port_find_pos(headp, bp->sysindex);
+
+ if (temp == NULL)
+ TAILQ_INSERT_HEAD(headp, bp, b_p);
+ else
+ TAILQ_INSERT_AFTER(headp, temp, bp, b_p);
+ *f_bp = bp;
+ }
+}
+
+/* The global ports list. */
+static struct bridge_ports bridge_ports = TAILQ_HEAD_INITIALIZER(bridge_ports);
+static time_t ports_list_age;
+
+void
+bridge_ports_update_listage(void)
+{
+ ports_list_age = time(NULL);
+}
+
+void
+bridge_ports_fini(void)
+{
+ bridge_ports_free(&bridge_ports);
+}
+
+void
+bridge_members_free(struct bridge_if *bif)
+{
+ bridge_port_memif_free(&bridge_ports, bif);
+}
+
+/*
+ * Find the first port in the ports list.
+ */
+static struct bridge_port *
+bridge_port_first(void)
+{
+ return (TAILQ_FIRST(&bridge_ports));
+}
+
+/*
+ * Find the next port in the ports list.
+ */
+static struct bridge_port *
+bridge_port_next(struct bridge_port *bp)
+{
+ return (TAILQ_NEXT(bp, b_p));
+}
+
+/*
+ * Find the first member of the specified bridge interface.
+ */
+struct bridge_port *
+bridge_port_bif_first(struct bridge_if *bif)
+{
+ return (bif->f_bp);
+}
+
+/*
+ * Find the next member of the specified bridge interface.
+ */
+struct bridge_port *
+bridge_port_bif_next(struct bridge_port *bp)
+{
+ struct bridge_port *bp_next;
+
+ if ((bp_next = TAILQ_NEXT(bp, b_p)) == NULL ||
+ bp_next->sysindex != bp->sysindex)
+ return (NULL);
+
+ return (bp_next);
+}
+
+/*
+ * Remove a bridge port from the ports list.
+ */
+void
+bridge_port_remove(struct bridge_port *bp, struct bridge_if *bif)
+{
+ if (bif->f_bp == bp)
+ bif->f_bp = bridge_port_bif_next(bp);
+
+ TAILQ_REMOVE(&bridge_ports, bp, b_p);
+ free(bp);
+}
+
+/*
+ * Allocate memory for a new bridge port and insert it
+ * in the base ports list. Return a pointer to the port's
+ * structure in case we want to do anything else with it.
+ */
+struct bridge_port *
+bridge_new_port(struct mibif *mif, struct bridge_if *bif)
+{
+ struct bridge_port *bp;
+
+ if ((bp = (struct bridge_port *) malloc(sizeof(*bp))) == NULL) {
+ syslog(LOG_ERR, "bridge new member: failed: %s",
+ strerror(errno));
+ return (NULL);
+ }
+
+ bzero(bp, sizeof(*bp));
+
+ bp->sysindex = bif->sysindex;
+ bp->if_idx = mif->index;
+ bp->port_no = mif->sysindex;
+ strlcpy(bp->p_name, mif->name, IFNAMSIZ);
+ bp->circuit = oid_zeroDotZero;
+
+ /*
+ * Initialize all rstpMib specific values to false/default.
+ * These will be set to their true values later if the bridge
+ * supports RSTP.
+ */
+ bp->proto_migr = TruthValue_false;
+ bp->admin_edge = TruthValue_false;
+ bp->oper_edge = TruthValue_false;
+ bp->oper_ptp = TruthValue_false;
+ bp->admin_ptp = StpPortAdminPointToPointType_auto;
+
+ bridge_port_memif_insert(&bridge_ports, bp, &(bif->f_bp));
+
+ return (bp);
+}
+
+/*
+ * Update our info from the corresponding mibII interface info.
+ */
+void
+bridge_port_getinfo_mibif(struct mibif *m_if, struct bridge_port *bp)
+{
+ bp->max_info = m_if->mib.ifmd_data.ifi_mtu;
+ bp->in_frames = m_if->mib.ifmd_data.ifi_ipackets;
+ bp->out_frames = m_if->mib.ifmd_data.ifi_opackets;
+ bp->in_drops = m_if->mib.ifmd_data.ifi_iqdrops;
+}
+
+/*
+ * Find a port, whose SNMP's mibII ifIndex matches one of the ports,
+ * members of the specified bridge interface.
+ */
+struct bridge_port *
+bridge_port_find(int32_t if_idx, struct bridge_if *bif)
+{
+ struct bridge_port *bp;
+
+ for (bp = bif->f_bp; bp != NULL; bp = TAILQ_NEXT(bp, b_p)) {
+ if (bp->sysindex != bif->sysindex) {
+ bp = NULL;
+ break;
+ }
+
+ if (bp->if_idx == if_idx)
+ break;
+ }
+
+ return (bp);
+}
+
+void
+bridge_ports_dump(struct bridge_if *bif)
+{
+ struct bridge_port *bp;
+
+ for (bp = bridge_port_bif_first(bif); bp != NULL;
+ bp = bridge_port_bif_next(bp)) {
+ syslog(LOG_ERR, "memif - %s, index - %d",
+ bp->p_name, bp->port_no);
+ }
+}
+
+/*
+ * RFC4188 specifics.
+ */
+int
+op_dot1d_base_port(struct snmp_context *c __unused, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
+ bridge_update_memif(bif) <= 0)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if (val->var.len - sub == 0) {
+ if ((bp = bridge_port_bif_first(bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ } else {
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL ||
+ (bp = bridge_port_bif_next(bp)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+ val->var.len = sub + 1;
+ val->var.subs[sub] = bp->port_no;
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ break;
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dBasePort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dBasePortIfIndex:
+ val->v.integer = bp->if_idx;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dBasePortCircuit:
+ val->v.oid = bp->circuit;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dBasePortDelayExceededDiscards:
+ val->v.uint32 = bp->dly_ex_drops;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dBasePortMtuExceededDiscards:
+ val->v.uint32 = bp->dly_mtu_drops;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_dot1d_stp_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
+ bridge_update_memif(bif) <= 0)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if (val->var.len - sub == 0) {
+ if ((bp = bridge_port_bif_first(bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ } else {
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL ||
+ (bp = bridge_port_bif_next(bp)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+ val->var.len = sub + 1;
+ val->var.subs[sub] = bp->port_no;
+ goto get;
+
+ case SNMP_OP_SET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortPriority:
+ if (val->v.integer < 0 || val->v.integer > 255)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->priority;
+ if (bridge_port_set_priority(bif->bif_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortEnable:
+ if (val->v.integer != dot1dStpPortEnable_enabled &&
+ val->v.integer != dot1dStpPortEnable_disabled)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->enable;
+ if (bridge_port_set_stp_enable(bif->bif_name,
+ bp, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortPathCost:
+ if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
+ val->v.integer > SNMP_PORT_MAX_PATHCOST)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->path_cost;
+ if (bridge_port_set_path_cost(bif->bif_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPort:
+ case LEAF_dot1dStpPortState:
+ case LEAF_dot1dStpPortDesignatedRoot:
+ case LEAF_dot1dStpPortDesignatedCost:
+ case LEAF_dot1dStpPortDesignatedBridge:
+ case LEAF_dot1dStpPortDesignatedPort:
+ case LEAF_dot1dStpPortForwardTransitions:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortPriority:
+ bridge_port_set_priority(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpPortEnable:
+ bridge_port_set_stp_enable(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpPortPathCost:
+ bridge_port_set_path_cost(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortPriority:
+ val->v.integer = bp->priority;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortState:
+ val->v.integer = bp->state;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortEnable:
+ val->v.integer = bp->enable;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortPathCost:
+ val->v.integer = bp->path_cost;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortDesignatedRoot:
+ return (string_get(val, bp->design_root,
+ SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_dot1dStpPortDesignatedCost:
+ val->v.integer = bp->design_cost;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortDesignatedBridge:
+ return (string_get(val, bp->design_bridge,
+ SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_dot1dStpPortDesignatedPort:
+ return (string_get(val, bp->design_port, 2));
+
+ case LEAF_dot1dStpPortForwardTransitions:
+ val->v.uint32 = bp->fwd_trans;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_dot1d_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
+ bridge_update_memif(bif) <= 0)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if (val->var.len - sub == 0) {
+ if ((bp = bridge_port_bif_first(bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ } else {
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL ||
+ (bp = bridge_port_bif_next(bp)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+ val->var.len = sub + 1;
+ val->var.subs[sub] = bp->port_no;
+ goto get;
+
+ case SNMP_OP_SET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortAdminEdgePort:
+ if (val->v.integer != TruthValue_true &&
+ val->v.integer != TruthValue_false)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_edge;
+ if (bridge_port_set_admin_edge(bif->bif_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortAdminPointToPoint:
+ if (val->v.integer < 0 || val->v.integer >
+ StpPortAdminPointToPointType_auto)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_ptp;
+ if (bridge_port_set_admin_ptp(bif->bif_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortAdminPathCost:
+ if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
+ val->v.integer > SNMP_PORT_MAX_PATHCOST)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_path_cost;
+ if (bridge_port_set_path_cost(bif->bif_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortProtocolMigration:
+ case LEAF_dot1dStpPortOperEdgePort:
+ case LEAF_dot1dStpPortOperPointToPoint:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortAdminEdgePort:
+ bridge_port_set_admin_edge(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpPortAdminPointToPoint:
+ bridge_port_set_admin_ptp(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_dot1dStpPortAdminPathCost:
+ bridge_port_set_path_cost(bif->bif_name, bp,
+ ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dStpPortProtocolMigration:
+ val->v.integer = bp->proto_migr;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortAdminEdgePort:
+ val->v.integer = bp->admin_edge;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortOperEdgePort:
+ val->v.integer = bp->oper_edge;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortAdminPointToPoint:
+ val->v.integer = bp->admin_ptp;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortOperPointToPoint:
+ val->v.integer = bp->oper_ptp;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dStpPortAdminPathCost:
+ val->v.integer = bp->admin_path_cost;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_dot1d_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if ((bif = bridge_get_default()) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
+ bridge_update_memif(bif) <= 0)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if (val->var.len - sub == 0) {
+ if ((bp = bridge_port_bif_first(bif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ } else {
+ if ((bp = bridge_port_find(val->var.subs[sub],
+ bif)) == NULL ||
+ (bp = bridge_port_bif_next(bp)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+ val->var.len = sub + 1;
+ val->var.subs[sub] = bp->port_no;
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ break;
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_dot1dTpPort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dTpPortMaxInfo:
+ val->v.integer = bp->max_info;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dTpPortInFrames:
+ val->v.uint32 = bp->in_frames;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dTpPortOutFrames:
+ val->v.uint32 = bp->out_frames;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_dot1dTpPortInDiscards:
+ val->v.uint32 = bp->in_drops;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+/*
+ * Private BEGEMOT-BRIDGE-MIB specifics.
+ */
+
+/*
+ * Construct a bridge port entry index.
+ */
+static int
+bridge_port_index_append(struct asn_oid *oid, uint sub,
+ const struct bridge_port *bp)
+{
+ uint i;
+ const char *b_name;
+
+ if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (-1);
+
+ oid->len = sub + strlen(b_name) + 1 + 1;
+ oid->subs[sub] = strlen(b_name);
+
+ for (i = 1; i <= strlen(b_name); i++)
+ oid->subs[sub + i] = b_name[i - 1];
+
+ oid->subs[sub + i] = bp->port_no;
+
+ return (0);
+}
+
+/*
+ * Get the port entry from an entry's index.
+ */
+static struct bridge_port *
+bridge_port_index_get(const struct asn_oid *oid, uint sub, int8_t status)
+{
+ uint i;
+ int32_t port_no;
+ char bif_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if (oid->len - sub != oid->subs[sub] + 2 ||
+ oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ bif_name[i] = oid->subs[sub + i + 1];
+ bif_name[i] = '\0';
+
+ port_no = oid->subs[sub + i + 1];
+
+ if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
+ return (NULL);
+
+ if ((bp = bridge_port_find(port_no, bif)) == NULL ||
+ (status == 0 && bp->status != RowStatus_active))
+ return (NULL);
+
+ return (bp);
+}
+
+/*
+ * Get the next port entry from an entry's index.
+ */
+static struct bridge_port *
+bridge_port_index_getnext(const struct asn_oid *oid, uint sub, int8_t status)
+{
+ uint i;
+ int32_t port_no;
+ char bif_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if (oid->len - sub == 0)
+ bp = bridge_port_first();
+ else {
+ if (oid->len - sub != oid->subs[sub] + 2 ||
+ oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ bif_name[i] = oid->subs[sub + i + 1];
+ bif_name[i] = '\0';
+
+ port_no = oid->subs[sub + i + 1];
+
+ if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
+ (bp = bridge_port_find(port_no, bif)) == NULL)
+ return (NULL);
+
+ bp = bridge_port_next(bp);
+ }
+
+ if (status == 1)
+ return (bp);
+
+ while (bp != NULL) {
+ if (bp->status == RowStatus_active)
+ break;
+ bp = bridge_port_next(bp);
+ }
+
+ return (bp);
+}
+
+/*
+ * Read the bridge name and port index from a ASN OID structure.
+ */
+static int
+bridge_port_index_decode(const struct asn_oid *oid, uint sub,
+ char *b_name, int32_t *idx)
+{
+ uint i;
+
+ if (oid->len - sub != oid->subs[sub] + 2 ||
+ oid->subs[sub] >= IFNAMSIZ)
+ return (-1);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ b_name[i] = oid->subs[sub + i + 1];
+ b_name[i] = '\0';
+
+ *idx = oid->subs[sub + i + 1];
+ return (0);
+}
+
+static int
+bridge_port_set_status(struct snmp_context *ctx,
+ struct snmp_value *val, uint sub)
+{
+ int32_t if_idx;
+ char b_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+ struct mibif *mif;
+
+ if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
+ (mif = mib_find_if(if_idx)) == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ bp = bridge_port_find(if_idx, bif);
+
+ switch (val->v.integer) {
+ case RowStatus_active:
+ if (bp == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if (bp->span_enable == 0)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ ctx->scratch->int1 = bp->status;
+ bp->status = RowStatus_active;
+ break;
+
+ case RowStatus_notInService:
+ if (bp == NULL || bp->span_enable == 0 ||
+ bp->status == RowStatus_active)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ ctx->scratch->int1 = bp->status;
+ bp->status = RowStatus_notInService;
+
+ case RowStatus_notReady:
+ /* FALLTHROUGH */
+ case RowStatus_createAndGo:
+ return (SNMP_ERR_INCONS_VALUE);
+
+ case RowStatus_createAndWait:
+ if (bp != NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((bp = bridge_new_port(mif, bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ ctx->scratch->int1 = RowStatus_destroy;
+ bp->status = RowStatus_notReady;
+ break;
+
+ case RowStatus_destroy:
+ if (bp == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ ctx->scratch->int1 = bp->status;
+ bp->status = RowStatus_destroy;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+static int
+bridge_port_rollback_status(struct snmp_context *ctx,
+ struct snmp_value *val, uint sub)
+{
+ int32_t if_idx;
+ char b_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
+ return (SNMP_ERR_GENERR);
+
+ if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
+ (bp = bridge_port_find(if_idx, bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ if (ctx->scratch->int1 == RowStatus_destroy)
+ bridge_port_remove(bp, bif);
+ else
+ bp->status = ctx->scratch->int1;
+
+ return (SNMP_ERR_NOERROR);
+}
+
+static int
+bridge_port_commit_status(struct snmp_value *val, uint sub)
+{
+ int32_t if_idx;
+ char b_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+
+ if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
+ return (SNMP_ERR_GENERR);
+
+ if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
+ (bp = bridge_port_find(if_idx, bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (bp->status) {
+ case RowStatus_active:
+ if (bridge_port_addm(bp, b_name) < 0)
+ return (SNMP_ERR_COMMIT_FAILED);
+ break;
+
+ case RowStatus_destroy:
+ if (bridge_port_delm(bp, b_name) < 0)
+ return (SNMP_ERR_COMMIT_FAILED);
+ bridge_port_remove(bp, bif);
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+static int
+bridge_port_set_span_enable(struct snmp_context *ctx,
+ struct snmp_value *val, uint sub)
+{
+ int32_t if_idx;
+ char b_name[IFNAMSIZ];
+ struct bridge_if *bif;
+ struct bridge_port *bp;
+ struct mibif *mif;
+
+ if (val->v.integer != begemotBridgeBaseSpanEnabled_enabled &&
+ val->v.integer != begemotBridgeBaseSpanEnabled_disabled)
+ return (SNMP_ERR_BADVALUE);
+
+ if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((bif = bridge_if_find_ifname(b_name)) == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((bp = bridge_port_find(if_idx, bif)) == NULL) {
+ if ((mif = mib_find_if(if_idx)) == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((bp = bridge_new_port(mif, bif)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ ctx->scratch->int1 = RowStatus_destroy;
+ } else if (bp->status == RowStatus_active) {
+ return (SNMP_ERR_INCONS_VALUE);
+ } else {
+ ctx->scratch->int1 = bp->status;
+ }
+
+ bp->span_enable = val->v.integer;
+ bp->status = RowStatus_notInService;
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_begemot_base_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ int8_t status, which;
+ const char *bname;
+ struct bridge_port *bp;
+
+ if (time(NULL) - ports_list_age > bridge_get_data_maxage())
+ bridge_update_all_ports();
+
+ which = val->var.subs[sub - 1];
+ status = 0;
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (which == LEAF_begemotBridgeBaseSpanEnabled ||
+ which == LEAF_begemotBridgeBasePortStatus)
+ status = 1;
+ if ((bp = bridge_port_index_get(&val->var, sub,
+ status)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if (which == LEAF_begemotBridgeBaseSpanEnabled ||
+ which == LEAF_begemotBridgeBasePortStatus)
+ status = 1;
+ if ((bp = bridge_port_index_getnext(&val->var, sub,
+ status)) == NULL ||
+ bridge_port_index_append(&val->var, sub, bp) < 0)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ switch (which) {
+ case LEAF_begemotBridgeBaseSpanEnabled:
+ return (bridge_port_set_span_enable(ctx, val, sub));
+
+ case LEAF_begemotBridgeBasePortStatus:
+ return (bridge_port_set_status(ctx, val, sub));
+
+ case LEAF_begemotBridgeBasePortPrivate:
+ if ((bp = bridge_port_index_get(&val->var, sub,
+ status)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+ ctx->scratch->int1 = bp->priv_set;
+ return (bridge_port_set_private(bname, bp,
+ val->v.integer));
+
+ case LEAF_begemotBridgeBasePort:
+ case LEAF_begemotBridgeBasePortIfIndex:
+ case LEAF_begemotBridgeBasePortDelayExceededDiscards:
+ case LEAF_begemotBridgeBasePortMtuExceededDiscards:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ switch (which) {
+ case LEAF_begemotBridgeBaseSpanEnabled:
+ /* FALLTHROUGH */
+ case LEAF_begemotBridgeBasePortStatus:
+ return (bridge_port_rollback_status(ctx, val, sub));
+ case LEAF_begemotBridgeBasePortPrivate:
+ if ((bp = bridge_port_index_get(&val->var, sub,
+ status)) == NULL)
+ return (SNMP_ERR_GENERR);
+ if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+ return (bridge_port_set_private(bname, bp,
+ ctx->scratch->int1));
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ if (which == LEAF_begemotBridgeBasePortStatus)
+ return (bridge_port_commit_status(val, sub));
+
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (which) {
+ case LEAF_begemotBridgeBasePort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBasePortIfIndex:
+ val->v.integer = bp->if_idx;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBaseSpanEnabled:
+ val->v.integer = bp->span_enable;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBasePortDelayExceededDiscards:
+ val->v.uint32 = bp->dly_ex_drops;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBasePortMtuExceededDiscards:
+ val->v.uint32 = bp->dly_mtu_drops;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBasePortStatus:
+ val->v.integer = bp->status;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeBasePortPrivate:
+ val->v.integer = bp->priv_set;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_port *bp;
+ const char *b_name;
+
+ if (time(NULL) - ports_list_age > bridge_get_data_maxage())
+ bridge_update_all_ports();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
+ NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortPriority:
+ if (val->v.integer < 0 || val->v.integer > 255)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->priority;
+ if (bridge_port_set_priority(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortEnable:
+ if (val->v.integer !=
+ begemotBridgeStpPortEnable_enabled ||
+ val->v.integer !=
+ begemotBridgeStpPortEnable_disabled)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->enable;
+ if (bridge_port_set_stp_enable(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortPathCost:
+ if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
+ val->v.integer > SNMP_PORT_MAX_PATHCOST)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->path_cost;
+ if (bridge_port_set_path_cost(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPort:
+ case LEAF_begemotBridgeStpPortState:
+ case LEAF_begemotBridgeStpPortDesignatedRoot:
+ case LEAF_begemotBridgeStpPortDesignatedCost:
+ case LEAF_begemotBridgeStpPortDesignatedBridge:
+ case LEAF_begemotBridgeStpPortDesignatedPort:
+ case LEAF_begemotBridgeStpPortForwardTransitions:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
+ (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortPriority:
+ bridge_port_set_priority(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_begemotBridgeStpPortEnable:
+ bridge_port_set_stp_enable(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_begemotBridgeStpPortPathCost:
+ bridge_port_set_path_cost(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortPriority:
+ val->v.integer = bp->priority;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortState:
+ val->v.integer = bp->state;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortEnable:
+ val->v.integer = bp->enable;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortPathCost:
+ val->v.integer = bp->path_cost;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortDesignatedRoot:
+ return (string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_begemotBridgeStpPortDesignatedCost:
+ val->v.integer = bp->design_cost;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortDesignatedBridge:
+ return (string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN));
+
+ case LEAF_begemotBridgeStpPortDesignatedPort:
+ return (string_get(val, bp->design_port, 2));
+
+ case LEAF_begemotBridgeStpPortForwardTransitions:
+ val->v.uint32 = bp->fwd_trans;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_begemot_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_port *bp;
+ const char *b_name;
+
+ if (time(NULL) - ports_list_age > bridge_get_data_maxage())
+ bridge_update_all_ports();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
+ NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortAdminEdgePort:
+ if (val->v.integer != TruthValue_true &&
+ val->v.integer != TruthValue_false)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_edge;
+ if (bridge_port_set_admin_edge(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortAdminPointToPoint:
+ if (val->v.integer < 0 || val->v.integer >
+ StpPortAdminPointToPointType_auto)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_ptp;
+ if (bridge_port_set_admin_ptp(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortAdminPathCost:
+ if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
+ val->v.integer > SNMP_PORT_MAX_PATHCOST)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ ctx->scratch->int1 = bp->admin_path_cost;
+ if (bridge_port_set_path_cost(b_name, bp,
+ val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortProtocolMigration:
+ case LEAF_begemotBridgeStpPortOperEdgePort:
+ case LEAF_begemotBridgeStpPortOperPointToPoint:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
+ (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortAdminEdgePort:
+ bridge_port_set_admin_edge(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_begemotBridgeStpPortAdminPointToPoint:
+ bridge_port_set_admin_ptp(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ case LEAF_begemotBridgeStpPortAdminPathCost:
+ bridge_port_set_path_cost(b_name, bp,
+ ctx->scratch->int1);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeStpPortProtocolMigration:
+ val->v.integer = bp->proto_migr;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortAdminEdgePort:
+ val->v.integer = bp->admin_edge;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortOperEdgePort:
+ val->v.integer = bp->oper_edge;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortAdminPointToPoint:
+ val->v.integer = bp->admin_ptp;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortOperPointToPoint:
+ val->v.integer = bp->oper_ptp;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeStpPortAdminPathCost:
+ val->v.integer = bp->admin_path_cost;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_begemot_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
+ uint sub, uint iidx __unused, enum snmp_op op)
+{
+ struct bridge_port *bp;
+
+ if (time(NULL) - ports_list_age > bridge_get_data_maxage())
+ bridge_update_all_ports();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_GETNEXT:
+ if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
+ NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ break;
+ }
+ abort();
+
+get:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_begemotBridgeTpPort:
+ val->v.integer = bp->port_no;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpPortMaxInfo:
+ val->v.integer = bp->max_info;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpPortInFrames:
+ val->v.uint32 = bp->in_frames;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpPortOutFrames:
+ val->v.uint32 = bp->out_frames;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeTpPortInDiscards:
+ val->v.uint32 = bp->in_drops;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
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..81acc4d
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.c
@@ -0,0 +1,338 @@
+/*-
+ * 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) {
+ bif_default = 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:
+ return (string_get(val, bridge_get_default_name(), -1));
+
+ case LEAF_begemotBridgeDataUpdate:
+ val->v.integer = bridge_data_maxage;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeDataPoll:
+ val->v.integer = bridge_poll_ticks / 100;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ 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);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeDataUpdate:
+ if (val->v.integer < SNMP_BRIDGE_DATA_MAXAGE_MIN ||
+ val->v.integer > SNMP_BRIDGE_DATA_MAXAGE_MAX)
+ return (SNMP_ERR_WRONG_VALUE);
+ ctx->scratch->int1 = bridge_data_maxage;
+ bridge_data_maxage = val->v.integer;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotBridgeDataPoll:
+ if (val->v.integer < SNMP_BRIDGE_POLL_INTERVAL_MIN ||
+ val->v.integer > SNMP_BRIDGE_POLL_INTERVAL_MAX)
+ return (SNMP_ERR_WRONG_VALUE);
+ ctx->scratch->int1 = val->v.integer;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ 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);
+ }
+
+ abort();
+}
+
+/*
+ * 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..7f48950
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.h
@@ -0,0 +1,357 @@
+/*-
+ * 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_BRIDGE_MIN_TXHC 1
+#define SNMP_BRIDGE_MAX_TXHC 10
+
+#define SNMP_BRIDGE_MIN_MAGE 600
+#define SNMP_BRIDGE_MAX_MAGE 4000
+
+#define SNMP_BRIDGE_MIN_HTIME 100
+#define SNMP_BRIDGE_MAX_HTIME 1000
+
+#define SNMP_BRIDGE_MIN_FDELAY 400
+#define SNMP_BRIDGE_MAX_FDELAY 3000
+
+#define SNMP_PORT_PATHCOST_OBSOLETE 65535
+#define SNMP_PORT_MIN_PATHCOST 0
+#define SNMP_PORT_MAX_PATHCOST 200000000
+#define SNMP_PORT_PATHCOST_AUTO 0
+
+#define SNMP_BRIDGE_DATA_MAXAGE 10
+#define SNMP_BRIDGE_DATA_MAXAGE_MIN 1
+#define SNMP_BRIDGE_DATA_MAXAGE_MAX 300
+
+/* By default poll kernel data every 5 minutes. */
+#define SNMP_BRIDGE_POLL_INTERVAL (5 * 60)
+#define SNMP_BRIDGE_POLL_INTERVAL_MIN 1
+#define SNMP_BRIDGE_POLL_INTERVAL_MAX 3600
+
+/* 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. */
+ enum TruthValue priv_set; /* The private flag. */
+
+ /* 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;
+
+ /* rstpMib extensions. */
+ int32_t admin_path_cost;
+ enum TruthValue proto_migr;
+ enum TruthValue admin_edge;
+ enum TruthValue oper_edge;
+ enum TruthValue oper_ptp;
+ enum StpPortAdminPointToPointType admin_ptp;
+
+ /* 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. */
+ int32_t tx_hold_count;
+ uint32_t top_changes;
+ enum dot1dStpVersion stp_version;
+ 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 TX hold count. */
+int bridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc);
+
+/* Set the bridge STP protocol version. */
+int bridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto);
+
+/* 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, size_t mlen);
+
+/* 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);
+
+/* Set admin point-to-point link. */
+int bridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp,
+ uint32_t admin_ptp);
+
+/* Set admin edge. */
+int bridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp,
+ uint32_t enable);
+
+/* Set 'private' flag. */
+int bridge_port_set_private(const char *bif_name, struct bridge_port *bp,
+ uint32_t priv_set);
+
+/* 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..f8644f4
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c
@@ -0,0 +1,1503 @@
+/*-
+ * 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>
+
+#include <net/bridgestp.h>
+#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;
+ bif->stp_version = b_req.ifbop_protocol;
+ bif->tx_hold_count = b_req.ifbop_holdcount;
+
+ 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;
+
+ 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)
+ * The conversion to 1/256 of a second happens in the kernel -
+ * just make sure we correctly convert the seconds to Timout
+ * and vice versa.
+ */
+static uint32_t
+snmp_timeout2_sec(int32_t secs)
+{
+ return (secs / 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 = snmp_timeout2_sec(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_timeout2_sec(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_timeout2_sec(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;
+
+ 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);
+}
+
+int
+bridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc)
+{
+ struct ifdrv ifd;
+ struct ifbrparam b_param;
+
+ if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC)
+ return (-1);
+
+ strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
+ ifd.ifd_len = sizeof(b_param);
+ ifd.ifd_data = &b_param;
+ b_param.ifbrp_txhc = tx_hc;
+ ifd.ifd_cmd = BRDGSTXHC;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ bif->tx_hold_count = b_param.ifbrp_txhc;
+ return (0);
+}
+
+int
+bridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto)
+{
+ 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_proto = stp_proto;
+ ifd.ifd_cmd = BRDGSPROTO;
+
+ if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
+ syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) "
+ "failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ bif->stp_version = b_param.ifbrp_proto;
+ 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, size_t mlen)
+{
+ int len;
+ char if_name[IFNAMSIZ];
+ struct ifaddrs *ifap, *ifa;
+ struct sockaddr_dl sdl;
+
+ if (getifaddrs(&ifap) != 0) {
+ syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
+ strerror(errno));
+ return (NULL);
+ }
+
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+
+ /*
+ * Not just casting because of alignment constraints
+ * on sparc64 and ia64.
+ */
+ bcopy(ifa->ifa_addr, &sdl, sizeof(struct sockaddr_dl));
+
+ if (sdl.sdl_alen > mlen)
+ continue;
+
+ if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
+ len = IFNAMSIZ - 1;
+
+ bcopy(sdl.sdl_data, if_name, len);
+ if_name[len] = '\0';
+
+ if (strcmp(bif_name, if_name) == 0) {
+ bcopy(sdl.sdl_data + sdl.sdl_nlen, mac, sdl.sdl_alen);
+ 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:
+ case BSTP_IFSTATE_DISCARDING:
+ 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 (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMCOST)
+ bp->admin_path_cost = k_info->ifbr_path_cost;
+ else
+ bp->admin_path_cost = 0;
+
+ 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;
+
+ if (k_info->ifbr_ifsflags & IFBIF_PRIVATE)
+ bp->priv_set = TruthValue_true;
+ else
+ bp->priv_set = TruthValue_false;
+
+ if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMEDGE)
+ bp->admin_edge = TruthValue_true;
+ else
+ bp->admin_edge = TruthValue_false;
+
+ if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE)
+ bp->oper_edge = TruthValue_true;
+ else
+ bp->oper_edge = TruthValue_false;
+
+ if (k_info->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP) {
+ bp->admin_ptp = StpPortAdminPointToPointType_auto;
+ if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP)
+ bp->oper_ptp = TruthValue_true;
+ else
+ bp->oper_ptp = TruthValue_false;
+ } else if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP) {
+ bp->admin_ptp = StpPortAdminPointToPointType_forceTrue;
+ bp->oper_ptp = TruthValue_true;
+ } else {
+ bp->admin_ptp = StpPortAdminPointToPointType_forceFalse;
+ bp->oper_ptp = TruthValue_false;
+ }
+}
+
+/*
+ * 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;
+
+ 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);
+
+ 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_MIN_PATHCOST ||
+ 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 = 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->admin_path_cost = path_cost;
+
+ return (0);
+}
+
+/*
+ * Set the PonitToPoint status of the link administratively.
+ */
+int
+bridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp,
+ uint32_t admin_ptp)
+{
+ struct ifdrv ifd;
+ struct ifbreq b_req;
+
+ if (bp->admin_ptp == admin_ptp)
+ return (0);
+
+ 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);
+ }
+
+ switch (admin_ptp) {
+ case StpPortAdminPointToPointType_forceTrue:
+ b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
+ b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP;
+ break;
+ case StpPortAdminPointToPointType_forceFalse:
+ b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
+ b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP;
+ break;
+ case StpPortAdminPointToPointType_auto:
+ b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
+ break;
+ }
+
+ 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->admin_ptp = admin_ptp;
+ return (0);
+}
+
+/*
+ * Set admin edge.
+ */
+int
+bridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp,
+ uint32_t enable)
+{
+ struct ifdrv ifd;
+ struct ifbreq b_req;
+
+ if (bp->admin_edge == enable)
+ return (0);
+
+ 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 == TruthValue_true) {
+ b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE;
+ b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE;
+ } else
+ b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE;
+
+ 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->admin_edge = enable;
+
+ return (0);
+}
+
+/*
+ * Set 'private' flag.
+ */
+int
+bridge_port_set_private(const char *bif_name, struct bridge_port *bp,
+ uint32_t priv_set)
+{
+ struct ifdrv ifd;
+ struct ifbreq b_req;
+
+ if (bp->priv_set == priv_set)
+ return (0);
+
+ 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 (priv_set == TruthValue_true)
+ b_req.ifbr_ifsflags |= IFBIF_PRIVATE;
+ else if (priv_set == TruthValue_false)
+ b_req.ifbr_ifsflags &= ~IFBIF_PRIVATE;
+ else
+ return (SNMP_ERR_WRONG_VALUE);
+
+ 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->priv_set = priv_set;
+
+ 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, struct ifbreq **buf)
+{
+ int n = 128;
+ uint32_t len;
+ struct ifbreq *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 ( ; ; ) {
+ len = n * sizeof(struct ifbreq);
+ if ((ninbuf = (struct ifbreq *)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_req = *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;
+
+ n += 64;
+ }
+
+ 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, struct ifbpstpreq **buf)
+{
+ int n = 128;
+ uint32_t len;
+ struct ifbpstpreq *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 ( ; ; ) {
+ len = n * sizeof(struct ifbpstpreq);
+ if ((ninbuf = (struct ifbpstpreq *)
+ 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_req = *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;
+
+ n += 64;
+ }
+
+ 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, struct ifbpstpreq *buf,
+ uint32_t buf_len)
+{
+ uint32_t i;
+ struct ifbpstpreq *bstp;
+
+ for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) {
+ bstp = 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 occurred.
+ */
+int
+bridge_getinfo_bif_ports(struct bridge_if *bif)
+{
+ uint32_t i;
+ int32_t buf_len;
+ struct ifbreq *b_req_buf, *b_req;
+ struct ifbpstpreq *bs_req_buf, *bs_req;
+ struct bridge_port *bp;
+ struct mibif *m_if;
+
+ if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
+ return (-1);
+
+ for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
+ b_req = b_req_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(b_req_buf);
+
+ if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_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,
+ bs_req_buf, buf_len)) == NULL)
+ bridge_port_clearinfo_opstp(bp);
+ else
+ bridge_port_getinfo_opstp(bs_req, bp);
+ }
+ free(bs_req_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;
+ struct ifbreq *b_req_buf, *b_req;
+ struct ifbpstpreq *bs_req_buf, *bs_req;
+ struct bridge_port *bp, *bp_next;
+ struct mibif *m_if;
+
+ if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
+ return (-1);
+
+ added = updated = 0;
+
+#define BP_FOUND 0x01
+ for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
+ b_req = b_req_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(b_req_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, &bs_req_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,
+ bs_req_buf, buf_len)) == NULL)
+ bridge_port_clearinfo_opstp(bp);
+ else
+ bridge_port_getinfo_opstp(bs_req, bp);
+ }
+ free(bs_req_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, struct ifbareq **buf)
+{
+ int n = 128;
+ uint32_t len;
+ struct ifbareq *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 ( ; ; ) {
+ len = n * sizeof(struct ifbareq);
+ if ((ninbuf = (struct ifbareq *)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_req = *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;
+
+ n += 64;
+ }
+
+ 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 occurred.
+ */
+int
+bridge_getinfo_bif_addrs(struct bridge_if *bif)
+{
+ uint32_t i;
+ int32_t buf_len;
+ struct ifbareq *addr_req_buf, *addr_req;
+ struct tp_entry *te;
+
+ if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
+ return (-1);
+
+ for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
+ addr_req = addr_req_buf + i;
+
+ if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
+ bridge_addrs_info_ifaddrlist(addr_req, te);
+ }
+
+ free(addr_req_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;
+ struct tp_entry *te, *te_next;
+ struct ifbareq *addr_req_buf, *addr_req;
+
+ if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
+ return (-1);
+
+ added = updated = 0;
+
+#define BA_FOUND 0x01
+ for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
+ addr_req = addr_req_buf + i;
+
+ if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
+ added++;
+
+ if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
+ == NULL)
+ continue;
+ } else
+ updated++;
+
+ bridge_addrs_info_ifaddrlist(addr_req, te);
+ te-> flags |= BA_FOUND;
+ }
+ free(addr_req_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..2e88e5e
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_tree.def
@@ -0,0 +1,283 @@
+#-
+# 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 RowStatus ENUM (
+ 1 active
+ 2 notInService
+ 3 notReady
+ 4 createAndGo
+ 5 createAndWait
+ 6 destroy
+)
+
+typedef TruthValue ENUM (
+ 1 true
+ 2 false
+)
+
+typedef StpPortState ENUM (
+ 1 disabled
+ 2 blocking
+ 3 listening
+ 4 learning
+ 5 forwarding
+ 6 broken
+)
+
+typedef StpPortAdminPointToPointType ENUM (
+ 0 forceTrue
+ 1 forceFalse
+ 2 auto
+)
+
+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)
+ ))
+ (16 dot1dStpVersion ENUM ( 0 stpCompatible 2 rstp ) op_dot1d_stp GET SET)
+ (17 dot1dStpTxHoldCount INTEGER op_dot1d_stp GET SET)
+ (19 dot1dStpExtPortTable
+ (1 dot1dStpExtPortEntry : INTEGER op_dot1d_stp_ext_port
+ (1 dot1dStpPortProtocolMigration TruthValue GET) # SET
+ (2 dot1dStpPortAdminEdgePort TruthValue GET SET)
+ (3 dot1dStpPortOperEdgePort TruthValue GET)
+ (4 dot1dStpPortAdminPointToPoint StpPortAdminPointToPointType GET SET)
+ (5 dot1dStpPortOperPointToPoint TruthValue GET)
+ (6 dot1dStpPortAdminPathCost INTEGER GET SET)
+ ))
+ )
+ (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
+ )
+ )
+ )
+ (134 rstpMIB
+ (0 rstpNotifications
+ )
+ (1 rstpObjects
+ )
+ (2 rstpConformance
+ (1 rstpGroups
+ )
+ (2 rstpCompliances
+ )
+ )
+ )))
+ (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)
+ (7 begemotBridgeBasePortPrivate TruthValue 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)
+ (15 begemotBridgeStpVersion ENUM ( 0 stpCompatible 2 rstp ) GET SET)
+ (16 begemotBridgeStpTxHoldCount 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 begemotBridgeStpExtPortTable
+ (1 begemotBridgeStpExtPortEntry : OCTETSTRING | BridgeIfName INTEGER op_begemot_stp_ext_port
+ (1 begemotBridgeStpPortProtocolMigration TruthValue GET) # SET
+ (2 begemotBridgeStpPortAdminEdgePort TruthValue GET SET)
+ (3 begemotBridgeStpPortOperEdgePort TruthValue GET)
+ (4 begemotBridgeStpPortAdminPointToPoint StpPortAdminPointToPointType GET SET)
+ (5 begemotBridgeStpPortOperPointToPoint TruthValue GET)
+ (6 begemotBridgeStpPortAdminPathCost INTEGER GET SET)
+ ))
+ )
+ (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..b77b5f7
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.3
@@ -0,0 +1,119 @@
+.\"-
+.\" 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 6, 2007
+.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, the RSTP-MIB
+standardized in RFC4318 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 communities 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 destroy the bridge interface.
+.El
+.It Va begemotBridgeBaseSpanEnabled
+A SNMP SET operation on this object is only successful 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
+.It Va begemotBridgeBasePortPrivate
+This object controls a bridge interface flag called PRIVATE where any private
+port can not communicate with another private port.
+.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/RSTP-MIB.txt
+This is the RSTP-MIB 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
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt b/usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt
new file mode 100644
index 0000000..ee8d284
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt
@@ -0,0 +1,125 @@
+--
+-- Copyright (c) 2005-2006
+-- Hartmut Brandt
+-- All rights reserved.
+--
+-- Author: Harti Brandt <harti@freebsd.org>
+--
+-- 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$
+--
+-- Additional stuff for the HOST-RESOURCES MIB.
+--
+BEGEMOT-HOSTRES-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, TimeTicks
+ FROM SNMPv2-SMI
+ begemot
+ FROM BEGEMOT-MIB;
+
+begemotHostres MODULE-IDENTITY
+ LAST-UPDATED "200601030000Z"
+ ORGANIZATION "German Aerospace Center"
+ CONTACT-INFO
+ " Hartmut Brandt
+
+ Postal: German Aerospace Center
+ Oberpfaffenhofen
+ 82234 Wessling
+ Germany
+
+ Fax: +49 8153 28 2843
+
+ E-mail: harti@freebsd.org"
+ DESCRIPTION
+ "The MIB for additional HOST-RESOURCES data."
+ ::= { begemot 202 }
+
+begemotHostresObjects OBJECT IDENTIFIER ::= { begemotHostres 1 }
+
+begemotHrStorageUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the storage table is cached."
+ DEFVAL { 700 }
+ ::= { begemotHostresObjects 1 }
+
+begemotHrFSUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the FS table is cached."
+ DEFVAL { 700 }
+ ::= { begemotHostresObjects 2 }
+
+begemotHrDiskStorageUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the disk storage table is cached."
+ DEFVAL { 300 }
+ ::= { begemotHostresObjects 3 }
+
+begemotHrNetworkUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the network table is cached."
+ DEFVAL { 700 }
+ ::= { begemotHostresObjects 4 }
+
+begemotHrSWInstalledUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the hrSWInstalledTable is cached."
+ DEFVAL { 1200 }
+ ::= { begemotHostresObjects 5 }
+
+begemotHrSWRunUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the hrSWRunTable and
+ hrSWRunPerfTable are cached."
+ DEFVAL { 300 }
+ ::= { begemotHostresObjects 6 }
+
+begemotHrPkgDir OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The path to the package DB directory."
+ DEFVAL { "/var/db/pkg" }
+ ::= { begemotHostresObjects 7 }
+
+END
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile b/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile
new file mode 100644
index 0000000..2922f45
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile
@@ -0,0 +1,82 @@
+#
+# Copyright (c) 2005-2006 The FreeBSD Project
+# All rights reserved.
+# Author: Victor Cruceru <soc-victor@freebsd.org>
+#
+# Redistribution of this software and documentation 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 or documentation 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$
+#
+
+LPRSRC= ${.CURDIR}/../../../lpr/common_source
+.PATH: ${LPRSRC}
+
+MOD= hostres
+SRCS= hostres_begemot.c \
+ hostres_device_tbl.c \
+ hostres_diskstorage_tbl.c \
+ hostres_fs_tbl.c \
+ hostres_network_tbl.c \
+ hostres_partition_tbl.c \
+ hostres_printer_tbl.c \
+ hostres_processor_tbl.c \
+ hostres_scalars.c \
+ hostres_snmp.c \
+ hostres_storage_tbl.c \
+ hostres_swinstalled_tbl.c \
+ hostres_swrun_tbl.c \
+ printcap.c
+
+#Not having NDEBUG defined will enable assertions and a lot of output on stderr
+CFLAGS+= -DNDEBUG -I${LPRSRC}
+XSYM= host hrStorageOther hrStorageRam hrStorageVirtualMemory \
+ hrStorageFixedDisk hrStorageRemovableDisk hrStorageFloppyDisk \
+ hrStorageCompactDisc hrStorageRamDisk hrStorageFlashMemory \
+ hrStorageNetworkDisk hrDeviceOther hrDeviceUnknown \
+ hrDeviceProcessor hrDeviceNetwork hrDevicePrinter \
+ hrDeviceDiskStorage hrDeviceVideo hrDeviceAudio \
+ hrDeviceCoprocessor hrDeviceKeyboard hrDeviceModem \
+ hrDeviceParallelPort hrDevicePointing \
+ hrDeviceSerialPort hrDeviceTape hrDeviceClock \
+ hrDeviceVolatileMemory hrDeviceNonVolatileMemory \
+ hrFSOther hrFSUnknown hrFSBerkeleyFFS hrFSSys5FS hrFSFat\
+ hrFSHPFS hrFSHFS hrFSMFS hrFSNTFS hrFSVNode hrFSJournaled \
+ hrFSiso9660 hrFSRockRidge hrFSNFS hrFSNetware hrFSAFS hrFSDFS \
+ hrFSAppleshare hrFSRFS hrFSDGCFS hrFSBFS hrFSFAT32 hrFSLinuxExt2
+
+MAN= snmp_hostres.3
+
+DEFS= ${MOD}_tree.def
+BMIBS= BEGEMOT-HOSTRES-MIB.txt
+
+DPADD= ${LIBKVM} ${LIBDEVINFO} ${LIBM} ${LIBGEOM} ${LIBMEMSTAT}
+LDADD= -lkvm -ldevinfo -lm -lgeom -lmemstat
+
+.include <bsd.snmpmod.mk>
+
+printcap.So: printcap.c
+ ${CC} ${PICFLAG} -DPIC ${CFLAGS:C/^-W.*//} -c ${.IMPSRC} -o ${.TARGET}
+
+smilint:
+ env SMIPATH=.:/usr/share/snmp/mibs:/usr/local/share/snmp/mibs \
+ smilint -c /dev/null -l6 -i group-membership BEGEMOT-HOSTRES-MIB
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c
new file mode 100644
index 0000000..f1cc5e3
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c
@@ -0,0 +1,171 @@
+/*-
+ * Copyright (c) 2005-2006.
+ * Hartmut Brandt.
+ * All rights reserved.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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 <stdlib.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+int
+op_begemot(struct snmp_context *ctx, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op op)
+{
+
+ switch (op) {
+
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotHrStorageUpdate:
+ value->v.uint32 = storage_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrFSUpdate:
+ value->v.uint32 = fs_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrDiskStorageUpdate:
+ value->v.uint32 = disk_storage_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrNetworkUpdate:
+ value->v.uint32 = network_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWInstalledUpdate:
+ value->v.uint32 = swins_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWRunUpdate:
+ value->v.uint32 = swrun_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrPkgDir:
+ return (string_get(value, pkg_dir, -1));
+ }
+ abort();
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_SET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotHrStorageUpdate:
+ ctx->scratch->int1 = storage_tbl_refresh;
+ storage_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrFSUpdate:
+ ctx->scratch->int1 = fs_tbl_refresh;
+ fs_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrDiskStorageUpdate:
+ ctx->scratch->int1 = disk_storage_tbl_refresh;
+ disk_storage_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrNetworkUpdate:
+ ctx->scratch->int1 = network_tbl_refresh;
+ network_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWInstalledUpdate:
+ ctx->scratch->int1 = swins_tbl_refresh;
+ swins_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWRunUpdate:
+ ctx->scratch->int1 = swrun_tbl_refresh;
+ swrun_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrPkgDir:
+ return (string_save(value, ctx, -1, &pkg_dir));
+ }
+ abort();
+
+ case SNMP_OP_COMMIT:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotHrStorageUpdate:
+ case LEAF_begemotHrFSUpdate:
+ case LEAF_begemotHrDiskStorageUpdate:
+ case LEAF_begemotHrNetworkUpdate:
+ case LEAF_begemotHrSWInstalledUpdate:
+ case LEAF_begemotHrSWRunUpdate:
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrPkgDir:
+ string_commit(ctx);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotHrStorageUpdate:
+ storage_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrFSUpdate:
+ fs_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrDiskStorageUpdate:
+ disk_storage_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrNetworkUpdate:
+ network_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWInstalledUpdate:
+ swins_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWRunUpdate:
+ swrun_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrPkgDir:
+ string_rollback(ctx, &pkg_dir);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+ }
+
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c
new file mode 100644
index 0000000..1741502
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c
@@ -0,0 +1,684 @@
+ /*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ */
+
+/*
+ * Host Resources MIB: hrDeviceTable implementation for SNMPd.
+ */
+
+#include <sys/un.h>
+#include <sys/limits.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sysexits.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+#define FREE_DEV_STRUCT(entry_p) do { \
+ free(entry_p->name); \
+ free(entry_p->location); \
+ free(entry_p->descr); \
+ free(entry_p); \
+} while (0)
+
+/*
+ * Status of a device
+ */
+enum DeviceStatus {
+ DS_UNKNOWN = 1,
+ DS_RUNNING = 2,
+ DS_WARNING = 3,
+ DS_TESTING = 4,
+ DS_DOWN = 5
+};
+
+TAILQ_HEAD(device_tbl, device_entry);
+
+/* the head of the list with hrDeviceTable's entries */
+static struct device_tbl device_tbl = TAILQ_HEAD_INITIALIZER(device_tbl);
+
+/* Table used for consistent device table indexing. */
+struct device_map device_map = STAILQ_HEAD_INITIALIZER(device_map);
+
+/* next int available for indexing the hrDeviceTable */
+static uint32_t next_device_index = 1;
+
+/* last (agent) tick when hrDeviceTable was updated */
+static uint64_t device_tick = 0;
+
+/* maximum number of ticks between updates of device table */
+uint32_t device_tbl_refresh = 10 * 100;
+
+/* socket for /var/run/devd.pipe */
+static int devd_sock = -1;
+
+/* used to wait notifications from /var/run/devd.pipe */
+static void *devd_fd;
+
+/* some constants */
+static const struct asn_oid OIDX_hrDeviceProcessor_c = OIDX_hrDeviceProcessor;
+static const struct asn_oid OIDX_hrDeviceOther_c = OIDX_hrDeviceOther;
+
+/**
+ * Create a new entry out of thin air.
+ */
+struct device_entry *
+device_entry_create(const char *name, const char *location, const char *descr)
+{
+ struct device_entry *entry = NULL;
+ struct device_map_entry *map = NULL;
+ size_t name_len;
+ size_t location_len;
+
+ assert((name[0] != 0) || (location[0] != 0));
+
+ if (name[0] == 0 && location[0] == 0)
+ return (NULL);
+
+ STAILQ_FOREACH(map, &device_map, link) {
+ assert(map->name_key != NULL);
+ assert(map->location_key != NULL);
+
+ if (strcmp(map->name_key, name) == 0 &&
+ strcmp(map->location_key, location) == 0) {
+ break;
+ }
+ }
+
+ if (map == NULL) {
+ /* new object - get a new index */
+ if (next_device_index > INT_MAX) {
+ syslog(LOG_ERR,
+ "%s: hrDeviceTable index wrap", __func__);
+ /* There isn't much we can do here.
+ * If the next_swins_index is consumed
+ * then we can't add entries to this table
+ * So it is better to exit - if the table is sparsed
+ * at the next agent run we can fill it fully.
+ */
+ errx(EX_SOFTWARE, "hrDeviceTable index wrap");
+ /* not reachable */
+ }
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ );
+ return (NULL);
+ }
+
+ map->entry_p = NULL;
+
+ name_len = strlen(name) + 1;
+ if (name_len > DEV_NAME_MLEN)
+ name_len = DEV_NAME_MLEN;
+
+ if ((map->name_key = malloc(name_len)) == NULL) {
+ syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ );
+ free(map);
+ return (NULL);
+ }
+
+ location_len = strlen(location) + 1;
+ if (location_len > DEV_LOC_MLEN)
+ location_len = DEV_LOC_MLEN;
+
+ if ((map->location_key = malloc(location_len )) == NULL) {
+ syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ );
+ free(map->name_key);
+ free(map);
+ return (NULL);
+ }
+
+ map->hrIndex = next_device_index++;
+
+ strlcpy(map->name_key, name, name_len);
+ strlcpy(map->location_key, location, location_len);
+
+ STAILQ_INSERT_TAIL(&device_map, map, link);
+ HRDBG("%s at %s added into hrDeviceMap at index=%d",
+ name, location, map->hrIndex);
+ } else {
+ HRDBG("%s at %s exists in hrDeviceMap index=%d",
+ name, location, map->hrIndex);
+ }
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "hrDeviceTable: %s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+
+ entry->index = map->hrIndex;
+ map->entry_p = entry;
+
+ if ((entry->name = strdup(map->name_key)) == NULL) {
+ syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ );
+ free(entry);
+ return (NULL);
+ }
+
+ if ((entry->location = strdup(map->location_key)) == NULL) {
+ syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ );
+ free(entry->name);
+ free(entry);
+ return (NULL);
+ }
+
+ /*
+ * From here till the end of this function we reuse name_len
+ * for a different purpose - for device_entry::descr
+ */
+ if (name[0] != '\0')
+ name_len = strlen(name) + strlen(descr) +
+ strlen(": ") + 1;
+ else
+ name_len = strlen(location) + strlen(descr) +
+ strlen("unknown at : ") + 1;
+
+ if (name_len > DEV_DESCR_MLEN)
+ name_len = DEV_DESCR_MLEN;
+
+ if ((entry->descr = malloc(name_len )) == NULL) {
+ syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ );
+ free(entry->name);
+ free(entry->location);
+ free(entry);
+ return (NULL);
+ }
+
+ memset(&entry->descr[0], '\0', name_len);
+
+ if (name[0] != '\0')
+ snprintf(entry->descr, name_len,
+ "%s: %s", name, descr);
+ else
+ snprintf(entry->descr, name_len,
+ "unknown at %s: %s", location, descr);
+
+ entry->id = &oid_zeroDotZero; /* unknown id - FIXME */
+ entry->status = (u_int)DS_UNKNOWN;
+ entry->errors = 0;
+ entry->type = &OIDX_hrDeviceOther_c;
+
+ INSERT_OBJECT_INT(entry, &device_tbl);
+
+ return (entry);
+}
+
+/**
+ * Create a new entry into the device table.
+ */
+static struct device_entry *
+device_entry_create_devinfo(const struct devinfo_dev *dev_p)
+{
+
+ assert(dev_p->dd_name != NULL);
+ assert(dev_p->dd_location != NULL);
+
+ return (device_entry_create(dev_p->dd_name, dev_p->dd_location,
+ dev_p->dd_desc));
+}
+
+/**
+ * Delete an entry from the device table.
+ */
+void
+device_entry_delete(struct device_entry *entry)
+{
+ struct device_map_entry *map;
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&device_tbl, entry, link);
+
+ STAILQ_FOREACH(map, &device_map, link)
+ if (map->entry_p == entry) {
+ map->entry_p = NULL;
+ break;
+ }
+
+ FREE_DEV_STRUCT(entry);
+}
+
+/**
+ * Find an entry given its name and location
+ */
+static struct device_entry *
+device_find_by_dev(const struct devinfo_dev *dev_p)
+{
+ struct device_map_entry *map;
+
+ assert(dev_p != NULL);
+
+ STAILQ_FOREACH(map, &device_map, link)
+ if (strcmp(map->name_key, dev_p->dd_name) == 0 &&
+ strcmp(map->location_key, dev_p->dd_location) == 0)
+ return (map->entry_p);
+ return (NULL);
+}
+
+/**
+ * Find an entry given its index.
+ */
+struct device_entry *
+device_find_by_index(int32_t idx)
+{
+ struct device_entry *entry;
+
+ TAILQ_FOREACH(entry, &device_tbl, link)
+ if (entry->index == idx)
+ return (entry);
+ return (NULL);
+}
+
+/**
+ * Find an device entry given its name.
+ */
+struct device_entry *
+device_find_by_name(const char *dev_name)
+{
+ struct device_map_entry *map;
+
+ assert(dev_name != NULL);
+
+ STAILQ_FOREACH(map, &device_map, link)
+ if (strcmp(map->name_key, dev_name) == 0)
+ return (map->entry_p);
+
+ return (NULL);
+}
+
+/**
+ * Find out the type of device. CPU only currently.
+ */
+static void
+device_get_type(struct devinfo_dev *dev_p, const struct asn_oid **out_type_p)
+{
+
+ assert(dev_p != NULL);
+ assert(out_type_p != NULL);
+
+ if (dev_p == NULL)
+ return;
+
+ if (strncmp(dev_p->dd_name, "cpu", strlen("cpu")) == 0 &&
+ strstr(dev_p->dd_location, ".CPU") != NULL) {
+ *out_type_p = &OIDX_hrDeviceProcessor_c;
+ return;
+ }
+}
+
+/**
+ * Get the status of a device
+ */
+static enum DeviceStatus
+device_get_status(struct devinfo_dev *dev)
+{
+
+ assert(dev != NULL);
+
+ switch (dev->dd_state) {
+ case DS_ALIVE: /* probe succeeded */
+ case DS_NOTPRESENT: /* not probed or probe failed */
+ return (DS_DOWN);
+ case DS_ATTACHED: /* attach method called */
+ case DS_BUSY: /* device is open */
+ return (DS_RUNNING);
+ default:
+ return (DS_UNKNOWN);
+ }
+}
+
+/**
+ * Get the info for the given device and then recursively process all
+ * child devices.
+ */
+static int
+device_collector(struct devinfo_dev *dev, void *arg)
+{
+ struct device_entry *entry;
+
+ HRDBG("%llu/%llu name='%s' desc='%s' drivername='%s' location='%s'",
+ (unsigned long long)dev->dd_handle,
+ (unsigned long long)dev->dd_parent, dev->dd_name, dev->dd_desc,
+ dev->dd_drivername, dev->dd_location);
+
+ if (dev->dd_name[0] != '\0' || dev->dd_location[0] != '\0') {
+ HRDBG("ANALYZING dev %s at %s",
+ dev->dd_name, dev->dd_location);
+
+ if ((entry = device_find_by_dev(dev)) != NULL) {
+ entry->flags |= HR_DEVICE_FOUND;
+ entry->status = (u_int)device_get_status(dev);
+ } else if ((entry = device_entry_create_devinfo(dev)) != NULL) {
+ device_get_type(dev, &entry->type);
+
+ entry->flags |= HR_DEVICE_FOUND;
+ entry->status = (u_int)device_get_status(dev);
+ }
+ } else {
+ HRDBG("SKIPPED unknown device at location '%s'",
+ dev->dd_location );
+ }
+
+ return (devinfo_foreach_device_child(dev, device_collector, arg));
+}
+
+/**
+ * Create the socket to the device daemon.
+ */
+static int
+create_devd_socket(void)
+{
+ int d_sock;
+ struct sockaddr_un devd_addr;
+
+ bzero(&devd_addr, sizeof(struct sockaddr_un));
+
+ if ((d_sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "Failed to create the socket for %s: %m",
+ PATH_DEVD_PIPE);
+ return (-1);
+ }
+
+ devd_addr.sun_family = PF_LOCAL;
+ devd_addr.sun_len = sizeof(devd_addr);
+ strlcpy(devd_addr.sun_path, PATH_DEVD_PIPE,
+ sizeof(devd_addr.sun_path) - 1);
+
+ if (connect(d_sock, (struct sockaddr *)&devd_addr,
+ sizeof(devd_addr)) == -1) {
+ syslog(LOG_ERR,"Failed to connect socket for %s: %m",
+ PATH_DEVD_PIPE);
+ if (close(d_sock) < 0 )
+ syslog(LOG_ERR,"Failed to close socket for %s: %m",
+ PATH_DEVD_PIPE);
+ return (-1);
+ }
+
+ return (d_sock);
+}
+
+/*
+ * Event on the devd socket.
+ *
+ * We should probably directly process entries here. For simplicity just
+ * call the refresh routine with the force flag for now.
+ */
+static void
+devd_socket_callback(int fd, void *arg __unused)
+{
+ char buf[512];
+ int read_len = -1;
+
+ assert(fd == devd_sock);
+
+ HRDBG("called");
+
+again:
+ read_len = read(fd, buf, sizeof(buf));
+ if (read_len < 0) {
+ if (errno == EBADF) {
+ devd_sock = -1;
+ if (devd_fd != NULL) {
+ fd_deselect(devd_fd);
+ devd_fd = NULL;
+ }
+ syslog(LOG_ERR, "Closing devd_fd, revert to "
+ "devinfo polling");
+ }
+
+ } else if (read_len == 0) {
+ syslog(LOG_ERR, "zero bytes read from devd pipe... "
+ "closing socket!");
+
+ if (close(devd_sock) < 0 )
+ syslog(LOG_ERR, "Failed to close devd socket: %m");
+
+ devd_sock = -1;
+ if (devd_fd != NULL) {
+ fd_deselect(devd_fd);
+ devd_fd = NULL;
+ }
+ syslog(LOG_ERR, "Closing devd_fd, revert to devinfo polling");
+
+ } else {
+ if (read_len == sizeof(buf))
+ goto again;
+ refresh_device_tbl(1);
+ }
+}
+
+/**
+ * Initialize and populate the device table.
+ */
+void
+init_device_tbl(void)
+{
+
+ /* initially populate table for the other tables */
+ refresh_device_tbl(1);
+
+ /* no problem if that fails - just use polling mode */
+ devd_sock = create_devd_socket();
+}
+
+/**
+ * Start devd(8) monitoring.
+ */
+void
+start_device_tbl(struct lmodule *mod)
+{
+
+ if (devd_sock > 0) {
+ devd_fd = fd_select(devd_sock, devd_socket_callback, NULL, mod);
+ if (devd_fd == NULL)
+ syslog(LOG_ERR, "fd_select failed on devd socket: %m");
+ }
+}
+
+/**
+ * Finalization routine for hrDeviceTable
+ * It destroys the lists and frees any allocated heap memory
+ */
+void
+fini_device_tbl(void)
+{
+ struct device_map_entry *n1;
+
+ if (devd_fd != NULL)
+ fd_deselect(devd_fd);
+
+ if (devd_sock != -1)
+ (void)close(devd_sock);
+
+ devinfo_free();
+
+ while ((n1 = STAILQ_FIRST(&device_map)) != NULL) {
+ STAILQ_REMOVE_HEAD(&device_map, link);
+ if (n1->entry_p != NULL) {
+ TAILQ_REMOVE(&device_tbl, n1->entry_p, link);
+ FREE_DEV_STRUCT(n1->entry_p);
+ }
+ free(n1->name_key);
+ free(n1->location_key);
+ free(n1);
+ }
+ assert(TAILQ_EMPTY(&device_tbl));
+}
+
+/**
+ * Refresh routine for hrDeviceTable. We don't refresh here if the devd socket
+ * is open, because in this case we have the actual information always. We
+ * also don't refresh when the table is new enough (if we don't have a devd
+ * socket). In either case a refresh can be forced by passing a non-zero value.
+ */
+void
+refresh_device_tbl(int force)
+{
+ struct device_entry *entry, *entry_tmp;
+ struct devinfo_dev *dev_root;
+ static int act = 0;
+
+ if (!force && (devd_sock >= 0 ||
+ (device_tick != 0 && this_tick - device_tick < device_tbl_refresh))){
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ if (act) {
+ syslog(LOG_ERR, "%s: recursive call", __func__);
+ return;
+ }
+
+ if (devinfo_init() != 0) {
+ syslog(LOG_ERR,"%s: devinfo_init failed: %m", __func__);
+ return;
+ }
+
+ act = 1;
+ if ((dev_root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL){
+ syslog(LOG_ERR, "%s: can't get the root device: %m", __func__);
+ goto out;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &device_tbl, link)
+ entry->flags &= ~HR_DEVICE_FOUND;
+
+ if (devinfo_foreach_device_child(dev_root, device_collector, NULL))
+ syslog(LOG_ERR, "%s: devinfo_foreach_device_child failed",
+ __func__);
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &device_tbl, link, entry_tmp) {
+ /*
+ * If HR_DEVICE_IMMUTABLE bit is set then this means that
+ * this entry was not detected by the above
+ * devinfo_foreach_device() call. So we are not deleting
+ * it there.
+ */
+ if (!(entry->flags & HR_DEVICE_FOUND) &&
+ !(entry->flags & HR_DEVICE_IMMUTABLE))
+ device_entry_delete(entry);
+ }
+
+ device_tick = this_tick;
+
+ /*
+ * Force a refresh for the hrDiskStorageTable
+ * XXX Why not the other dependen tables?
+ */
+ refresh_disk_storage_tbl(1);
+
+ out:
+ devinfo_free();
+ act = 0;
+}
+
+/**
+ * This is the implementation for a generated (by a SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrDeviceTable
+ */
+int
+op_hrDeviceTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct device_entry *entry;
+
+ refresh_device_tbl(0);
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&device_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&device_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&device_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrDeviceIndex:
+ value->v.integer = entry->index;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDeviceType:
+ assert(entry->type != NULL);
+ value->v.oid = *(entry->type);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDeviceDescr:
+ return (string_get(value, entry->descr, -1));
+
+ case LEAF_hrDeviceID:
+ value->v.oid = *(entry->id);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDeviceStatus:
+ value->v.integer = entry->status;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDeviceErrors:
+ value->v.uint32 = entry->errors;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c
new file mode 100644
index 0000000..25ba56a
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c
@@ -0,0 +1,647 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ */
+
+/*
+ * Host Resources MIB for SNMPd. Implementation for the hrDiskStorageTable
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ata.h>
+#include <sys/disk.h>
+#include <sys/linker.h>
+#include <sys/mdioctl.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+enum hrDiskStrorageAccess {
+ DS_READ_WRITE = 1,
+ DS_READ_ONLY = 2
+};
+
+enum hrDiskStrorageMedia {
+ DSM_OTHER = 1,
+ DSM_UNKNOWN = 2,
+ DSM_HARDDISK = 3,
+ DSM_FLOPPYDISK = 4,
+ DSM_OPTICALDISKROM= 5,
+ DSM_OPTICALDISKWORM= 6,
+ DSM_OPTICALDISKRW= 7,
+ DSM_RAMDISK = 8
+};
+
+/*
+ * This structure is used to hold a SNMP table entry for HOST-RESOURCES-MIB's
+ * hrDiskStorageTable. Note that index is external being allocated and
+ * maintained by the hrDeviceTable code.
+ *
+ * NOTE: according to MIB removable means removable media, not the
+ * device itself (like a USB card reader)
+ */
+struct disk_entry {
+ int32_t index;
+ int32_t access; /* enum hrDiskStrorageAccess */
+ int32_t media; /* enum hrDiskStrorageMedia*/
+ int32_t removable; /* enum snmpTCTruthValue*/
+ int32_t capacity;
+ TAILQ_ENTRY(disk_entry) link;
+ /*
+ * next items are not from the SNMP mib table, only to be used
+ * internally
+ */
+#define HR_DISKSTORAGE_FOUND 0x001
+#define HR_DISKSTORAGE_ATA 0x002 /* belongs to the ATA subsystem */
+#define HR_DISKSTORAGE_MD 0x004 /* it is a MD (memory disk) */
+ uint32_t flags;
+ uint64_t r_tick;
+ u_char dev_name[32]; /* device name, i.e. "ad4" or "acd0" */
+};
+TAILQ_HEAD(disk_tbl, disk_entry);
+
+/* the head of the list with hrDiskStorageTable's entries */
+static struct disk_tbl disk_tbl =
+ TAILQ_HEAD_INITIALIZER(disk_tbl);
+
+/* last tick when hrFSTable was updated */
+static uint64_t disk_storage_tick;
+
+/* minimum number of ticks between refreshs */
+uint32_t disk_storage_tbl_refresh = HR_DISK_TBL_REFRESH * 100;
+
+/* fd for "/dev/mdctl"*/
+static int md_fd = -1;
+
+/* buffer for sysctl("kern.disks") */
+static char *disk_list;
+static size_t disk_list_len;
+
+/* some constants */
+static const struct asn_oid OIDX_hrDeviceDiskStorage_c =
+ OIDX_hrDeviceDiskStorage;
+
+/**
+ * Load the MD driver if it isn't loaded already.
+ */
+static void
+mdmaybeload(void)
+{
+ char name1[64], name2[64];
+
+ snprintf(name1, sizeof(name1), "g_%s", MD_NAME);
+ snprintf(name2, sizeof(name2), "geom_%s", MD_NAME);
+ if (modfind(name1) == -1) {
+ /* Not present in kernel, try loading it. */
+ if (kldload(name2) == -1 || modfind(name1) == -1) {
+ if (errno != EEXIST) {
+ errx(EXIT_FAILURE,
+ "%s module not available!", name2);
+ }
+ }
+ }
+}
+
+/**
+ * Create a new entry into the DiskStorageTable.
+ */
+static struct disk_entry *
+disk_entry_create(const struct device_entry *devEntry)
+{
+ struct disk_entry *entry;
+
+ assert(devEntry != NULL);
+ if (devEntry == NULL)
+ return NULL;
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "hrDiskStorageTable: %s: %m", __func__);
+ return (NULL);
+ }
+
+ memset(entry, 0, sizeof(*entry));
+ entry->index = devEntry->index;
+ INSERT_OBJECT_INT(entry, &disk_tbl);
+
+ return (entry);
+}
+
+/**
+ * Delete a disk table entry.
+ */
+static void
+disk_entry_delete(struct disk_entry *entry)
+{
+ struct device_entry *devEntry;
+
+ assert(entry != NULL);
+ TAILQ_REMOVE(&disk_tbl, entry, link);
+
+ devEntry = device_find_by_index(entry->index);
+
+ free(entry);
+
+ /*
+ * Also delete the respective device entry -
+ * this is needed for disk devices that are not
+ * detected by libdevinfo
+ */
+ if (devEntry != NULL &&
+ (devEntry->flags & HR_DEVICE_IMMUTABLE) == HR_DEVICE_IMMUTABLE)
+ device_entry_delete(devEntry);
+}
+
+/**
+ * Find a disk storage entry given its index.
+ */
+static struct disk_entry *
+disk_find_by_index(int32_t idx)
+{
+ struct disk_entry *entry;
+
+ TAILQ_FOREACH(entry, &disk_tbl, link)
+ if (entry->index == idx)
+ return (entry);
+
+ return (NULL);
+}
+
+/**
+ * Get the disk parameters
+ */
+static void
+disk_query_disk(struct disk_entry *entry)
+{
+ char dev_path[128];
+ int fd;
+ off_t mediasize;
+
+ if (entry == NULL || entry->dev_name[0] == '\0')
+ return;
+
+ snprintf(dev_path, sizeof(dev_path),
+ "%s%s", _PATH_DEV, entry->dev_name);
+ entry->capacity = 0;
+
+ HRDBG("OPENING device %s", dev_path);
+ if ((fd = open(dev_path, O_RDONLY|O_NONBLOCK)) == -1) {
+ HRDBG("OPEN device %s failed: %s", dev_path, strerror(errno));
+ return;
+ }
+
+ if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
+ HRDBG("DIOCGMEDIASIZE for device %s failed: %s",
+ dev_path, strerror(errno));
+ (void)close(fd);
+ return;
+ }
+
+ mediasize = mediasize / 1024;
+ entry->capacity = (mediasize > INT_MAX ? INT_MAX : mediasize);
+ partition_tbl_handle_disk(entry->index, entry->dev_name);
+
+ (void)close(fd);
+}
+
+/**
+ * Find all ATA disks in the device table.
+ */
+static void
+disk_OS_get_ATA_disks(void)
+{
+ struct device_map_entry *map;
+ struct device_entry *entry;
+ struct disk_entry *disk_entry;
+ const struct disk_entry *found;
+
+ /* Things we know are ata disks */
+ static const struct disk_entry lookup[] = {
+ {
+ .dev_name = "ad",
+ .media = DSM_HARDDISK,
+ .removable = SNMP_FALSE
+ },
+ {
+ .dev_name = "ar",
+ .media = DSM_OTHER,
+ .removable = SNMP_FALSE
+ },
+ {
+ .dev_name = "acd",
+ .media = DSM_OPTICALDISKROM,
+ .removable = SNMP_TRUE
+ },
+ {
+ .dev_name = "afd",
+ .media = DSM_FLOPPYDISK,
+ .removable = SNMP_TRUE
+ },
+ {
+ .dev_name = "ast",
+ .media = DSM_OTHER,
+ .removable = SNMP_TRUE
+ },
+
+ { .media = DSM_UNKNOWN }
+ };
+
+ /* Walk over the device table looking for ata disks */
+ STAILQ_FOREACH(map, &device_map, link) {
+ for (found = lookup; found->media != DSM_UNKNOWN; found++) {
+ if (strncmp(map->name_key, found->dev_name,
+ strlen(found->dev_name)) != 0)
+ continue;
+
+ /*
+ * Avoid false disk devices. For example adw(4) and
+ * adv(4) - they are not disks!
+ */
+ if (strlen(map->name_key) > strlen(found->dev_name) &&
+ !isdigit(map->name_key[strlen(found->dev_name)]))
+ continue;
+
+ /* First get the entry from the hrDeviceTbl */
+ entry = map->entry_p;
+ entry->type = &OIDX_hrDeviceDiskStorage_c;
+
+ /* Then check hrDiskStorage table for this device */
+ disk_entry = disk_find_by_index(entry->index);
+ if (disk_entry == NULL) {
+ disk_entry = disk_entry_create(entry);
+ if (disk_entry == NULL)
+ continue;
+
+ disk_entry->access = DS_READ_WRITE;
+ strlcpy(disk_entry->dev_name, entry->name,
+ sizeof(disk_entry->dev_name));
+
+ disk_entry->media = found->media;
+ disk_entry->removable = found->removable;
+ }
+
+ disk_entry->flags |= HR_DISKSTORAGE_FOUND;
+ disk_entry->flags |= HR_DISKSTORAGE_ATA;
+
+ disk_query_disk(disk_entry);
+ disk_entry->r_tick = this_tick;
+ }
+ }
+}
+
+/**
+ * Find MD disks in the device table.
+ */
+static void
+disk_OS_get_MD_disks(void)
+{
+ struct device_map_entry *map;
+ struct device_entry *entry;
+ struct disk_entry *disk_entry;
+ struct md_ioctl mdio;
+ int unit;
+
+ if (md_fd <= 0)
+ return;
+
+ /* Look for md devices */
+ STAILQ_FOREACH(map, &device_map, link) {
+ if (sscanf(map->name_key, "md%d", &unit) != 1)
+ continue;
+
+ /* First get the entry from the hrDeviceTbl */
+ entry = device_find_by_index(map->hrIndex);
+ entry->type = &OIDX_hrDeviceDiskStorage_c;
+
+ /* Then check hrDiskStorage table for this device */
+ disk_entry = disk_find_by_index(entry->index);
+ if (disk_entry == NULL) {
+ disk_entry = disk_entry_create(entry);
+ if (disk_entry == NULL)
+ continue;
+
+ memset(&mdio, 0, sizeof(mdio));
+ mdio.md_version = MDIOVERSION;
+ mdio.md_unit = unit;
+
+ if (ioctl(md_fd, MDIOCQUERY, &mdio) < 0) {
+ syslog(LOG_ERR,
+ "hrDiskStorageTable: Couldnt ioctl");
+ continue;
+ }
+
+ if ((mdio.md_options & MD_READONLY) == MD_READONLY)
+ disk_entry->access = DS_READ_ONLY;
+ else
+ disk_entry->access = DS_READ_WRITE;
+
+ strlcpy(disk_entry->dev_name, entry->name,
+ sizeof(disk_entry->dev_name));
+
+ disk_entry->media = DSM_RAMDISK;
+ disk_entry->removable = SNMP_FALSE;
+ }
+
+ disk_entry->flags |= HR_DISKSTORAGE_FOUND;
+ disk_entry->flags |= HR_DISKSTORAGE_MD;
+ disk_entry->r_tick = this_tick;
+ }
+}
+
+/**
+ * Find rest of disks
+ */
+static void
+disk_OS_get_disks(void)
+{
+ size_t disk_cnt = 0;
+ struct device_entry *entry;
+ struct disk_entry *disk_entry;
+
+ size_t need = 0;
+
+ if (sysctlbyname("kern.disks", NULL, &need, NULL, 0) == -1) {
+ syslog(LOG_ERR, "%s: sysctl_1 kern.disks failed: %m", __func__);
+ return;
+ }
+
+ if (need == 0)
+ return;
+
+ if (disk_list_len != need + 1 || disk_list == NULL) {
+ disk_list_len = need + 1;
+ disk_list = reallocf(disk_list, disk_list_len);
+ }
+
+ if (disk_list == NULL) {
+ syslog(LOG_ERR, "%s: reallocf failed", __func__);
+ disk_list_len = 0;
+ return;
+ }
+
+ memset(disk_list, 0, disk_list_len);
+
+ if (sysctlbyname("kern.disks", disk_list, &need, NULL, 0) == -1 ||
+ disk_list[0] == 0) {
+ syslog(LOG_ERR, "%s: sysctl_2 kern.disks failed: %m", __func__);
+ return;
+ }
+
+ for (disk_cnt = 0; disk_cnt < need; disk_cnt++) {
+ char *disk = NULL;
+ char disk_device[128] = "";
+
+ disk = strsep(&disk_list, " ");
+ if (disk == NULL)
+ break;
+
+ snprintf(disk_device, sizeof(disk_device),
+ "%s%s", _PATH_DEV, disk);
+
+ /* First check if the disk is in the hrDeviceTable. */
+ if ((entry = device_find_by_name(disk)) == NULL) {
+ /*
+ * not found there - insert it as immutable
+ */
+ syslog(LOG_WARNING, "%s: adding device '%s' to "
+ "device list", __func__, disk);
+
+ if ((entry = device_entry_create(disk, "", "")) == NULL)
+ continue;
+
+ entry->flags |= HR_DEVICE_IMMUTABLE;
+ }
+
+ entry->type = &OIDX_hrDeviceDiskStorage_c;
+
+ /* Then check hrDiskStorage table for this device */
+ disk_entry = disk_find_by_index(entry->index);
+ if (disk_entry == NULL) {
+ disk_entry = disk_entry_create(entry);
+ if (disk_entry == NULL)
+ continue;
+ }
+
+ disk_entry->flags |= HR_DISKSTORAGE_FOUND;
+
+ if ((disk_entry->flags & HR_DISKSTORAGE_ATA) ||
+ (disk_entry->flags & HR_DISKSTORAGE_MD)) {
+ /*
+ * ATA/MD detection is running before this one,
+ * so don't waste the time here
+ */
+ continue;
+ }
+
+ disk_entry->access = DS_READ_WRITE;
+ disk_entry->media = DSM_UNKNOWN;
+ disk_entry->removable = SNMP_FALSE;
+
+ if (strncmp(disk_entry->dev_name, "da", 2) == 0 ||
+ strncmp(disk_entry->dev_name, "ada", 3) == 0) {
+ disk_entry->media = DSM_HARDDISK;
+ disk_entry->removable = SNMP_FALSE;
+ } else if (strncmp(disk_entry->dev_name, "cd", 2) == 0) {
+ disk_entry->media = DSM_OPTICALDISKROM;
+ disk_entry->removable = SNMP_TRUE;
+ } else {
+ disk_entry->media = DSM_UNKNOWN;
+ disk_entry->removable = SNMP_FALSE;
+ }
+
+ strlcpy((char *)disk_entry->dev_name, disk,
+ sizeof(disk_entry->dev_name));
+
+ disk_query_disk(disk_entry);
+ disk_entry->r_tick = this_tick;
+ }
+}
+
+/**
+ * Refresh routine for hrDiskStorageTable
+ * Usable for polling the system for any changes.
+ */
+void
+refresh_disk_storage_tbl(int force)
+{
+ struct disk_entry *entry, *entry_tmp;
+
+ if (disk_storage_tick != 0 && !force &&
+ this_tick - disk_storage_tick < disk_storage_tbl_refresh) {
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ partition_tbl_pre_refresh();
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &disk_tbl, link)
+ entry->flags &= ~HR_DISKSTORAGE_FOUND;
+
+ disk_OS_get_ATA_disks(); /* this must be called first ! */
+ disk_OS_get_MD_disks();
+ disk_OS_get_disks();
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &disk_tbl, link, entry_tmp)
+ if (!(entry->flags & HR_DISKSTORAGE_FOUND))
+ /* XXX remove IMMUTABLE entries that have disappeared */
+ disk_entry_delete(entry);
+
+ disk_storage_tick = this_tick;
+
+ partition_tbl_post_refresh();
+
+ HRDBG("refresh DONE");
+}
+
+/*
+ * Init the things for both of hrDiskStorageTable
+ */
+int
+init_disk_storage_tbl(void)
+{
+ char mddev[32] = "";
+
+ /* Try to load md.ko if not loaded already */
+ mdmaybeload();
+
+ md_fd = -1;
+ snprintf(mddev, sizeof(mddev) - 1, "%s%s", _PATH_DEV, MDCTL_NAME);
+ if ((md_fd = open(mddev, O_RDWR)) == -1) {
+ syslog(LOG_ERR, "open %s failed - will not include md(4) "
+ "info: %m", mddev);
+ }
+
+ refresh_disk_storage_tbl(1);
+
+ return (0);
+}
+
+/*
+ * Finalization routine for hrDiskStorageTable
+ * It destroys the lists and frees any allocated heap memory
+ */
+void
+fini_disk_storage_tbl(void)
+{
+ struct disk_entry *n1;
+
+ while ((n1 = TAILQ_FIRST(&disk_tbl)) != NULL) {
+ TAILQ_REMOVE(&disk_tbl, n1, link);
+ free(n1);
+ }
+
+ free(disk_list);
+
+ if (md_fd > 0) {
+ if (close(md_fd) == -1)
+ syslog(LOG_ERR,"close (/dev/mdctl) failed: %m");
+ md_fd = -1;
+ }
+}
+
+/*
+ * This is the implementation for a generated (by our SNMP "compiler" tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrDiskStorageTable
+ */
+int
+op_hrDiskStorageTable(struct snmp_context *ctx __unused,
+ struct snmp_value *value, u_int sub, u_int iidx __unused,
+ enum snmp_op curr_op)
+{
+ struct disk_entry *entry;
+
+ refresh_disk_storage_tbl(0);
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&disk_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&disk_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&disk_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrDiskStorageAccess:
+ value->v.integer = entry->access;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDiskStorageMedia:
+ value->v.integer = entry->media;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDiskStorageRemovable:
+ value->v.integer = entry->removable;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDiskStorageCapacity:
+ value->v.integer = entry->capacity;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c
new file mode 100644
index 0000000..91505d5
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c
@@ -0,0 +1,473 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ */
+
+/*
+ * Host Resources MIB for SNMPd. Implementation for hrFSTable
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/mount.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sysexits.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/*
+ * File system access enum
+ */
+enum hrFSAccess {
+ FS_READ_WRITE = 1,
+ FS_READ_ONLY = 2
+};
+
+/* maximum length (according to MIB) for fs_entry::mountPoint */
+#define FS_MP_MLEN (128 + 1)
+
+/* maximum length (according to MIB) for fs_entry::remoteMountPoint */
+#define FS_RMP_MLEN (128 + 1)
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrFSTable
+ */
+struct fs_entry {
+ int32_t index;
+ u_char *mountPoint;
+ u_char *remoteMountPoint;
+ const struct asn_oid *type;
+ int32_t access; /* enum hrFSAccess, see above */
+ int32_t bootable; /* TruthValue */
+ int32_t storageIndex; /* hrStorageTblEntry::index */
+ u_char lastFullBackupDate[11];
+ u_char lastPartialBackupDate[11];
+#define HR_FS_FOUND 0x001
+ uint32_t flags; /* not in mib table, for internal use */
+ TAILQ_ENTRY(fs_entry) link;
+};
+TAILQ_HEAD(fs_tbl, fs_entry);
+
+/*
+ * Next structure is used to keep o list of mappings from a specific name
+ * (a_name) to an entry in the hrFSTblEntry. We are trying to keep the same
+ * index for a specific name at least for the duration of one SNMP agent run.
+ */
+struct fs_map_entry {
+ int32_t hrIndex; /* used for fs_entry::index */
+ u_char *a_name; /* map key same as fs_entry::mountPoint */
+
+ /* may be NULL if the respective hrFSTblEntry is (temporally) gone */
+ struct fs_entry *entry;
+ STAILQ_ENTRY(fs_map_entry) link;
+};
+STAILQ_HEAD(fs_map, fs_map_entry);
+
+/* head of the list with hrFSTable's entries */
+static struct fs_tbl fs_tbl = TAILQ_HEAD_INITIALIZER(fs_tbl);
+
+/* for consistent table indexing */
+static struct fs_map fs_map = STAILQ_HEAD_INITIALIZER(fs_map);
+
+/* next index available for hrFSTable */
+static uint32_t next_fs_index = 1;
+
+/* last tick when hrFSTable was updated */
+static uint64_t fs_tick;
+
+/* maximum number of ticks between refreshs */
+uint32_t fs_tbl_refresh = HR_FS_TBL_REFRESH * 100;
+
+/* some constants */
+static const struct asn_oid OIDX_hrFSBerkeleyFFS_c = OIDX_hrFSBerkeleyFFS;
+static const struct asn_oid OIDX_hrFSiso9660_c = OIDX_hrFSiso9660;
+static const struct asn_oid OIDX_hrFSNFS_c = OIDX_hrFSNFS;
+static const struct asn_oid OIDX_hrFSLinuxExt2_c = OIDX_hrFSLinuxExt2;
+static const struct asn_oid OIDX_hrFSOther_c = OIDX_hrFSOther;
+static const struct asn_oid OIDX_hrFSFAT32_c = OIDX_hrFSFAT32;
+static const struct asn_oid OIDX_hrFSNTFS_c = OIDX_hrFSNTFS;
+static const struct asn_oid OIDX_hrFSNetware_c = OIDX_hrFSNetware;
+static const struct asn_oid OIDX_hrFSHPFS_c = OIDX_hrFSHPFS;
+static const struct asn_oid OIDX_hrFSUnknown_c = OIDX_hrFSUnknown;
+
+/* file system type map */
+static const struct {
+ const char *str; /* the type string */
+ const struct asn_oid *oid; /* the OID to return */
+} fs_type_map[] = {
+ { "ufs", &OIDX_hrFSBerkeleyFFS_c },
+ { "zfs", &OIDX_hrFSOther_c },
+ { "cd9660", &OIDX_hrFSiso9660_c },
+ { "nfs", &OIDX_hrFSNFS_c },
+ { "ext2fs", &OIDX_hrFSLinuxExt2_c },
+ { "procfs", &OIDX_hrFSOther_c },
+ { "devfs", &OIDX_hrFSOther_c },
+ { "msdosfs", &OIDX_hrFSFAT32_c },
+ { "ntfs", &OIDX_hrFSNTFS_c },
+ { "nwfs", &OIDX_hrFSNetware_c },
+ { "hpfs", &OIDX_hrFSHPFS_c },
+ { "smbfs", &OIDX_hrFSOther_c },
+};
+#define N_FS_TYPE_MAP (sizeof(fs_type_map) / sizeof(fs_type_map[0]))
+
+/**
+ * Create an entry into the FS table and an entry in the map (if needed).
+ */
+static struct fs_entry *
+fs_entry_create(const char *name)
+{
+ struct fs_entry *entry;
+ struct fs_map_entry *map;
+
+ assert(name != NULL);
+ assert(strlen(name) > 0);
+
+ STAILQ_FOREACH(map, &fs_map, link)
+ if (strcmp(map->a_name, name) == 0)
+ break;
+
+ if (map == NULL) {
+ size_t mount_point_len;
+
+ /* new object - get a new index */
+ if (next_fs_index > INT_MAX) {
+ /* Unrecoverable error - die clean and quicly*/
+ syslog(LOG_ERR, "%s: hrFSTable index wrap", __func__);
+ errx(EX_SOFTWARE, "hrFSTable index wrap");
+ }
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ syslog(LOG_ERR, "%s: %m", __func__);
+ return (NULL);
+ }
+
+ mount_point_len = strlen(name) + 1;
+ if (mount_point_len > FS_MP_MLEN)
+ mount_point_len = FS_MP_MLEN;
+
+ if ((map->a_name = malloc(mount_point_len)) == NULL) {
+ syslog(LOG_ERR, "%s: %m", __func__);
+ free(map);
+ return (NULL);
+ }
+
+ strlcpy(map->a_name, name, mount_point_len);
+
+ map->hrIndex = next_fs_index++;
+ map->entry = NULL;
+ STAILQ_INSERT_TAIL(&fs_map, map, link);
+
+ HRDBG("%s added into hrFSMap at index=%d", name, map->hrIndex);
+ } else {
+ HRDBG("%s exists in hrFSMap index=%d", name, map->hrIndex);
+ }
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return (NULL);
+ }
+
+ if ((entry->mountPoint = strdup(name)) == NULL) {
+ syslog(LOG_ERR, "%s: %m", __func__);
+ free(entry);
+ return (NULL);
+ }
+
+ entry->index = map->hrIndex;
+ map->entry = entry;
+
+ INSERT_OBJECT_INT(entry, &fs_tbl);
+ return (entry);
+}
+
+/**
+ * Delete an entry in the FS table.
+ */
+static void
+fs_entry_delete(struct fs_entry* entry)
+{
+ struct fs_map_entry *map;
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&fs_tbl, entry, link);
+ STAILQ_FOREACH(map, &fs_map, link)
+ if (map->entry == entry) {
+ map->entry = NULL;
+ break;
+ }
+ free(entry->mountPoint);
+ free(entry->remoteMountPoint);
+ free(entry);
+}
+
+/**
+ * Find a table entry by its name
+ */
+static struct fs_entry *
+fs_find_by_name(const char *name)
+{
+ struct fs_entry *entry;
+
+ TAILQ_FOREACH(entry, &fs_tbl, link)
+ if (strcmp(entry->mountPoint, name) == 0)
+ return (entry);
+
+ return (NULL);
+}
+
+/**
+ * Get rid of all data
+ */
+void
+fini_fs_tbl(void)
+{
+ struct fs_map_entry *n1;
+
+ while ((n1 = STAILQ_FIRST(&fs_map)) != NULL) {
+ STAILQ_REMOVE_HEAD(&fs_map, link);
+ if (n1->entry != NULL) {
+ TAILQ_REMOVE(&fs_tbl, n1->entry, link);
+ free(n1->entry->mountPoint);
+ free(n1->entry->remoteMountPoint);
+ free(n1->entry);
+ }
+ free(n1->a_name);
+ free(n1);
+ }
+ assert(TAILQ_EMPTY(&fs_tbl));
+}
+
+/**
+ * Called before the refreshing is started from the storage table.
+ */
+void
+fs_tbl_pre_refresh(void)
+{
+ struct fs_entry *entry;
+
+ /* mark each entry as missisng */
+ TAILQ_FOREACH(entry, &fs_tbl, link)
+ entry->flags &= ~HR_FS_FOUND;
+}
+
+/**
+ * Called after refreshing from the storage table.
+ */
+void
+fs_tbl_post_refresh(void)
+{
+ struct fs_entry *entry, *entry_tmp;
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &fs_tbl, link, entry_tmp)
+ if (!(entry->flags & HR_FS_FOUND))
+ fs_entry_delete(entry);
+
+ fs_tick = this_tick;
+}
+
+/*
+ * Refresh the FS table. This is done by forcing a refresh of the storage table.
+ */
+void
+refresh_fs_tbl(void)
+{
+
+ if (fs_tick == 0 || this_tick - fs_tick >= fs_tbl_refresh) {
+ refresh_storage_tbl(1);
+ HRDBG("refresh DONE");
+ }
+}
+
+/**
+ * Get the type OID for a given file system
+ */
+const struct asn_oid *
+fs_get_type(const struct statfs *fs_p)
+{
+ u_int t;
+
+ assert(fs_p != NULL);
+
+ for (t = 0; t < N_FS_TYPE_MAP; t++)
+ if (strcmp(fs_type_map[t].str, fs_p->f_fstypename) == 0)
+ return (fs_type_map[t].oid);
+
+ return (&OIDX_hrFSUnknown_c);
+}
+
+/*
+ * Given information returned from statfs(2) either create a new entry into
+ * the fs_tbl or refresh the entry if it is already there.
+ */
+void
+fs_tbl_process_statfs_entry(const struct statfs *fs_p, int32_t storage_idx)
+{
+ struct fs_entry *entry;
+
+ assert(fs_p != 0);
+
+ HRDBG("for hrStorageEntry::index %d", storage_idx);
+
+ if (fs_p == NULL)
+ return;
+
+ if ((entry = fs_find_by_name(fs_p->f_mntonname)) != NULL ||
+ (entry = fs_entry_create(fs_p->f_mntonname)) != NULL) {
+ entry->flags |= HR_FS_FOUND;
+
+ if (!(fs_p->f_flags & MNT_LOCAL)) {
+ /* this is a remote mount */
+ entry->remoteMountPoint = strdup(fs_p->f_mntfromname);
+ /* if strdup failed, let it be NULL */
+
+ } else {
+ entry->remoteMountPoint = strdup("");
+ /* if strdup failed, let it be NULL */
+ }
+
+ entry->type = fs_get_type(fs_p);
+
+ if ((fs_p->f_flags & MNT_RDONLY) == MNT_RDONLY)
+ entry->access = FS_READ_ONLY;
+ else
+ entry->access = FS_READ_WRITE;
+
+ /* FIXME - bootable fs ?! */
+ entry->bootable = TRUTH_MK((fs_p->f_flags & MNT_ROOTFS)
+ == MNT_ROOTFS);
+
+ entry->storageIndex = storage_idx;
+
+ /* Info not available */
+ memset(entry->lastFullBackupDate, 0,
+ sizeof(entry->lastFullBackupDate));
+
+ /* Info not available */
+ memset(entry->lastPartialBackupDate, 0,
+ sizeof(entry->lastPartialBackupDate));
+
+ handle_partition_fs_index(fs_p->f_mntfromname, entry->index);
+ }
+}
+
+/*
+ * This is the implementation for a generated (by our SNMP "compiler" tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrFSTable
+ */
+int
+op_hrFSTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct fs_entry *entry;
+
+ refresh_fs_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&fs_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&fs_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&fs_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrFSIndex:
+ value->v.integer = entry->index;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrFSMountPoint:
+ return (string_get(value, entry->mountPoint, -1));
+
+ case LEAF_hrFSRemoteMountPoint:
+ if (entry->remoteMountPoint == NULL)
+ return (string_get(value, "", -1));
+ else
+ return (string_get(value, entry->remoteMountPoint, -1));
+ break;
+
+ case LEAF_hrFSType:
+ assert(entry->type != NULL);
+ value->v.oid = *(entry->type);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrFSAccess:
+ value->v.integer = entry->access;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrFSBootable:
+ value->v.integer = entry->bootable;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrFSStorageIndex:
+ value->v.integer = entry->storageIndex;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrFSLastFullBackupDate:
+ return (string_get(value, entry->lastFullBackupDate, 8));
+
+ case LEAF_hrFSLastPartialBackupDate:
+ return (string_get(value, entry->lastPartialBackupDate, 8));
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c
new file mode 100644
index 0000000..4329a1c
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c
@@ -0,0 +1,302 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ */
+
+/*
+ * Host Resources MIB implementation for SNMPd: instrumentation for
+ * hrNetworkTable
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_mib.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+#include <bsnmp/snmp_mibII.h>
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrNetworkTable
+ */
+struct network_entry {
+ int32_t index;
+ int32_t ifIndex;
+ TAILQ_ENTRY(network_entry) link;
+#define HR_NETWORK_FOUND 0x001
+ uint32_t flags;
+
+};
+TAILQ_HEAD(network_tbl, network_entry);
+
+/* the head of the list with hrNetworkTable's entries */
+static struct network_tbl network_tbl = TAILQ_HEAD_INITIALIZER(network_tbl);
+
+/* last (agent) tick when hrNetworkTable was updated */
+static uint64_t network_tick;
+
+/* maximum number of ticks between updates of network table */
+uint32_t network_tbl_refresh = HR_NETWORK_TBL_REFRESH * 100;
+
+/* Constants */
+static const struct asn_oid OIDX_hrDeviceNetwork_c = OIDX_hrDeviceNetwork;
+
+/**
+ * Create a new entry into the network table
+ */
+static struct network_entry *
+network_entry_create(const struct device_entry *devEntry)
+{
+ struct network_entry *entry;
+
+ assert(devEntry != NULL);
+ if (devEntry == NULL)
+ return (NULL);
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return (NULL);
+ }
+
+ memset(entry, 0, sizeof(*entry));
+ entry->index = devEntry->index;
+ INSERT_OBJECT_INT(entry, &network_tbl);
+
+ return (entry);
+}
+
+/**
+ * Delete an entry in the network table
+ */
+static void
+network_entry_delete(struct network_entry* entry)
+{
+
+ TAILQ_REMOVE(&network_tbl, entry, link);
+ free(entry);
+}
+
+/**
+ * Fetch the interfaces from the mibII module, get their real name from the
+ * kernel and try to find it in the device table.
+ */
+static void
+network_get_interfaces(void)
+{
+ struct device_entry *dev;
+ struct network_entry *net;
+ struct mibif *ifp;
+ int name[6];
+ size_t len;
+ char *dname;
+
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+ name[3] = IFMIB_IFDATA;
+ name[5] = IFDATA_DRIVERNAME;
+
+ for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) {
+ HRDBG("%s %s", ifp->name, ifp->descr);
+
+ name[4] = ifp->sysindex;
+
+ /* get the original name */
+ len = 0;
+ if (sysctl(name, 6, NULL, &len, 0, 0) < 0) {
+ syslog(LOG_ERR, "sysctl(net.link.ifdata.%d."
+ "drivername): %m", ifp->sysindex);
+ continue;
+ }
+ if ((dname = malloc(len)) == NULL) {
+ syslog(LOG_ERR, "malloc: %m");
+ continue;
+ }
+ if (sysctl(name, 6, dname, &len, 0, 0) < 0) {
+ syslog(LOG_ERR, "sysctl(net.link.ifdata.%d."
+ "drivername): %m", ifp->sysindex);
+ free(dname);
+ continue;
+ }
+
+ HRDBG("got device %s (%s)", ifp->name, dname);
+
+ if ((dev = device_find_by_name(dname)) == NULL) {
+ HRDBG("%s not in hrDeviceTable", dname);
+ free(dname);
+ continue;
+ }
+ HRDBG("%s found in hrDeviceTable", dname);
+
+ dev->type = &OIDX_hrDeviceNetwork_c;
+ dev->flags |= HR_DEVICE_IMMUTABLE;
+
+ free(dname);
+
+ /* Then check hrNetworkTable for this device */
+ TAILQ_FOREACH(net, &network_tbl, link)
+ if (net->index == dev->index)
+ break;
+
+ if (net == NULL && (net = network_entry_create(dev)) == NULL)
+ continue;
+
+ net->flags |= HR_NETWORK_FOUND;
+ net->ifIndex = ifp->index;
+ }
+
+ network_tick = this_tick;
+}
+
+/**
+ * Finalization routine for hrNetworkTable.
+ * It destroys the lists and frees any allocated heap memory.
+ */
+void
+fini_network_tbl(void)
+{
+ struct network_entry *n1;
+
+ while ((n1 = TAILQ_FIRST(&network_tbl)) != NULL) {
+ TAILQ_REMOVE(&network_tbl, n1, link);
+ free(n1);
+ }
+}
+
+/**
+ * Get the interface list from mibII only at this point to be sure that
+ * it is there already.
+ */
+void
+start_network_tbl(void)
+{
+
+ mib_refresh_iflist();
+ network_get_interfaces();
+}
+
+/**
+ * Refresh the table.
+ */
+static void
+refresh_network_tbl(void)
+{
+ struct network_entry *entry, *entry_tmp;
+
+ if (this_tick - network_tick < network_tbl_refresh) {
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &network_tbl, link)
+ entry->flags &= ~HR_NETWORK_FOUND;
+
+ network_get_interfaces();
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &network_tbl, link, entry_tmp) {
+ if (!(entry->flags & HR_NETWORK_FOUND))
+ network_entry_delete(entry);
+ }
+
+ HRDBG("refresh DONE");
+}
+
+/*
+ * This is the implementation for a generated (by our SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrNetworkTable
+ */
+int
+op_hrNetworkTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct network_entry *entry;
+
+ refresh_network_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&network_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&network_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&network_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrNetworkIfIndex:
+ value->v.integer = entry->ifIndex;
+ return (SNMP_ERR_NOERROR);
+
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_partition_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_partition_tbl.c
new file mode 100644
index 0000000..65c0012
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_partition_tbl.c
@@ -0,0 +1,630 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ */
+
+/*
+ * Host Resources MIB: hrPartitionTable implementation for SNMPd.
+ */
+
+#include <sys/types.h>
+#include <sys/limits.h>
+
+#include <assert.h>
+#include <err.h>
+#include <inttypes.h>
+#include <libgeom.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sysexits.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+#ifdef PC98
+#define HR_FREEBSD_PART_TYPE 0xc494
+#else
+#define HR_FREEBSD_PART_TYPE 165
+#endif
+
+/* Maximum length for label and id including \0 */
+#define PART_STR_MLEN (128 + 1)
+
+/*
+ * One row in the hrPartitionTable
+ */
+struct partition_entry {
+ asn_subid_t index[2];
+ u_char *label; /* max allocated len will be PART_STR_MLEN */
+ u_char *id; /* max allocated len will be PART_STR_MLEN */
+ int32_t size;
+ int32_t fs_Index;
+ TAILQ_ENTRY(partition_entry) link;
+#define HR_PARTITION_FOUND 0x001
+ uint32_t flags;
+};
+TAILQ_HEAD(partition_tbl, partition_entry);
+
+/*
+ * This table is used to get a consistent indexing. It saves the name -> index
+ * mapping while we rebuild the partition table.
+ */
+struct partition_map_entry {
+ int32_t index; /* partition_entry::index */
+ u_char *id; /* max allocated len will be PART_STR_MLEN */
+
+ /*
+ * next may be NULL if the respective partition_entry
+ * is (temporally) gone.
+ */
+ struct partition_entry *entry;
+ STAILQ_ENTRY(partition_map_entry) link;
+};
+STAILQ_HEAD(partition_map, partition_map_entry);
+
+/* Mapping table for consistent indexing */
+static struct partition_map partition_map =
+ STAILQ_HEAD_INITIALIZER(partition_map);
+
+/* THE partition table. */
+static struct partition_tbl partition_tbl =
+ TAILQ_HEAD_INITIALIZER(partition_tbl);
+
+/* next int available for indexing the hrPartitionTable */
+static uint32_t next_partition_index = 1;
+
+/*
+ * Partition_entry_cmp is used for INSERT_OBJECT_FUNC_LINK
+ * macro.
+ */
+static int
+partition_entry_cmp(const struct partition_entry *a,
+ const struct partition_entry *b)
+{
+ assert(a != NULL);
+ assert(b != NULL);
+
+ if (a->index[0] < b->index[0])
+ return (-1);
+
+ if (a->index[0] > b->index[0])
+ return (+1);
+
+ if (a->index[1] < b->index[1])
+ return (-1);
+
+ if (a->index[1] > b->index[1])
+ return (+1);
+
+ return (0);
+}
+
+/*
+ * Partition_idx_cmp is used for NEXT_OBJECT_FUNC and FIND_OBJECT_FUNC
+ * macros
+ */
+static int
+partition_idx_cmp(const struct asn_oid *oid, u_int sub,
+ const struct partition_entry *entry)
+{
+ u_int i;
+
+ for (i = 0; i < 2 && i < oid->len - sub; i++) {
+ if (oid->subs[sub + i] < entry->index[i])
+ return (-1);
+ if (oid->subs[sub + i] > entry->index[i])
+ return (+1);
+ }
+ if (oid->len - sub < 2)
+ return (-1);
+ if (oid->len - sub > 2)
+ return (+1);
+
+ return (0);
+}
+
+/**
+ * Create a new partition table entry
+ */
+static struct partition_entry *
+partition_entry_create(int32_t ds_index, const char *chunk_name)
+{
+ struct partition_entry *entry;
+ struct partition_map_entry *map;
+ size_t id_len;
+
+ /* sanity checks */
+ assert(chunk_name != NULL);
+ if (chunk_name == NULL || chunk_name[0] == '\0')
+ return (NULL);
+
+ /* check whether we already have seen this partition */
+ STAILQ_FOREACH(map, &partition_map, link)
+ if (strcmp(map->id, chunk_name) == 0)
+ break;
+
+ if (map == NULL) {
+ /* new object - get a new index and create a map */
+
+ if (next_partition_index > INT_MAX) {
+ /* Unrecoverable error - die clean and quicly*/
+ syslog(LOG_ERR, "%s: hrPartitionTable index wrap",
+ __func__);
+ errx(EX_SOFTWARE, "hrPartitionTable index wrap");
+ }
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ syslog(LOG_ERR, "hrPartitionTable: %s: %m", __func__);
+ return (NULL);
+ }
+
+ id_len = strlen(chunk_name) + 1;
+ if (id_len > PART_STR_MLEN)
+ id_len = PART_STR_MLEN;
+
+ if ((map->id = malloc(id_len)) == NULL) {
+ free(map);
+ return (NULL);
+ }
+
+ map->index = next_partition_index++;
+
+ strlcpy(map->id, chunk_name, id_len);
+
+ map->entry = NULL;
+
+ STAILQ_INSERT_TAIL(&partition_map, map, link);
+
+ HRDBG("%s added into hrPartitionMap at index=%d",
+ chunk_name, map->index);
+
+ } else {
+ HRDBG("%s exists in hrPartitionMap index=%d",
+ chunk_name, map->index);
+ }
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "hrPartitionTable: %s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+
+ /* create the index */
+ entry->index[0] = ds_index;
+ entry->index[1] = map->index;
+
+ map->entry = entry;
+
+ if ((entry->id = strdup(map->id)) == NULL) {
+ free(entry);
+ return (NULL);
+ }
+
+ /*
+ * reuse id_len from here till the end of this function
+ * for partition_entry::label
+ */
+ id_len = strlen(_PATH_DEV) + strlen(chunk_name) + 1;
+
+ if (id_len > PART_STR_MLEN)
+ id_len = PART_STR_MLEN;
+
+ if ((entry->label = malloc(id_len )) == NULL) {
+ free(entry->id);
+ free(entry);
+ return (NULL);
+ }
+
+ snprintf(entry->label, id_len, "%s%s", _PATH_DEV, chunk_name);
+
+ INSERT_OBJECT_FUNC_LINK(entry, &partition_tbl, link,
+ partition_entry_cmp);
+
+ return (entry);
+}
+
+/**
+ * Delete a partition table entry but keep the map entry intact.
+ */
+static void
+partition_entry_delete(struct partition_entry *entry)
+{
+ struct partition_map_entry *map;
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&partition_tbl, entry, link);
+ STAILQ_FOREACH(map, &partition_map, link)
+ if (map->entry == entry) {
+ map->entry = NULL;
+ break;
+ }
+ free(entry->id);
+ free(entry->label);
+ free(entry);
+}
+
+/**
+ * Find a partition table entry by name. If none is found, return NULL.
+ */
+static struct partition_entry *
+partition_entry_find_by_name(const char *name)
+{
+ struct partition_entry *entry = NULL;
+
+ TAILQ_FOREACH(entry, &partition_tbl, link)
+ if (strcmp(entry->id, name) == 0)
+ return (entry);
+
+ return (NULL);
+}
+
+/**
+ * Find a partition table entry by label. If none is found, return NULL.
+ */
+static struct partition_entry *
+partition_entry_find_by_label(const char *name)
+{
+ struct partition_entry *entry = NULL;
+
+ TAILQ_FOREACH(entry, &partition_tbl, link)
+ if (strcmp(entry->label, name) == 0)
+ return (entry);
+
+ return (NULL);
+}
+
+/**
+ * Process a chunk from libgeom(4). A chunk is either a slice or a partition.
+ * If necessary create a new partition table entry for it. In any case
+ * set the size field of the entry and set the FOUND flag.
+ */
+static void
+handle_chunk(int32_t ds_index, const char *chunk_name, off_t chunk_size)
+{
+ struct partition_entry *entry;
+ daddr_t k_size;
+
+ assert(chunk_name != NULL);
+ assert(chunk_name[0] != '\0');
+ if (chunk_name == NULL || chunk_name == '\0')
+ return;
+
+ HRDBG("ANALYZE chunk %s", chunk_name);
+
+ if ((entry = partition_entry_find_by_name(chunk_name)) == NULL)
+ if ((entry = partition_entry_create(ds_index,
+ chunk_name)) == NULL)
+ return;
+
+ entry->flags |= HR_PARTITION_FOUND;
+
+ /* actual size may overflow the SNMP type */
+ k_size = chunk_size / 1024;
+ entry->size = (k_size > (off_t)INT_MAX ? INT_MAX : k_size);
+}
+
+/**
+ * Start refreshing the partition table. A call to this function will
+ * be followed by a call to handleDiskStorage() for every disk, followed
+ * by a single call to the post_refresh function.
+ */
+void
+partition_tbl_pre_refresh(void)
+{
+ struct partition_entry *entry;
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &partition_tbl, link)
+ entry->flags &= ~HR_PARTITION_FOUND;
+}
+
+/**
+ * Try to find a geom(4) class by its name. Returns a pointer to that
+ * class if found NULL otherways.
+ */
+static struct gclass *
+find_class(struct gmesh *mesh, const char *name)
+{
+ struct gclass *classp;
+
+ LIST_FOREACH(classp, &mesh->lg_class, lg_class)
+ if (strcmp(classp->lg_name, name) == 0)
+ return (classp);
+ return (NULL);
+}
+
+/**
+ * Process all MBR-type partitions from the given disk.
+ */
+static void
+get_mbr(struct gclass *classp, int32_t ds_index, const char *disk_dev_name)
+{
+ struct ggeom *gp;
+ struct gprovider *pp;
+ struct gconfig *conf;
+ long part_type;
+
+ LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
+ /* We are only interested in partitions from this disk */
+ if (strcmp(gp->lg_name, disk_dev_name) != 0)
+ continue;
+
+ /*
+ * Find all the non-BSD providers (these are handled in get_bsd)
+ */
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+ LIST_FOREACH(conf, &pp->lg_config, lg_config) {
+ if (conf->lg_name == NULL ||
+ conf->lg_val == NULL ||
+ strcmp(conf->lg_name, "type") != 0)
+ continue;
+
+ /*
+ * We are not interested in BSD partitions
+ * (ie ad0s1 is not interesting at this point).
+ * We'll take care of them in detail (slice
+ * by slice) in get_bsd.
+ */
+ part_type = strtol(conf->lg_val, NULL, 10);
+ if (part_type == HR_FREEBSD_PART_TYPE)
+ break;
+ HRDBG("-> MBR PROVIDER Name: %s", pp->lg_name);
+ HRDBG("Mediasize: %jd",
+ (intmax_t)pp->lg_mediasize / 1024);
+ HRDBG("Sectorsize: %u", pp->lg_sectorsize);
+ HRDBG("Mode: %s", pp->lg_mode);
+ HRDBG("CONFIG: %s: %s",
+ conf->lg_name, conf->lg_val);
+
+ handle_chunk(ds_index, pp->lg_name,
+ pp->lg_mediasize);
+ }
+ }
+ }
+}
+
+/**
+ * Process all BSD-type partitions from the given disk.
+ */
+static void
+get_bsd_sun(struct gclass *classp, int32_t ds_index, const char *disk_dev_name)
+{
+ struct ggeom *gp;
+ struct gprovider *pp;
+
+ LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
+ /*
+ * We are only interested in those geoms starting with
+ * the disk_dev_name passed as parameter to this function.
+ */
+ if (strncmp(gp->lg_name, disk_dev_name,
+ strlen(disk_dev_name)) != 0)
+ continue;
+
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+ if (pp->lg_name == NULL)
+ continue;
+ handle_chunk(ds_index, pp->lg_name, pp->lg_mediasize);
+ }
+ }
+}
+
+/**
+ * Called from the DiskStorage table for every row. Open the GEOM(4) framework
+ * and process all the partitions in it.
+ * ds_index is the index into the DiskStorage table.
+ * This is done in two steps: for non BSD partitions the geom class "MBR" is
+ * used, for our BSD slices the "BSD" geom class.
+ */
+void
+partition_tbl_handle_disk(int32_t ds_index, const char *disk_dev_name)
+{
+ struct gmesh mesh; /* GEOM userland tree */
+ struct gclass *classp;
+ int error;
+
+ assert(disk_dev_name != NULL);
+ assert(ds_index > 0);
+
+ HRDBG("===> getting partitions for %s <===", disk_dev_name);
+
+ /* try to construct the GEOM tree */
+ if ((error = geom_gettree(&mesh)) != 0) {
+ syslog(LOG_WARNING, "cannot get GEOM tree: %m");
+ return;
+ }
+
+ /*
+ * First try the GEOM "MBR" class.
+ * This is needed for non-BSD slices (aka partitions)
+ * on PC architectures.
+ */
+ if ((classp = find_class(&mesh, "MBR")) != NULL) {
+ get_mbr(classp, ds_index, disk_dev_name);
+ } else {
+ HRDBG("cannot find \"MBR\" geom class");
+ }
+
+ /*
+ * Get the "BSD" GEOM class.
+ * Here we'll find all the info needed about the BSD slices.
+ */
+ if ((classp = find_class(&mesh, "BSD")) != NULL) {
+ get_bsd_sun(classp, ds_index, disk_dev_name);
+ } else {
+ /* no problem on sparc64 */
+ HRDBG("cannot find \"BSD\" geom class");
+ }
+
+ /*
+ * Get the "SUN" GEOM class.
+ * Here we'll find all the info needed about the BSD slices.
+ */
+ if ((classp = find_class(&mesh, "SUN")) != NULL) {
+ get_bsd_sun(classp, ds_index, disk_dev_name);
+ } else {
+ /* no problem on i386 */
+ HRDBG("cannot find \"SUN\" geom class");
+ }
+
+ geom_deletetree(&mesh);
+}
+
+/**
+ * Finish refreshing the table.
+ */
+void
+partition_tbl_post_refresh(void)
+{
+ struct partition_entry *e, *etmp;
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(e, &partition_tbl, link, etmp)
+ if (!(e->flags & HR_PARTITION_FOUND))
+ partition_entry_delete(e);
+}
+
+/*
+ * Finalization routine for hrPartitionTable
+ * It destroys the lists and frees any allocated heap memory
+ */
+void
+fini_partition_tbl(void)
+{
+ struct partition_map_entry *m;
+
+ while ((m = STAILQ_FIRST(&partition_map)) != NULL) {
+ STAILQ_REMOVE_HEAD(&partition_map, link);
+ if(m->entry != NULL) {
+ TAILQ_REMOVE(&partition_tbl, m->entry, link);
+ free(m->entry->id);
+ free(m->entry->label);
+ free(m->entry);
+ }
+ free(m->id);
+ free(m);
+ }
+ assert(TAILQ_EMPTY(&partition_tbl));
+}
+
+/**
+ * Called from the file system code to insert the file system table index
+ * into the partition table entry. Note, that an partition table entry exists
+ * only for local file systems.
+ */
+void
+handle_partition_fs_index(const char *name, int32_t fs_idx)
+{
+ struct partition_entry *entry;
+
+ if ((entry = partition_entry_find_by_label(name)) == NULL) {
+ HRDBG("%s IS MISSING from hrPartitionTable", name);
+ return;
+ }
+ HRDBG("%s [FS index = %d] IS in hrPartitionTable", name, fs_idx);
+ entry->fs_Index = fs_idx;
+}
+
+/*
+ * This is the implementation for a generated (by our SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrPartitionTable
+ */
+int
+op_hrPartitionTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op op)
+{
+ struct partition_entry *entry;
+
+ /*
+ * Refresh the disk storage table (which refreshes the partition
+ * table) if necessary.
+ */
+ refresh_disk_storage_tbl(0);
+
+ switch (op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_FUNC(&partition_tbl,
+ &value->var, sub, partition_idx_cmp)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ value->var.len = sub + 2;
+ value->var.subs[sub] = entry->index[0];
+ value->var.subs[sub + 1] = entry->index[1];
+
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_FUNC(&partition_tbl,
+ &value->var, sub, partition_idx_cmp)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_FUNC(&partition_tbl,
+ &value->var, sub, partition_idx_cmp)) == NULL)
+ return (SNMP_ERR_NOT_WRITEABLE);
+ return (SNMP_ERR_NO_CREATION);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrPartitionIndex:
+ value->v.integer = entry->index[1];
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrPartitionLabel:
+ return (string_get(value, entry->label, -1));
+
+ case LEAF_hrPartitionID:
+ return(string_get(value, entry->id, -1));
+
+ case LEAF_hrPartitionSize:
+ value->v.integer = entry->size;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrPartitionFSIndex:
+ value->v.integer = entry->fs_Index;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c
new file mode 100644
index 0000000..883d67a
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c
@@ -0,0 +1,398 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ */
+
+/*
+ * Host Resources MIB implementation for SNMPd: instrumentation for
+ * hrPrinterTable
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+#include <sys/dirent.h>
+#include "lp.h"
+
+/* Constants */
+static const struct asn_oid OIDX_hrDevicePrinter_c = OIDX_hrDevicePrinter;
+
+enum PrinterStatus {
+ PS_OTHER = 1,
+ PS_UNKNOWN = 2,
+ PS_IDLE = 3,
+ PS_PRINTING = 4,
+ PS_WARMUP = 5
+};
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrPrinterTable.
+ */
+struct printer_entry {
+ int32_t index;
+ int32_t status; /* values from PrinterStatus enum above */
+ u_char detectedErrorState[2];
+ TAILQ_ENTRY(printer_entry) link;
+#define HR_PRINTER_FOUND 0x001
+ uint32_t flags;
+
+};
+TAILQ_HEAD(printer_tbl, printer_entry);
+
+/* the hrPrinterTable */
+static struct printer_tbl printer_tbl = TAILQ_HEAD_INITIALIZER(printer_tbl);
+
+/* last (agent) tick when hrPrinterTable was updated */
+static uint64_t printer_tick;
+
+/**
+ * Create entry into the printer table.
+ */
+static struct printer_entry *
+printer_entry_create(const struct device_entry *devEntry)
+{
+ struct printer_entry *entry = NULL;
+
+ assert(devEntry != NULL);
+ if (devEntry == NULL)
+ return (NULL);
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "hrPrinterTable: %s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+ entry->index = devEntry->index;
+ INSERT_OBJECT_INT(entry, &printer_tbl);
+ return (entry);
+}
+
+/**
+ * Delete entry from the printer table.
+ */
+static void
+printer_entry_delete(struct printer_entry *entry)
+{
+
+ assert(entry != NULL);
+ if (entry == NULL)
+ return;
+
+ TAILQ_REMOVE(&printer_tbl, entry, link);
+ free(entry);
+}
+
+/**
+ * Find a printer by its index
+ */
+static struct printer_entry *
+printer_find_by_index(int32_t idx)
+{
+ struct printer_entry *entry;
+
+ TAILQ_FOREACH(entry, &printer_tbl, link)
+ if (entry->index == idx)
+ return (entry);
+
+ return (NULL);
+}
+
+/**
+ * Get the status of a printer
+ */
+static enum PrinterStatus
+get_printer_status(const struct printer *pp)
+{
+ char statfile[MAXPATHLEN];
+ char lockfile[MAXPATHLEN];
+ char fline[128];
+ int fd;
+ FILE *f = NULL;
+ enum PrinterStatus ps = PS_UNKNOWN;
+
+ if (pp->lock_file[0] == '/')
+ strlcpy(lockfile, pp->lock_file, sizeof(lockfile));
+ else
+ snprintf(lockfile, sizeof(lockfile), "%s/%s",
+ pp->spool_dir, pp->lock_file);
+
+ fd = open(lockfile, O_RDONLY);
+ if (fd < 0 || flock(fd, LOCK_SH | LOCK_NB) == 0) {
+ ps = PS_IDLE;
+ goto LABEL_DONE;
+ }
+
+ if (pp->status_file[0] == '/')
+ strlcpy(statfile, pp->status_file, sizeof(statfile));
+ else
+ snprintf(statfile, sizeof(statfile), "%s/%s",
+ pp->spool_dir, pp->status_file);
+
+ f = fopen(statfile, "r");
+ if (f == NULL) {
+ syslog(LOG_ERR, "cannot open status file: %s", strerror(errno));
+ ps = PS_UNKNOWN;
+ goto LABEL_DONE;
+ }
+
+ memset(&fline[0], '\0', sizeof(line));
+ if (fgets(fline, sizeof(fline) -1, f) == NULL) {
+ ps = PS_UNKNOWN;
+ goto LABEL_DONE;
+ }
+
+ if (strstr(fline, "is ready and printing") != NULL) {
+ ps = PS_PRINTING;
+ goto LABEL_DONE;
+ }
+
+ if (strstr(fline, "to become ready (offline?)") != NULL) {
+ ps = PS_OTHER;
+ goto LABEL_DONE;
+ }
+
+LABEL_DONE:
+ if (fd >= 0)
+ (void)close(fd); /* unlocks as well */
+
+ if (f != NULL)
+ (void)fclose(f);
+
+ return (ps);
+}
+
+/**
+ * Called for each printer found in /etc/printcap.
+ */
+static void
+handle_printer(struct printer *pp)
+{
+ struct device_entry *dev_entry;
+ struct printer_entry *printer_entry;
+ char dev_only[128];
+ struct stat sb;
+
+ if (pp->remote_host != NULL) {
+ HRDBG("skipped %s -- remote", pp->printer);
+ return;
+ }
+
+ if (strncmp(pp->lp, _PATH_DEV, strlen(_PATH_DEV)) != 0) {
+ HRDBG("skipped %s [device %s] -- remote", pp->printer, pp->lp);
+ return;
+ }
+
+ memset(dev_only, '\0', sizeof(dev_only));
+ snprintf(dev_only, sizeof(dev_only), "%s", pp->lp + strlen(_PATH_DEV));
+
+ HRDBG("printer %s has device %s", pp->printer, dev_only);
+
+ if (stat(pp->lp, &sb) < 0) {
+ if (errno == ENOENT) {
+ HRDBG("skipped %s -- device %s missing",
+ pp->printer, pp->lp);
+ return;
+ }
+ }
+
+ if ((dev_entry = device_find_by_name(dev_only)) == NULL) {
+ HRDBG("%s not in hrDeviceTable", pp->lp);
+ return;
+ }
+ HRDBG("%s found in hrDeviceTable", pp->lp);
+ dev_entry->type = &OIDX_hrDevicePrinter_c;
+
+ dev_entry->flags |= HR_DEVICE_IMMUTABLE;
+
+ /* Then check hrPrinterTable for this device */
+ if ((printer_entry = printer_find_by_index(dev_entry->index)) == NULL &&
+ (printer_entry = printer_entry_create(dev_entry)) == NULL)
+ return;
+
+ printer_entry->flags |= HR_PRINTER_FOUND;
+ printer_entry->status = get_printer_status(pp);
+ memset(printer_entry->detectedErrorState, 0,
+ sizeof(printer_entry->detectedErrorState));
+}
+
+static void
+hrPrinter_get_OS_entries(void)
+{
+ int status, more;
+ struct printer myprinter, *pp = &myprinter;
+
+ init_printer(pp);
+ HRDBG("---->Getting printers .....");
+ more = firstprinter(pp, &status);
+ if (status)
+ goto errloop;
+
+ while (more) {
+ do {
+ HRDBG("---->Got printer %s", pp->printer);
+
+ handle_printer(pp);
+ more = nextprinter(pp, &status);
+errloop:
+ if (status)
+ syslog(LOG_WARNING,
+ "hrPrinterTable: printcap entry for %s "
+ "has errors, skipping",
+ pp->printer ? pp->printer : "<noname?>");
+ } while (more && status);
+ }
+
+ lastprinter();
+ printer_tick = this_tick;
+}
+
+/**
+ * Init the things for hrPrinterTable
+ */
+void
+init_printer_tbl(void)
+{
+
+ hrPrinter_get_OS_entries();
+}
+
+/**
+ * Finalization routine for hrPrinterTable
+ * It destroys the lists and frees any allocated heap memory
+ */
+void
+fini_printer_tbl(void)
+{
+ struct printer_entry *n1;
+
+ while ((n1 = TAILQ_FIRST(&printer_tbl)) != NULL) {
+ TAILQ_REMOVE(&printer_tbl, n1, link);
+ free(n1);
+ }
+}
+
+/**
+ * Refresh the printer table if needed.
+ */
+void
+refresh_printer_tbl(void)
+{
+ struct printer_entry *entry;
+ struct printer_entry *entry_tmp;
+
+ if (this_tick <= printer_tick) {
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &printer_tbl, link)
+ entry->flags &= ~HR_PRINTER_FOUND;
+
+ hrPrinter_get_OS_entries();
+
+ /*
+ * Purge items that disappeared
+ */
+ entry = TAILQ_FIRST(&printer_tbl);
+ while (entry != NULL) {
+ entry_tmp = TAILQ_NEXT(entry, link);
+ if (!(entry->flags & HR_PRINTER_FOUND))
+ printer_entry_delete(entry);
+ entry = entry_tmp;
+ }
+
+ printer_tick = this_tick;
+
+ HRDBG("refresh DONE ");
+}
+
+int
+op_hrPrinterTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct printer_entry *entry;
+
+ refresh_printer_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&printer_tbl, &value->var,
+ sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&printer_tbl, &value->var,
+ sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&printer_tbl, &value->var,
+ sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrPrinterStatus:
+ value->v.integer = entry->status;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrPrinterDetectedErrorState:
+ return (string_get(value, entry->detectedErrorState,
+ sizeof(entry->detectedErrorState)));
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c
new file mode 100644
index 0000000..e75b55e
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c
@@ -0,0 +1,431 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ */
+
+/*
+ * Host Resources MIB for SNMPd. Implementation for hrProcessorTable
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrProcessorTable.
+ * Note that index is external being allocated & maintained
+ * by the hrDeviceTable code..
+ */
+struct processor_entry {
+ int32_t index;
+ const struct asn_oid *frwId;
+ int32_t load; /* average cpu usage */
+ int32_t sample_cnt; /* number of usage samples */
+ int32_t cur_sample_idx; /* current valid sample */
+ TAILQ_ENTRY(processor_entry) link;
+ u_char cpu_no; /* which cpu, counted from 0 */
+
+ /* the samples from the last minute, as required by MIB */
+ double samples[MAX_CPU_SAMPLES];
+ long states[MAX_CPU_SAMPLES][CPUSTATES];
+};
+TAILQ_HEAD(processor_tbl, processor_entry);
+
+/* the head of the list with hrDeviceTable's entries */
+static struct processor_tbl processor_tbl =
+ TAILQ_HEAD_INITIALIZER(processor_tbl);
+
+/* number of processors in dev tbl */
+static int32_t detected_processor_count;
+
+/* sysctlbyname(hw.ncpu) */
+static int hw_ncpu;
+
+/* sysctlbyname(kern.cp_times) */
+static int cpmib[2];
+static size_t cplen;
+
+/* periodic timer used to get cpu load stats */
+static void *cpus_load_timer;
+
+/**
+ * Returns the CPU usage of a given processor entry.
+ *
+ * It needs at least two cp_times "tick" samples to calculate a delta and
+ * thus, the usage over the sampling period.
+ */
+static int
+get_avg_load(struct processor_entry *e)
+{
+ u_int i, oldest;
+ long delta = 0;
+ double usage = 0.0;
+
+ assert(e != NULL);
+
+ /* Need two samples to perform delta calculation. */
+ if (e->sample_cnt <= 1)
+ return (0);
+
+ /* Oldest usable index, we wrap around. */
+ if (e->sample_cnt == MAX_CPU_SAMPLES)
+ oldest = (e->cur_sample_idx + 1) % MAX_CPU_SAMPLES;
+ else
+ oldest = 0;
+
+ /* Sum delta for all states. */
+ for (i = 0; i < CPUSTATES; i++) {
+ delta += e->states[e->cur_sample_idx][i];
+ delta -= e->states[oldest][i];
+ }
+ if (delta == 0)
+ return 0;
+
+ /* Take idle time from the last element and convert to
+ * percent usage by contrasting with total ticks delta. */
+ usage = (double)(e->states[e->cur_sample_idx][CPUSTATES-1] -
+ e->states[oldest][CPUSTATES-1]) / delta;
+ usage = 100 - (usage * 100);
+ HRDBG("CPU no. %d, delta ticks %ld, pct usage %.2f", e->cpu_no,
+ delta, usage);
+
+ return ((int)(usage));
+}
+
+/**
+ * Save a new sample to proc entry and get the average usage.
+ *
+ * Samples are stored in a ringbuffer from 0..(MAX_CPU_SAMPLES-1)
+ */
+static void
+save_sample(struct processor_entry *e, long *cp_times)
+{
+ int i;
+
+ e->cur_sample_idx = (e->cur_sample_idx + 1) % MAX_CPU_SAMPLES;
+ for (i = 0; cp_times != NULL && i < CPUSTATES; i++)
+ e->states[e->cur_sample_idx][i] = cp_times[i];
+
+ e->sample_cnt++;
+ if (e->sample_cnt > MAX_CPU_SAMPLES)
+ e->sample_cnt = MAX_CPU_SAMPLES;
+
+ HRDBG("sample count for CPU no. %d went to %d", e->cpu_no, e->sample_cnt);
+ e->load = get_avg_load(e);
+
+}
+
+/**
+ * Create a new entry into the processor table.
+ */
+static struct processor_entry *
+proc_create_entry(u_int cpu_no, struct device_map_entry *map)
+{
+ struct device_entry *dev;
+ struct processor_entry *entry;
+ char name[128];
+
+ /*
+ * If there is no map entry create one by creating a device table
+ * entry.
+ */
+ if (map == NULL) {
+ snprintf(name, sizeof(name), "cpu%u", cpu_no);
+ if ((dev = device_entry_create(name, "", "")) == NULL)
+ return (NULL);
+ dev->flags |= HR_DEVICE_IMMUTABLE;
+ STAILQ_FOREACH(map, &device_map, link)
+ if (strcmp(map->name_key, name) == 0)
+ break;
+ if (map == NULL)
+ abort();
+ }
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_ERR, "hrProcessorTable: %s malloc "
+ "failed: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+
+ entry->index = map->hrIndex;
+ entry->load = 0;
+ entry->sample_cnt = 0;
+ entry->cur_sample_idx = -1;
+ entry->cpu_no = (u_char)cpu_no;
+ entry->frwId = &oid_zeroDotZero; /* unknown id FIXME */
+
+ INSERT_OBJECT_INT(entry, &processor_tbl);
+
+ HRDBG("CPU %d added with SNMP index=%d",
+ entry->cpu_no, entry->index);
+
+ return (entry);
+}
+
+/**
+ * Scan the device map table for CPUs and create an entry into the
+ * processor table for each CPU.
+ *
+ * Make sure that the number of processors announced by the kernel hw.ncpu
+ * is equal to the number of processors we have found in the device table.
+ */
+static void
+create_proc_table(void)
+{
+ struct device_map_entry *map;
+ struct processor_entry *entry;
+ int cpu_no;
+ size_t len;
+
+ detected_processor_count = 0;
+
+ /*
+ * Because hrProcessorTable depends on hrDeviceTable,
+ * the device detection must be performed at this point.
+ * If not, no entries will be present in the hrProcessor Table.
+ *
+ * For non-ACPI system the processors are not in the device table,
+ * therefore insert them after checking hw.ncpu.
+ */
+ STAILQ_FOREACH(map, &device_map, link)
+ if (strncmp(map->name_key, "cpu", strlen("cpu")) == 0 &&
+ strstr(map->location_key, ".CPU") != NULL) {
+ if (sscanf(map->name_key,"cpu%d", &cpu_no) != 1) {
+ syslog(LOG_ERR, "hrProcessorTable: Failed to "
+ "get cpu no. from device named '%s'",
+ map->name_key);
+ continue;
+ }
+
+ if ((entry = proc_create_entry(cpu_no, map)) == NULL)
+ continue;
+
+ detected_processor_count++;
+ }
+
+ len = sizeof(hw_ncpu);
+ if (sysctlbyname("hw.ncpu", &hw_ncpu, &len, NULL, 0) == -1 ||
+ len != sizeof(hw_ncpu)) {
+ syslog(LOG_ERR, "hrProcessorTable: sysctl(hw.ncpu) failed");
+ hw_ncpu = 0;
+ }
+
+ HRDBG("%d CPUs detected via device table; hw.ncpu is %d",
+ detected_processor_count, hw_ncpu);
+
+ /* XXX Can happen on non-ACPI systems? Create entries by hand. */
+ for (; detected_processor_count < hw_ncpu; detected_processor_count++)
+ proc_create_entry(detected_processor_count, NULL);
+
+ len = 2;
+ if (sysctlnametomib("kern.cp_times", cpmib, &len)) {
+ syslog(LOG_ERR, "hrProcessorTable: sysctlnametomib(kern.cp_times) failed");
+ cpmib[0] = 0;
+ cpmib[1] = 0;
+ cplen = 0;
+ } else if (sysctl(cpmib, 2, NULL, &len, NULL, 0)) {
+ syslog(LOG_ERR, "hrProcessorTable: sysctl(kern.cp_times) length query failed");
+ cplen = 0;
+ } else {
+ cplen = len / sizeof(long);
+ }
+ HRDBG("%zu entries for kern.cp_times", cplen);
+
+}
+
+/**
+ * Free the processor table
+ */
+static void
+free_proc_table(void)
+{
+ struct processor_entry *n1;
+
+ while ((n1 = TAILQ_FIRST(&processor_tbl)) != NULL) {
+ TAILQ_REMOVE(&processor_tbl, n1, link);
+ free(n1);
+ detected_processor_count--;
+ }
+
+ assert(detected_processor_count == 0);
+ detected_processor_count = 0;
+}
+
+/**
+ * Refresh all values in the processor table. We call this once for
+ * every PDU that accesses the table.
+ */
+static void
+refresh_processor_tbl(void)
+{
+ struct processor_entry *entry;
+ size_t size;
+
+ long pcpu_cp_times[cplen];
+ memset(pcpu_cp_times, 0, sizeof(pcpu_cp_times));
+
+ size = cplen * sizeof(long);
+ if (sysctl(cpmib, 2, pcpu_cp_times, &size, NULL, 0) == -1 &&
+ !(errno == ENOMEM && size >= cplen * sizeof(long))) {
+ syslog(LOG_ERR, "hrProcessorTable: sysctl(kern.cp_times) failed");
+ return;
+ }
+
+ TAILQ_FOREACH(entry, &processor_tbl, link) {
+ assert(hr_kd != NULL);
+ save_sample(entry, &pcpu_cp_times[entry->cpu_no * CPUSTATES]);
+ }
+
+}
+
+/**
+ * This function is called MAX_CPU_SAMPLES times per minute to collect the
+ * CPU load.
+ */
+static void
+get_cpus_samples(void *arg __unused)
+{
+
+ HRDBG("[%llu] ENTER", (unsigned long long)get_ticks());
+ refresh_processor_tbl();
+ HRDBG("[%llu] EXIT", (unsigned long long)get_ticks());
+}
+
+/**
+ * Called to start this table. We need to start the periodic idle
+ * time collection.
+ */
+void
+start_processor_tbl(struct lmodule *mod)
+{
+
+ /*
+ * Start the cpu stats collector
+ * The semantics of timer_start parameters is in "SNMP ticks";
+ * we have 100 "SNMP ticks" per second, thus we are trying below
+ * to get MAX_CPU_SAMPLES per minute
+ */
+ cpus_load_timer = timer_start_repeat(100, 100 * 60 / MAX_CPU_SAMPLES,
+ get_cpus_samples, NULL, mod);
+}
+
+/**
+ * Init the things for hrProcessorTable.
+ * Scan the device table for processor entries.
+ */
+void
+init_processor_tbl(void)
+{
+
+ /* create the initial processor table */
+ create_proc_table();
+ /* and get first samples */
+ refresh_processor_tbl();
+}
+
+/**
+ * Finalization routine for hrProcessorTable.
+ * It destroys the lists and frees any allocated heap memory.
+ */
+void
+fini_processor_tbl(void)
+{
+
+ if (cpus_load_timer != NULL) {
+ timer_stop(cpus_load_timer);
+ cpus_load_timer = NULL;
+ }
+
+ free_proc_table();
+}
+
+/**
+ * Access routine for the processor table.
+ */
+int
+op_hrProcessorTable(struct snmp_context *ctx __unused,
+ struct snmp_value *value, u_int sub, u_int iidx __unused,
+ enum snmp_op curr_op)
+{
+ struct processor_entry *entry;
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&processor_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&processor_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&processor_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrProcessorFrwID:
+ assert(entry->frwId != NULL);
+ value->v.oid = *entry->frwId;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrProcessorLoad:
+ value->v.integer = entry->load;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c
new file mode 100644
index 0000000..87b78e8
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c
@@ -0,0 +1,492 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ */
+
+/*
+ * Host Resources MIB scalars implementation for SNMPd.
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <pwd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <syslog.h>
+#include <utmpx.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/* boot timestamp in centi-seconds */
+static uint64_t kernel_boot;
+
+/* physical memory size in Kb */
+static uint64_t phys_mem_size;
+
+/* boot line (malloced) */
+static u_char *boot_line;
+
+/* maximum number of processes */
+static uint32_t max_proc;
+
+/**
+ * Free all static data
+ */
+void
+fini_scalars(void)
+{
+
+ free(boot_line);
+}
+
+/**
+ * Get system uptime in hundredths of seconds since the epoch
+ * Returns 0 in case of an error
+ */
+static int
+OS_getSystemUptime(uint32_t *ut)
+{
+ struct timeval right_now;
+ uint64_t now;
+
+ if (kernel_boot == 0) {
+ /* first time, do the sysctl */
+ struct timeval kernel_boot_timestamp;
+ int mib[2] = { CTL_KERN, KERN_BOOTTIME };
+ size_t len = sizeof(kernel_boot_timestamp);
+
+ if (sysctl(mib, 2, &kernel_boot_timestamp,
+ &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "sysctl KERN_BOOTTIME failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ HRDBG("boot timestamp from kernel: {%lld, %ld}",
+ (long long)kernel_boot_timestamp.tv_sec,
+ (long)kernel_boot_timestamp.tv_usec);
+
+ kernel_boot = ((uint64_t)kernel_boot_timestamp.tv_sec * 100) +
+ (kernel_boot_timestamp.tv_usec / 10000);
+ }
+
+ if (gettimeofday(&right_now, NULL) < 0) {
+ syslog(LOG_ERR, "gettimeofday failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+ now = ((uint64_t)right_now.tv_sec * 100) + (right_now.tv_usec / 10000);
+
+ if (now - kernel_boot > UINT32_MAX)
+ *ut = UINT32_MAX;
+ else
+ *ut = now - kernel_boot;
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get system local date and time in a foramt suitable for DateAndTime TC:
+ * field octets contents range
+ * ----- ------ -------- -----
+ * 1 1-2 year* 0..65536
+ * 2 3 month 1..12
+ * 3 4 day 1..31
+ * 4 5 hour 0..23
+ * 5 6 minutes 0..59
+ * 6 7 seconds 0..60
+ * (use 60 for leap-second)
+ * 7 8 deci-seconds 0..9
+ * 8 9 direction from UTC '+' / '-'
+ * 9 10 hours from UTC* 0..13
+ * 10 11 minutes from UTC 0..59
+ *
+ * * Notes:
+ * - the value of year is in network-byte order
+ * - daylight saving time in New Zealand is +13
+ *
+ * For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+ * displayed as:
+ *
+ * 1992-5-26,13:30:15.0,-4:0
+ *
+ * Returns -1 in case of an error or the length of the string (8 or 11)
+ * Actually returns always 11 on freebsd
+ */
+static int
+OS_getSystemDate(struct snmp_value *value)
+{
+ u_char s_date_time[11];
+ struct tm tloc_tm;
+ time_t tloc_time_t;
+ struct timeval right_now;
+ int string_len;
+
+ if (gettimeofday(&right_now, NULL) < 0) {
+ syslog(LOG_ERR, "gettimeofday failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ tloc_time_t = right_now.tv_sec;
+
+ if (localtime_r(&tloc_time_t, &tloc_tm) == NULL) {
+ syslog(LOG_ERR, "localtime_r() failed: %m ");
+ return (SNMP_ERR_GENERR);
+ }
+
+ string_len = make_date_time(s_date_time, &tloc_tm,
+ right_now.tv_usec / 100000);
+
+ return (string_get(value, s_date_time, string_len));
+}
+
+/**
+ * Get kernel boot path. For FreeBSD it seems that no arguments are
+ * present. Returns NULL if an error occurred. The returned data is a
+ * pointer to a global storage.
+ */
+int
+OS_getSystemInitialLoadParameters(u_char **params)
+{
+
+ if (boot_line == NULL) {
+ int mib[2] = { CTL_KERN, KERN_BOOTFILE };
+ char *buf;
+ size_t buf_len = 0;
+
+ /* get the needed buffer len */
+ if (sysctl(mib, 2, NULL, &buf_len, NULL, 0) != 0) {
+ syslog(LOG_ERR,
+ "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ if ((buf = malloc(buf_len)) == NULL) {
+ syslog(LOG_ERR, "malloc failed");
+ return (SNMP_ERR_GENERR);
+ }
+ if (sysctl(mib, 2, buf, &buf_len, NULL, 0)) {
+ syslog(LOG_ERR,
+ "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");
+ free(buf);
+ return (SNMP_ERR_GENERR);
+ }
+
+ boot_line = buf;
+ HRDBG("kernel boot file: %s", boot_line);
+ }
+
+ *params = boot_line;
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get number of current users which are logged in
+ */
+static int
+OS_getSystemNumUsers(uint32_t *nu)
+{
+ struct utmpx *utmp;
+
+ setutxent();
+ *nu = 0;
+ while ((utmp = getutxent()) != NULL) {
+ if (utmp->ut_type == USER_PROCESS)
+ (*nu)++;
+ }
+ endutxent();
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get number of current processes existing into the system
+ */
+static int
+OS_getSystemProcesses(uint32_t *proc_count)
+{
+ int pc;
+
+ if (hr_kd == NULL)
+ return (SNMP_ERR_GENERR);
+
+ if (kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &pc) == NULL) {
+ syslog(LOG_ERR, "kvm_getprocs failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ *proc_count = pc;
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get maximum number of processes allowed on this system
+ */
+static int
+OS_getSystemMaxProcesses(uint32_t *mproc)
+{
+
+ if (max_proc == 0) {
+ int mib[2] = { CTL_KERN, KERN_MAXPROC };
+ int mp;
+ size_t len = sizeof(mp);
+
+ if (sysctl(mib, 2, &mp, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "sysctl KERN_MAXPROC failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+ max_proc = mp;
+ }
+
+ *mproc = max_proc;
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Get the physical memeory size in Kbytes.
+ * Returns SNMP error code.
+ */
+static int
+OS_getMemorySize(uint32_t *ms)
+{
+
+ if (phys_mem_size == 0) {
+ int mib[2] = { CTL_HW, HW_PHYSMEM };
+ u_long physmem;
+ size_t len = sizeof(physmem);
+
+ if (sysctl(mib, 2, &physmem, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR,
+ "sysctl({ CTL_HW, HW_PHYSMEM }) failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ phys_mem_size = physmem / 1024;
+ }
+
+ if (phys_mem_size > UINT32_MAX)
+ *ms = UINT32_MAX;
+ else
+ *ms = phys_mem_size;
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Try to use the s_date_time parameter as a DateAndTime TC to fill in
+ * the second parameter.
+ * Returns 0 on succes and -1 for an error.
+ * Bug: time zone info is not used
+ */
+static struct timeval *
+OS_checkSystemDateInput(const u_char *str, u_int len)
+{
+ struct tm tm_to_set;
+ time_t t;
+ struct timeval *tv;
+
+ if (len != 8 && len != 11)
+ return (NULL);
+
+ if (str[2] == 0 || str[2] > 12 ||
+ str[3] == 0 || str[3] > 31 ||
+ str[4] > 23 || str[5] > 59 || str[6] > 60 || str[7] > 9)
+ return (NULL);
+
+ tm_to_set.tm_year = ((str[0] << 8) + str[1]) - 1900;
+ tm_to_set.tm_mon = str[2] - 1;
+ tm_to_set.tm_mday = str[3];
+ tm_to_set.tm_hour = str[4];
+ tm_to_set.tm_min = str[5];
+ tm_to_set.tm_sec = str[6];
+ tm_to_set.tm_isdst = 0;
+
+ /* now make UTC from it */
+ if ((t = timegm(&tm_to_set)) == (time_t)-1)
+ return (NULL);
+
+ /* now apply timezone if specified */
+ if (len == 11) {
+ if (str[9] > 13 || str[10] > 59)
+ return (NULL);
+ if (str[8] == '+')
+ t += 3600 * str[9] + 60 * str[10];
+ else
+ t -= 3600 * str[9] + 60 * str[10];
+ }
+
+ if ((tv = malloc(sizeof(*tv))) == NULL)
+ return (NULL);
+
+ tv->tv_sec = t;
+ tv->tv_usec = (int32_t)str[7] * 100000;
+
+ return (tv);
+}
+
+/*
+ * Set system date and time. Timezone is not changed
+ */
+static int
+OS_setSystemDate(const struct timeval *timeval_to_set)
+{
+ if (settimeofday(timeval_to_set, NULL) == -1) {
+ syslog(LOG_ERR, "settimeofday failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * prototype of this function was genrated by gensnmptree tool in header file
+ * hostres_tree.h
+ * Returns SNMP_ERR_NOERROR on success
+ */
+int
+op_hrSystem(struct snmp_context *ctx, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ int err;
+ u_char *str;
+
+ switch (curr_op) {
+
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemUptime:
+ return (OS_getSystemUptime(&value->v.uint32));
+
+ case LEAF_hrSystemDate:
+ return (OS_getSystemDate(value));
+
+ case LEAF_hrSystemInitialLoadDevice:
+ value->v.uint32 = 0; /* FIXME */
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadParameters:
+ if ((err = OS_getSystemInitialLoadParameters(&str)) !=
+ SNMP_ERR_NOERROR)
+ return (err);
+ return (string_get(value, str, -1));
+
+ case LEAF_hrSystemNumUsers:
+ return (OS_getSystemNumUsers(&value->v.uint32));
+
+ case LEAF_hrSystemProcesses:
+ return (OS_getSystemProcesses(&value->v.uint32));
+
+ case LEAF_hrSystemMaxProcesses:
+ return (OS_getSystemMaxProcesses(&value->v.uint32));
+ }
+ abort();
+
+ case SNMP_OP_SET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemDate:
+ if ((ctx->scratch->ptr1 =
+ OS_checkSystemDateInput(value->v.octetstring.octets,
+ value->v.octetstring.len)) == NULL)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadDevice:
+ case LEAF_hrSystemInitialLoadParameters:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemDate:
+ free(ctx->scratch->ptr1);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadDevice:
+ case LEAF_hrSystemInitialLoadParameters:
+ abort();
+ }
+ abort();
+
+ case SNMP_OP_COMMIT:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemDate:
+ (void)OS_setSystemDate(ctx->scratch->ptr1);
+ free(ctx->scratch->ptr1);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadDevice:
+ case LEAF_hrSystemInitialLoadParameters:
+ abort();
+ }
+ abort();
+
+ case SNMP_OP_GETNEXT:
+ abort();
+ }
+ abort();
+}
+
+/*
+ * prototype of this function was genrated by gensnmptree tool
+ * in the header file hostres_tree.h
+ * Returns SNMP_ERR_NOERROR on success
+ */
+int
+op_hrStorage(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+
+ /* only GET is possible */
+ switch (curr_op) {
+
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrMemorySize:
+ return (OS_getMemorySize(&value->v.uint32));
+ }
+ abort();
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_GETNEXT:
+ abort();
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c
new file mode 100644
index 0000000..c2a06db
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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.
+ *
+ * This C file contains code developed by Poul-Henning Kamp under the
+ * following license:
+ *
+ * FreeBSD: src/sbin/mdconfig/mdconfig.c,v 1.33.2.1 2004/09/14 03:32:21 jmg Exp
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB implementation for bsnmpd.
+ */
+
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/* Internal id got after we'll register this module with the agent */
+static u_int host_registration_id = 0;
+
+/* This our hostres module */
+static struct lmodule *hostres_module;
+
+/* See the generated file hostres_oid.h */
+static const struct asn_oid oid_host = OIDX_host;
+
+/* descriptor to access kernel memory */
+kvm_t *hr_kd;
+
+/*
+ * HOST RESOURCES mib module finalization hook.
+ * Returns 0 on success, < 0 on error
+ */
+static int
+hostres_fini(void)
+{
+
+ if (hr_kd != NULL)
+ (void)kvm_close(hr_kd);
+
+ fini_storage_tbl();
+ fini_fs_tbl();
+ fini_processor_tbl();
+ fini_disk_storage_tbl();
+ fini_device_tbl();
+ fini_partition_tbl();
+ fini_network_tbl();
+ fini_printer_tbl();
+
+ fini_swrun_tbl();
+ fini_swins_tbl();
+
+ fini_scalars();
+
+ if (host_registration_id > 0)
+ or_unregister(host_registration_id);
+
+ HRDBG("done.");
+ return (0);
+}
+
+/*
+ * HOST RESOURCES mib module initialization hook.
+ * Returns 0 on success, < 0 on error
+ */
+static int
+hostres_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
+{
+
+ hostres_module = mod;
+
+ /*
+ * NOTE: order of these calls is important here!
+ */
+ if ((hr_kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY,
+ "kvm_open")) == NULL) {
+ syslog(LOG_ERR, "kvm_open failed: %m ");
+ return (-1);
+ }
+
+ /*
+ * The order is relevant here, because some table depend on each other.
+ */
+ init_device_tbl();
+
+ /* populates partition table too */
+ if (init_disk_storage_tbl()) {
+ hostres_fini();
+ return (-1);
+ }
+ init_processor_tbl();
+ init_printer_tbl();
+
+ /*
+ * populate storage and FS tables. Must be done after device
+ * initialisation because the FS refresh code calls into the
+ * partition refresh code.
+ */
+ init_storage_tbl();
+
+
+ /* also the hrSWRunPerfTable's support is initialized here */
+ init_swrun_tbl();
+ init_swins_tbl();
+
+ HRDBG("done.");
+
+ return (0);
+}
+
+/*
+ * HOST RESOURCES mib module start operation
+ * returns nothing
+ */
+static void
+hostres_start(void)
+{
+
+ host_registration_id = or_register(&oid_host,
+ "The MIB module for Host Resource MIB (RFC 2790).",
+ hostres_module);
+
+ start_device_tbl(hostres_module);
+ start_processor_tbl(hostres_module);
+ start_network_tbl();
+
+ HRDBG("done.");
+}
+
+/* this identifies the HOST RESOURCES mib module */
+const struct snmp_module config = {
+ "This module implements the host resource mib (rfc 2790)",
+ hostres_init,
+ hostres_fini,
+ NULL, /* idle function, do not use it */
+ NULL,
+ NULL,
+ hostres_start,
+ NULL, /* proxy a PDU */
+ hostres_ctree, /* see the generated hostres_tree.h */
+ hostres_CTREE_SIZE, /* see the generated hostres_tree.h */
+ NULL
+};
+
+/**
+ * Make an SNMP DateAndTime from a struct tm. This should be in the library.
+ */
+int
+make_date_time(u_char *str, const struct tm *tm, u_int decisecs)
+{
+
+ str[0] = (u_char)((tm->tm_year + 1900) >> 8);
+ str[1] = (u_char)(tm->tm_year + 1900);
+ str[2] = tm->tm_mon + 1;
+ str[3] = tm->tm_mday;
+ str[4] = tm->tm_hour;
+ str[5] = tm->tm_min;
+ str[6] = tm->tm_sec;
+ str[7] = decisecs;
+ if (tm->tm_gmtoff < 0)
+ str[8] = '-';
+ else
+ str[8] = '+';
+
+ str[9] = (u_char)(abs(tm->tm_gmtoff) / 3600);
+ str[10] = (u_char)((abs(tm->tm_gmtoff) % 3600) / 60);
+
+ return (11);
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h
new file mode 100644
index 0000000..04928d2
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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.
+ *
+ * Host Resources MIB for SNMPd.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef HOSTRES_SNMP_H_1132245017
+#define HOSTRES_SNMP_H_1132245017
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <devinfo.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+
+#include <bsnmp/snmpmod.h>
+
+/*
+ * Default package directory for hrSWInstalledTable. Can be overridden
+ * via SNMP or configuration file.
+ */
+#define PATH_PKGDIR "/var/db/pkg"
+
+/*
+ * These are the default maximum caching intervals for the various tables
+ * in seconds. They can be overridden from the configuration file.
+ */
+#define HR_STORAGE_TBL_REFRESH 7
+#define HR_FS_TBL_REFRESH 7
+#define HR_DISK_TBL_REFRESH 7
+#define HR_NETWORK_TBL_REFRESH 7
+#define HR_SWINS_TBL_REFRESH 120
+#define HR_SWRUN_TBL_REFRESH 3
+
+struct tm;
+struct statfs;
+
+/* a debug macro */
+#ifndef NDEBUG
+
+#define HRDBG(...) do { \
+ fprintf(stderr, "HRDEBUG: %s: ", __func__); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ } while (0)
+
+#else
+
+#define HRDBG(...) do { } while (0)
+
+#endif /*NDEBUG*/
+
+/* path to devd(8) output pipe */
+#define PATH_DEVD_PIPE "/var/run/devd.pipe"
+
+#define IS_KERNPROC(kp) (((kp)->ki_flag & P_KTHREAD) == P_KTHREAD)
+
+enum snmpTCTruthValue {
+ SNMP_TRUE = 1,
+ SNMP_FALSE= 2
+};
+
+/* The number of CPU load samples per one minute, per each CPU */
+#define MAX_CPU_SAMPLES 4
+
+
+/*
+ * max len (including '\0'), for device_entry::descr field below,
+ * according to MIB
+ */
+#define DEV_DESCR_MLEN (64 + 1)
+
+/*
+ * max len (including '\0'), for device_entry::name and
+ * device_map_entry::name_key fields below, according to MIB
+ */
+#define DEV_NAME_MLEN (32 + 1)
+
+/*
+ * max len (including '\0'), for device_entry::location and
+ * device_map_entry::location_key fields below, according to MIB
+ */
+#define DEV_LOC_MLEN (128 + 1)
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrDeviceTable
+ */
+struct device_entry {
+ int32_t index;
+ const struct asn_oid *type;
+ u_char *descr;
+ const struct asn_oid *id; /* only oid_zeroDotZero as (*id) value*/
+ int32_t status; /* enum DeviceStatus */
+ uint32_t errors;
+
+#define HR_DEVICE_FOUND 0x001
+ /* not dectected by libdevice, so don't try to refresh it*/
+#define HR_DEVICE_IMMUTABLE 0x002
+
+ /* next 3 are not from the SNMP mib table, only to be used internally */
+ uint32_t flags;
+
+ u_char *name;
+ u_char *location;
+ TAILQ_ENTRY(device_entry) link;
+};
+
+/*
+ * Next structure is used to keep o list of mappings from a specific
+ * name (a_name) to an entry in the hrFSTblEntry;
+ * We are trying to keep the same index for a specific name at least
+ * for the duration of one SNMP agent run.
+ */
+struct device_map_entry {
+ int32_t hrIndex; /* used for hrDeviceTblEntry::index */
+
+ /* map key is the pair (name_key, location_key) */
+ u_char *name_key; /* copy of device name */
+ u_char *location_key;
+
+ /*
+ * Next may be NULL if the respective hrDeviceTblEntry
+ * is (temporally) gone.
+ */
+ struct device_entry *entry_p;
+ STAILQ_ENTRY(device_map_entry) link;
+};
+STAILQ_HEAD(device_map, device_map_entry);
+
+/* descriptor to access kernel memory */
+extern kvm_t *hr_kd;
+
+/* Table used for consistent device table indexing. */
+extern struct device_map device_map;
+
+/* Maximum number of ticks between two updates for hrStorageTable */
+extern uint32_t storage_tbl_refresh;
+
+/* Maximum number of ticks between updated of FS table */
+extern uint32_t fs_tbl_refresh;
+
+/* maximum number of ticks between updates of SWRun and SWRunPerf table */
+extern uint32_t swrun_tbl_refresh;
+
+/* Maximum number of ticks between device table refreshs. */
+extern uint32_t device_tbl_refresh;
+
+/* maximum number of ticks between refreshs */
+extern uint32_t disk_storage_tbl_refresh;
+
+/* maximum number of ticks between updates of network table */
+extern uint32_t swins_tbl_refresh;
+
+/* maximum number of ticks between updates of network table */
+extern uint32_t network_tbl_refresh;
+
+/* package directory */
+extern u_char *pkg_dir;
+
+/* Initialize and populate storage table */
+void init_storage_tbl(void);
+
+/* Finalization routine for hrStorageTable. */
+void fini_storage_tbl(void);
+
+/* Refresh routine for hrStorageTable. */
+void refresh_storage_tbl(int);
+
+/*
+ * Get the type of filesystem referenced in a struct statfs * -
+ * used by FSTbl and StorageTbl functions.
+ */
+const struct asn_oid *fs_get_type(const struct statfs *);
+
+/*
+ * Because hrFSTable depends to hrStorageTable we are
+ * refreshing hrFSTable by refreshing hrStorageTable.
+ * When one entry "of type" fs from hrStorageTable is refreshed
+ * then the corresponding entry from hrFSTable is refreshed
+ * FS_tbl_pre_refresh_v() is called before refeshing fs part of hrStorageTable
+ */
+void fs_tbl_pre_refresh(void);
+void fs_tbl_process_statfs_entry(const struct statfs *, int32_t);
+
+/* Called after refreshing fs part of hrStorageTable */
+void fs_tbl_post_refresh(void);
+
+/* Refresh the FS table if necessary. */
+void refresh_fs_tbl(void);
+
+/* Finalization routine for hrFSTable. */
+void fini_fs_tbl(void);
+
+/* Init the things for both of hrSWRunTable and hrSWRunPerfTable */
+void init_swrun_tbl(void);
+
+/* Finalization routine for both of hrSWRunTable and hrSWRunPerfTable */
+void fini_swrun_tbl(void);
+
+/* Init and populate hrDeviceTable */
+void init_device_tbl(void);
+
+/* start devd monitoring */
+void start_device_tbl(struct lmodule *);
+
+/* Finalization routine for hrDeviceTable */
+void fini_device_tbl(void);
+
+/* Refresh routine for hrDeviceTable. */
+void refresh_device_tbl(int);
+
+/* Find an item in hrDeviceTbl by its entry->index. */
+struct device_entry *device_find_by_index(int32_t);
+
+/* Find an item in hrDeviceTbl by name. */
+struct device_entry *device_find_by_name(const char *);
+
+/* Create a new entry out of thin air. */
+struct device_entry *device_entry_create(const char *, const char *,
+ const char *);
+
+/* Delete an entry from hrDeviceTbl */
+void device_entry_delete(struct device_entry *entry);
+
+/* Init the things for hrProcessorTable. */
+void init_processor_tbl(void);
+
+/* Finalization routine for hrProcessorTable. */
+void fini_processor_tbl(void);
+
+/* Start the processor table CPU load collector. */
+void start_processor_tbl(struct lmodule *);
+
+/* Init the things for hrDiskStorageTable */
+int init_disk_storage_tbl(void);
+
+/* Finalization routine for hrDiskStorageTable. */
+void fini_disk_storage_tbl(void);
+
+/* Refresh routine for hrDiskStorageTable. */
+void refresh_disk_storage_tbl(int);
+
+/* Finalization routine for hrPartitionTable. */
+void fini_partition_tbl(void);
+
+/* Finalization routine for hrNetworkTable. */
+void fini_network_tbl(void);
+
+/* populate network table */
+void start_network_tbl(void);
+
+/* initialize installed software table */
+void init_swins_tbl(void);
+
+/* finalize installed software table */
+void fini_swins_tbl(void);
+
+/* refresh the hrSWInstalledTable if necessary */
+void refresh_swins_tbl(void);
+
+/* Init the things for hrPrinterTable */
+void init_printer_tbl(void);
+
+/* Finalization routine for hrPrinterTable. */
+void fini_printer_tbl(void);
+
+/* Refresh printer table */
+void refresh_printer_tbl(void);
+
+/* get boot command line */
+int OS_getSystemInitialLoadParameters(u_char **);
+
+/* Start refreshing the partition table */
+void partition_tbl_post_refresh(void);
+
+/* Handle refresh for the given disk */
+void partition_tbl_handle_disk(int32_t, const char *);
+
+/* Finish refreshing the partition table. */
+void partition_tbl_pre_refresh(void);
+
+/* Set the FS index in a partition table entry */
+void handle_partition_fs_index(const char *, int32_t);
+
+/* Make an SNMP DateAndTime from a struct tm. */
+int make_date_time(u_char *, const struct tm *, u_int);
+
+/* Free all static data */
+void fini_scalars(void);
+
+#endif /* HOSTRES_SNMP_H_1132245017 */
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_storage_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_storage_tbl.c
new file mode 100644
index 0000000..ee8bdcc
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_storage_tbl.c
@@ -0,0 +1,668 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ */
+
+/*
+ * Host Resources MIB for SNMPd. Implementation for hrStorageTable
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/vmmeter.h>
+#include <sys/mount.h>
+
+#include <vm/vm_param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <limits.h>
+#include <memstat.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h> /* for getpagesize() */
+#include <sysexits.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/* maximum length for descritpion string according to MIB */
+#define SE_DESC_MLEN (255 + 1)
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrStorageTable
+ */
+struct storage_entry {
+ int32_t index;
+ const struct asn_oid *type;
+ u_char *descr;
+ int32_t allocationUnits;
+ int32_t size;
+ int32_t used;
+ uint32_t allocationFailures;
+#define HR_STORAGE_FOUND 0x001
+ uint32_t flags; /* to be used internally*/
+ TAILQ_ENTRY(storage_entry) link;
+};
+TAILQ_HEAD(storage_tbl, storage_entry);
+
+/*
+ * Next structure is used to keep o list of mappings from a specific name
+ * (a_name) to an entry in the hrStorageTblEntry. We are trying to keep the
+ * same index for a specific name at least for the duration of one SNMP agent
+ * run.
+ */
+struct storage_map_entry {
+ int32_t hrIndex; /* used for storage_entry::index */
+
+ /* map key, also used for storage_entry::descr */
+ u_char *a_name;
+
+ /*
+ * next may be NULL if the respective storage_entry
+ * is (temporally) gone
+ */
+ struct storage_entry *entry;
+ STAILQ_ENTRY(storage_map_entry) link;
+};
+STAILQ_HEAD(storage_map, storage_map_entry);
+
+/* the head of the list with table's entries */
+static struct storage_tbl storage_tbl = TAILQ_HEAD_INITIALIZER(storage_tbl);
+
+/*for consistent table indexing*/
+static struct storage_map storage_map =
+ STAILQ_HEAD_INITIALIZER(storage_map);
+
+/* last (agent) tick when hrStorageTable was updated */
+static uint64_t storage_tick;
+
+/* maximum number of ticks between two refreshs */
+uint32_t storage_tbl_refresh = HR_STORAGE_TBL_REFRESH * 100;
+
+/* for kvm_getswapinfo, malloc'd */
+static struct kvm_swap *swap_devs;
+static size_t swap_devs_len; /* item count for swap_devs */
+
+/* for getfsstat, malloc'd */
+static struct statfs *fs_buf;
+static size_t fs_buf_count; /* item count for fs_buf */
+
+static struct vmtotal mem_stats;
+
+/* next int available for indexing the hrStorageTable */
+static uint32_t next_storage_index = 1;
+
+/* start of list for memory detailed stats */
+static struct memory_type_list *mt_list;
+
+/* Constants */
+static const struct asn_oid OIDX_hrStorageRam_c = OIDX_hrStorageRam;
+static const struct asn_oid OIDX_hrStorageVirtualMemory_c =
+ OIDX_hrStorageVirtualMemory;
+
+/**
+ * Create a new entry into the storage table and, if necessary, an
+ * entry into the storage map.
+ */
+static struct storage_entry *
+storage_entry_create(const char *name)
+{
+ struct storage_entry *entry;
+ struct storage_map_entry *map;
+ size_t name_len;
+
+ assert(name != NULL);
+ assert(strlen(name) > 0);
+
+ STAILQ_FOREACH(map, &storage_map, link)
+ if (strcmp(map->a_name, name) == 0)
+ break;
+
+ if (map == NULL) {
+ /* new object - get a new index */
+ if (next_storage_index > INT_MAX) {
+ syslog(LOG_ERR,
+ "%s: hrStorageTable index wrap", __func__);
+ errx(EX_SOFTWARE, "hrStorageTable index wrap");
+ }
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ syslog(LOG_ERR, "hrStorageTable: %s: %m", __func__ );
+ return (NULL);
+ }
+
+ name_len = strlen(name) + 1;
+ if (name_len > SE_DESC_MLEN)
+ name_len = SE_DESC_MLEN;
+
+ if ((map->a_name = malloc(name_len)) == NULL) {
+ free(map);
+ return (NULL);
+ }
+
+ strlcpy(map->a_name, name, name_len);
+ map->hrIndex = next_storage_index++;
+
+ STAILQ_INSERT_TAIL(&storage_map, map, link);
+
+ HRDBG("%s added into hrStorageMap at index=%d",
+ name, map->hrIndex);
+ } else {
+ HRDBG("%s exists in hrStorageMap index=%d\n",
+ name, map->hrIndex);
+ }
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+
+ entry->index = map->hrIndex;
+
+ if ((entry->descr = strdup(map->a_name)) == NULL) {
+ free(entry);
+ return (NULL);
+ }
+
+ map->entry = entry;
+
+ INSERT_OBJECT_INT(entry, &storage_tbl);
+
+ return (entry);
+}
+
+/**
+ * Delete an entry from the storage table.
+ */
+static void
+storage_entry_delete(struct storage_entry *entry)
+{
+ struct storage_map_entry *map;
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&storage_tbl, entry, link);
+ STAILQ_FOREACH(map, &storage_map, link)
+ if (map->entry == entry) {
+ map->entry = NULL;
+ break;
+ }
+ free(entry->descr);
+ free(entry);
+}
+
+/**
+ * Find a table entry by its name.
+ */
+static struct storage_entry *
+storage_find_by_name(const char *name)
+{
+ struct storage_entry *entry;
+
+ TAILQ_FOREACH(entry, &storage_tbl, link)
+ if (strcmp(entry->descr, name) == 0)
+ return (entry);
+
+ return (NULL);
+}
+
+/*
+ * VM info.
+ */
+static void
+storage_OS_get_vm(void)
+{
+ int mib[2] = { CTL_VM, VM_TOTAL };
+ size_t len = sizeof(mem_stats);
+ int page_size_bytes;
+ struct storage_entry *entry;
+
+ if (sysctl(mib, 2, &mem_stats, &len, NULL, 0) < 0) {
+ syslog(LOG_ERR,
+ "hrStoragetable: %s: sysctl({CTL_VM, VM_METER}) "
+ "failed: %m", __func__);
+ assert(0);
+ return;
+ }
+
+ page_size_bytes = getpagesize();
+
+ /* Real Memory Metrics */
+ if ((entry = storage_find_by_name("Real Memory Metrics")) == NULL &&
+ (entry = storage_entry_create("Real Memory Metrics")) == NULL)
+ return; /* I'm out of luck now, maybe next time */
+
+ entry->flags |= HR_STORAGE_FOUND;
+ entry->type = &OIDX_hrStorageRam_c;
+ entry->allocationUnits = page_size_bytes;
+ entry->size = mem_stats.t_rm;
+ entry->used = mem_stats.t_arm; /* ACTIVE is not USED - FIXME */
+ entry->allocationFailures = 0;
+
+ /* Shared Real Memory Metrics */
+ if ((entry = storage_find_by_name("Shared Real Memory Metrics")) ==
+ NULL &&
+ (entry = storage_entry_create("Shared Real Memory Metrics")) ==
+ NULL)
+ return;
+
+ entry->flags |= HR_STORAGE_FOUND;
+ entry->type = &OIDX_hrStorageRam_c;
+ entry->allocationUnits = page_size_bytes;
+ entry->size = mem_stats.t_rmshr;
+ /* ACTIVE is not USED - FIXME */
+ entry->used = mem_stats.t_armshr;
+ entry->allocationFailures = 0;
+}
+
+static void
+storage_OS_get_memstat(void)
+{
+ struct memory_type *mt_item;
+ struct storage_entry *entry;
+
+ if (mt_list == NULL) {
+ if ((mt_list = memstat_mtl_alloc()) == NULL)
+ /* again? we have a serious problem */
+ return;
+ }
+
+ if (memstat_sysctl_all(mt_list, 0) < 0) {
+ syslog(LOG_ERR, "memstat_sysctl_all failed: %s",
+ memstat_strerror(memstat_mtl_geterror(mt_list)) );
+ return;
+ }
+
+ if ((mt_item = memstat_mtl_first(mt_list)) == NULL) {
+ /* usually this is not an error, no errno for this failure*/
+ HRDBG("memstat_mtl_first failed");
+ return;
+ }
+
+ do {
+ const char *memstat_name;
+ uint64_t tmp_size;
+ int allocator;
+ char alloc_descr[SE_DESC_MLEN];
+
+ memstat_name = memstat_get_name(mt_item);
+
+ if (memstat_name == NULL || strlen(memstat_name) == 0)
+ continue;
+
+ switch (allocator = memstat_get_allocator(mt_item)) {
+
+ case ALLOCATOR_MALLOC:
+ snprintf(alloc_descr, sizeof(alloc_descr),
+ "MALLOC: %s", memstat_name);
+ break;
+
+ case ALLOCATOR_UMA:
+ snprintf(alloc_descr, sizeof(alloc_descr),
+ "UMA: %s", memstat_name);
+ break;
+
+ default:
+ snprintf(alloc_descr, sizeof(alloc_descr),
+ "UNKNOWN%d: %s", allocator, memstat_name);
+ break;
+ }
+
+ if ((entry = storage_find_by_name(alloc_descr)) == NULL &&
+ (entry = storage_entry_create(alloc_descr)) == NULL)
+ return;
+
+ entry->flags |= HR_STORAGE_FOUND;
+ entry->type = &OIDX_hrStorageRam_c;
+
+ if ((tmp_size = memstat_get_size(mt_item)) == 0)
+ tmp_size = memstat_get_sizemask(mt_item);
+ entry->allocationUnits =
+ (tmp_size > INT_MAX ? INT_MAX : (int32_t)tmp_size);
+
+ tmp_size = memstat_get_countlimit(mt_item);
+ entry->size =
+ (tmp_size > INT_MAX ? INT_MAX : (int32_t)tmp_size);
+
+ tmp_size = memstat_get_count(mt_item);
+ entry->used =
+ (tmp_size > INT_MAX ? INT_MAX : (int32_t)tmp_size);
+
+ tmp_size = memstat_get_failures(mt_item);
+ entry->allocationFailures =
+ (tmp_size > INT_MAX ? INT_MAX : (int32_t)tmp_size);
+
+ } while((mt_item = memstat_mtl_next(mt_item)) != NULL);
+}
+
+/**
+ * Get swap info
+ */
+static void
+storage_OS_get_swap(void)
+{
+ int nswapdev = 0;
+ size_t len = sizeof(nswapdev);
+ struct storage_entry *entry;
+ char swap_w_prefix[SE_DESC_MLEN];
+
+ if (sysctlbyname("vm.nswapdev", &nswapdev, &len, NULL,0 ) < 0) {
+ syslog(LOG_ERR,
+ "hrStorageTable: sysctlbyname(\"vm.nswapdev\") "
+ "failed. %m");
+ assert(0);
+ return;
+ }
+
+ if (nswapdev <= 0) {
+ HRDBG("vm.nswapdev is %d", nswapdev);
+ return;
+ }
+
+ if (nswapdev + 1 != (int)swap_devs_len || swap_devs == NULL) {
+ swap_devs_len = nswapdev + 1;
+ swap_devs = reallocf(swap_devs,
+ swap_devs_len * sizeof(struct kvm_swap));
+
+ assert(swap_devs != NULL);
+ if (swap_devs == NULL) {
+ swap_devs_len = 0;
+ return;
+ }
+ }
+
+ nswapdev = kvm_getswapinfo(hr_kd, swap_devs, swap_devs_len, 0);
+ if (nswapdev < 0) {
+ syslog(LOG_ERR,
+ "hrStorageTable: kvm_getswapinfo failed. %m\n");
+ assert(0);
+ return;
+ }
+
+ for (len = 0; len < (size_t)nswapdev; len++) {
+ memset(&swap_w_prefix[0], '\0', sizeof(swap_w_prefix));
+ snprintf(swap_w_prefix, sizeof(swap_w_prefix) - 1,
+ "Swap:%s%s", _PATH_DEV, swap_devs[len].ksw_devname);
+
+ entry = storage_find_by_name(swap_w_prefix);
+ if (entry == NULL)
+ entry = storage_entry_create(swap_w_prefix);
+
+ assert (entry != NULL);
+ if (entry == NULL)
+ return; /* Out of luck */
+
+ entry->flags |= HR_STORAGE_FOUND;
+ entry->type = &OIDX_hrStorageVirtualMemory_c;
+ entry->allocationUnits = getpagesize();
+ entry->size = swap_devs[len].ksw_total;
+ entry->used = swap_devs[len].ksw_used;
+ entry->allocationFailures = 0;
+ }
+}
+
+/**
+ * Query the underlaying OS for the mounted file systems
+ * anf fill in the respective lists (for hrStorageTable and for hrFSTable)
+ */
+static void
+storage_OS_get_fs(void)
+{
+ struct storage_entry *entry;
+ uint64_t used_blocks_count = 0;
+ char fs_string[SE_DESC_MLEN];
+ int mounted_fs_count;
+ int i = 0;
+
+ if ((mounted_fs_count = getfsstat(NULL, 0, MNT_NOWAIT)) < 0) {
+ syslog(LOG_ERR, "hrStorageTable: getfsstat() failed: %m");
+ return; /* out of luck this time */
+ }
+
+ if (mounted_fs_count != (int)fs_buf_count || fs_buf == NULL) {
+ fs_buf_count = mounted_fs_count;
+ fs_buf = reallocf(fs_buf, fs_buf_count * sizeof(struct statfs));
+ if (fs_buf == NULL) {
+ fs_buf_count = 0;
+ assert(0);
+ return;
+ }
+ }
+
+ if ((mounted_fs_count = getfsstat(fs_buf,
+ fs_buf_count * sizeof(struct statfs), MNT_NOWAIT)) < 0) {
+ syslog(LOG_ERR, "hrStorageTable: getfsstat() failed: %m");
+ return; /* out of luck this time */
+ }
+
+ HRDBG("got %d mounted FS", mounted_fs_count);
+
+ fs_tbl_pre_refresh();
+
+ for (i = 0; i < mounted_fs_count; i++) {
+ snprintf(fs_string, sizeof(fs_string),
+ "%s, type: %s, dev: %s", fs_buf[i].f_mntonname,
+ fs_buf[i].f_fstypename, fs_buf[i].f_mntfromname);
+
+ entry = storage_find_by_name(fs_string);
+ if (entry == NULL)
+ entry = storage_entry_create(fs_string);
+
+ assert (entry != NULL);
+ if (entry == NULL)
+ return; /* Out of luck */
+
+ entry->flags |= HR_STORAGE_FOUND;
+ entry->type = fs_get_type(&fs_buf[i]); /*XXX - This is wrong*/
+
+ if (fs_buf[i].f_bsize > INT_MAX)
+ entry->allocationUnits = INT_MAX;
+ else
+ entry->allocationUnits = fs_buf[i].f_bsize;
+
+ if (fs_buf[i].f_blocks > INT_MAX)
+ entry->size = INT_MAX;
+ else
+ entry->size = fs_buf[i].f_blocks;
+
+ used_blocks_count = fs_buf[i].f_blocks - fs_buf[i].f_bfree;
+
+ if (used_blocks_count > INT_MAX)
+ entry->used = INT_MAX;
+ else
+ entry->used = used_blocks_count;
+
+ entry->allocationFailures = 0;
+
+ /* take care of hrFSTable */
+ fs_tbl_process_statfs_entry(&fs_buf[i], entry->index);
+ }
+
+ fs_tbl_post_refresh();
+}
+
+/**
+ * Initialize storage table and populate it.
+ */
+void
+init_storage_tbl(void)
+{
+ if ((mt_list = memstat_mtl_alloc()) == NULL)
+ syslog(LOG_ERR,
+ "hrStorageTable: memstat_mtl_alloc() failed: %m");
+
+ refresh_storage_tbl(1);
+}
+
+void
+fini_storage_tbl(void)
+{
+ struct storage_map_entry *n1;
+
+ if (swap_devs != NULL) {
+ free(swap_devs);
+ swap_devs = NULL;
+ }
+ swap_devs_len = 0;
+
+ if (fs_buf != NULL) {
+ free(fs_buf);
+ fs_buf = NULL;
+ }
+ fs_buf_count = 0;
+
+ while ((n1 = STAILQ_FIRST(&storage_map)) != NULL) {
+ STAILQ_REMOVE_HEAD(&storage_map, link);
+ if (n1->entry != NULL) {
+ TAILQ_REMOVE(&storage_tbl, n1->entry, link);
+ free(n1->entry->descr);
+ free(n1->entry);
+ }
+ free(n1->a_name);
+ free(n1);
+ }
+ assert(TAILQ_EMPTY(&storage_tbl));
+}
+
+void
+refresh_storage_tbl(int force)
+{
+ struct storage_entry *entry, *entry_tmp;
+
+ if (!force && storage_tick != 0 &&
+ this_tick - storage_tick < storage_tbl_refresh) {
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &storage_tbl, link)
+ entry->flags &= ~HR_STORAGE_FOUND;
+
+ storage_OS_get_vm();
+ storage_OS_get_swap();
+ storage_OS_get_fs();
+ storage_OS_get_memstat();
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &storage_tbl, link, entry_tmp)
+ if (!(entry->flags & HR_STORAGE_FOUND))
+ storage_entry_delete(entry);
+
+ storage_tick = this_tick;
+
+ HRDBG("refresh DONE");
+}
+
+/*
+ * This is the implementation for a generated (by our SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrStorageTable
+ */
+int
+op_hrStorageTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct storage_entry *entry;
+
+ refresh_storage_tbl(0);
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&storage_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&storage_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&storage_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrStorageIndex:
+ value->v.integer = entry->index;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrStorageType:
+ assert(entry->type != NULL);
+ value->v.oid = *entry->type;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrStorageDescr:
+ assert(entry->descr != NULL);
+ return (string_get(value, entry->descr, -1));
+ break;
+
+ case LEAF_hrStorageAllocationUnits:
+ value->v.integer = entry->allocationUnits;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrStorageSize:
+ value->v.integer = entry->size;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrStorageUsed:
+ value->v.integer = entry->used;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrStorageAllocationFailures:
+ value->v.uint32 = entry->allocationFailures;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c
new file mode 100644
index 0000000..5fa5b4c
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c
@@ -0,0 +1,555 @@
+/*
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ *
+ * Host Resources MIB implementation for SNMPd: instrumentation for
+ * hrSWInstalledTable
+ */
+
+#include <sys/limits.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sysexits.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+#define CONTENTS_FNAME "+CONTENTS"
+
+enum SWInstalledType {
+ SWI_UNKNOWN = 1,
+ SWI_OPERATING_SYSTEM = 2,
+ SWI_DEVICE_DRIVER = 3,
+ SWI_APPLICATION = 4
+};
+
+#define SW_NAME_MLEN (64 + 1)
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrSWInstalledTable
+ */
+struct swins_entry {
+ int32_t index;
+ u_char *name; /* max len for this is SW_NAME_MLEN */
+ const struct asn_oid *id;
+ int32_t type; /* from enum SWInstalledType */
+ u_char date[11];
+ u_int date_len;
+
+#define HR_SWINSTALLED_FOUND 0x001
+#define HR_SWINSTALLED_IMMUTABLE 0x002
+ uint32_t flags;
+
+ TAILQ_ENTRY(swins_entry) link;
+};
+TAILQ_HEAD(swins_tbl, swins_entry);
+
+/*
+ * Table to keep a conistent mapping between software and indexes.
+ */
+struct swins_map_entry {
+ int32_t index; /* swins_entry::index */
+ u_char *name; /* map key,a copy of swins_entry::name*/
+
+ /*
+ * next may be NULL if the respective hrSWInstalledTblEntry
+ * is (temporally) gone
+ */
+ struct swins_entry *entry;
+
+ STAILQ_ENTRY(swins_map_entry) link;
+};
+STAILQ_HEAD(swins_map, swins_map_entry);
+
+/* map for consistent indexing */
+static struct swins_map swins_map = STAILQ_HEAD_INITIALIZER(swins_map);
+
+/* the head of the list with hrSWInstalledTable's entries */
+static struct swins_tbl swins_tbl = TAILQ_HEAD_INITIALIZER(swins_tbl);
+
+/* next int available for indexing the hrSWInstalledTable */
+static uint32_t next_swins_index = 1;
+
+/* last (agent) tick when hrSWInstalledTable was updated */
+static uint64_t swins_tick;
+
+/* maximum number of ticks between updates of network table */
+uint32_t swins_tbl_refresh = HR_SWINS_TBL_REFRESH * 100;
+
+/* package directory */
+u_char *pkg_dir;
+
+/* last change of package list */
+static time_t os_pkg_last_change;
+
+/**
+ * Create a new entry into the hrSWInstalledTable
+ */
+static struct swins_entry *
+swins_entry_create(const char *name)
+{
+ struct swins_entry *entry;
+ struct swins_map_entry *map;
+
+ STAILQ_FOREACH(map, &swins_map, link)
+ if (strcmp((const char *)map->name, name) == 0)
+ break;
+
+ if (map == NULL) {
+ size_t name_len;
+ /* new object - get a new index */
+ if (next_swins_index > INT_MAX) {
+ syslog(LOG_ERR, "%s: hrSWInstalledTable index wrap",
+ __func__ );
+ /* There isn't much we can do here.
+ * If the next_swins_index is consumed
+ * then we can't add entries to this table
+ * So it is better to exit - if the table is sparsed
+ * at the next agent run we can fill it fully.
+ */
+ errx(EX_SOFTWARE, "hrSWInstalledTable index wrap");
+ }
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ syslog(LOG_ERR, "%s: %m", __func__ );
+ return (NULL);
+ }
+
+ name_len = strlen(name) + 1;
+ if (name_len > SW_NAME_MLEN)
+ name_len = SW_NAME_MLEN;
+
+ if ((map->name = malloc(name_len)) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ free(map);
+ return (NULL);
+ }
+
+ map->index = next_swins_index++;
+ strlcpy((char *)map->name, name, name_len);
+
+ STAILQ_INSERT_TAIL(&swins_map, map, link);
+
+ HRDBG("%s added into hrSWInstalled at %d", name, map->index);
+ }
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+
+ if ((entry->name = strdup(map->name)) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ free(entry);
+ return (NULL);
+ }
+
+ entry->index = map->index;
+ map->entry = entry;
+
+ INSERT_OBJECT_INT(entry, &swins_tbl);
+
+ return (entry);
+}
+
+/**
+ * Delete an entry in the hrSWInstalledTable
+ */
+static void
+swins_entry_delete(struct swins_entry *entry)
+{
+ struct swins_map_entry *map;
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&swins_tbl, entry, link);
+
+ STAILQ_FOREACH(map, &swins_map, link)
+ if (map->entry == entry) {
+ map->entry = NULL;
+ break;
+ }
+
+ free(entry->name);
+ free(entry);
+}
+
+/**
+ * Find an entry given it's name
+ */
+static struct swins_entry *
+swins_find_by_name(const char *name)
+{
+ struct swins_entry *entry;
+
+ TAILQ_FOREACH(entry, &swins_tbl, link)
+ if (strcmp((const char*)entry->name, name) == 0)
+ return (entry);
+ return (NULL);
+}
+
+/**
+ * Finalize this table
+ */
+void
+fini_swins_tbl(void)
+{
+ struct swins_map_entry *n1;
+
+ while ((n1 = STAILQ_FIRST(&swins_map)) != NULL) {
+ STAILQ_REMOVE_HEAD(&swins_map, link);
+ if (n1->entry != NULL) {
+ TAILQ_REMOVE(&swins_tbl, n1->entry, link);
+ free(n1->entry->name);
+ free(n1->entry);
+ }
+ free(n1->name);
+ free(n1);
+ }
+ assert(TAILQ_EMPTY(&swins_tbl));
+}
+
+/**
+ * Get the *running* O/S identification
+ */
+static void
+swins_get_OS_ident(void)
+{
+ struct utsname os_id;
+ char os_string[SW_NAME_MLEN] = "";
+ struct swins_entry *entry;
+ u_char *boot;
+ struct stat sb;
+ struct tm k_ts;
+
+ if (uname(&os_id) == -1) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return;
+ }
+
+ snprintf(os_string, sizeof(os_string), "%s: %s",
+ os_id.sysname, os_id.version);
+
+ if ((entry = swins_find_by_name(os_string)) != NULL ||
+ (entry = swins_entry_create(os_string)) == NULL)
+ return;
+
+ entry->flags |= (HR_SWINSTALLED_FOUND | HR_SWINSTALLED_IMMUTABLE);
+ entry->id = &oid_zeroDotZero;
+ entry->type = (int32_t)SWI_OPERATING_SYSTEM;
+ memset(entry->date, 0, sizeof(entry->date));
+
+ if (OS_getSystemInitialLoadParameters(&boot) == SNMP_ERR_NOERROR &&
+ strlen(boot) > 0 && stat(boot, &sb) == 0 &&
+ localtime_r(&sb.st_ctime, &k_ts) != NULL)
+ entry->date_len = make_date_time(entry->date, &k_ts, 0);
+}
+
+/**
+ * Read the installed packages
+ */
+static int
+swins_get_packages(void)
+{
+ struct stat sb;
+ DIR *p_dir;
+ struct dirent *ent;
+ struct tm k_ts;
+ char *pkg_file;
+ struct swins_entry *entry;
+ int ret = 0;
+
+ if (pkg_dir == NULL)
+ /* initialisation may have failed */
+ return (-1);
+
+ if (stat(pkg_dir, &sb) != 0) {
+ syslog(LOG_ERR, "hrSWInstalledTable: stat(\"%s\") failed: %m",
+ pkg_dir);
+ return (-1);
+ }
+ if (!S_ISDIR(sb.st_mode)) {
+ syslog(LOG_ERR, "hrSWInstalledTable: \"%s\" is not a directory",
+ pkg_dir);
+ return (-1);
+ }
+ if (sb.st_ctime <= os_pkg_last_change) {
+ HRDBG("no need to rescan installed packages -- "
+ "directory time-stamp unmodified");
+
+ TAILQ_FOREACH(entry, &swins_tbl, link)
+ entry->flags |= HR_SWINSTALLED_FOUND;
+
+ return (0);
+ }
+
+ if ((p_dir = opendir(pkg_dir)) == NULL) {
+ syslog(LOG_ERR, "hrSWInstalledTable: opendir(\"%s\") failed: "
+ "%m", pkg_dir);
+ return (-1);
+ }
+
+ while (errno = 0, (ent = readdir(p_dir)) != NULL) {
+ HRDBG(" pkg file: %s", ent->d_name);
+
+ /* check that the contents file is a regular file */
+ if (asprintf(&pkg_file, "%s/%s/%s", pkg_dir, ent->d_name,
+ CONTENTS_FNAME) == -1)
+ continue;
+
+ if (stat(pkg_file, &sb) != 0 ) {
+ free(pkg_file);
+ continue;
+ }
+
+ if (!S_ISREG(sb.st_mode)) {
+ syslog(LOG_ERR, "hrSWInstalledTable: \"%s\" not a "
+ "regular file -- skipped", pkg_file);
+ free(pkg_file);
+ continue;
+ }
+ free(pkg_file);
+
+ /* read directory timestamp on package */
+ if (asprintf(&pkg_file, "%s/%s", pkg_dir, ent->d_name) == -1)
+ continue;
+
+ if (stat(pkg_file, &sb) == -1 ||
+ localtime_r(&sb.st_ctime, &k_ts) == NULL) {
+ free(pkg_file);
+ continue;
+ }
+ free(pkg_file);
+
+ /* update or create entry */
+ if ((entry = swins_find_by_name(ent->d_name)) == NULL &&
+ (entry = swins_entry_create(ent->d_name)) == NULL) {
+ ret = -1;
+ goto PKG_LOOP_END;
+ }
+
+ entry->flags |= HR_SWINSTALLED_FOUND;
+ entry->id = &oid_zeroDotZero;
+ entry->type = (int32_t)SWI_APPLICATION;
+
+ entry->date_len = make_date_time(entry->date, &k_ts, 0);
+ }
+
+ if (errno != 0) {
+ syslog(LOG_ERR, "hrSWInstalledTable: readdir_r(\"%s\") failed:"
+ " %m", pkg_dir);
+ ret = -1;
+ } else {
+ /*
+ * save the timestamp of directory
+ * to avoid any further scanning
+ */
+ os_pkg_last_change = sb.st_ctime;
+ }
+ PKG_LOOP_END:
+ (void)closedir(p_dir);
+ return (ret);
+}
+
+/**
+ * Refresh the installed software table.
+ */
+void
+refresh_swins_tbl(void)
+{
+ int ret;
+ struct swins_entry *entry, *entry_tmp;
+
+ if (this_tick - swins_tick < swins_tbl_refresh) {
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &swins_tbl, link)
+ entry->flags &= ~HR_SWINSTALLED_FOUND;
+
+ ret = swins_get_packages();
+
+ TAILQ_FOREACH_SAFE(entry, &swins_tbl, link, entry_tmp)
+ if (!(entry->flags & HR_SWINSTALLED_FOUND) &&
+ !(entry->flags & HR_SWINSTALLED_IMMUTABLE))
+ swins_entry_delete(entry);
+
+ if (ret == 0)
+ swins_tick = this_tick;
+}
+
+/**
+ * Create and populate the package table
+ */
+void
+init_swins_tbl(void)
+{
+
+ if ((pkg_dir = malloc(sizeof(PATH_PKGDIR))) == NULL)
+ syslog(LOG_ERR, "%s: %m", __func__);
+ else
+ strcpy(pkg_dir, PATH_PKGDIR);
+
+ swins_get_OS_ident();
+ refresh_swins_tbl();
+
+ HRDBG("init done");
+}
+
+/**
+ * SNMP handler
+ */
+int
+op_hrSWInstalledTable(struct snmp_context *ctx __unused,
+ struct snmp_value *value, u_int sub, u_int iidx __unused,
+ enum snmp_op curr_op)
+{
+ struct swins_entry *entry;
+
+ refresh_swins_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&swins_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&swins_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&swins_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWInstalledIndex:
+ value->v.integer = entry->index;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSWInstalledName:
+ return (string_get(value, entry->name, -1));
+ break;
+
+ case LEAF_hrSWInstalledID:
+ assert(entry->id != NULL);
+ value->v.oid = *entry->id;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSWInstalledType:
+ value->v.integer = entry->type;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSWInstalledDate:
+ return (string_get(value, entry->date, entry->date_len));
+ }
+ abort();
+}
+
+/**
+ * Scalars
+ */
+int
+op_hrSWInstalled(struct snmp_context *ctx __unused,
+ struct snmp_value *value __unused, u_int sub,
+ u_int iidx __unused, enum snmp_op curr_op)
+{
+
+ /* only SNMP GET is possible */
+ switch (curr_op) {
+
+ case SNMP_OP_GET:
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_GETNEXT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWInstalledLastChange:
+ case LEAF_hrSWInstalledLastUpdateTime:
+ /*
+ * We always update the entire table so these two tick
+ * values should be equal.
+ */
+ refresh_swins_tbl();
+ if (swins_tick <= start_tick)
+ value->v.uint32 = 0;
+ else {
+ uint64_t lastChange = swins_tick - start_tick;
+
+ /* may overflow the SNMP type */
+ value->v.uint32 =
+ (lastChange > UINT_MAX ? UINT_MAX : lastChange);
+ }
+
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c
new file mode 100644
index 0000000..1f82648
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c
@@ -0,0 +1,792 @@
+/*
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ *
+ * Host Resources MIB for SNMPd. Implementation for hrSWRunTable
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <sys/linker.h>
+
+#include <assert.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/*
+ * Ugly thing: PID_MAX, NO_PID defined only in kernel
+ */
+#define NO_PID 100000
+
+enum SWRunType {
+ SRT_UNKNOWN = 1,
+ SRT_OPERATING_SYSTEM = 2,
+ SRT_DEVICE_DRIVER = 3,
+ SRT_APPLICATION = 4
+
+};
+
+enum SWRunStatus {
+ SRS_RUNNING = 1,
+ SRS_RUNNABLE = 2,
+ SRS_NOT_RUNNABLE = 3,
+ SRS_INVALID = 4
+};
+
+/* Maximum lengths for the strings according to the MIB */
+#define SWR_NAME_MLEN (64 + 1)
+#define SWR_PATH_MLEN (128 + 1)
+#define SWR_PARAM_MLEN (128 + 1)
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for both hrSWRunTable and hrSWRunPerfTable because
+ * hrSWRunPerfTable AUGMENTS hrSWRunTable
+ */
+struct swrun_entry {
+ int32_t index;
+ u_char *name; /* it may be NULL */
+ const struct asn_oid *id;
+ u_char *path; /* it may be NULL */
+ u_char *parameters; /* it may be NULL */
+ int32_t type; /* enum SWRunType */
+ int32_t status; /* enum SWRunStatus */
+ int32_t perfCPU;
+ int32_t perfMemory;
+#define HR_SWRUN_FOUND 0x001
+ uint32_t flags;
+ uint64_t r_tick; /* tick when entry refreshed */
+ TAILQ_ENTRY(swrun_entry) link;
+};
+TAILQ_HEAD(swrun_tbl, swrun_entry);
+
+/* the head of the list with hrSWRunTable's entries */
+static struct swrun_tbl swrun_tbl = TAILQ_HEAD_INITIALIZER(swrun_tbl);
+
+/* last (agent) tick when hrSWRunTable and hrSWRunPerTable was updated */
+static uint64_t swrun_tick;
+
+/* maximum number of ticks between updates of SWRun and SWRunPerf table */
+uint32_t swrun_tbl_refresh = HR_SWRUN_TBL_REFRESH * 100;
+
+/* the value of the MIB object with the same name */
+static int32_t SWOSIndex;
+
+/**
+ * Malloc a new entry and add it to the list
+ * associated to this table. The item identified by
+ * the index parameter must not exist in this list.
+ */
+static struct swrun_entry *
+swrun_entry_create(int32_t idx)
+{
+ struct swrun_entry *entry;
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+ entry->index = idx;
+
+ INSERT_OBJECT_INT(entry, &swrun_tbl);
+ return (entry);
+}
+
+/**
+ * Unlink the entry from the list and then free its heap memory
+ */
+static void
+swrun_entry_delete(struct swrun_entry *entry)
+{
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&swrun_tbl, entry, link);
+
+ free(entry->name);
+ free(entry->path);
+ free(entry->parameters);
+ free(entry);
+}
+
+/**
+ * Search one item by its index, return NULL if none found
+ */
+static struct swrun_entry *
+swrun_entry_find_by_index(int32_t idx)
+{
+ struct swrun_entry *entry;
+
+ TAILQ_FOREACH(entry, &swrun_tbl, link)
+ if (entry->index == idx)
+ return (entry);
+ return (NULL);
+}
+
+/**
+ * Translate the kernel's process status to SNMP.
+ */
+static enum SWRunStatus
+swrun_OS_get_proc_status(const struct kinfo_proc *kp)
+{
+
+ assert(kp != NULL);
+ if(kp == NULL) {
+ return (SRS_INVALID);
+ }
+
+ /*
+ * I'm using the old style flags - they look cleaner to me,
+ * at least for the purpose of this SNMP table
+ */
+ switch (kp->ki_stat) {
+
+ case SSTOP:
+ return (SRS_NOT_RUNNABLE);
+
+ case SWAIT:
+ case SLOCK:
+ case SSLEEP:
+ return (SRS_RUNNABLE);
+
+ case SZOMB:
+ return (SRS_INVALID);
+
+ case SIDL:
+ case SRUN:
+ return (SRS_RUNNING);
+
+ default:
+ syslog(LOG_ERR,"Unknown process state: %d", kp->ki_stat);
+ return (SRS_INVALID);
+ }
+}
+
+/**
+ * Make an SNMP table entry from a kernel one.
+ */
+static void
+kinfo_proc_to_swrun_entry(const struct kinfo_proc *kp,
+ struct swrun_entry *entry)
+{
+ char **argv = NULL;
+ uint64_t cpu_time = 0;
+ size_t pname_len;
+
+ pname_len = strlen(kp->ki_comm) + 1;
+ entry->name = reallocf(entry->name, pname_len);
+ if (entry->name != NULL)
+ strlcpy(entry->name, kp->ki_comm, pname_len);
+
+ entry->id = &oid_zeroDotZero; /* unknown id - FIXME */
+
+ assert(hr_kd != NULL);
+
+ argv = kvm_getargv(hr_kd, kp, SWR_PARAM_MLEN - 1);
+ if(argv != NULL){
+ u_char param[SWR_PARAM_MLEN];
+
+ memset(param, '\0', sizeof(param));
+
+ /*
+ * FIXME
+ * Path seems to not be available.
+ * Try to hack the info in argv[0];
+ * this argv is under control of the program so this info
+ * is not realiable
+ */
+ if(*argv != NULL && (*argv)[0] == '/') {
+ size_t path_len;
+
+ path_len = strlen(*argv) + 1;
+ if (path_len > SWR_PATH_MLEN)
+ path_len = SWR_PATH_MLEN;
+
+ entry->path = reallocf(entry->path, path_len);
+ if (entry->path != NULL) {
+ memset(entry->path, '\0', path_len);
+ strlcpy((char*)entry->path, *argv, path_len);
+ }
+ }
+
+ argv++; /* skip the first one which was used for path */
+
+ while (argv != NULL && *argv != NULL ) {
+ if (param[0] != 0) {
+ /*
+ * add a space between parameters,
+ * except before the first one
+ */
+ strlcat((char *)param, " ", sizeof(param));
+ }
+ strlcat((char *)param, *argv, sizeof(param));
+ argv++;
+ }
+ /* reuse pname_len */
+ pname_len = strlen(param) + 1;
+ if (pname_len > SWR_PARAM_MLEN)
+ pname_len = SWR_PARAM_MLEN;
+
+ entry->parameters = reallocf(entry->parameters, pname_len);
+ strlcpy(entry->parameters, param, pname_len);
+ }
+
+ entry->type = (int32_t)(IS_KERNPROC(kp) ? SRT_OPERATING_SYSTEM :
+ SRT_APPLICATION);
+
+ entry->status = (int32_t)swrun_OS_get_proc_status(kp);
+ cpu_time = kp->ki_runtime / 100000; /* centi-seconds */
+
+ /* may overflow the snmp type */
+ entry->perfCPU = (cpu_time > (uint64_t)INT_MAX ? INT_MAX : cpu_time);
+ entry->perfMemory = kp->ki_size / 1024; /* in kilo-bytes */
+ entry->r_tick = get_ticks();
+}
+
+/**
+ * Create a table entry for a KLD
+ */
+static void
+kld_file_stat_to_swrun(const struct kld_file_stat *kfs,
+ struct swrun_entry *entry)
+{
+ size_t name_len;
+
+ assert(kfs != NULL);
+ assert(entry != NULL);
+
+ name_len = strlen(kfs->name) + 1;
+ if (name_len > SWR_NAME_MLEN)
+ name_len = SWR_NAME_MLEN;
+
+ entry->name = reallocf(entry->name, name_len);
+ if (entry->name != NULL)
+ strlcpy((char *)entry->name, kfs->name, name_len);
+
+ /* FIXME: can we find the location where the module was loaded from? */
+ entry->path = NULL;
+
+ /* no parameters for kernel files (.ko) of for the kernel */
+ entry->parameters = NULL;
+
+ entry->id = &oid_zeroDotZero; /* unknown id - FIXME */
+
+ if (strcmp(kfs->name, "kernel") == 0) {
+ entry->type = (int32_t)SRT_OPERATING_SYSTEM;
+ SWOSIndex = entry->index;
+ } else {
+ entry->type = (int32_t)SRT_DEVICE_DRIVER; /* well, not really */
+ }
+ entry->status = (int32_t)SRS_RUNNING;
+ entry->perfCPU = 0; /* Info not available */
+ entry->perfMemory = kfs->size / 1024; /* in kilo-bytes */
+ entry->r_tick = get_ticks();
+}
+
+/**
+ * Get all visible proceses including the kernel visible threads
+ */
+static void
+swrun_OS_get_procs(void)
+{
+ struct kinfo_proc *plist, *kp;
+ int i;
+ int nproc;
+ struct swrun_entry *entry;
+
+ plist = kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &nproc);
+ if (plist == NULL || nproc < 0) {
+ syslog(LOG_ERR, "kvm_getprocs() failed: %m");
+ return;
+ }
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+ /*
+ * The SNMP table's index must begin from 1 (as specified by
+ * this table definition), the PIDs are starting from 0
+ * so we are translating the PIDs to +1
+ */
+ entry = swrun_entry_find_by_index((int32_t)kp->ki_pid + 1);
+ if (entry == NULL) {
+ /* new entry - get memory for it */
+ entry = swrun_entry_create((int32_t)kp->ki_pid + 1);
+ if (entry == NULL)
+ continue;
+ }
+ entry->flags |= HR_SWRUN_FOUND; /* mark it as found */
+
+ kinfo_proc_to_swrun_entry(kp, entry);
+ }
+}
+
+/*
+ * Get kernel items: first the kernel itself, then the loaded modules.
+ */
+static void
+swrun_OS_get_kinfo(void)
+{
+ int fileid;
+ struct swrun_entry *entry;
+ struct kld_file_stat stat;
+
+ for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
+ stat.version = sizeof(struct kld_file_stat);
+ if (kldstat(fileid, &stat) < 0) {
+ syslog(LOG_ERR, "kldstat() failed: %m");
+ continue;
+ }
+
+ /*
+ * kernel and kernel files (*.ko) will be indexed starting with
+ * NO_PID + 1; NO_PID is PID_MAX + 1 thus it will be no risk to
+ * overlap with real PIDs which are in range of 1 .. NO_PID
+ */
+ entry = swrun_entry_find_by_index(NO_PID + 1 + stat.id);
+ if (entry == NULL) {
+ /* new entry - get memory for it */
+ entry = swrun_entry_create(NO_PID + 1 + stat.id);
+ if (entry == NULL)
+ continue;
+ }
+ entry->flags |= HR_SWRUN_FOUND; /* mark it as found */
+
+ kld_file_stat_to_swrun(&stat, entry);
+ }
+}
+
+/**
+ * Refresh the hrSWRun and hrSWRunPert tables.
+ */
+static void
+refresh_swrun_tbl(void)
+{
+
+ struct swrun_entry *entry, *entry_tmp;
+
+ if (this_tick - swrun_tick < swrun_tbl_refresh) {
+ HRDBG("no refresh needed ");
+ return;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &swrun_tbl, link)
+ entry->flags &= ~HR_SWRUN_FOUND;
+
+ swrun_OS_get_procs();
+ swrun_OS_get_kinfo();
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &swrun_tbl, link, entry_tmp)
+ if (!(entry->flags & HR_SWRUN_FOUND))
+ swrun_entry_delete(entry);
+
+ swrun_tick = this_tick;
+
+ HRDBG("refresh DONE");
+}
+
+/**
+ * Update the information in this entry
+ */
+static void
+fetch_swrun_entry(struct swrun_entry *entry)
+{
+ struct kinfo_proc *plist;
+ int nproc;
+ struct kld_file_stat stat;
+
+ assert(entry != NULL);
+
+ if (entry->index >= NO_PID + 1) {
+ /*
+ * kernel and kernel files (*.ko) will be indexed
+ * starting with NO_PID + 1; NO_PID is PID_MAX + 1
+ * thus it will be no risk to overlap with real PIDs
+ * which are in range of 1 .. NO_PID
+ */
+ stat.version = sizeof(stat);
+ if (kldstat(entry->index - NO_PID - 1, &stat) == -1) {
+ /*
+ * not found, it's gone. Mark it as invalid for now, it
+ * will be removed from the list at next global refersh
+ */
+ HRDBG("missing item with kid=%d",
+ entry->index - NO_PID - 1);
+ entry->status = (int32_t)SRS_INVALID;
+ } else
+ kld_file_stat_to_swrun(&stat, entry);
+
+ } else {
+ /* this is a process */
+ assert(hr_kd != NULL);
+ plist = kvm_getprocs(hr_kd, KERN_PROC_PID,
+ entry->index - 1, &nproc);
+ if (plist == NULL || nproc != 1) {
+ HRDBG("missing item with PID=%d", entry->index - 1);
+ entry->status = (int32_t)SRS_INVALID;
+ } else
+ kinfo_proc_to_swrun_entry(plist, entry);
+ }
+}
+
+/**
+ * Invalidate entry. For KLDs we try to unload it, for processes we SIGKILL it.
+ */
+static int
+invalidate_swrun_entry(struct swrun_entry *entry, int commit)
+{
+ struct kinfo_proc *plist;
+ int nproc;
+ struct kld_file_stat stat;
+
+ assert(entry != NULL);
+
+ if (entry->index >= NO_PID + 1) {
+ /* this is a kernel item */
+ HRDBG("atempt to unload KLD %d",
+ entry->index - NO_PID - 1);
+
+ if (entry->index == SWOSIndex) {
+ /* can't invalidate the kernel itself */
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+
+ stat.version = sizeof(stat);
+ if (kldstat(entry->index - NO_PID - 1, &stat) == -1) {
+ /*
+ * not found, it's gone. Mark it as invalid for now, it
+ * will be removed from the list at next global
+ * refresh
+ */
+ HRDBG("missing item with kid=%d",
+ entry->index - NO_PID - 1);
+ entry->status = (int32_t)SRS_INVALID;
+ return (SNMP_ERR_NOERROR);
+ }
+ /*
+ * There is no way to try to unload a module. There seems
+ * also no way to find out whether it is busy without unloading
+ * it. We can assume that it is busy, if the reference count
+ * is larger than 2, but if it is 1 nothing helps.
+ */
+ if (!commit) {
+ if (stat.refs > 1)
+ return (SNMP_ERR_NOT_WRITEABLE);
+ return (SNMP_ERR_NOERROR);
+ }
+ if (kldunload(stat.id) == -1) {
+ syslog(LOG_ERR,"kldunload for %d/%s failed: %m",
+ stat.id, stat.name);
+ if (errno == EBUSY)
+ return (SNMP_ERR_NOT_WRITEABLE);
+ else
+ return (SNMP_ERR_RES_UNAVAIL);
+ }
+ } else {
+ /* this is a process */
+ assert(hr_kd != NULL);
+
+ plist = kvm_getprocs(hr_kd, KERN_PROC_PID,
+ entry->index - 1, &nproc);
+ if (plist == NULL || nproc != 1) {
+ HRDBG("missing item with PID=%d", entry->index - 1);
+ entry->status = (int32_t)SRS_INVALID;
+ return (SNMP_ERR_NOERROR);
+ }
+ if (IS_KERNPROC(plist)) {
+ /* you don't want to do this */
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ if (kill(entry->index - 1, commit ? SIGKILL : 0) < 0) {
+ syslog(LOG_ERR,"kill (%d, SIGKILL) failed: %m",
+ entry->index - 1);
+ if (errno == ESRCH) {
+ /* race: just gone */
+ entry->status = (int32_t)SRS_INVALID;
+ return (SNMP_ERR_NOERROR);
+ }
+ return (SNMP_ERR_GENERR);
+ }
+ }
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Popuplate the hrSWRunTable.
+ */
+void
+init_swrun_tbl(void)
+{
+
+ refresh_swrun_tbl();
+ HRDBG("done");
+}
+
+/**
+ * Finalize the hrSWRunTable.
+ */
+void
+fini_swrun_tbl(void)
+{
+ struct swrun_entry *n1;
+
+ while ((n1 = TAILQ_FIRST(&swrun_tbl)) != NULL) {
+ TAILQ_REMOVE(&swrun_tbl, n1, link);
+ free(n1);
+ }
+}
+
+/*
+ * This is the implementation for a generated (by a SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It hanldes the SNMP operations for hrSWRunTable
+ */
+int
+op_hrSWRunTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct swrun_entry *entry;
+ int ret;
+
+ refresh_swrun_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+
+ if (entry->r_tick < this_tick)
+ fetch_swrun_entry(entry);
+
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWRunStatus:
+ if (value->v.integer != (int32_t)SRS_INVALID)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ if (entry->status == (int32_t)SRS_INVALID)
+ return (SNMP_ERR_NOERROR);
+
+ /*
+ * Here we have a problem with the entire SNMP
+ * model: if we kill now, we cannot rollback.
+ * If we kill in the commit code, we cannot
+ * return an error. Because things may change between
+ * SET and COMMIT this is impossible to handle
+ * correctly.
+ */
+ return (invalidate_swrun_entry(entry, 0));
+ }
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ if ((entry = FIND_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOERROR);
+
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWRunStatus:
+ if (value->v.integer == (int32_t)SRS_INVALID &&
+ entry->status != (int32_t)SRS_INVALID)
+ (void)invalidate_swrun_entry(entry, 1);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+ }
+ abort();
+
+ get:
+ ret = SNMP_ERR_NOERROR;
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWRunIndex:
+ value->v.integer = entry->index;
+ break;
+
+ case LEAF_hrSWRunName:
+ if (entry->name != NULL)
+ ret = string_get(value, entry->name, -1);
+ else
+ ret = string_get(value, "", -1);
+ break;
+
+ case LEAF_hrSWRunID:
+ assert(entry->id != NULL);
+ value->v.oid = *entry->id;
+ break;
+
+ case LEAF_hrSWRunPath:
+ if (entry->path != NULL)
+ ret = string_get(value, entry->path, -1);
+ else
+ ret = string_get(value, "", -1);
+ break;
+
+ case LEAF_hrSWRunParameters:
+ if (entry->parameters != NULL)
+ ret = string_get(value, entry->parameters, -1);
+ else
+ ret = string_get(value, "", -1);
+ break;
+
+ case LEAF_hrSWRunType:
+ value->v.integer = entry->type;
+ break;
+
+ case LEAF_hrSWRunStatus:
+ value->v.integer = entry->status;
+ break;
+
+ default:
+ abort();
+ }
+ return (ret);
+}
+
+/**
+ * Scalar(s) in the SWRun group
+ */
+int
+op_hrSWRun(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+
+ /* only SNMP GET is possible */
+ switch (curr_op) {
+
+ case SNMP_OP_GET:
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_GETNEXT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWOSIndex:
+ value->v.uint32 = SWOSIndex;
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+}
+
+/*
+ * This is the implementation for a generated (by a SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrSWRunPerfTable
+ */
+int
+op_hrSWRunPerfTable(struct snmp_context *ctx __unused,
+ struct snmp_value *value, u_int sub, u_int iidx __unused,
+ enum snmp_op curr_op )
+{
+ struct swrun_entry *entry;
+
+ refresh_swrun_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWRunPerfCPU:
+ value->v.integer = entry->perfCPU;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSWRunPerfMem:
+ value->v.integer = entry->perfMemory;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_tree.def b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_tree.def
new file mode 100644
index 0000000..83c187b
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_tree.def
@@ -0,0 +1,292 @@
+#
+# Copyright (c) 2005-2006 The FreeBSD Project
+# All rights reserved.
+#
+# Author: Victor Cruceru <soc-victor@freebsd.org>
+#
+# 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$
+#
+# This is the .def file for both HOST-RESOURCES-MIB and HOST-RESOURCES-TYPES
+#
+
+(1 internet
+ (2 mgmt
+ (1 mib_2
+ (25 host
+ (1 hrSystem
+ (1 hrSystemUptime TIMETICKS op_hrSystem GET)
+ (2 hrSystemDate OCTETSTRING op_hrSystem GET SET)
+ (3 hrSystemInitialLoadDevice INTEGER op_hrSystem GET SET)
+ (4 hrSystemInitialLoadParameters OCTETSTRING op_hrSystem GET SET)
+ (5 hrSystemNumUsers GAUGE op_hrSystem GET)
+ (6 hrSystemProcesses GAUGE op_hrSystem GET)
+ (7 hrSystemMaxProcesses INTEGER op_hrSystem GET)
+ )
+ (2 hrStorage
+ (1 hrStorageTypes
+ (1 hrStorageOther
+ )
+ (2 hrStorageRam
+ )
+ (3 hrStorageVirtualMemory
+ )
+ (4 hrStorageFixedDisk
+ )
+ (5 hrStorageRemovableDisk
+ )
+ (6 hrStorageFloppyDisk
+ )
+ (7 hrStorageCompactDisc
+ )
+ (8 hrStorageRamDisk
+ )
+ (9 hrStorageFlashMemory
+ )
+ (10 hrStorageNetworkDisk
+ )
+ )
+ (2 hrMemorySize INTEGER op_hrStorage GET)
+ (3 hrStorageTable
+ (1 hrStorageEntry : INTEGER op_hrStorageTable
+ (1 hrStorageIndex INTEGER GET)
+ (2 hrStorageType OID GET)
+ (3 hrStorageDescr OCTETSTRING GET)
+ (4 hrStorageAllocationUnits INTEGER GET)
+ (5 hrStorageSize INTEGER GET SET)
+ (6 hrStorageUsed INTEGER GET)
+ (7 hrStorageAllocationFailures COUNTER GET)
+ )
+ )
+ )
+ (3 hrDevice
+ (1 hrDeviceTypes
+ (1 hrDeviceOther
+ )
+ (2 hrDeviceUnknown
+ )
+ (3 hrDeviceProcessor
+ )
+ (4 hrDeviceNetwork
+ )
+ (5 hrDevicePrinter
+ )
+ (6 hrDeviceDiskStorage
+ )
+ (10 hrDeviceVideo
+ )
+ (11 hrDeviceAudio
+ )
+ (12 hrDeviceCoprocessor
+ )
+ (13 hrDeviceKeyboard
+ )
+ (14 hrDeviceModem
+ )
+ (15 hrDeviceParallelPort
+ )
+ (16 hrDevicePointing
+ )
+ (17 hrDeviceSerialPort
+ )
+ (18 hrDeviceTape
+ )
+ (19 hrDeviceClock
+ )
+ (20 hrDeviceVolatileMemory
+ )
+ (21 hrDeviceNonVolatileMemory
+ )
+ )
+ (2 hrDeviceTable
+ (1 hrDeviceEntry : INTEGER op_hrDeviceTable
+ (1 hrDeviceIndex INTEGER GET)
+ (2 hrDeviceType OID GET)
+ (3 hrDeviceDescr OCTETSTRING GET)
+ (4 hrDeviceID OID GET)
+ (5 hrDeviceStatus INTEGER GET)
+ (6 hrDeviceErrors COUNTER GET)
+ )
+ )
+ (3 hrProcessorTable
+ (1 hrProcessorEntry : INTEGER op_hrProcessorTable
+ (1 hrProcessorFrwID OID GET)
+ (2 hrProcessorLoad INTEGER GET)
+ )
+ )
+ (4 hrNetworkTable
+ (1 hrNetworkEntry : INTEGER op_hrNetworkTable
+ (1 hrNetworkIfIndex INTEGER GET)
+ )
+ )
+ (5 hrPrinterTable
+ (1 hrPrinterEntry : INTEGER op_hrPrinterTable
+ (1 hrPrinterStatus INTEGER GET)
+ (2 hrPrinterDetectedErrorState OCTETSTRING GET)
+ )
+ )
+ (6 hrDiskStorageTable
+ (1 hrDiskStorageEntry : INTEGER op_hrDiskStorageTable
+ (1 hrDiskStorageAccess INTEGER GET)
+ (2 hrDiskStorageMedia INTEGER GET)
+ (3 hrDiskStorageRemovable INTEGER GET)
+ (4 hrDiskStorageCapacity INTEGER GET)
+ )
+ )
+ (7 hrPartitionTable
+ (1 hrPartitionEntry : INTEGER INTEGER op_hrPartitionTable
+ (1 hrPartitionIndex INTEGER GET)
+ (2 hrPartitionLabel OCTETSTRING GET)
+ (3 hrPartitionID OCTETSTRING GET)
+ (4 hrPartitionSize INTEGER GET)
+ (5 hrPartitionFSIndex INTEGER GET)
+ )
+ )
+ (8 hrFSTable
+ (1 hrFSEntry : INTEGER op_hrFSTable
+ (1 hrFSIndex INTEGER GET)
+ (2 hrFSMountPoint OCTETSTRING GET)
+ (3 hrFSRemoteMountPoint OCTETSTRING GET)
+ (4 hrFSType OID GET)
+ (5 hrFSAccess INTEGER GET)
+ (6 hrFSBootable INTEGER GET)
+ (7 hrFSStorageIndex INTEGER GET)
+ (8 hrFSLastFullBackupDate OCTETSTRING GET SET)
+ (9 hrFSLastPartialBackupDate OCTETSTRING GET SET)
+ )
+ )
+ (9 hrFSTypes
+ (1 hrFSOther
+ )
+ (2 hrFSUnknown
+ )
+ (3 hrFSBerkeleyFFS
+ )
+ (4 hrFSSys5FS
+ )
+ (5 hrFSFat
+ )
+ (6 hrFSHPFS
+ )
+ (7 hrFSHFS
+ )
+ (8 hrFSMFS
+ )
+ (9 hrFSNTFS
+ )
+ (10 hrFSVNode
+ )
+ (11 hrFSJournaled
+ )
+ (12 hrFSiso9660
+ )
+ (13 hrFSRockRidge
+ )
+ (14 hrFSNFS
+ )
+ (15 hrFSNetware
+ )
+ (16 hrFSAFS
+ )
+ (17 hrFSDFS
+ )
+ (18 hrFSAppleshare
+ )
+ (19 hrFSRFS
+ )
+ (20 hrFSDGCFS
+ )
+ (21 hrFSBFS
+ )
+ (22 hrFSFAT32
+ )
+ (23 hrFSLinuxExt2
+ )
+ )
+ )
+ (4 hrSWRun
+ (1 hrSWOSIndex INTEGER op_hrSWRun GET)
+ (2 hrSWRunTable
+ (1 hrSWRunEntry : INTEGER op_hrSWRunTable
+ (1 hrSWRunIndex INTEGER GET)
+ (2 hrSWRunName OCTETSTRING GET)
+ (3 hrSWRunID OID GET)
+ (4 hrSWRunPath OCTETSTRING GET)
+ (5 hrSWRunParameters OCTETSTRING GET)
+ (6 hrSWRunType INTEGER GET)
+ (7 hrSWRunStatus INTEGER GET SET)
+ )
+ )
+ )
+ (5 hrSWRunPerf
+ (1 hrSWRunPerfTable
+ (1 hrSWRunPerfEntry : INTEGER op_hrSWRunPerfTable
+ (1 hrSWRunPerfCPU INTEGER GET)
+ (2 hrSWRunPerfMem INTEGER GET)
+ )
+ )
+ )
+ (6 hrSWInstalled
+ (1 hrSWInstalledLastChange TIMETICKS op_hrSWInstalled GET)
+ (2 hrSWInstalledLastUpdateTime TIMETICKS op_hrSWInstalled GET)
+ (3 hrSWInstalledTable
+ (1 hrSWInstalledEntry : INTEGER op_hrSWInstalledTable
+ (1 hrSWInstalledIndex INTEGER GET)
+ (2 hrSWInstalledName OCTETSTRING GET)
+ (3 hrSWInstalledID OID GET)
+ (4 hrSWInstalledType INTEGER GET)
+ (5 hrSWInstalledDate OCTETSTRING GET)
+ )
+ )
+ )
+ (7 hrMIBAdminInfo
+ (1 hostResourcesMibModule
+ )
+ (2 hrMIBCompliances
+ )
+ (3 hrMIBGroups
+ )
+ )
+ )
+ )
+ )
+ (4 private
+ (1 enterprises
+ (12325 fokus
+ (1 begemot
+ (202 begemotHostres
+ (1 begemotHostresObjects
+ (1 begemotHrStorageUpdate TIMETICKS op_begemot GET SET)
+ (2 begemotHrFSUpdate TIMETICKS op_begemot GET SET)
+ (3 begemotHrDiskStorageUpdate TIMETICKS op_begemot GET SET)
+ (4 begemotHrNetworkUpdate TIMETICKS op_begemot GET SET)
+ (5 begemotHrSWInstalledUpdate TIMETICKS op_begemot GET SET)
+ (6 begemotHrSWRunUpdate TIMETICKS op_begemot GET SET)
+ (7 begemotHrPkgDir OCTETSTRING op_begemot GET SET)
+ )
+ )
+ )
+ )
+ )
+ )
+)
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3 b/usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3
new file mode 100644
index 0000000..774c027
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3
@@ -0,0 +1,88 @@
+.\"
+.\" Copyright (C) 2005-2006
+.\" The FreeBSD Project.
+.\" All rights reserved.
+.\"
+.\" Author: Harti Brandt <harti@FreeBSD.org>
+.\"
+.\" 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 January 3, 2006
+.Dt SNMP_HOSTRES 3
+.Os
+.Sh NAME
+.Nm snmp_hostres
+.Nd host resources module for
+.Xr bsnmpd 8
+.Sh LIBRARY
+.Pq begemotSnmpdModulePath."hostres" = "/usr/lib/snmp_hostres.so"
+.Sh DESCRIPTION
+The
+.Nm
+module implements the HOST-RESOURCES-MIB as standardized in RFC 2790.
+.Sh RESTRICTIONS
+Not all information in the MIB is meaningful in FreeBSD or is available.
+The following variables are not implemented or carry no information:
+.Bl -tag -width indent
+.It Va hrFSType
+There are several types of file systems for which no appropriate OID
+exists yet which are supported by
+.Fx .
+For smbfs, procfs and devfs ,
+.Va hrFSOther
+is returned.
+In all other cases,
+.Va hrFSUnknown .
+.It Va hrFSBootable
+It is questionable what bootable means here.
+Does it mean that the BIOS is available to start a boot on that file system
+or does it mean that there is something bootable?
+In either case this information is not available so this variable returns True
+for the root file system (which is not necessarily correct) and False for
+all others.
+.It Va hrFSLastFullBackupDate , hrFSLastPartialBackupDate
+This is not available and always returns an empty string.
+Theoretically, this could be retrieved from
+.Pa /etc/dumpdates ,
+which would
+hardly be correct given the different ways of doing backups.
+.It Va hrDiskStorageTable
+Floppy devices are currently not reported.
+Also the names of the disks are hard-coded in the module.
+.El
+.Sh FILES
+.Bl -tag -width indent
+.It Pa /usr/share/snmp/defs/hostres_tree.def
+The description of the MIB tree implemented by
+.Nm .
+.It Pa /usr/share/snmp/mibs/HOST-RESOURCES-TYPES.txt
+.It Pa /usr/share/snmp/mibs/HOST-RESOURCES-MIB.txt
+.It Pa /usr/share/snmp/mibs/BEGEMOT-HOSTRES-MIB.txt
+This is the MIB that is implemented by this module.
+.El
+.Sh SEE ALSO
+.Xr gensnmptree 1 ,
+.Xr snmpmod 3
+.Sh AUTHORS
+.An Victor Cruceru Aq soc-victor@FreeBSD.org
diff --git a/usr.sbin/bsnmpd/modules/snmp_mibII/Makefile b/usr.sbin/bsnmpd/modules/snmp_mibII/Makefile
new file mode 100644
index 0000000..32bca7d
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_mibII/Makefile
@@ -0,0 +1,29 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+
+CONTRIB= ${.CURDIR}/../../../../contrib/bsnmp
+.PATH: ${CONTRIB}/snmp_mibII
+
+MOD= mibII
+SRCS= mibII.c mibII_begemot.c mibII_ifmib.c mibII_ifstack.c \
+ mibII_interfaces.c mibII_ip.c mibII_ipaddr.c mibII_nettomedia.c \
+ mibII_rcvaddr.c mibII_route.c mibII_tcp.c mibII_udp.c
+XSYM= ipAddrTable ifTable ifRcvAddressEntry ifMIB ipMIB tcpMIB udpMIB \
+ ipForward ifIndex linkDown linkUp
+MAN= snmp_mibII.3
+
+CFLAGS+= -I${CONTRIB}/lib -I${CONTRIB}/snmpd
+CFLAGS+= -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY -DHAVE_SYS_TREE_H
+# XXX Work around clang warning, until maintainer approves fix.
+NO_WERROR.clang=
+
+DEFS= ${MOD}_tree.def
+INCS= snmp_${MOD}.h
+BMIBS= BEGEMOT-IP-MIB.txt BEGEMOT-MIB2-MIB.txt
+
+.include <bsd.snmpmod.mk>
+
+smilint:
+ env SMIPATH=/usr/share/snmp/mibs:/usr/local/share/snmp/mibs \
+ smilint -c /dev/null -l6 -i group-membership ${BMIBS:C/^/${CONTRIB}\/snmp_mibII\//}
diff --git a/usr.sbin/bsnmpd/modules/snmp_netgraph/BEGEMOT-NETGRAPH.txt b/usr.sbin/bsnmpd/modules/snmp_netgraph/BEGEMOT-NETGRAPH.txt
new file mode 100644
index 0000000..1896fe6
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_netgraph/BEGEMOT-NETGRAPH.txt
@@ -0,0 +1,398 @@
+--
+-- Copyright (c) 2001-2003
+-- Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+-- All rights reserved.
+--
+-- Author: Harti Brandt <harti@freebsd.org>
+--
+-- Redistribution of this software and documentation 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 or documentation 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 AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
+-- AND ITS 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
+-- FRAUNHOFER FOKUS OR ITS 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$
+--
+-- Private MIB for netgraph part of Begemot SNMP daemon.
+--
+BEGEMOT-NETGRAPH-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, Counter32, Unsigned32
+ FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION, TruthValue
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP
+ FROM SNMPv2-CONF
+ begemot
+ FROM BEGEMOT-MIB;
+
+begemotNg MODULE-IDENTITY
+ LAST-UPDATED "200311140000Z"
+ ORGANIZATION "Fraunhofer FOKUS, CATS"
+ CONTACT-INFO
+ " Hartmut Brandt
+
+ Postal: Fraunhofer Institute for Open Communication Systems
+ Kaiserin-Augusta-Allee 31
+ 10589 Berlin
+ Germany
+
+ Fax: +49 30 3463 7352
+
+ E-mail: harti@freebsd.org"
+ DESCRIPTION
+ "The MIB for the NetGraph access module for SNMP."
+ ::= { begemot 2 }
+
+begemotNgObjects OBJECT IDENTIFIER ::= { begemotNg 1 }
+
+-- --------------------------------------------------------------------------
+
+NgTypeName ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "31a"
+ STATUS current
+ DESCRIPTION
+ "Name of a netgraph type."
+ SYNTAX OCTET STRING (SIZE(1..31))
+
+NgNodeName ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "31a"
+ STATUS current
+ DESCRIPTION
+ "Name of a netgraph node."
+ SYNTAX OCTET STRING (SIZE(1..31))
+
+NgNodeNameOrEmpty ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "31a"
+ STATUS current
+ DESCRIPTION
+ "Name of a netgraph node."
+ SYNTAX OCTET STRING (SIZE(0..31))
+
+NgHookName ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "31a"
+ STATUS current
+ DESCRIPTION
+ "Name of a netgraph hook."
+ SYNTAX OCTET STRING (SIZE(1..31))
+
+NgNodeId ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "x"
+ STATUS current
+ DESCRIPTION
+ "Node identifier."
+ SYNTAX Unsigned32 (1..4294967295)
+
+NgNodeIdOrZero ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "x"
+ STATUS current
+ DESCRIPTION
+ "Node identifier or 0 for 'no-node'."
+ SYNTAX Unsigned32 (0..4294967295)
+
+-- --------------------------------------------------------------------------
+--
+-- Configuration parameters
+--
+begemotNgConfig OBJECT IDENTIFIER ::= { begemotNgObjects 1 }
+
+begemotNgControlNodeName OBJECT-TYPE
+ SYNTAX NgNodeName
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the netgraph node of this daemon. The name is
+ writeable during initialisation. If the name is set from
+ the empty string to the non-empty string, the netgraph socket
+ is created. Once set it cannot be changed."
+ ::= { begemotNgConfig 1 }
+
+begemotNgResBufSiz OBJECT-TYPE
+ SYNTAX INTEGER (1024..65536)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The size of the receive buffers for netgraph messages."
+ DEFVAL { 20000 }
+ ::= { begemotNgConfig 2 }
+
+begemotNgTimeout OBJECT-TYPE
+ SYNTAX INTEGER (10..10000)
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum time to wait for a response to a netgraph message."
+ DEFVAL { 1000 }
+ ::= { begemotNgConfig 3 }
+
+begemotNgDebugLevel OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The netgraph library debug level. This should be set only
+ if the daemon is run with a terminal attached."
+ DEFVAL { 0 }
+ ::= { begemotNgConfig 4 }
+
+-- --------------------------------------------------------------------------
+--
+-- The STATISTICS Group
+--
+begemotNgStats OBJECT IDENTIFIER ::= { begemotNgObjects 2 }
+
+begemotNgNoMems OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of times a memory allocation has failed for buffers
+ or the message queue."
+ ::= { begemotNgStats 1 }
+
+begemotNgMsgReadErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of times reading a netgraph message has failed."
+ ::= { begemotNgStats 2 }
+
+begemotNgTooLargeMsgs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of times a netgraph message was too large for
+ the buffer. Try increasing begemotNgResBufSiz if
+ this happens."
+ ::= { begemotNgStats 3 }
+
+begemotNgDataReadErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of times reading a netgraph data message has failed."
+ ::= { begemotNgStats 4 }
+
+begemotNgTooLargeDatas OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of times a netgraph data message was too large.
+ You need to increase begemotNgResBufSiz."
+ ::= { begemotNgStats 5 }
+
+-- -----------------------------------------------------
+--
+-- The NODE table
+--
+begemotNgTypeTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotNgTypeEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table containing information about all netgraph node types."
+ ::= { begemotNgObjects 3 }
+
+begemotNgTypeEntry OBJECT-TYPE
+ SYNTAX BegemotNgTypeEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Table entry that describes one netgraph node."
+ INDEX { begemotNgTypeName }
+ ::= { begemotNgTypeTable 1 }
+
+BegemotNgTypeEntry ::= SEQUENCE {
+ begemotNgTypeName NgTypeName,
+ begemotNgTypeStatus INTEGER
+}
+
+begemotNgTypeName OBJECT-TYPE
+ SYNTAX NgTypeName
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The name of the type. Used as index."
+ ::= { begemotNgTypeEntry 1 }
+
+begemotNgTypeStatus OBJECT-TYPE
+ SYNTAX INTEGER { loaded(1), unloaded(2) }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "If loaded then the node type is available. A type can be load
+ by setting this field to loaded. It is unload if the field is
+ set to unloaded. Note, that a type cannot be unloaded if it
+ is compiled into the kernel or has nodes of this type. The name
+ of the file containing the type implementation is constructed by
+ prepending ng_ to the type name."
+ ::= { begemotNgTypeEntry 2 }
+
+--
+-- Node table
+--
+begemotNgNodeTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotNgNodeEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table containing information about all netgraph nodes."
+ ::= { begemotNgObjects 4 }
+
+begemotNgNodeEntry OBJECT-TYPE
+ SYNTAX BegemotNgNodeEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Table entry that describes one netgraph node."
+ INDEX { begemotNgNodeId }
+ ::= { begemotNgNodeTable 1 }
+
+BegemotNgNodeEntry ::= SEQUENCE {
+ begemotNgNodeId NgNodeId,
+ begemotNgNodeStatus INTEGER,
+ begemotNgNodeName NgNodeNameOrEmpty,
+ begemotNgNodeType NgTypeName,
+ begemotNgNodeHooks Unsigned32
+}
+
+begemotNgNodeId OBJECT-TYPE
+ SYNTAX NgNodeId
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The 32bit node id of this node. 0 is an illegal value."
+ ::= { begemotNgNodeEntry 1 }
+
+begemotNgNodeStatus OBJECT-TYPE
+ SYNTAX INTEGER { valid(1), invalid(2) }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates whether the node exists or not."
+ ::= { begemotNgNodeEntry 2 }
+
+begemotNgNodeName OBJECT-TYPE
+ SYNTAX NgNodeNameOrEmpty
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Name of the node (if any)."
+ ::= { begemotNgNodeEntry 3 }
+
+begemotNgNodeType OBJECT-TYPE
+ SYNTAX NgTypeName
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Type name of the node."
+ ::= { begemotNgNodeEntry 4 }
+
+begemotNgNodeHooks OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of hooks on this node."
+ ::= { begemotNgNodeEntry 5 }
+
+--
+-- Hook table
+--
+begemotNgHookTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BegemotNgHookEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table containing information about all netgraph hooks."
+ ::= { begemotNgObjects 5 }
+
+begemotNgHookEntry OBJECT-TYPE
+ SYNTAX BegemotNgHookEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Table entry that describes one netgraph node."
+ INDEX { begemotNgHookNodeId, begemotNgHookHook }
+ ::= { begemotNgHookTable 1 }
+
+BegemotNgHookEntry ::= SEQUENCE {
+ begemotNgHookNodeId NgNodeId,
+ begemotNgHookHook NgHookName,
+ begemotNgHookStatus INTEGER,
+ begemotNgHookPeerNodeId NgNodeId,
+ begemotNgHookPeerHook NgHookName,
+ begemotNgHookPeerType NgTypeName
+}
+
+begemotNgHookNodeId OBJECT-TYPE
+ SYNTAX NgNodeId
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The 32bit node id of this node."
+ ::= { begemotNgHookEntry 1 }
+
+begemotNgHookHook OBJECT-TYPE
+ SYNTAX NgHookName
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Name of the hook."
+ ::= { begemotNgHookEntry 2 }
+
+begemotNgHookStatus OBJECT-TYPE
+ SYNTAX INTEGER { valid(1), invalid(2) }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates whether the hook exists or not."
+ ::= { begemotNgHookEntry 3 }
+
+begemotNgHookPeerNodeId OBJECT-TYPE
+ SYNTAX NgNodeId
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The 32bit node id of the peer node of this hook."
+ ::= { begemotNgHookEntry 4 }
+
+begemotNgHookPeerHook OBJECT-TYPE
+ SYNTAX NgHookName
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Name of the peer hook."
+ ::= { begemotNgHookEntry 5 }
+
+begemotNgHookPeerType OBJECT-TYPE
+ SYNTAX NgTypeName
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Name of the peer type."
+ ::= { begemotNgHookEntry 6 }
+
+END
diff --git a/usr.sbin/bsnmpd/modules/snmp_netgraph/Makefile b/usr.sbin/bsnmpd/modules/snmp_netgraph/Makefile
new file mode 100644
index 0000000..7caf7e4
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_netgraph/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+
+MOD= netgraph
+SRCS= snmp_netgraph.c
+XSYM= begemotNg
+MAN= snmp_netgraph.3
+
+BMIBS= BEGEMOT-NETGRAPH.txt
+DEFS= ${MOD}_tree.def
+INCS= snmp_${MOD}.h
+
+DPADD= ${LIBNETGRAPH}
+LDADD= -lnetgraph
+
+.include <bsd.snmpmod.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_netgraph/netgraph_tree.def b/usr.sbin/bsnmpd/modules/snmp_netgraph/netgraph_tree.def
new file mode 100644
index 0000000..eff59ff
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_netgraph/netgraph_tree.def
@@ -0,0 +1,78 @@
+#
+# Copyright (c) 2001-2003
+# Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+# All rights reserved.
+#
+# Author: Harti Brandt <harti@freebsd.org>
+#
+# Redistribution of this software and documentation 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 or documentation 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 AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
+# AND ITS 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
+# FRAUNHOFER FOKUS OR ITS 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$
+#
+# Definition of the tree implemented by snmp_netgraph.
+#
+(1 internet
+ (4 private
+ (1 enterprises
+ (12325 fokus
+ (1 begemot
+ (2 begemotNg
+ (1 begemotNgObjects
+ (1 begemotNgConfig
+ (1 begemotNgControlNodeName OCTETSTRING op_ng_config GET SET)
+ (2 begemotNgResBufSiz INTEGER op_ng_config GET SET)
+ (3 begemotNgTimeout INTEGER op_ng_config GET SET)
+ (4 begemotNgDebugLevel UNSIGNED32 op_ng_config GET SET)
+ )
+# Change definition of stats array if you change StatsGroup
+ (2 begemotNgStats
+ (1 begemotNgNoMems COUNTER op_ng_stats GET)
+ (2 begemotNgMsgReadErrs COUNTER op_ng_stats GET)
+ (3 begemotNgTooLargeMsgs COUNTER op_ng_stats GET)
+ (4 begemotNgDataReadErrs COUNTER op_ng_stats GET)
+ (5 begemotNgTooLargeDatas COUNTER op_ng_stats GET)
+ )
+ (3 begemotNgTypeTable
+ (1 begemotNgTypeEntry : OCTETSTRING op_ng_type
+ (1 begemotNgTypeName OCTETSTRING)
+ (2 begemotNgTypeStatus INTEGER GET SET)
+ ))
+ (4 begemotNgNodeTable
+ (1 begemotNgNodeEntry : INTEGER op_ng_node
+ (1 begemotNgNodeId UNSIGNED32)
+ (2 begemotNgNodeStatus INTEGER GET)
+ (3 begemotNgNodeName OCTETSTRING GET)
+ (4 begemotNgNodeType OCTETSTRING GET)
+ (5 begemotNgNodeHooks UNSIGNED32 GET)
+ ))
+ (5 begemotNgHookTable
+ (1 begemotNgHookEntry : UNSIGNED32 OCTETSTRING op_ng_hook
+ (1 begemotNgHookNodeId UNSIGNED32)
+ (2 begemotNgHookHook OCTETSTRING)
+ (3 begemotNgHookStatus INTEGER GET)
+ (4 begemotNgHookPeerNodeId UNSIGNED32 GET)
+ (5 begemotNgHookPeerHook OCTETSTRING GET)
+ (6 begemotNgHookPeerType OCTETSTRING GET)
+ ))
+ ))
+)))))
diff --git a/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.3 b/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.3
new file mode 100644
index 0000000..9d9e599
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.3
@@ -0,0 +1,436 @@
+.\"
+.\" Copyright (c) 2001-2003
+.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+.\" All rights reserved.
+.\"
+.\" Author: Harti Brandt <harti@FreeBSD.org>
+.\"
+.\" Redistribution of this software and documentation 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 or documentation 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 AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
+.\" AND ITS 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
+.\" FRAUNHOFER FOKUS OR ITS 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 November 14, 2003
+.Dt SNMP_NETGRAPH 3
+.Os
+.Sh NAME
+.Nm snmp_netgraph ,
+.Nm snmp_node ,
+.Nm snmp_nodename ,
+.Nm ng_cookie_f ,
+.Nm ng_hook_f ,
+.Nm ng_register_cookie ,
+.Nm ng_unregister_cookie ,
+.Nm ng_register_hook ,
+.Nm ng_unregister_hook ,
+.Nm ng_unregister_module ,
+.Nm ng_output ,
+.Nm ng_output_node ,
+.Nm ng_output_id ,
+.Nm ng_dialog ,
+.Nm ng_dialog_node ,
+.Nm ng_dialog_id ,
+.Nm ng_send_data ,
+.Nm ng_mkpeer_id ,
+.Nm ng_connect_node ,
+.Nm ng_connect_id ,
+.Nm ng_connect2_id ,
+.Nm ng_connect2_tee_id ,
+.Nm ng_rmhook ,
+.Nm ng_rmhook_id ,
+.Nm ng_rmhook_tee_id ,
+.Nm ng_shutdown_id ,
+.Nm ng_next_node_id ,
+.Nm ng_node_id ,
+.Nm ng_node_id_node ,
+.Nm ng_node_name ,
+.Nm ng_node_type ,
+.Nm ng_peer_hook_id
+.Nd "netgraph module for snmpd"
+.Sh LIBRARY
+.Pq begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
+.Sh SYNOPSIS
+.In bsnmp/snmpmod.h
+.In bsnmp/snmp_netgraph.h
+.Vt extern ng_ID_t snmp_node ;
+.Vt extern u_char *snmp_nodename ;
+.Ft typedef void
+.Fn ng_cookie_f "const struct ng_mesg *mesg" "const char *path" "ng_ID_t id" "void *uarg"
+.Ft typedef void
+.Fn ng_hook_f "const char *hook" "const u_char *mesg" "size_t len" "void *uarg"
+.Ft void *
+.Fn ng_register_cookie "const struct lmodule *mod" "uint32_t cookie" "ng_ID_t id" "ng_cookie_f *func" "void *uarg"
+.Ft void
+.Fn ng_unregister_cookie "void *reg"
+.Ft void *
+.Fn ng_register_hook "const struct lmodule *mod" "const char *hook" "ng_hook_f *func" "void *uarg"
+.Ft void
+.Fn ng_unregister_hook "void *reg"
+.Ft void
+.Fn ng_unregister_module "const struct lmodule *mod"
+.Ft int
+.Fn ng_output "const char *path" "u_int cookie" "u_int opcode" "const void *arg" "size_t arglen"
+.Ft int
+.Fn ng_output_node "const char *node" "u_int cookie" "u_int opcode" "const void *arg" "size_t arglen"
+.Ft int
+.Fn ng_output_id "ng_ID_t node" "u_int cookie" "u_int opcode" "const void *arg" "size_t arglen"
+.Ft struct ng_mesg *
+.Fn ng_dialog "const char *path" "u_int cookie" "u_int opcode" "const void *arg" "size_t arglen"
+.Ft struct ng_mesg *
+.Fn ng_dialog_node "const char *node" "u_int cookie" "u_int opcode" "const void *arg" "size_t arglen"
+.Ft struct ng_mesg *
+.Fn ng_dialog_id "ng_ID_t id" "u_int cookie" "u_int opcode" "const void *arg" "size_t arglen"
+.Ft int
+.Fn ng_send_data "const char *hook" "const void *sndbuf" "size_t sndlen"
+.Ft ng_ID_t
+.Fn ng_mkpeer_id "ng_ID_t id" "const char *name" "const char *type" "const char *hook" "const char *peerhook"
+.Ft int
+.Fn ng_connect_node "const char *node" "const char *ourhook" "const char *peerhook"
+.Ft int
+.Fn ng_connect_id "ng_ID_t id" "const char *ourhook" "const char *peerhook"
+.Ft int
+.Fn ng_connect2_id "ng_ID_t id" "ng_ID_t peer" "const char *ourhook" "const char *peerhook"
+.Ft int
+.Fn ng_connect2_tee_id "ng_ID_t id" "ng_ID_t peer" "const char *ourhook" "const char *peerhook"
+.Ft int
+.Fn ng_rmhook "const char *ourhook"
+.Ft int
+.Fn ng_rmhook_id "ng_ID_t id" "const char *hook"
+.Ft int
+.Fn ng_rmhook_tee_id "ng_ID_t id" "const char *hook"
+.Ft int
+.Fn ng_shutdown_id "ng_ID_t id"
+.Ft ng_ID_t
+.Fn ng_next_node_id "ng_ID_t node" "const char *type" "const char *hook"
+.Ft ng_ID_t
+.Fn ng_node_id "const char *path"
+.Ft ng_ID_t
+.Fn ng_node_id_node "const char *node"
+.Ft ng_ID_t
+.Fn ng_node_name "ng_ID_t id" "char *name"
+.Ft ng_ID_t
+.Fn ng_node_type "ng_ID_t id" "char *type"
+.Ft int
+.Fn ng_peer_hook_id "ng_ID_t id" "const char *hook" "char *peerhook"
+.Sh DESCRIPTION
+The
+.Nm snmp_netgraph
+module implements a number of tables and scalars that enable remote access to
+the netgraph subsystem.
+It also exports a number of global variables and
+functions, that allow other modules to easily use the netgraph system.
+.Pp
+If upon start up of the module the variable
+.Va begemotNgControlNodeName
+is not empty the module opens a netgraph socket and names that socket node.
+If the variable is empty, the socket is created, as soon as the variable is
+written with a non-empty name.
+The socket can be closed by writing an empty
+string to the variable.
+The socket itself and its name are available in
+.Va snmp_node
+and
+.Va snmp_nodename .
+.Ss SENDING AND RECEIVING MESSAGES AND DATA
+There are three functions for sending control message:
+.Bl -tag -width ".It Fn ng_output_node"
+.It Fn ng_output
+sends a control message along the given
+.Fa path .
+.It Fn ng_output_node
+sends a control message to the node with name
+.Fa node
+and
+.It Fn ng_output_id
+sends a control message to the node with node id
+.Fa id .
+.El
+.Pp
+Each of these functions takes the following arguments:
+.Bl -tag -width ".It Fa cookie"
+.It Fa cookie
+is the node specific command cookie,
+.It Fa opcode
+is the node specific code for the operation to perform,
+.It Fa arg
+is a pointer to the message itself.
+This message must start with a
+.Vt struct ng_mesg .
+.It Fa arglen
+is the overall length of the message (header plus arguments).
+.El
+The functions return the message id that can be used to match incoming responses
+or -1 if an error occurs.
+.Pp
+Another class of functions is used to send a control message and to wait for
+a matching response.
+Note, that this operation blocks the daemon, so use it
+only if you are sure that the response will happen.
+There is a maximum timeout
+that is configurable in the MIB variable
+.Va begemotNgTimeout .
+Other messages arriving while the functions are waiting for the response are
+queued and delivered on the next call to the module's idle function.
+.Bl -tag -width ".It Fn ng_output_node"
+.It Fn ng_dialog
+sends a control message along the given
+.Fa path
+and waits for a matching response.
+.It Fn ng_dialog_node
+sends a control message to the node with name
+.Fa node
+and waits for a matching response.
+.It Fn ng_dialog_id
+sends a control message to the node with id
+.Fa id
+and waits for a matching response.
+.El
+.Pp
+All three functions take the same arguments as the
+.Fn ng_output*
+functions.
+The functions return the response message in a buffer allocated by
+.Xr malloc 3
+or NULL in case of an error.
+The maximum size of the response buffer can be
+configured in the variable
+.Va begemotNgResBufSiz .
+.Pp
+A data message can be send with the function
+.Fn ng_send_data .
+This function takes the name of the
+.Va snmp_node Ns 's
+hook through which to send the data, a pointer to the message buffer and
+the size of the message.
+It returns -1 if an error happens.
+.Ss ASYNCHRONOUS CONTROL AND DATA MESSAGES
+A module can register functions to asynchronously receive control and data
+message.
+.Pp
+The function
+.Fn ng_register_cookie
+registers a control message receive function.
+If a control message is
+received, that is not consumed by the dialog functions, the list of registered
+control message receive functions is scanned.
+If the cookie in the received
+message is the same as the
+.Fa cookie
+argument to the
+.Fn ng_register_cookie
+call and the
+.Fa id
+argument to the
+.Fn ng_register_cookie
+call was either 0 or equals the node id which sent the control message, the
+handler function
+.Fa func
+is called with a pointer to the received message, the hook on which the
+message was received (or NULL if it was received not on a hook), the id
+of the sender's node and the
+.Fa uarg
+argument of the registration call.
+The handler function should not modify
+the contents of the message, because more than one function may be registered
+to the same cookie and node id.
+.Pp
+A control message registration can be undone by calling
+.Fn ng_unregister_cookie
+with the return value of the registration call.
+If an error occurs while registering,
+.Fn ng_register_cookie
+returns NULL.
+.Pp
+A module can call
+.Fn ng_register_hook
+to register a callback for data messages on one of the
+.Va snmp_node Ns 's
+hooks.
+If a data message is received on that hook, the callback function
+.Fa func
+is called with the hook name, a pointer to the data message, the size of
+the message and the argument
+.Fa uarg
+to the registration function.
+The message should be treated as read-only.
+A data message registration can be undone by calling
+.Fn ng_unregister_hook
+with the return value of the registration call.
+If an error occurs while registering,
+.Fn ng_register_hook
+returns NULL.
+.Pp
+The function
+.Fn ng_unregister_module
+removes all control and data registrations for that module.
+.Ss FINDING NODES AND NODE CHARACTERISTICS
+The function
+.Fn ng_node_id
+returns the id of the node addressed by
+.Fa path
+or 0 if the node does not exists.
+.Pp
+The function
+.Fn ng_node_id_node
+returns the id of the node with name
+.Fa node
+or 0 if the node does not exist.
+.Pp
+The function
+.Fn ng_node_node
+retrieves the name of the node with id
+.Fa id
+and writes it to the buffer pointed to by
+.Fa name .
+This buffer should be at least
+.Li NG_NODESIZ
+bytes long.
+The function returns the node id or 0 if the
+node is not found.
+.Pp
+The function
+.Fn ng_node_type
+retrieves the name of the node with id
+.Fa id
+and writes it to the buffer pointed to by
+.Fa type .
+This buffer should be at least
+.Li NG_TYPESIZ
+bytes long.
+The function returns the node id or 0 if the
+node is not found.
+.Pp
+The function
+.Fn ng_peer_hook_id
+writes the name of the peer hook of the hook
+.Fa hook
+on the node with
+.Fa id
+to the buffer pointed to by
+.Fa peer_hook .
+The buffer should be at least
+.Li NG_HOOKSIZ
+bytes long.
+The function returns 0 if the node and the hook is found, -1
+otherwise.
+The function skips intermediate tee nodes (see
+.Xr ng_tee 4 ) .
+.Pp
+The function
+.Fn ng_next_node_id
+returns the node id of the peer node that is on the other side of hook
+.Fa hook
+of node
+.Fa id .
+If
+.Fa type
+is not NULL, the function checks, that the peer node's type is
+.Fa type .
+The function skips intermediate tee nodes (see
+.Xr ng_tee 4 ) .
+It returns the node id of the peer node or 0 if an error occurs or the
+types do not match.
+.Ss CHANGING THE GRAPH
+A number of functions can be used to create or destroy nodes and hooks.
+.Pp
+The function
+.Fn ng_mkpeer_id
+creates a new node of type
+.Fa type
+whose hook
+.Fa peerhook
+will be connected to
+.Fa hook
+of node
+.Fa id .
+If
+.Fa name
+is not NULL the new node is named with this name.
+The function returns
+The node id of the new node or 0 if an error happens.
+.Pp
+The functions
+.Fn ng_connect_node
+and
+.Fn ng_connect_id
+make a new hook connecting
+.Fa ourhook
+of the modules socket node
+.Va snmp_node
+to
+.Fa peerhook
+of the node identified by id
+.Fa id
+or name
+.Fa node .
+The functions return 0 on success or -1 otherwise.
+.Pp
+The function
+.Fn ng_connect2_id
+connects hook
+.Fa ourhook
+of the node with id
+.Fa id
+to hook
+.Fa peerhook
+of the node with id
+.Fa peer .
+The functions return 0 on success or -1 otherwise.
+The function
+.Fn ng_connect2_tee_id
+does the same as
+.Fn ng_connect2_id
+except, that it puts an unnamed tee node between the two nodes.
+.Pp
+The function
+.Fn ng_rmhook
+removes hook
+.Fa hook
+on the module's
+.Va snmp_node .
+The function
+.Fn ng_rmhook_id
+removes hook
+.Fa hook
+on the node with id
+.Fa id .
+The function
+.Fn ng_rmhook_tee_id
+additionally shuts down all tee nodes between the node and the first non-tee
+peer.
+.Pp
+The function
+.Fn ng_shutdown_id
+destroys the given node.
+.Sh FILES
+.Bl -tag -width "XXXXXXXXX"
+.It Pa /usr/share/bsnmp/defs/netgraph_tree.def
+The description of the MIB tree implemented by
+.Nm .
+.It Pa /usr/share/bsnmp/mibs/BEGEMOT-NETGRAPH.txt
+This is the MIB that is implemented by this module.
+.El
+.Sh SEE ALSO
+.Xr gensnmptree 1 ,
+.Xr snmpmod 3
+.Sh AUTHORS
+.An Hartmut Brandt Aq harti@FreeBSD.org
diff --git a/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.c b/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.c
new file mode 100644
index 0000000..d9d136a
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.c
@@ -0,0 +1,1690 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Author: Harti Brandt <harti@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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 AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
+ * AND ITS 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
+ * FRAUNHOFER FOKUS OR ITS 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$
+ *
+ * Netgraph interface for SNMPd.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <netgraph.h>
+#include <bsnmp/snmpmod.h>
+#include "snmp_netgraph.h"
+#include "netgraph_tree.h"
+#include "netgraph_oid.h"
+
+/* maximum message size */
+#define RESBUFSIZ 20000
+
+/* default node name */
+#define NODENAME "NgSnmpd"
+
+/* my node Id */
+ng_ID_t snmp_node;
+u_char *snmp_nodename;
+
+/* the Object Resource registration index */
+static u_int reg_index;
+static const struct asn_oid oid_begemotNg = OIDX_begemotNg;
+
+/* configuration */
+/* this must be smaller than int32_t because the functions in libnetgraph
+ * falsely return an int */
+static size_t resbufsiz = RESBUFSIZ;
+static u_int timeout = 1000;
+static u_int debug_level;
+
+/* number of microseconds per clock tick */
+static struct clockinfo clockinfo;
+
+/* Csock buffers. Communication on the csock is asynchronuous. This means
+ * if we wait for a specific response, we may get other messages. Put these
+ * into a queue and execute them when we are idle. */
+struct csock_buf {
+ STAILQ_ENTRY(csock_buf) link;
+ struct ng_mesg *mesg;
+ char path[NG_PATHSIZ];
+};
+static STAILQ_HEAD(, csock_buf) csock_bufs =
+ STAILQ_HEAD_INITIALIZER(csock_bufs);
+
+/*
+ * We dispatch unsolicieted messages by node cookies and ids.
+ * So we must keep a list of hook names and dispatch functions.
+ */
+struct msgreg {
+ u_int32_t cookie;
+ ng_ID_t id;
+ ng_cookie_f *func;
+ void *arg;
+ const struct lmodule *mod;
+ SLIST_ENTRY(msgreg) link;
+};
+static SLIST_HEAD(, msgreg) msgreg_list =
+ SLIST_HEAD_INITIALIZER(msgreg_list);
+
+/*
+ * Data messages are dispatched by hook names.
+ */
+struct datareg {
+ char hook[NG_HOOKSIZ];
+ ng_hook_f *func;
+ void *arg;
+ const struct lmodule *mod;
+ SLIST_ENTRY(datareg) link;
+};
+static SLIST_HEAD(, datareg) datareg_list =
+ SLIST_HEAD_INITIALIZER(datareg_list);
+
+/* the netgraph sockets */
+static int csock, dsock;
+static void *csock_fd, *dsock_fd;
+
+/* our module handle */
+static struct lmodule *module;
+
+/* statistics */
+static u_int32_t stats[LEAF_begemotNgTooLargeDatas+1];
+
+/* netgraph type list */
+struct ngtype {
+ char name[NG_TYPESIZ];
+ struct asn_oid index;
+ TAILQ_ENTRY(ngtype) link;
+};
+TAILQ_HEAD(ngtype_list, ngtype);
+
+static struct ngtype_list ngtype_list;
+static uint64_t ngtype_tick;
+
+
+/*
+ * Register a function to receive unsolicited messages
+ */
+void *
+ng_register_cookie(const struct lmodule *mod, u_int32_t cookie, ng_ID_t id,
+ ng_cookie_f *func, void *arg)
+{
+ struct msgreg *d;
+
+ if ((d = malloc(sizeof(*d))) == NULL)
+ return (NULL);
+
+ d->cookie = cookie;
+ d->id = id;
+ d->func = func;
+ d->arg = arg;
+ d->mod = mod;
+
+ SLIST_INSERT_HEAD(&msgreg_list, d, link);
+
+ return (d);
+}
+
+/*
+ * Remove a registration.
+ */
+void
+ng_unregister_cookie(void *dd)
+{
+ struct msgreg *d = dd;
+
+ SLIST_REMOVE(&msgreg_list, d, msgreg, link);
+ free(d);
+}
+
+/*
+ * Register a function for hook data.
+ */
+void *
+ng_register_hook(const struct lmodule *mod, const char *hook,
+ ng_hook_f *func, void *arg)
+{
+ struct datareg *d;
+
+ if ((d = malloc(sizeof(*d))) == NULL)
+ return (NULL);
+
+ strcpy(d->hook, hook);
+ d->func = func;
+ d->arg = arg;
+ d->mod = mod;
+
+ SLIST_INSERT_HEAD(&datareg_list, d, link);
+
+ return (d);
+}
+
+/*
+ * Unregister a hook function
+ */
+void
+ng_unregister_hook(void *dd)
+{
+ struct datareg *d = dd;
+
+ SLIST_REMOVE(&datareg_list, d, datareg, link);
+ free(d);
+}
+
+/*
+ * Unregister all hooks and cookies for that module. Note: doesn't disconnect
+ * any hooks!
+ */
+void
+ng_unregister_module(const struct lmodule *mod)
+{
+ struct msgreg *m, *m1;
+ struct datareg *d, *d1;
+
+ m = SLIST_FIRST(&msgreg_list);
+ while (m != NULL) {
+ m1 = SLIST_NEXT(m, link);
+ if (m->mod == mod) {
+ SLIST_REMOVE(&msgreg_list, m, msgreg, link);
+ free(m);
+ }
+ m = m1;
+ }
+
+ d = SLIST_FIRST(&datareg_list);
+ while (d != NULL) {
+ d1 = SLIST_NEXT(d, link);
+ if (d->mod == mod) {
+ SLIST_REMOVE(&datareg_list, d, datareg, link);
+ free(d);
+ }
+ d = d1;
+ }
+}
+
+/*
+ * Dispatch a message to the correct module and delete it. More than one
+ * module can get a message.
+ */
+static void
+csock_handle(struct ng_mesg *mesg, const char *path)
+{
+ struct msgreg *d, *d1;
+ u_int id;
+ int len;
+
+ if (sscanf(path, "[%x]:%n", &id, &len) != 1 ||
+ (u_int)len != strlen(path)) {
+ syslog(LOG_ERR, "cannot parse message path '%s'", path);
+ id = 0;
+ }
+
+ d = SLIST_FIRST(&msgreg_list);
+ while (d != NULL) {
+ d1 = SLIST_NEXT(d, link);
+ if (d->cookie == mesg->header.typecookie &&
+ (d->id == 0 || d->id == id || id == 0))
+ (*d->func)(mesg, path, id, d->arg);
+ d = d1;
+ }
+ free(mesg);
+}
+
+/*
+ * Input from the control socket.
+ */
+static struct ng_mesg *
+csock_read(char *path)
+{
+ struct ng_mesg *mesg;
+ int ret, err;
+
+ if ((mesg = malloc(resbufsiz + 1)) == NULL) {
+ stats[LEAF_begemotNgNoMems]++;
+ syslog(LOG_CRIT, "out of memory");
+ errno = ENOMEM;
+ return (NULL);
+ }
+ if ((ret = NgRecvMsg(csock, mesg, resbufsiz + 1, path)) < 0) {
+ err = errno;
+ free(mesg);
+ if (errno == EWOULDBLOCK) {
+ errno = err;
+ return (NULL);
+ }
+ stats[LEAF_begemotNgMsgReadErrs]++;
+ syslog(LOG_WARNING, "read from csock: %m");
+ errno = err;
+ return (NULL);
+ }
+ if (ret == 0) {
+ syslog(LOG_DEBUG, "node closed -- exiting");
+ exit(0);
+ }
+ if ((size_t)ret > resbufsiz) {
+ stats[LEAF_begemotNgTooLargeMsgs]++;
+ syslog(LOG_WARNING, "ng message too large");
+ free(mesg);
+ errno = EFBIG;
+ return (NULL);
+ }
+ return (mesg);
+}
+
+static void
+csock_input(int fd __unused, void *udata __unused)
+{
+ struct ng_mesg *mesg;
+ char path[NG_PATHSIZ];
+
+ if ((mesg = csock_read(path)) == NULL)
+ return;
+
+ csock_handle(mesg, path);
+}
+
+/*
+ * Write a message to a node.
+ */
+int
+ng_output(const char *path, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen)
+{
+ return (NgSendMsg(csock, path, (int)cookie, (int)opcode, arg, arglen));
+}
+int
+ng_output_node(const char *node, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen)
+{
+ char path[NG_PATHSIZ];
+
+ sprintf(path, "%s:", node);
+ return (ng_output(path, cookie, opcode, arg, arglen));
+}
+int
+ng_output_id(ng_ID_t node, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen)
+{
+ char path[NG_PATHSIZ];
+
+ sprintf(path, "[%x]:", node);
+ return (ng_output(path, cookie, opcode, arg, arglen));
+}
+
+
+
+/*
+ * Execute a synchronuous dialog with the csock. All message we receive, that
+ * do not match our request, are queue until the next call to the IDLE function.
+ */
+struct ng_mesg *
+ng_dialog(const char *path, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen)
+{
+ int token, err;
+ struct ng_mesg *mesg;
+ char rpath[NG_PATHSIZ];
+ struct csock_buf *b;
+ struct timeval end, tv;
+
+ if ((token = ng_output(path, cookie, opcode, arg, arglen)) < 0)
+ return (NULL);
+
+ if (csock_fd)
+ fd_suspend(csock_fd);
+
+ gettimeofday(&end, NULL);
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ timeradd(&end, &tv, &end);
+ for (;;) {
+ mesg = NULL;
+ gettimeofday(&tv, NULL);
+ if (timercmp(&tv, &end, >=)) {
+ block:
+ syslog(LOG_WARNING, "no response for request %u/%u",
+ cookie, opcode);
+ errno = EWOULDBLOCK;
+ break;
+ }
+ timersub(&end, &tv, &tv);
+ if (tv.tv_sec == 0 && tv.tv_usec < clockinfo.tick)
+ goto block;
+
+ if (setsockopt(csock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1)
+ syslog(LOG_WARNING, "setsockopt(SO_RCVTIMEO): %m");
+ if ((mesg = csock_read(rpath)) == NULL) {
+ if (errno == EWOULDBLOCK)
+ continue;
+ break;
+ }
+ if (mesg->header.token == (u_int)token)
+ break;
+ if ((b = malloc(sizeof(*b))) == NULL) {
+ stats[LEAF_begemotNgNoMems]++;
+ syslog(LOG_ERR, "out of memory");
+ free(mesg);
+ continue;
+ }
+ b->mesg = mesg;
+ strcpy(b->path, rpath);
+ STAILQ_INSERT_TAIL(&csock_bufs, b, link);
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ if (setsockopt(csock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1)
+ syslog(LOG_WARNING, "setsockopt(SO_RCVTIMEO,0): %m");
+
+ if (csock_fd) {
+ err = errno;
+ fd_resume(csock_fd);
+ errno = err;
+ }
+
+ return (mesg);
+}
+struct ng_mesg *
+ng_dialog_node(const char *node, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen)
+{
+ char path[NG_PATHSIZ];
+
+ sprintf(path, "%s:", node);
+ return (ng_dialog(path, cookie, opcode, arg, arglen));
+}
+struct ng_mesg *
+ng_dialog_id(ng_ID_t id, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen)
+{
+ char path[NG_PATHSIZ];
+
+ sprintf(path, "[%x]:", id);
+ return (ng_dialog(path, cookie, opcode, arg, arglen));
+}
+
+
+/*
+ * Send a data message to a given hook.
+ */
+int
+ng_send_data(const char *hook, const void *sndbuf, size_t sndlen)
+{
+ return (NgSendData(dsock, hook, sndbuf, sndlen));
+}
+
+/*
+ * Input from a data socket. Dispatch to the function for that hook.
+ */
+static void
+dsock_input(int fd __unused, void *udata __unused)
+{
+ u_char *resbuf, embuf[100];
+ ssize_t len;
+ char hook[NG_HOOKSIZ];
+ struct datareg *d, *d1;
+
+ if ((resbuf = malloc(resbufsiz + 1)) == NULL) {
+ stats[LEAF_begemotNgNoMems]++;
+ syslog(LOG_CRIT, "out of memory");
+ (void)NgRecvData(fd, embuf, sizeof(embuf), hook);
+ errno = ENOMEM;
+ return;
+ }
+ if ((len = NgRecvData(fd, resbuf, resbufsiz + 1, hook)) == -1) {
+ stats[LEAF_begemotNgDataReadErrs]++;
+ syslog(LOG_ERR, "reading message: %m");
+ free(resbuf);
+ return;
+ }
+ if (len == 0) {
+ free(resbuf);
+ return;
+ }
+ if ((size_t)len == resbufsiz + 1) {
+ stats[LEAF_begemotNgTooLargeDatas]++;
+ syslog(LOG_WARNING, "message too long");
+ free(resbuf);
+ return;
+ }
+
+ /*
+ * Dispatch message. Maybe dispatched to more than one function.
+ */
+ d = SLIST_FIRST(&datareg_list);
+ while (d != NULL) {
+ d1 = SLIST_NEXT(d, link);
+ if (strcmp(hook, d->hook) == 0)
+ (*d->func)(hook, resbuf, len, d->arg);
+ d = d1;
+ }
+
+ free(resbuf);
+}
+
+/*
+ * The SNMP daemon is about to wait for an event. Look whether we have
+ * netgraph messages waiting. If yes, drain the queue.
+ */
+static void
+ng_idle(void)
+{
+ struct csock_buf *b;
+
+ /* execute waiting csock_bufs */
+ while ((b = STAILQ_FIRST(&csock_bufs)) != NULL) {
+ STAILQ_REMOVE_HEAD(&csock_bufs, link);
+ csock_handle(b->mesg, b->path);
+ free(b);
+ }
+}
+
+/*
+ * Called when the module is loaded. Returning a non-zero value means,
+ * rejecting the initialisation.
+ *
+ * We make the netgraph socket.
+ */
+static int
+ng_init(struct lmodule *mod, int argc, char *argv[])
+{
+ int name[2];
+ size_t len;
+
+ module = mod;
+
+ if (argc == 0) {
+ if ((snmp_nodename = malloc(strlen(NODENAME) + 1)) == NULL)
+ return (ENOMEM);
+ strcpy(snmp_nodename, NODENAME);
+ } else {
+ if ((snmp_nodename = malloc(NG_NODESIZ)) == NULL)
+ return (ENOMEM);
+ strlcpy(snmp_nodename, argv[0], NG_NODESIZ);
+ }
+
+ /* fetch clockinfo (for the number of microseconds per tick) */
+ name[0] = CTL_KERN;
+ name[1] = KERN_CLOCKRATE;
+ len = sizeof(clockinfo);
+ if (sysctl(name, 2, &clockinfo, &len, NULL, 0) == -1)
+ return (errno);
+
+ TAILQ_INIT(&ngtype_list);
+
+ return (0);
+}
+
+/*
+ * Get the node Id/name/type of a node.
+ */
+ng_ID_t
+ng_node_id(const char *path)
+{
+ struct ng_mesg *resp;
+ ng_ID_t id;
+
+ if ((resp = ng_dialog(path, NGM_GENERIC_COOKIE, NGM_NODEINFO,
+ NULL, 0)) == NULL)
+ return (0);
+ id = ((struct nodeinfo *)(void *)resp->data)->id;
+ free(resp);
+ return (id);
+}
+ng_ID_t
+ng_node_id_node(const char *node)
+{
+ struct ng_mesg *resp;
+ ng_ID_t id;
+
+ if ((resp = ng_dialog_node(node, NGM_GENERIC_COOKIE, NGM_NODEINFO,
+ NULL, 0)) == NULL)
+ return (0);
+ id = ((struct nodeinfo *)(void *)resp->data)->id;
+ free(resp);
+ return (id);
+}
+ng_ID_t
+ng_node_name(ng_ID_t id, char *name)
+{
+ struct ng_mesg *resp;
+
+ if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO,
+ NULL, 0)) == NULL)
+ return (0);
+ strcpy(name, ((struct nodeinfo *)(void *)resp->data)->name);
+ free(resp);
+ return (id);
+
+}
+ng_ID_t
+ng_node_type(ng_ID_t id, char *type)
+{
+ struct ng_mesg *resp;
+
+ if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO,
+ NULL, 0)) == NULL)
+ return (0);
+ strcpy(type, ((struct nodeinfo *)(void *)resp->data)->type);
+ free(resp);
+ return (id);
+}
+
+/*
+ * Connect our node to some other node
+ */
+int
+ng_connect_node(const char *node, const char *ourhook, const char *peerhook)
+{
+ struct ngm_connect conn;
+
+ snprintf(conn.path, NG_PATHSIZ, "%s:", node);
+ strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ);
+ strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ);
+ return (NgSendMsg(csock, ".:",
+ NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn)));
+}
+int
+ng_connect_id(ng_ID_t id, const char *ourhook, const char *peerhook)
+{
+ struct ngm_connect conn;
+
+ snprintf(conn.path, NG_PATHSIZ, "[%x]:", id);
+ strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ);
+ strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ);
+ return (NgSendMsg(csock, ".:",
+ NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn)));
+}
+
+int
+ng_connect2_id(ng_ID_t id, ng_ID_t peer, const char *ourhook,
+ const char *peerhook)
+{
+ struct ngm_connect conn;
+ char path[NG_PATHSIZ];
+
+ snprintf(path, NG_PATHSIZ, "[%x]:", id);
+
+ snprintf(conn.path, NG_PATHSIZ, "[%x]:", peer);
+ strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ);
+ strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ);
+ return (NgSendMsg(csock, path,
+ NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn)));
+}
+
+int
+ng_connect2_tee_id(ng_ID_t id, ng_ID_t peer, const char *ourhook,
+ const char *peerhook)
+{
+ struct ngm_connect conn;
+ char path[NG_PATHSIZ];
+ ng_ID_t tee;
+
+ if ((tee = ng_mkpeer_id(id, NULL, "tee", ourhook, "left")) == 0)
+ return (-1);
+
+ snprintf(path, NG_PATHSIZ, "[%x]:", tee);
+
+ snprintf(conn.path, NG_PATHSIZ, "[%x]:", peer);
+ strlcpy(conn.ourhook, "right", NG_HOOKSIZ);
+ strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ);
+ return (NgSendMsg(csock, path,
+ NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn)));
+}
+
+/*
+ * Ensure that a node of type 'type' is connected to 'hook' of 'node'
+ * and return its node id. tee nodes between node and the target node
+ * are skipped. If the type is wrong, or the hook is a dead-end return 0.
+ * If type is NULL, it is not checked.
+ */
+static ng_ID_t
+ng_next_node_id_internal(ng_ID_t node, const char *type, const char *hook,
+ int skip_tee)
+{
+ struct ng_mesg *resp;
+ struct hooklist *hooklist;
+ u_int i;
+
+ if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
+ NULL, 0)) == NULL) {
+ syslog(LOG_ERR, "get hook list: %m");
+ exit(1);
+ }
+ hooklist = (struct hooklist *)(void *)resp->data;
+
+ for (i = 0; i < hooklist->nodeinfo.hooks; i++)
+ if (strcmp(hooklist->link[i].ourhook, hook) == 0)
+ break;
+
+ if (i == hooklist->nodeinfo.hooks) {
+ free(resp);
+ return (0);
+ }
+
+ node = hooklist->link[i].nodeinfo.id;
+
+ if (skip_tee && strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) {
+ if (strcmp(hooklist->link[i].peerhook, "left") == 0)
+ node = ng_next_node_id(node, type, "right");
+ else if (strcmp(hooklist->link[i].peerhook, "right") == 0)
+ node = ng_next_node_id(node, type, "left");
+ else if (type != NULL &&
+ strcmp(hooklist->link[i].nodeinfo.type, type) != 0)
+ node = 0;
+
+ } else if (type != NULL &&
+ strcmp(hooklist->link[i].nodeinfo.type, type) != 0)
+ node = 0;
+
+ free(resp);
+
+ return (node);
+}
+
+/*
+ * Ensure that a node of type 'type' is connected to 'hook' of 'node'
+ * and return its node id. tee nodes between node and the target node
+ * are skipped. If the type is wrong, or the hook is a dead-end return 0.
+ * If type is NULL, it is not checked.
+ */
+ng_ID_t
+ng_next_node_id(ng_ID_t node, const char *type, const char *hook)
+{
+ return (ng_next_node_id_internal(node, type, hook, 1));
+}
+
+ng_ID_t
+ng_mkpeer_id(ng_ID_t id, const char *nodename, const char *type,
+ const char *hook, const char *peerhook)
+{
+ char path[NG_PATHSIZ];
+ struct ngm_mkpeer mkpeer;
+ struct ngm_name name;
+
+ strlcpy(mkpeer.type, type, NG_TYPESIZ);
+ strlcpy(mkpeer.ourhook, hook, NG_HOOKSIZ);
+ strlcpy(mkpeer.peerhook, peerhook, NG_HOOKSIZ);
+
+ sprintf(path, "[%x]:", id);
+ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER,
+ &mkpeer, sizeof(mkpeer)) == -1)
+ return (0);
+
+ if ((id = ng_next_node_id_internal(id, NULL, hook, 0)) == 0)
+ return (0);
+
+ if (nodename != NULL) {
+ strcpy(name.name, nodename);
+ sprintf(path, "[%x]:", id);
+ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_NAME,
+ &name, sizeof(name)) == -1)
+ return (0);
+ }
+ return (id);
+}
+
+/*
+ * SHutdown node
+ */
+int
+ng_shutdown_id(ng_ID_t id)
+{
+ char path[NG_PATHSIZ];
+
+ snprintf(path, NG_PATHSIZ, "[%x]:", id);
+ return (NgSendMsg(csock, path, NGM_GENERIC_COOKIE,
+ NGM_SHUTDOWN, NULL, 0));
+}
+
+/*
+ * Disconnect one of our hooks
+ */
+int
+ng_rmhook(const char *ourhook)
+{
+ struct ngm_rmhook rmhook;
+
+ strlcpy(rmhook.ourhook, ourhook, NG_HOOKSIZ);
+ return (NgSendMsg(csock, ".:",
+ NGM_GENERIC_COOKIE, NGM_RMHOOK, &rmhook, sizeof(rmhook)));
+}
+
+/*
+ * Disconnect a hook of a node
+ */
+int
+ng_rmhook_id(ng_ID_t id, const char *hook)
+{
+ struct ngm_rmhook rmhook;
+ char path[NG_PATHSIZ];
+
+ strlcpy(rmhook.ourhook, hook, NG_HOOKSIZ);
+ snprintf(path, NG_PATHSIZ, "[%x]:", id);
+ return (NgSendMsg(csock, path,
+ NGM_GENERIC_COOKIE, NGM_RMHOOK, &rmhook, sizeof(rmhook)));
+}
+
+/*
+ * Disconnect a hook and shutdown all tee nodes that were connected to that
+ * hook.
+ */
+int
+ng_rmhook_tee_id(ng_ID_t node, const char *hook)
+{
+ struct ng_mesg *resp;
+ struct hooklist *hooklist;
+ u_int i;
+ int first = 1;
+ ng_ID_t next_node;
+ const char *next_hook;
+
+ again:
+ /* if we have just shutdown a tee node, which had no other hooks
+ * connected, the node id may already be wrong here. */
+ if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
+ NULL, 0)) == NULL)
+ return (0);
+
+ hooklist = (struct hooklist *)(void *)resp->data;
+
+ for (i = 0; i < hooklist->nodeinfo.hooks; i++)
+ if (strcmp(hooklist->link[i].ourhook, hook) == 0)
+ break;
+
+ if (i == hooklist->nodeinfo.hooks) {
+ free(resp);
+ return (0);
+ }
+
+ next_node = 0;
+ next_hook = NULL;
+ if (strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) {
+ if (strcmp(hooklist->link[i].peerhook, "left") == 0) {
+ next_node = hooklist->link[i].nodeinfo.id;
+ next_hook = "right";
+ } else if (strcmp(hooklist->link[i].peerhook, "right") == 0) {
+ next_node = hooklist->link[i].nodeinfo.id;
+ next_hook = "left";
+ }
+ }
+ free(resp);
+
+ if (first) {
+ ng_rmhook_id(node, hook);
+ first = 0;
+ } else {
+ ng_shutdown_id(node);
+ }
+ if ((node = next_node) == 0)
+ return (0);
+ hook = next_hook;
+
+ goto again;
+}
+
+/*
+ * Get the peer hook of a hook on a given node. Skip any tee nodes in between
+ */
+int
+ng_peer_hook_id(ng_ID_t node, const char *hook, char *peerhook)
+{
+ struct ng_mesg *resp;
+ struct hooklist *hooklist;
+ u_int i;
+ int ret;
+
+ if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
+ NULL, 0)) == NULL) {
+ syslog(LOG_ERR, "get hook list: %m");
+ exit(1);
+ }
+ hooklist = (struct hooklist *)(void *)resp->data;
+
+ for (i = 0; i < hooklist->nodeinfo.hooks; i++)
+ if (strcmp(hooklist->link[i].ourhook, hook) == 0)
+ break;
+
+ if (i == hooklist->nodeinfo.hooks) {
+ free(resp);
+ return (-1);
+ }
+
+ node = hooklist->link[i].nodeinfo.id;
+
+ ret = 0;
+ if (strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) {
+ if (strcmp(hooklist->link[i].peerhook, "left") == 0)
+ ret = ng_peer_hook_id(node, "right", peerhook);
+ else if (strcmp(hooklist->link[i].peerhook, "right") == 0)
+ ret = ng_peer_hook_id(node, "left", peerhook);
+ else
+ strcpy(peerhook, hooklist->link[i].peerhook);
+
+ } else
+ strcpy(peerhook, hooklist->link[i].peerhook);
+
+ free(resp);
+
+ return (ret);
+}
+
+
+/*
+ * Now the module is started. Select on the sockets, so that we can get
+ * unsolicited input.
+ */
+static void
+ng_start(void)
+{
+ if (snmp_node == 0) {
+ if (NgMkSockNode(snmp_nodename, &csock, &dsock) < 0) {
+ syslog(LOG_ERR, "NgMkSockNode: %m");
+ exit(1);
+ }
+ snmp_node = ng_node_id(".:");
+ }
+
+ if ((csock_fd = fd_select(csock, csock_input, NULL, module)) == NULL) {
+ syslog(LOG_ERR, "fd_select failed on csock: %m");
+ return;
+ }
+ if ((dsock_fd = fd_select(dsock, dsock_input, NULL, module)) == NULL) {
+ syslog(LOG_ERR, "fd_select failed on dsock: %m");
+ return;
+ }
+
+ reg_index = or_register(&oid_begemotNg,
+ "The MIB for the NetGraph access module for SNMP.", module);
+}
+
+/*
+ * Called, when the module is to be unloaded after it was successfully loaded
+ */
+static int
+ng_fini(void)
+{
+ struct ngtype *t;
+
+ while ((t = TAILQ_FIRST(&ngtype_list)) != NULL) {
+ TAILQ_REMOVE(&ngtype_list, t, link);
+ free(t);
+ }
+
+ if (csock_fd != NULL)
+ fd_deselect(csock_fd);
+ (void)close(csock);
+
+ if (dsock_fd != NULL)
+ fd_deselect(dsock_fd);
+ (void)close(dsock);
+
+ free(snmp_nodename);
+
+ or_unregister(reg_index);
+
+ return (0);
+}
+
+const struct snmp_module config = {
+ "This module implements access to the netgraph sub-system",
+ ng_init,
+ ng_fini,
+ ng_idle,
+ NULL,
+ NULL,
+ ng_start,
+ NULL,
+ netgraph_ctree,
+ netgraph_CTREE_SIZE,
+ NULL
+};
+
+int
+op_ng_config(struct snmp_context *ctx, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op op)
+{
+ asn_subid_t which = value->var.subs[sub - 1];
+ int ret;
+
+ switch (op) {
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_GET:
+ /*
+ * Come here for GET, GETNEXT and COMMIT
+ */
+ switch (which) {
+
+ case LEAF_begemotNgControlNodeName:
+ return (string_get(value, snmp_nodename, -1));
+
+ case LEAF_begemotNgResBufSiz:
+ value->v.integer = resbufsiz;
+ break;
+
+ case LEAF_begemotNgTimeout:
+ value->v.integer = timeout;
+ break;
+
+ case LEAF_begemotNgDebugLevel:
+ value->v.uint32 = debug_level;
+ break;
+
+ default:
+ abort();
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_SET:
+ switch (which) {
+
+ case LEAF_begemotNgControlNodeName:
+ /* only at initialisation */
+ if (community != COMM_INITIALIZE)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (snmp_node != 0)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if ((ret = string_save(value, ctx, -1, &snmp_nodename))
+ != SNMP_ERR_NOERROR)
+ return (ret);
+
+ if (NgMkSockNode(snmp_nodename, &csock, &dsock) < 0) {
+ syslog(LOG_ERR, "NgMkSockNode: %m");
+ string_rollback(ctx, &snmp_nodename);
+ return (SNMP_ERR_GENERR);
+ }
+ snmp_node = ng_node_id(".:");
+
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotNgResBufSiz:
+ ctx->scratch->int1 = resbufsiz;
+ if (value->v.integer < 1024 ||
+ value->v.integer > 0x10000)
+ return (SNMP_ERR_WRONG_VALUE);
+ resbufsiz = value->v.integer;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotNgTimeout:
+ ctx->scratch->int1 = timeout;
+ if (value->v.integer < 10 ||
+ value->v.integer > 10000)
+ return (SNMP_ERR_WRONG_VALUE);
+ timeout = value->v.integer;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotNgDebugLevel:
+ ctx->scratch->int1 = debug_level;
+ debug_level = value->v.uint32;
+ NgSetDebug(debug_level);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ switch (which) {
+
+ case LEAF_begemotNgControlNodeName:
+ string_rollback(ctx, &snmp_nodename);
+ close(csock);
+ close(dsock);
+ snmp_node = 0;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotNgResBufSiz:
+ resbufsiz = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotNgTimeout:
+ timeout = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotNgDebugLevel:
+ debug_level = ctx->scratch->int1;
+ NgSetDebug(debug_level);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ case SNMP_OP_COMMIT:
+ switch (which) {
+
+ case LEAF_begemotNgControlNodeName:
+ string_commit(ctx);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotNgResBufSiz:
+ case LEAF_begemotNgTimeout:
+ case LEAF_begemotNgDebugLevel:
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+ }
+ abort();
+}
+
+int
+op_ng_stats(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op op)
+{
+ switch (op) {
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_GET:
+ value->v.uint32 = stats[value->var.subs[sub - 1] - 1];
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+}
+
+/*
+ * Netgraph type table
+ */
+static int
+fetch_types(void)
+{
+ struct ngtype *t;
+ struct typelist *typelist;
+ struct ng_mesg *resp;
+ u_int u, i;
+
+ if (this_tick <= ngtype_tick)
+ return (0);
+
+ while ((t = TAILQ_FIRST(&ngtype_list)) != NULL) {
+ TAILQ_REMOVE(&ngtype_list, t, link);
+ free(t);
+ }
+
+ if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE,
+ NGM_LISTTYPES, NULL, 0)) == NULL)
+ return (SNMP_ERR_GENERR);
+ typelist = (struct typelist *)(void *)resp->data;
+
+ for (u = 0; u < typelist->numtypes; u++) {
+ if ((t = malloc(sizeof(*t))) == NULL) {
+ free(resp);
+ return (SNMP_ERR_GENERR);
+ }
+ strcpy(t->name, typelist->typeinfo[u].type_name);
+ t->index.subs[0] = strlen(t->name);
+ t->index.len = t->index.subs[0] + 1;
+ for (i = 0; i < t->index.subs[0]; i++)
+ t->index.subs[i + 1] = t->name[i];
+
+ INSERT_OBJECT_OID(t, &ngtype_list);
+ }
+
+ ngtype_tick = this_tick;
+
+ free(resp);
+ return (0);
+}
+
+/*
+ * Try to load the netgraph type with the given name. We assume, that
+ * type 'type' is implemented in the kernel module 'ng_type'.
+ */
+static int
+ngtype_load(const u_char *name, size_t namelen)
+{
+ char *mod;
+ int ret;
+
+ if ((mod = malloc(namelen + 4)) == NULL)
+ return (-1);
+ strcpy(mod, "ng_");
+ strncpy(mod + 3, name, namelen);
+ mod[namelen + 3] = '\0';
+
+ ret = kldload(mod);
+ free(mod);
+ return (ret);
+}
+
+/*
+ * Unload a netgraph type.
+ */
+static int
+ngtype_unload(const u_char *name, size_t namelen)
+{
+ char *mod;
+ int id;
+
+ if ((mod = malloc(namelen + 4)) == NULL)
+ return (-1);
+ strcpy(mod, "ng_");
+ strncpy(mod + 3, name, namelen);
+ mod[namelen + 3] = '\0';
+
+ if ((id = kldfind(mod)) == -1) {
+ free(mod);
+ return (-1);
+ }
+ free(mod);
+ return (kldunload(id));
+}
+
+int
+op_ng_type(struct snmp_context *ctx, struct snmp_value *value,
+ u_int sub, u_int iidx, enum snmp_op op)
+{
+ asn_subid_t which = value->var.subs[sub - 1];
+ struct ngtype *t;
+ u_char *name;
+ size_t namelen;
+ int status = 1;
+ int ret;
+
+ switch (op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((ret = fetch_types()) != 0)
+ return (ret);
+ if ((t = NEXT_OBJECT_OID(&ngtype_list, &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ index_append(&value->var, sub, &t->index);
+ break;
+
+ case SNMP_OP_GET:
+ if ((ret = fetch_types()) != 0)
+ return (ret);
+ if ((t = FIND_OBJECT_OID(&ngtype_list, &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_SET:
+ if (index_decode(&value->var, sub, iidx, &name, &namelen))
+ return (SNMP_ERR_NO_CREATION);
+ if (namelen == 0 || namelen >= NG_TYPESIZ) {
+ free(name);
+ return (SNMP_ERR_NO_CREATION);
+ }
+ if ((ret = fetch_types()) != 0) {
+ free(name);
+ return (ret);
+ }
+ t = FIND_OBJECT_OID(&ngtype_list, &value->var, sub);
+
+ if (which != LEAF_begemotNgTypeStatus) {
+ free(name);
+ if (t != NULL)
+ return (SNMP_ERR_NOT_WRITEABLE);
+ return (SNMP_ERR_NO_CREATION);
+ }
+ if (!TRUTH_OK(value->v.integer)) {
+ free(name);
+ return (SNMP_ERR_WRONG_VALUE);
+ }
+ ctx->scratch->int1 = TRUTH_GET(value->v.integer);
+ ctx->scratch->int1 |= (t != NULL) << 1;
+ ctx->scratch->ptr2 = name;
+ ctx->scratch->int2 = namelen;
+
+ if (t == NULL) {
+ /* type not loaded */
+ if (ctx->scratch->int1 & 1) {
+ /* request to load */
+ if (ngtype_load(name, namelen) == -1) {
+ free(name);
+ if (errno == ENOENT)
+ return (SNMP_ERR_INCONS_NAME);
+ else
+ return (SNMP_ERR_GENERR);
+ }
+ }
+ } else {
+ /* is type loaded */
+ if (!(ctx->scratch->int1 & 1)) {
+ /* request to unload */
+ if (ngtype_unload(name, namelen) == -1) {
+ free(name);
+ return (SNMP_ERR_GENERR);
+ }
+ }
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ ret = SNMP_ERR_NOERROR;
+ if (!(ctx->scratch->int1 & 2)) {
+ /* did not exist */
+ if (ctx->scratch->int1 & 1) {
+ /* request to load - unload */
+ if (ngtype_unload(ctx->scratch->ptr2,
+ ctx->scratch->int2) == -1)
+ ret = SNMP_ERR_UNDO_FAILED;
+ }
+ } else {
+ /* did exist */
+ if (!(ctx->scratch->int1 & 1)) {
+ /* request to unload - reload */
+ if (ngtype_load(ctx->scratch->ptr2,
+ ctx->scratch->int2) == -1)
+ ret = SNMP_ERR_UNDO_FAILED;
+ }
+ }
+ free(ctx->scratch->ptr2);
+ return (ret);
+
+ case SNMP_OP_COMMIT:
+ free(ctx->scratch->ptr2);
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+
+ /*
+ * Come here for GET and COMMIT
+ */
+ switch (which) {
+
+ case LEAF_begemotNgTypeStatus:
+ value->v.integer = status;
+ break;
+
+ default:
+ abort();
+ }
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Implement the node table
+ */
+static int
+find_node(const struct asn_oid *oid, u_int sub, struct nodeinfo *info)
+{
+ ng_ID_t id = oid->subs[sub];
+ struct ng_mesg *resp;
+
+ if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO,
+ NULL, 0)) == NULL)
+ return (-1);
+
+ *info = *(struct nodeinfo *)(void *)resp->data;
+ free(resp);
+ return (0);
+}
+
+static int
+ncmp(const void *p1, const void *p2)
+{
+ const struct nodeinfo *i1 = p1;
+ const struct nodeinfo *i2 = p2;
+
+ if (i1->id < i2->id)
+ return (-1);
+ if (i1->id > i2->id)
+ return (+1);
+ return (0);
+}
+
+static int
+find_node_next(const struct asn_oid *oid, u_int sub, struct nodeinfo *info)
+{
+ u_int idxlen = oid->len - sub;
+ struct ng_mesg *resp;
+ struct namelist *list;
+ ng_ID_t id;
+ u_int i;
+
+ if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, NGM_LISTNODES,
+ NULL, 0)) == NULL)
+ return (-1);
+ list = (struct namelist *)(void *)resp->data;
+
+ qsort(list->nodeinfo, list->numnames, sizeof(list->nodeinfo[0]), ncmp);
+
+ if (idxlen == 0) {
+ if (list->numnames == 0) {
+ free(resp);
+ return (-1);
+ }
+ *info = list->nodeinfo[0];
+ free(resp);
+ return (0);
+ }
+ id = oid->subs[sub];
+
+ for (i = 0; i < list->numnames; i++)
+ if (list->nodeinfo[i].id > id) {
+ *info = list->nodeinfo[i];
+ free(resp);
+ return (0);
+ }
+
+ free(resp);
+ return (-1);
+}
+
+int
+op_ng_node(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op op)
+{
+ asn_subid_t which = value->var.subs[sub - 1];
+ u_int idxlen = value->var.len - sub;
+ struct nodeinfo nodeinfo;
+
+ switch (op) {
+
+ case SNMP_OP_GETNEXT:
+ if (find_node_next(&value->var, sub, &nodeinfo) == -1)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = nodeinfo.id;
+ break;
+
+ case SNMP_OP_GET:
+ if (idxlen != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (find_node(&value->var, sub, &nodeinfo) == -1)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_SET:
+ if (idxlen != 1)
+ return (SNMP_ERR_NO_CREATION);
+ if (find_node(&value->var, sub, &nodeinfo) == -1)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ default:
+ abort();
+ }
+
+ /*
+ * Come here for GET and COMMIT
+ */
+ switch (which) {
+
+ case LEAF_begemotNgNodeStatus:
+ value->v.integer = 1;
+ break;
+ case LEAF_begemotNgNodeName:
+ return (string_get(value, nodeinfo.name, -1));
+ case LEAF_begemotNgNodeType:
+ return (string_get(value, nodeinfo.type, -1));
+ case LEAF_begemotNgNodeHooks:
+ value->v.uint32 = nodeinfo.hooks;
+ break;
+
+ default:
+ abort();
+ }
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Implement the hook table
+ */
+static int
+find_hook(int32_t id, const u_char *hook, size_t hooklen, struct linkinfo *info)
+{
+ struct ng_mesg *resp;
+ struct hooklist *list;
+ u_int i;
+
+ if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE,
+ NGM_LISTHOOKS, NULL, 0)) == NULL)
+ return (-1);
+
+ list = (struct hooklist *)(void *)resp->data;
+
+ for (i = 0; i < list->nodeinfo.hooks; i++) {
+ if (strlen(list->link[i].ourhook) == hooklen &&
+ strncmp(list->link[i].ourhook, hook, hooklen) == 0) {
+ *info = list->link[i];
+ free(resp);
+ return (0);
+ }
+ }
+ free(resp);
+ return (-1);
+}
+
+static int
+hook_cmp(const void *p1, const void *p2)
+{
+ const struct linkinfo *i1 = p1;
+ const struct linkinfo *i2 = p2;
+
+ if (strlen(i1->ourhook) < strlen(i2->ourhook))
+ return (-1);
+ if (strlen(i1->ourhook) > strlen(i2->ourhook))
+ return (+1);
+ return (strcmp(i1->ourhook, i2->ourhook));
+}
+
+static int
+find_hook_next(const struct asn_oid *oid, u_int sub, struct nodeinfo *nodeinfo,
+ struct linkinfo *linkinfo)
+{
+ u_int idxlen = oid->len - sub;
+ struct namelist *list;
+ struct ng_mesg *resp;
+ struct hooklist *hooks;
+ struct ng_mesg *resp1;
+ u_int node_index;
+ struct asn_oid idx;
+ u_int i, j;
+
+ /*
+ * Get and sort Node list
+ */
+ if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, NGM_LISTNODES,
+ NULL, 0)) == NULL)
+ return (-1);
+ list = (struct namelist *)(void *)resp->data;
+
+ qsort(list->nodeinfo, list->numnames, sizeof(list->nodeinfo[0]), ncmp);
+
+ /*
+ * If we have no index, take the first node and return the
+ * first hook.
+ */
+ if (idxlen == 0) {
+ node_index = 0;
+ goto return_first_hook;
+ }
+
+ /*
+ * Locate node
+ */
+ for (node_index = 0; node_index < list->numnames; node_index++)
+ if (list->nodeinfo[node_index].id >= oid->subs[sub])
+ break;
+
+ /*
+ * If we have only the node part of the index take, or
+ * there is no node with that Id, take the first hook of that node.
+ */
+ if (idxlen == 1 || node_index >= list->numnames ||
+ list->nodeinfo[node_index].id > oid->subs[sub])
+ goto return_first_hook;
+
+ /*
+ * We had an exact match on the node id and have (at last part)
+ * of the hook name index. Loop through the hooks of the node
+ * and find the next one.
+ */
+ if ((resp1 = ng_dialog_id(list->nodeinfo[node_index].id,
+ NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0)) == NULL) {
+ free(resp);
+ return (-1);
+ }
+ hooks = (struct hooklist *)(void *)resp1->data;
+ if (hooks->nodeinfo.hooks > 0) {
+ qsort(hooks->link, hooks->nodeinfo.hooks,
+ sizeof(hooks->link[0]), hook_cmp);
+ for (i = 0; i < hooks->nodeinfo.hooks; i++) {
+ idx.len = strlen(hooks->link[i].ourhook) + 1;
+ idx.subs[0] = idx.len - 1;
+ for (j = 0; j < idx.len; j++)
+ idx.subs[j + 1] = hooks->link[i].ourhook[j];
+ if (index_compare(oid, sub + 1, &idx) < 0)
+ break;
+ }
+ if (i < hooks->nodeinfo.hooks) {
+ *nodeinfo = hooks->nodeinfo;
+ *linkinfo = hooks->link[i];
+
+ free(resp);
+ free(resp1);
+ return (0);
+ }
+ }
+
+ /* no hook found larger than the index on the index node - take
+ * first hook of next node */
+ free(resp1);
+ node_index++;
+
+ return_first_hook:
+ while (node_index < list->numnames) {
+ if ((resp1 = ng_dialog_id(list->nodeinfo[node_index].id,
+ NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0)) == NULL)
+ break;
+ hooks = (struct hooklist *)(void *)resp1->data;
+ if (hooks->nodeinfo.hooks > 0) {
+ qsort(hooks->link, hooks->nodeinfo.hooks,
+ sizeof(hooks->link[0]), hook_cmp);
+
+ *nodeinfo = hooks->nodeinfo;
+ *linkinfo = hooks->link[0];
+
+ free(resp);
+ free(resp1);
+ return (0);
+ }
+
+ /* if we don't have hooks, try next node */
+ free(resp1);
+ node_index++;
+ }
+
+ free(resp);
+ return (-1);
+}
+
+int
+op_ng_hook(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx, enum snmp_op op)
+{
+ asn_subid_t which = value->var.subs[sub - 1];
+ struct linkinfo linkinfo;
+ struct nodeinfo nodeinfo;
+ u_int32_t lid;
+ u_char *hook;
+ size_t hooklen;
+ u_int i;
+
+ switch (op) {
+
+ case SNMP_OP_GETNEXT:
+ if (find_hook_next(&value->var, sub, &nodeinfo, &linkinfo) == -1)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ value->var.len = sub + 1 + 1 + strlen(linkinfo.ourhook);
+ value->var.subs[sub] = nodeinfo.id;
+ value->var.subs[sub + 1] = strlen(linkinfo.ourhook);
+ for (i = 0; i < strlen(linkinfo.ourhook); i++)
+ value->var.subs[sub + i + 2] =
+ linkinfo.ourhook[i];
+ break;
+
+ case SNMP_OP_GET:
+ if (index_decode(&value->var, sub, iidx, &lid,
+ &hook, &hooklen))
+ return (SNMP_ERR_NOSUCHNAME);
+ if (find_hook(lid, hook, hooklen, &linkinfo) == -1) {
+ free(hook);
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+ free(hook);
+ break;
+
+ case SNMP_OP_SET:
+ if (index_decode(&value->var, sub, iidx, &lid,
+ &hook, &hooklen))
+ return (SNMP_ERR_NO_CREATION);
+ if (find_hook(lid, hook, hooklen, &linkinfo) == -1) {
+ free(hook);
+ return (SNMP_ERR_NO_CREATION);
+ }
+ free(hook);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ default:
+ abort();
+
+ }
+
+ switch (which) {
+
+ case LEAF_begemotNgHookStatus:
+ value->v.integer = 1;
+ break;
+ case LEAF_begemotNgHookPeerNodeId:
+ value->v.uint32 = linkinfo.nodeinfo.id;
+ break;
+ case LEAF_begemotNgHookPeerHook:
+ return (string_get(value, linkinfo.peerhook, -1));
+ case LEAF_begemotNgHookPeerType:
+ return (string_get(value, linkinfo.nodeinfo.type, -1));
+ default:
+ abort();
+ }
+ return (SNMP_ERR_NOERROR);
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.h b/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.h
new file mode 100644
index 0000000..21e553c
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Author: Harti Brandt <harti@freebsd.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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 AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
+ * AND ITS 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
+ * FRAUNHOFER FOKUS OR ITS 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$
+ *
+ * Netgraph interface for SNMPd. Exported stuff.
+ */
+#ifndef SNMP_NETGRAPH_H_
+#define SNMP_NETGRAPH_H_
+
+#include <netgraph/ng_message.h>
+
+extern ng_ID_t snmp_node;
+extern u_char *snmp_nodename;
+
+typedef void ng_cookie_f(const struct ng_mesg *, const char *, ng_ID_t, void *);
+typedef void ng_hook_f(const char *, const u_char *, size_t, void *);
+
+void *ng_register_cookie(const struct lmodule *, u_int32_t cookie,
+ ng_ID_t, ng_cookie_f *, void *);
+void ng_unregister_cookie(void *reg);
+
+void *ng_register_hook(const struct lmodule *, const char *,
+ ng_hook_f *, void *);
+void ng_unregister_hook(void *reg);
+
+void ng_unregister_module(const struct lmodule *);
+
+int ng_output(const char *path, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen);
+int ng_output_node(const char *node, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen);
+int ng_output_id(ng_ID_t node, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen);
+
+struct ng_mesg *ng_dialog(const char *path, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen);
+struct ng_mesg *ng_dialog_node(const char *node, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen);
+struct ng_mesg *ng_dialog_id(ng_ID_t id, u_int cookie, u_int opcode,
+ const void *arg, size_t arglen);
+
+int ng_send_data(const char *hook, const void *sndbuf, size_t sndlen);
+
+ng_ID_t ng_mkpeer_id(ng_ID_t, const char *name, const char *type,
+ const char *hook, const char *peerhook);
+int ng_connect_node(const char *node, const char *ourhook, const char *peerhook);
+int ng_connect_id(ng_ID_t id, const char *ourhook, const char *peerhook);
+int ng_connect2_id(ng_ID_t id, ng_ID_t peer, const char *ourhook,
+ const char *peerhook);
+int ng_connect2_tee_id(ng_ID_t id, ng_ID_t peer, const char *ourhook,
+ const char *peerhook);
+int ng_rmhook(const char *ourhook);
+int ng_rmhook_id(ng_ID_t, const char *);
+int ng_rmhook_tee_id(ng_ID_t, const char *);
+int ng_shutdown_id(ng_ID_t);
+
+ng_ID_t ng_next_node_id(ng_ID_t node, const char *type, const char *hook);
+ng_ID_t ng_node_id(const char *path);
+ng_ID_t ng_node_id_node(const char *node);
+ng_ID_t ng_node_name(ng_ID_t, char *);
+ng_ID_t ng_node_type(ng_ID_t, char *);
+int ng_peer_hook_id(ng_ID_t, const char *, char *);
+
+#endif
diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/BEGEMOT-PF-MIB.txt b/usr.sbin/bsnmpd/modules/snmp_pf/BEGEMOT-PF-MIB.txt
new file mode 100644
index 0000000..0b90bb2
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_pf/BEGEMOT-PF-MIB.txt
@@ -0,0 +1,1347 @@
+--
+-- ----------------------------------------------------------------------------
+-- "THE BEER-WARE LICENSE" (Revision 42):
+-- <philip@FreeBSD.org> wrote this file. As long as you retain this notice you
+-- can do whatever you want with this stuff. If we meet some day, and you think
+-- this stuff is worth it, you can buy me a beer in return. -Philip Paeps
+-- ----------------------------------------------------------------------------
+--
+-- $FreeBSD$
+--
+
+BEGEMOT-PF-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, Counter64, Integer32,
+ TimeTicks, Unsigned32
+ FROM SNMPv2-SMI
+ TruthValue
+ FROM SNMPv2-TC
+ InetAddress, InetAddressType, InetAddressPrefixLength
+ FROM INET-ADDRESS-MIB
+ begemot
+ FROM BEGEMOT-MIB;
+
+begemotPf MODULE-IDENTITY
+ LAST-UPDATED "201003180000Z"
+ ORGANIZATION "NixSys BVBA"
+ CONTACT-INFO
+ " Philip Paeps
+
+ Postal: NixSys BVBA
+ Louizastraat 14
+ BE-2800 Mechelen
+ Belgium
+
+ E-Mail: philip@FreeBSD.org"
+ DESCRIPTION
+ "The Begemot MIB for the pf packet filter."
+ REVISION "201003180000Z"
+ DESCRIPTION
+ "Modified pfTablesAddrEntry to support IPv6
+ addresses - added pfTablesAddrNetType column
+ and modified type of pfTablesAddrNet to
+ InetAddress."
+ REVISION "200912050000Z"
+ DESCRIPTION
+ "Added support for retrieving counters of labeled
+ pf filter rules via pfLabelspfLabels subtree."
+ REVISION "200501240000Z"
+ DESCRIPTION
+ "Initial revision."
+
+ ::= { begemot 200 }
+
+begemotPfObjects OBJECT IDENTIFIER ::= { begemotPf 1 }
+
+-- --------------------------------------------------------------------------
+
+pfStatus OBJECT IDENTIFIER ::= { begemotPfObjects 1 }
+pfCounter OBJECT IDENTIFIER ::= { begemotPfObjects 2 }
+pfStateTable OBJECT IDENTIFIER ::= { begemotPfObjects 3 }
+pfSrcNodes OBJECT IDENTIFIER ::= { begemotPfObjects 4 }
+pfLimits OBJECT IDENTIFIER ::= { begemotPfObjects 5 }
+pfTimeouts OBJECT IDENTIFIER ::= { begemotPfObjects 6 }
+pfLogInterface OBJECT IDENTIFIER ::= { begemotPfObjects 7 }
+pfInterfaces OBJECT IDENTIFIER ::= { begemotPfObjects 8 }
+pfTables OBJECT IDENTIFIER ::= { begemotPfObjects 9 }
+pfAltq OBJECT IDENTIFIER ::= { begemotPfObjects 10 }
+pfLabels OBJECT IDENTIFIER ::= { begemotPfObjects 11 }
+
+-- --------------------------------------------------------------------------
+
+--
+-- status information
+--
+
+pfStatusRunning OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "True if pf is currently enabled."
+ ::= { pfStatus 1 }
+
+pfStatusRuntime OBJECT-TYPE
+ SYNTAX TimeTicks
+ UNITS "1/100th of a Second"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates how long pf has been enabled. If pf is not currently
+ enabled, indicates how long it has been disabled. If pf has not
+ been enabled or disabled since the system was started, the value
+ will be 0."
+ ::= { pfStatus 2 }
+
+pfStatusDebug OBJECT-TYPE
+ SYNTAX INTEGER { none(0), urgent(1), misc(2), loud(3) }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates the debug level at which pf is running."
+ ::= { pfStatus 3 }
+
+pfStatusHostId OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The (unique) host identifier of the machine running pf."
+ ::= { pfStatus 4 }
+
+-- --------------------------------------------------------------------------
+
+--
+-- counters
+--
+
+pfCounterMatch OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of packets that matched a filter rule."
+ ::= { pfCounter 1 }
+
+pfCounterBadOffset OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of packets with bad offset."
+ ::= { pfCounter 2 }
+
+pfCounterFragment OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of fragmented packets."
+ ::= { pfCounter 3 }
+
+pfCounterShort OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of short packets."
+ ::= { pfCounter 4 }
+
+pfCounterNormalize OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of normalized packets."
+ ::= { pfCounter 5 }
+
+pfCounterMemDrop OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of packets dropped due to memory limitations."
+ ::= { pfCounter 6 }
+
+-- --------------------------------------------------------------------------
+
+--
+-- state table
+--
+
+pfStateTableCount OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of entries in the state table."
+ ::= { pfStateTable 1 }
+
+pfStateTableSearches OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of searches against the state table."
+ ::= { pfStateTable 2 }
+
+pfStateTableInserts OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of entries inserted into the state table."
+ ::= { pfStateTable 3 }
+
+pfStateTableRemovals OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of entries removed from the state table."
+ ::= { pfStateTable 4 }
+
+-- --------------------------------------------------------------------------
+
+--
+-- source nodes
+--
+
+pfSrcNodesCount OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of entries in the source tracking table."
+ ::= { pfSrcNodes 1 }
+
+pfSrcNodesSearches OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of searches against the source tracking table."
+ ::= { pfSrcNodes 2 }
+
+pfSrcNodesInserts OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of entries inserted into the source tracking table."
+ ::= { pfSrcNodes 3 }
+
+pfSrcNodesRemovals OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of entries removed from the source tracking table."
+ ::= { pfSrcNodes 4 }
+
+-- --------------------------------------------------------------------------
+
+--
+-- limits
+--
+
+pfLimitsStates OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum number of 'keep state' rules in the ruleset."
+ ::= { pfLimits 1 }
+
+pfLimitsSrcNodes OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum number of 'sticky-address' or 'source-track' rules
+ in the ruleset."
+ ::= { pfLimits 2 }
+
+pfLimitsFrags OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum number of 'scrub' rules in the ruleset."
+ ::= { pfLimits 3 }
+
+-- --------------------------------------------------------------------------
+
+--
+-- timeouts
+--
+
+pfTimeoutsTcpFirst OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State after the first packet in a connection."
+ ::= { pfTimeouts 1 }
+
+pfTimeoutsTcpOpening OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State before the destination host ever sends a packet."
+ ::= { pfTimeouts 2 }
+
+pfTimeoutsTcpEstablished OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The fully established state."
+ ::= { pfTimeouts 3 }
+
+pfTimeoutsTcpClosing OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State after the first FIN has been sent."
+ ::= { pfTimeouts 4 }
+
+pfTimeoutsTcpFinWait OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State after both FINs have been exchanged and the
+ connection is closed."
+ ::= { pfTimeouts 5 }
+
+pfTimeoutsTcpClosed OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State after one endpoint sends an RST."
+ ::= { pfTimeouts 6 }
+
+pfTimeoutsUdpFirst OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State after the first packet."
+ ::= { pfTimeouts 7 }
+
+pfTimeoutsUdpSingle OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State if the source host sends more than one packet but
+ the destination host has never sent one back."
+ ::= { pfTimeouts 8 }
+
+pfTimeoutsUdpMultiple OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State if both hosts have sent packets."
+ ::= { pfTimeouts 9 }
+
+pfTimeoutsIcmpFirst OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State after the first packet."
+ ::= { pfTimeouts 10 }
+
+pfTimeoutsIcmpError OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State after an ICMP error came back in response to an
+ ICMP packet."
+ ::= { pfTimeouts 11 }
+
+pfTimeoutsOtherFirst OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State after the first packet."
+ ::= { pfTimeouts 12 }
+
+pfTimeoutsOtherSingle OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State if the source host sends more than one packet but
+ the destination host has never sent one back."
+ ::= { pfTimeouts 13 }
+
+pfTimeoutsOtherMultiple OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "State if both hosts have sent packets."
+ ::= { pfTimeouts 14 }
+
+pfTimeoutsFragment OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Seconds before an unassembled fragment is expired."
+ ::= { pfTimeouts 15 }
+
+pfTimeoutsInterval OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Interval between purging expired states and fragments."
+ ::= { pfTimeouts 16 }
+
+pfTimeoutsAdaptiveStart OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "When the number of state entries exceeds this value,
+ adaptive scaling begins."
+ ::= { pfTimeouts 17 }
+
+pfTimeoutsAdaptiveEnd OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "When reaching this number of state entries, all timeout
+ values become zero, effectively purging all state entries
+ immediately."
+ ::= { pfTimeouts 18 }
+
+pfTimeoutsSrcNode OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Length of time to retain a source tracking entry after
+ the last state expires."
+ ::= { pfTimeouts 19 }
+
+-- --------------------------------------------------------------------------
+
+--
+-- log interface
+--
+
+pfLogInterfaceName OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the interface configured with 'set loginterface'.
+ If no interface has been configured, the object will be empty."
+ ::= { pfLogInterface 1 }
+
+pfLogInterfaceIp4BytesIn OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv4 bytes passed in on the loginterface."
+ ::= { pfLogInterface 2 }
+
+pfLogInterfaceIp4BytesOut OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv4 bytes passed out on the loginterface."
+ ::= { pfLogInterface 3 }
+
+pfLogInterfaceIp4PktsInPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv4 packets passed in on the loginterface."
+ ::= { pfLogInterface 4 }
+
+pfLogInterfaceIp4PktsInDrop OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv4 packets dropped coming in on the loginterface."
+ ::= { pfLogInterface 5 }
+
+pfLogInterfaceIp4PktsOutPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv4 packets passed out on the loginterface."
+ ::= { pfLogInterface 6 }
+
+pfLogInterfaceIp4PktsOutDrop OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv4 packets dropped going out on the loginterface."
+ ::= { pfLogInterface 7 }
+
+pfLogInterfaceIp6BytesIn OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv6 bytes passed in on the loginterface."
+ ::= { pfLogInterface 8 }
+
+pfLogInterfaceIp6BytesOut OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv6 bytes passed out on the loginterface."
+ ::= { pfLogInterface 9 }
+
+pfLogInterfaceIp6PktsInPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv6 packets passed in on the loginterface."
+ ::= { pfLogInterface 10 }
+
+pfLogInterfaceIp6PktsInDrop OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv6 packets dropped coming in on the loginterface."
+ ::= { pfLogInterface 11 }
+
+pfLogInterfaceIp6PktsOutPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv6 packets passed out on the loginterface."
+ ::= { pfLogInterface 12 }
+
+pfLogInterfaceIp6PktsOutDrop OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of IPv6 packets dropped going out on the loginterface."
+ ::= { pfLogInterface 13 }
+
+-- --------------------------------------------------------------------------
+
+--
+-- interfaces
+--
+
+pfInterfacesIfNumber OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of network interfaces on this system."
+ ::= { pfInterfaces 1 }
+
+pfInterfacesIfTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PfInterfacesIfEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Table of network interfaces, indexed on pfInterfacesIfNumber."
+ ::= { pfInterfaces 2 }
+
+pfInterfacesIfEntry OBJECT-TYPE
+ SYNTAX PfInterfacesIfEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry in the pfInterfacesIfTable containing information
+ about a particular network interface in the machine."
+ INDEX { pfInterfacesIfIndex }
+ ::= { pfInterfacesIfTable 1 }
+
+PfInterfacesIfEntry ::= SEQUENCE {
+ pfInterfacesIfIndex Integer32,
+ pfInterfacesIfDescr OCTET STRING,
+ pfInterfacesIfType INTEGER,
+ pfInterfacesIfTZero TimeTicks,
+ pfInterfacesIfRefsState Unsigned32,
+ pfInterfacesIfRefsRule Unsigned32,
+ pfInterfacesIf4BytesInPass Counter64,
+ pfInterfacesIf4BytesInBlock Counter64,
+ pfInterfacesIf4BytesOutPass Counter64,
+ pfInterfacesIf4BytesOutBlock Counter64,
+ pfInterfacesIf4PktsInPass Counter64,
+ pfInterfacesIf4PktsInBlock Counter64,
+ pfInterfacesIf4PktsOutPass Counter64,
+ pfInterfacesIf4PktsOutBlock Counter64,
+ pfInterfacesIf6BytesInPass Counter64,
+ pfInterfacesIf6BytesInBlock Counter64,
+ pfInterfacesIf6BytesOutPass Counter64,
+ pfInterfacesIf6BytesOutBlock Counter64,
+ pfInterfacesIf6PktsInPass Counter64,
+ pfInterfacesIf6PktsInBlock Counter64,
+ pfInterfacesIf6PktsOutPass Counter64,
+ pfInterfacesIf6PktsOutBlock Counter64
+}
+
+pfInterfacesIfIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value, greater than zero, for each interface."
+ ::= { pfInterfacesIfEntry 1 }
+
+pfInterfacesIfDescr OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the interface."
+ ::= { pfInterfacesIfEntry 2 }
+
+pfInterfacesIfType OBJECT-TYPE
+ SYNTAX INTEGER { group(0), instance(1), detached(2) }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates whether the interface is a group inteface, an
+ interface instance, or whether it has been removed or
+ destroyed."
+ ::= { pfInterfacesIfEntry 3 }
+
+pfInterfacesIfTZero OBJECT-TYPE
+ SYNTAX TimeTicks
+ UNITS "1/100th of a Second"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Time since statistics were last reset or since the
+ interface was loaded."
+ ::= { pfInterfacesIfEntry 4 }
+
+pfInterfacesIfRefsState OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of state and/or source track entries referencing
+ this interface."
+ ::= { pfInterfacesIfEntry 5 }
+
+pfInterfacesIfRefsRule OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of rules referencing this interface."
+ ::= { pfInterfacesIfEntry 6 }
+
+pfInterfacesIf4BytesInPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv4 bytes passed coming in on this interface."
+ ::= { pfInterfacesIfEntry 7 }
+
+pfInterfacesIf4BytesInBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv4 bytes blocked coming in on this interface."
+ ::= { pfInterfacesIfEntry 8 }
+
+pfInterfacesIf4BytesOutPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv4 bytes passed going out on this interface."
+ ::= { pfInterfacesIfEntry 9 }
+
+pfInterfacesIf4BytesOutBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv4 bytes blocked going out on this interface."
+ ::= { pfInterfacesIfEntry 10 }
+
+pfInterfacesIf4PktsInPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv4 packets passed coming in on this interface."
+ ::= { pfInterfacesIfEntry 11 }
+
+pfInterfacesIf4PktsInBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv4 packets blocked coming in on this interface."
+ ::= { pfInterfacesIfEntry 12 }
+
+pfInterfacesIf4PktsOutPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv4 packets passed going out on this interface."
+ ::= { pfInterfacesIfEntry 13 }
+
+pfInterfacesIf4PktsOutBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv4 packets blocked going out on this interface."
+ ::= { pfInterfacesIfEntry 14 }
+
+pfInterfacesIf6BytesInPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv6 bytes passed coming in on this interface."
+ ::= { pfInterfacesIfEntry 15 }
+
+pfInterfacesIf6BytesInBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv6 bytes blocked coming in on this interface."
+ ::= { pfInterfacesIfEntry 16 }
+
+pfInterfacesIf6BytesOutPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv6 bytes passed going out on this interface."
+ ::= { pfInterfacesIfEntry 17 }
+
+pfInterfacesIf6BytesOutBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv6 bytes blocked going out on this interface."
+ ::= { pfInterfacesIfEntry 18 }
+
+
+pfInterfacesIf6PktsInPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv6 packets passed coming in on this interface."
+ ::= { pfInterfacesIfEntry 19 }
+
+pfInterfacesIf6PktsInBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv6 packets blocked coming in on this interface."
+ ::= { pfInterfacesIfEntry 20 }
+
+pfInterfacesIf6PktsOutPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv6 packets passed going out on this interface."
+ ::= { pfInterfacesIfEntry 21 }
+
+pfInterfacesIf6PktsOutBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of IPv6 packets blocked going out on this interface."
+ ::= { pfInterfacesIfEntry 22 }
+
+-- --------------------------------------------------------------------------
+
+--
+-- tables
+--
+
+pfTablesTblNumber OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of tables on this system."
+ ::= { pfTables 1 }
+
+pfTablesTblTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PfTablesTblEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Table of tables, index on pfTablesTblIndex."
+ ::= { pfTables 2 }
+
+pfTablesTblEntry OBJECT-TYPE
+ SYNTAX PfTablesTblEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Any entry in the pfTablesTblTable containing information
+ about a particular table on the system."
+ INDEX { pfTablesTblIndex }
+ ::= { pfTablesTblTable 1 }
+
+PfTablesTblEntry ::= SEQUENCE {
+ pfTablesTblIndex Integer32,
+ pfTablesTblDescr OCTET STRING,
+ pfTablesTblCount Integer32,
+ pfTablesTblTZero TimeTicks,
+ pfTablesTblRefsAnchor Integer32,
+ pfTablesTblRefsRule Integer32,
+ pfTablesTblEvalMatch Counter64,
+ pfTablesTblEvalNoMatch Counter64,
+ pfTablesTblBytesInPass Counter64,
+ pfTablesTblBytesInBlock Counter64,
+ pfTablesTblBytesInXPass Counter64,
+ pfTablesTblBytesOutPass Counter64,
+ pfTablesTblBytesOutBlock Counter64,
+ pfTablesTblBytesOutXPass Counter64,
+ pfTablesTblPktsInPass Counter64,
+ pfTablesTblPktsInBlock Counter64,
+ pfTablesTblPktsInXPass Counter64,
+ pfTablesTblPktsOutPass Counter64,
+ pfTablesTblPktsOutBlock Counter64,
+ pfTablesTblPktsOutXPass Counter64
+}
+
+pfTablesTblIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value, greater than zero, for each table."
+ ::= { pfTablesTblEntry 1 }
+
+pfTablesTblDescr OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the table."
+ ::= { pfTablesTblEntry 2 }
+
+pfTablesTblCount OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of addresses in the table."
+ ::= { pfTablesTblEntry 3 }
+
+pfTablesTblTZero OBJECT-TYPE
+ SYNTAX TimeTicks
+ UNITS "1/100th of a Second"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The time passed since the statistics of this table were last
+ cleared or the time since this table was loaded, whichever is
+ sooner."
+ ::= { pfTablesTblEntry 4 }
+
+pfTablesTblRefsAnchor OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of anchors referencing this table."
+ ::= { pfTablesTblEntry 5 }
+
+pfTablesTblRefsRule OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of rules referencing this table."
+ ::= { pfTablesTblEntry 6 }
+
+pfTablesTblEvalMatch OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of evaluations returning a match."
+ ::= { pfTablesTblEntry 7 }
+
+pfTablesTblEvalNoMatch OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of evaluations not returning a match."
+ ::= { pfTablesTblEntry 8 }
+
+pfTablesTblBytesInPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of bytes passed in matching the table."
+ ::= { pfTablesTblEntry 9 }
+
+pfTablesTblBytesInBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of bytes blocked coming in matching the table."
+ ::= { pfTablesTblEntry 10 }
+
+pfTablesTblBytesInXPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of bytes statefully passed in where the state
+ entry refers to the table, but the table no longer contains
+ the address in question."
+ ::= { pfTablesTblEntry 11 }
+
+pfTablesTblBytesOutPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of bytes passed out matching the table."
+ ::= { pfTablesTblEntry 12 }
+
+pfTablesTblBytesOutBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of bytes blocked going out matching the table."
+ ::= { pfTablesTblEntry 13 }
+
+pfTablesTblBytesOutXPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of bytes statefully passed out where the state
+ entry refers to the table, but the table no longer contains
+ the address in question."
+ ::= { pfTablesTblEntry 14 }
+
+pfTablesTblPktsInPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets passed in matching the table."
+ ::= { pfTablesTblEntry 15 }
+
+pfTablesTblPktsInBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets blocked coming in matching the table."
+ ::= { pfTablesTblEntry 16 }
+
+pfTablesTblPktsInXPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets statefully passed in where the state
+ entry refers to the table, but the table no longer contains
+ the address in question."
+ ::= { pfTablesTblEntry 17 }
+
+pfTablesTblPktsOutPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets passed out matching the table."
+ ::= { pfTablesTblEntry 18 }
+
+pfTablesTblPktsOutBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets blocked going out matching the table."
+ ::= { pfTablesTblEntry 19 }
+
+pfTablesTblPktsOutXPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets statefully passed out where the state
+ entry refers to the table, but the table no longer contains
+ the address in question."
+ ::= { pfTablesTblEntry 20 }
+
+pfTablesAddrTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PfTablesAddrEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Table of addresses from every table on the system."
+ ::= { pfTables 3 }
+
+pfTablesAddrEntry OBJECT-TYPE
+ SYNTAX PfTablesAddrEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry in the pfTablesAddrTable containing information
+ about a particular entry in a table."
+ INDEX { pfTablesAddrIndex }
+ ::= { pfTablesAddrTable 1 }
+
+PfTablesAddrEntry ::= SEQUENCE {
+ pfTablesAddrIndex Integer32,
+ pfTablesAddrNetType InetAddressType,
+ pfTablesAddrNet InetAddress,
+ pfTablesAddrPrefix InetAddressPrefixLength,
+ pfTablesAddrTZero TimeTicks,
+ pfTablesAddrBytesInPass Counter64,
+ pfTablesAddrBytesInBlock Counter64,
+ pfTablesAddrBytesOutPass Counter64,
+ pfTablesAddrBytesOutBlock Counter64,
+ pfTablesAddrPktsInPass Counter64,
+ pfTablesAddrPktsInBlock Counter64,
+ pfTablesAddrPktsOutPass Counter64,
+ pfTablesAddrPktsOutBlock Counter64
+}
+
+pfTablesAddrIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value, greater than zero, for each address."
+ ::= { pfTablesAddrEntry 1 }
+
+pfTablesAddrNetType OBJECT-TYPE
+ SYNTAX InetAddressType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of address in the corresponding pfTablesAddrNet object."
+ ::= { pfTablesAddrEntry 2 }
+
+pfTablesAddrNet OBJECT-TYPE
+ SYNTAX InetAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The IP address of this particular table entry."
+ ::= { pfTablesAddrEntry 3 }
+
+pfTablesAddrPrefix OBJECT-TYPE
+ SYNTAX InetAddressPrefixLength
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The CIDR netmask of this particular table entry."
+ ::= { pfTablesAddrEntry 4 }
+
+pfTablesAddrTZero OBJECT-TYPE
+ SYNTAX TimeTicks
+ UNITS "1/100th of a Second"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The time passed since this entry's statistics were last
+ cleared, or the time passed since this entry was loaded
+ into the table, whichever is sooner."
+ ::= { pfTablesAddrEntry 5 }
+
+pfTablesAddrBytesInPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of inbound bytes passed as a result of this entry."
+ ::= { pfTablesAddrEntry 6 }
+
+pfTablesAddrBytesInBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of inbound bytes blocked as a result of this entry."
+ ::= { pfTablesAddrEntry 7 }
+
+pfTablesAddrBytesOutPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of outbound bytes passed as a result of this entry."
+ ::= { pfTablesAddrEntry 8 }
+
+pfTablesAddrBytesOutBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of outbound bytes blocked as a result of this entry."
+ ::= { pfTablesAddrEntry 9 }
+
+pfTablesAddrPktsInPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of inbound packets passed as a result of this entry."
+ ::= { pfTablesAddrEntry 10 }
+
+pfTablesAddrPktsInBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of inbound packets blocked as a result of this entry."
+ ::= { pfTablesAddrEntry 11 }
+
+pfTablesAddrPktsOutPass OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of outbound packets passed as a result of this entry."
+ ::= { pfTablesAddrEntry 12 }
+
+pfTablesAddrPktsOutBlock OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of outbound packets blocked as a result of this
+ entry."
+ ::= { pfTablesAddrEntry 13 }
+
+-- --------------------------------------------------------------------------
+
+--
+-- Altq information
+--
+
+pfAltqQueueNumber OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of queues in the active set."
+ ::= { pfAltq 1 }
+
+pfAltqQueueTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PfAltqQueueEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Table containing the rules that are active on this system."
+ ::= { pfAltq 2 }
+
+pfAltqQueueEntry OBJECT-TYPE
+ SYNTAX PfAltqQueueEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry in the pfAltqQueueTable table."
+ INDEX { pfAltqQueueIndex }
+ ::= { pfAltqQueueTable 1 }
+
+PfAltqQueueEntry ::= SEQUENCE {
+ pfAltqQueueIndex Integer32,
+ pfAltqQueueDescr OCTET STRING,
+ pfAltqQueueParent OCTET STRING,
+ pfAltqQueueScheduler INTEGER,
+ pfAltqQueueBandwidth Unsigned32,
+ pfAltqQueuePriority Integer32,
+ pfAltqQueueLimit Integer32
+}
+
+pfAltqQueueIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value, greater than zero, for each queue."
+ ::= { pfAltqQueueEntry 1 }
+
+pfAltqQueueDescr OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the queue."
+ ::= { pfAltqQueueEntry 2 }
+
+pfAltqQueueParent OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Name of the queue's parent if it has one."
+ ::= { pfAltqQueueEntry 3 }
+
+pfAltqQueueScheduler OBJECT-TYPE
+ SYNTAX INTEGER { cbq(1), hfsc(8), priq(11) }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Scheduler algorithm implemented by this queue."
+ ::= { pfAltqQueueEntry 4 }
+
+pfAltqQueueBandwidth OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Bandwitch assigned to this queue."
+ ::= { pfAltqQueueEntry 5 }
+
+pfAltqQueuePriority OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Priority level of the queue."
+ ::= { pfAltqQueueEntry 6 }
+
+pfAltqQueueLimit OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum number of packets in the queue."
+ ::= { pfAltqQueueEntry 7 }
+
+pfLabelsLblNumber OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of labeled filter rules on this system."
+ ::= { pfLabels 1 }
+
+pfLabelsLblTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PfLabelsLblEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Table of filter rules, index on pfLabelsLblIndex."
+ ::= { pfLabels 2 }
+
+pfLabelsLblEntry OBJECT-TYPE
+ SYNTAX PfLabelsLblEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Any entry in the pfLabelsLblTable containing information
+ about a particular filter rule on the system."
+ INDEX { pfLabelsLblIndex }
+ ::= { pfLabelsLblTable 1 }
+
+PfLabelsLblEntry ::= SEQUENCE {
+ pfLabelsLblIndex Integer32,
+ pfLabelsLblName OCTET STRING,
+ pfLabelsLblEvals Counter64,
+ pfLabelsLblBytesIn Counter64,
+ pfLabelsLblBytesOut Counter64,
+ pfLabelsLblPktsIn Counter64,
+ pfLabelsLblPktsOut Counter64
+}
+
+pfLabelsLblIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value, greater than zero, for each label."
+ ::= { pfLabelsLblEntry 1 }
+
+pfLabelsLblName OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the rule label."
+ ::= { pfLabelsLblEntry 2 }
+
+pfLabelsLblEvals OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of rule evaluations."
+ ::= { pfLabelsLblEntry 3 }
+
+pfLabelsLblBytesIn OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of incoming bytes matched by the rule."
+ ::= { pfLabelsLblEntry 4 }
+
+pfLabelsLblBytesOut OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of outgoing bytes matched by the rule."
+ ::= { pfLabelsLblEntry 5 }
+
+pfLabelsLblPktsIn OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of incoming packets matched by the rule."
+ ::= { pfLabelsLblEntry 6 }
+
+pfLabelsLblPktsOut OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of outgoing packets matched by the rule."
+ ::= { pfLabelsLblEntry 7 }
+
+END
diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/Makefile b/usr.sbin/bsnmpd/modules/snmp_pf/Makefile
new file mode 100644
index 0000000..6218932
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_pf/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+#
+# Author: Philip Paeps <philip@freebsd.org>
+
+MOD= pf
+SRCS= pf_snmp.c
+CFLAGS+= -DSNMPTREE_TYPES
+
+XSYM= begemotPf
+DEFS= ${MOD}_tree.def
+BMIBS= BEGEMOT-PF-MIB.txt
+
+.include <bsd.snmpmod.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
new file mode 100644
index 0000000..bc4bc35
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
@@ -0,0 +1,1800 @@
+/*-
+ * Copyright (c) 2005 Philip Paeps <philip@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 <sys/queue.h>
+#include <bsnmp/snmpmod.h>
+
+#include <net/pfvar.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "pf_oid.h"
+#include "pf_tree.h"
+
+struct lmodule *module;
+
+static int dev = -1;
+static int started;
+static uint64_t pf_tick;
+
+static struct pf_status pfs;
+
+enum { IN, OUT };
+enum { IPV4, IPV6 };
+enum { PASS, BLOCK };
+
+#define PFI_IFTYPE_GROUP 0
+#define PFI_IFTYPE_INSTANCE 1
+#define PFI_IFTYPE_DETACHED 2
+
+struct pfi_entry {
+ struct pfi_kif pfi;
+ u_int index;
+ TAILQ_ENTRY(pfi_entry) link;
+};
+TAILQ_HEAD(pfi_table, pfi_entry);
+
+static struct pfi_table pfi_table;
+static time_t pfi_table_age;
+static int pfi_table_count;
+
+#define PFI_TABLE_MAXAGE 5
+
+struct pft_entry {
+ struct pfr_tstats pft;
+ u_int index;
+ TAILQ_ENTRY(pft_entry) link;
+};
+TAILQ_HEAD(pft_table, pft_entry);
+
+static struct pft_table pft_table;
+static time_t pft_table_age;
+static int pft_table_count;
+
+#define PFT_TABLE_MAXAGE 5
+
+struct pfa_entry {
+ struct pfr_astats pfas;
+ u_int index;
+ TAILQ_ENTRY(pfa_entry) link;
+};
+TAILQ_HEAD(pfa_table, pfa_entry);
+
+static struct pfa_table pfa_table;
+static time_t pfa_table_age;
+static int pfa_table_count;
+
+#define PFA_TABLE_MAXAGE 5
+
+struct pfq_entry {
+ struct pf_altq altq;
+ u_int index;
+ TAILQ_ENTRY(pfq_entry) link;
+};
+TAILQ_HEAD(pfq_table, pfq_entry);
+
+static struct pfq_table pfq_table;
+static time_t pfq_table_age;
+static int pfq_table_count;
+
+static int altq_enabled = 0;
+
+#define PFQ_TABLE_MAXAGE 5
+
+struct pfl_entry {
+ char name[MAXPATHLEN + PF_RULE_LABEL_SIZE];
+ u_int64_t evals;
+ u_int64_t bytes[2];
+ u_int64_t pkts[2];
+ u_int index;
+ TAILQ_ENTRY(pfl_entry) link;
+};
+TAILQ_HEAD(pfl_table, pfl_entry);
+
+static struct pfl_table pfl_table;
+static time_t pfl_table_age;
+static int pfl_table_count;
+
+#define PFL_TABLE_MAXAGE 5
+
+/* Forward declarations */
+static int pfi_refresh(void);
+static int pfq_refresh(void);
+static int pfs_refresh(void);
+static int pft_refresh(void);
+static int pfa_refresh(void);
+static int pfl_refresh(void);
+static struct pfi_entry * pfi_table_find(u_int idx);
+static struct pfq_entry * pfq_table_find(u_int idx);
+static struct pft_entry * pft_table_find(u_int idx);
+static struct pfa_entry * pfa_table_find(u_int idx);
+static struct pfl_entry * pfl_table_find(u_int idx);
+
+static int altq_is_enabled(int pfdevice);
+
+int
+pf_status(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+ time_t runtime;
+ unsigned char str[128];
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ if (pfs_refresh() == -1)
+ return (SNMP_ERR_GENERR);
+
+ switch (which) {
+ case LEAF_pfStatusRunning:
+ val->v.uint32 = pfs.running;
+ break;
+ case LEAF_pfStatusRuntime:
+ runtime = (pfs.since > 0) ?
+ time(NULL) - pfs.since : 0;
+ val->v.uint32 = runtime * 100;
+ break;
+ case LEAF_pfStatusDebug:
+ val->v.uint32 = pfs.debug;
+ break;
+ case LEAF_pfStatusHostId:
+ sprintf(str, "0x%08x", ntohl(pfs.hostid));
+ return (string_get(val, str, strlen(str)));
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+pf_counter(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ if (pfs_refresh() == -1)
+ return (SNMP_ERR_GENERR);
+
+ switch (which) {
+ case LEAF_pfCounterMatch:
+ val->v.counter64 = pfs.counters[PFRES_MATCH];
+ break;
+ case LEAF_pfCounterBadOffset:
+ val->v.counter64 = pfs.counters[PFRES_BADOFF];
+ break;
+ case LEAF_pfCounterFragment:
+ val->v.counter64 = pfs.counters[PFRES_FRAG];
+ break;
+ case LEAF_pfCounterShort:
+ val->v.counter64 = pfs.counters[PFRES_SHORT];
+ break;
+ case LEAF_pfCounterNormalize:
+ val->v.counter64 = pfs.counters[PFRES_NORM];
+ break;
+ case LEAF_pfCounterMemDrop:
+ val->v.counter64 = pfs.counters[PFRES_MEMORY];
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+pf_statetable(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ if (pfs_refresh() == -1)
+ return (SNMP_ERR_GENERR);
+
+ switch (which) {
+ case LEAF_pfStateTableCount:
+ val->v.uint32 = pfs.states;
+ break;
+ case LEAF_pfStateTableSearches:
+ val->v.counter64 =
+ pfs.fcounters[FCNT_STATE_SEARCH];
+ break;
+ case LEAF_pfStateTableInserts:
+ val->v.counter64 =
+ pfs.fcounters[FCNT_STATE_INSERT];
+ break;
+ case LEAF_pfStateTableRemovals:
+ val->v.counter64 =
+ pfs.fcounters[FCNT_STATE_REMOVALS];
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+pf_srcnodes(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ if (pfs_refresh() == -1)
+ return (SNMP_ERR_GENERR);
+
+ switch (which) {
+ case LEAF_pfSrcNodesCount:
+ val->v.uint32 = pfs.src_nodes;
+ break;
+ case LEAF_pfSrcNodesSearches:
+ val->v.counter64 =
+ pfs.scounters[SCNT_SRC_NODE_SEARCH];
+ break;
+ case LEAF_pfSrcNodesInserts:
+ val->v.counter64 =
+ pfs.scounters[SCNT_SRC_NODE_INSERT];
+ break;
+ case LEAF_pfSrcNodesRemovals:
+ val->v.counter64 =
+ pfs.scounters[SCNT_SRC_NODE_REMOVALS];
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+pf_limits(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+ struct pfioc_limit pl;
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ bzero(&pl, sizeof(struct pfioc_limit));
+
+ switch (which) {
+ case LEAF_pfLimitsStates:
+ pl.index = PF_LIMIT_STATES;
+ break;
+ case LEAF_pfLimitsSrcNodes:
+ pl.index = PF_LIMIT_SRC_NODES;
+ break;
+ case LEAF_pfLimitsFrags:
+ pl.index = PF_LIMIT_FRAGS;
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ if (ioctl(dev, DIOCGETLIMIT, &pl)) {
+ syslog(LOG_ERR, "pf_limits(): ioctl(): %s",
+ strerror(errno));
+ return (SNMP_ERR_GENERR);
+ }
+
+ val->v.uint32 = pl.limit;
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+pf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+ struct pfioc_tm pt;
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ bzero(&pt, sizeof(struct pfioc_tm));
+
+ switch (which) {
+ case LEAF_pfTimeoutsTcpFirst:
+ pt.timeout = PFTM_TCP_FIRST_PACKET;
+ break;
+ case LEAF_pfTimeoutsTcpOpening:
+ pt.timeout = PFTM_TCP_OPENING;
+ break;
+ case LEAF_pfTimeoutsTcpEstablished:
+ pt.timeout = PFTM_TCP_ESTABLISHED;
+ break;
+ case LEAF_pfTimeoutsTcpClosing:
+ pt.timeout = PFTM_TCP_CLOSING;
+ break;
+ case LEAF_pfTimeoutsTcpFinWait:
+ pt.timeout = PFTM_TCP_FIN_WAIT;
+ break;
+ case LEAF_pfTimeoutsTcpClosed:
+ pt.timeout = PFTM_TCP_CLOSED;
+ break;
+ case LEAF_pfTimeoutsUdpFirst:
+ pt.timeout = PFTM_UDP_FIRST_PACKET;
+ break;
+ case LEAF_pfTimeoutsUdpSingle:
+ pt.timeout = PFTM_UDP_SINGLE;
+ break;
+ case LEAF_pfTimeoutsUdpMultiple:
+ pt.timeout = PFTM_UDP_MULTIPLE;
+ break;
+ case LEAF_pfTimeoutsIcmpFirst:
+ pt.timeout = PFTM_ICMP_FIRST_PACKET;
+ break;
+ case LEAF_pfTimeoutsIcmpError:
+ pt.timeout = PFTM_ICMP_ERROR_REPLY;
+ break;
+ case LEAF_pfTimeoutsOtherFirst:
+ pt.timeout = PFTM_OTHER_FIRST_PACKET;
+ break;
+ case LEAF_pfTimeoutsOtherSingle:
+ pt.timeout = PFTM_OTHER_SINGLE;
+ break;
+ case LEAF_pfTimeoutsOtherMultiple:
+ pt.timeout = PFTM_OTHER_MULTIPLE;
+ break;
+ case LEAF_pfTimeoutsFragment:
+ pt.timeout = PFTM_FRAG;
+ break;
+ case LEAF_pfTimeoutsInterval:
+ pt.timeout = PFTM_INTERVAL;
+ break;
+ case LEAF_pfTimeoutsAdaptiveStart:
+ pt.timeout = PFTM_ADAPTIVE_START;
+ break;
+ case LEAF_pfTimeoutsAdaptiveEnd:
+ pt.timeout = PFTM_ADAPTIVE_END;
+ break;
+ case LEAF_pfTimeoutsSrcNode:
+ pt.timeout = PFTM_SRC_NODE;
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ if (ioctl(dev, DIOCGETTIMEOUT, &pt)) {
+ syslog(LOG_ERR, "pf_timeouts(): ioctl(): %s",
+ strerror(errno));
+ return (SNMP_ERR_GENERR);
+ }
+
+ val->v.integer = pt.seconds;
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+pf_logif(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+ unsigned char str[IFNAMSIZ];
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ if (pfs_refresh() == -1)
+ return (SNMP_ERR_GENERR);
+
+ switch (which) {
+ case LEAF_pfLogInterfaceName:
+ strlcpy(str, pfs.ifname, sizeof str);
+ return (string_get(val, str, strlen(str)));
+ case LEAF_pfLogInterfaceIp4BytesIn:
+ val->v.counter64 = pfs.bcounters[IPV4][IN];
+ break;
+ case LEAF_pfLogInterfaceIp4BytesOut:
+ val->v.counter64 = pfs.bcounters[IPV4][OUT];
+ break;
+ case LEAF_pfLogInterfaceIp4PktsInPass:
+ val->v.counter64 =
+ pfs.pcounters[IPV4][IN][PF_PASS];
+ break;
+ case LEAF_pfLogInterfaceIp4PktsInDrop:
+ val->v.counter64 =
+ pfs.pcounters[IPV4][IN][PF_DROP];
+ break;
+ case LEAF_pfLogInterfaceIp4PktsOutPass:
+ val->v.counter64 =
+ pfs.pcounters[IPV4][OUT][PF_PASS];
+ break;
+ case LEAF_pfLogInterfaceIp4PktsOutDrop:
+ val->v.counter64 =
+ pfs.pcounters[IPV4][OUT][PF_DROP];
+ break;
+ case LEAF_pfLogInterfaceIp6BytesIn:
+ val->v.counter64 = pfs.bcounters[IPV6][IN];
+ break;
+ case LEAF_pfLogInterfaceIp6BytesOut:
+ val->v.counter64 = pfs.bcounters[IPV6][OUT];
+ break;
+ case LEAF_pfLogInterfaceIp6PktsInPass:
+ val->v.counter64 =
+ pfs.pcounters[IPV6][IN][PF_PASS];
+ break;
+ case LEAF_pfLogInterfaceIp6PktsInDrop:
+ val->v.counter64 =
+ pfs.pcounters[IPV6][IN][PF_DROP];
+ break;
+ case LEAF_pfLogInterfaceIp6PktsOutPass:
+ val->v.counter64 =
+ pfs.pcounters[IPV6][OUT][PF_PASS];
+ break;
+ case LEAF_pfLogInterfaceIp6PktsOutDrop:
+ val->v.counter64 =
+ pfs.pcounters[IPV6][OUT][PF_DROP];
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+pf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
+ if (pfi_refresh() == -1)
+ return (SNMP_ERR_GENERR);
+
+ switch (which) {
+ case LEAF_pfInterfacesIfNumber:
+ val->v.uint32 = pfi_table_count;
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+ struct pfi_entry *e = NULL;
+
+ if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
+ pfi_refresh();
+
+ switch (op) {
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_GETNEXT:
+ if ((e = NEXT_OBJECT_INT(&pfi_table,
+ &val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ val->var.len = sub + 1;
+ val->var.subs[sub] = e->index;
+ break;
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((e = pfi_table_find(val->var.subs[sub])) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_ROLLBACK:
+ default:
+ abort();
+ }
+
+ switch (which) {
+ case LEAF_pfInterfacesIfDescr:
+ return (string_get(val, e->pfi.pfik_name, -1));
+ case LEAF_pfInterfacesIfType:
+ val->v.integer = PFI_IFTYPE_INSTANCE;
+ break;
+ case LEAF_pfInterfacesIfTZero:
+ val->v.uint32 =
+ (time(NULL) - e->pfi.pfik_tzero) * 100;
+ break;
+ case LEAF_pfInterfacesIfRefsState:
+ val->v.uint32 = e->pfi.pfik_states;
+ break;
+ case LEAF_pfInterfacesIfRefsRule:
+ val->v.uint32 = e->pfi.pfik_rules;
+ break;
+ case LEAF_pfInterfacesIf4BytesInPass:
+ val->v.counter64 =
+ e->pfi.pfik_bytes[IPV4][IN][PASS];
+ break;
+ case LEAF_pfInterfacesIf4BytesInBlock:
+ val->v.counter64 =
+ e->pfi.pfik_bytes[IPV4][IN][BLOCK];
+ break;
+ case LEAF_pfInterfacesIf4BytesOutPass:
+ val->v.counter64 =
+ e->pfi.pfik_bytes[IPV4][OUT][PASS];
+ break;
+ case LEAF_pfInterfacesIf4BytesOutBlock:
+ val->v.counter64 =
+ e->pfi.pfik_bytes[IPV4][OUT][BLOCK];
+ break;
+ case LEAF_pfInterfacesIf4PktsInPass:
+ val->v.counter64 =
+ e->pfi.pfik_packets[IPV4][IN][PASS];
+ break;
+ case LEAF_pfInterfacesIf4PktsInBlock:
+ val->v.counter64 =
+ e->pfi.pfik_packets[IPV4][IN][BLOCK];
+ break;
+ case LEAF_pfInterfacesIf4PktsOutPass:
+ val->v.counter64 =
+ e->pfi.pfik_packets[IPV4][OUT][PASS];
+ break;
+ case LEAF_pfInterfacesIf4PktsOutBlock:
+ val->v.counter64 =
+ e->pfi.pfik_packets[IPV4][OUT][BLOCK];
+ break;
+ case LEAF_pfInterfacesIf6BytesInPass:
+ val->v.counter64 =
+ e->pfi.pfik_bytes[IPV6][IN][PASS];
+ break;
+ case LEAF_pfInterfacesIf6BytesInBlock:
+ val->v.counter64 =
+ e->pfi.pfik_bytes[IPV6][IN][BLOCK];
+ break;
+ case LEAF_pfInterfacesIf6BytesOutPass:
+ val->v.counter64 =
+ e->pfi.pfik_bytes[IPV6][OUT][PASS];
+ break;
+ case LEAF_pfInterfacesIf6BytesOutBlock:
+ val->v.counter64 =
+ e->pfi.pfik_bytes[IPV6][OUT][BLOCK];
+ break;
+ case LEAF_pfInterfacesIf6PktsInPass:
+ val->v.counter64 =
+ e->pfi.pfik_packets[IPV6][IN][PASS];
+ break;
+ case LEAF_pfInterfacesIf6PktsInBlock:
+ val->v.counter64 =
+ e->pfi.pfik_packets[IPV6][IN][BLOCK];
+ break;
+ case LEAF_pfInterfacesIf6PktsOutPass:
+ val->v.counter64 =
+ e->pfi.pfik_packets[IPV6][OUT][PASS];
+ break;
+ case LEAF_pfInterfacesIf6PktsOutBlock:
+ val->v.counter64 =
+ e->pfi.pfik_packets[IPV6][OUT][BLOCK];
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
+ if (pft_refresh() == -1)
+ return (SNMP_ERR_GENERR);
+
+ switch (which) {
+ case LEAF_pfTablesTblNumber:
+ val->v.uint32 = pft_table_count;
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+ struct pft_entry *e = NULL;
+
+ if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
+ pft_refresh();
+
+ switch (op) {
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_GETNEXT:
+ if ((e = NEXT_OBJECT_INT(&pft_table,
+ &val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ val->var.len = sub + 1;
+ val->var.subs[sub] = e->index;
+ break;
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((e = pft_table_find(val->var.subs[sub])) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_ROLLBACK:
+ default:
+ abort();
+ }
+
+ switch (which) {
+ case LEAF_pfTablesTblDescr:
+ return (string_get(val, e->pft.pfrts_name, -1));
+ case LEAF_pfTablesTblCount:
+ val->v.integer = e->pft.pfrts_cnt;
+ break;
+ case LEAF_pfTablesTblTZero:
+ val->v.uint32 =
+ (time(NULL) - e->pft.pfrts_tzero) * 100;
+ break;
+ case LEAF_pfTablesTblRefsAnchor:
+ val->v.integer =
+ e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR];
+ break;
+ case LEAF_pfTablesTblRefsRule:
+ val->v.integer =
+ e->pft.pfrts_refcnt[PFR_REFCNT_RULE];
+ break;
+ case LEAF_pfTablesTblEvalMatch:
+ val->v.counter64 = e->pft.pfrts_match;
+ break;
+ case LEAF_pfTablesTblEvalNoMatch:
+ val->v.counter64 = e->pft.pfrts_nomatch;
+ break;
+ case LEAF_pfTablesTblBytesInPass:
+ val->v.counter64 =
+ e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS];
+ break;
+ case LEAF_pfTablesTblBytesInBlock:
+ val->v.counter64 =
+ e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
+ break;
+ case LEAF_pfTablesTblBytesInXPass:
+ val->v.counter64 =
+ e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS];
+ break;
+ case LEAF_pfTablesTblBytesOutPass:
+ val->v.counter64 =
+ e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS];
+ break;
+ case LEAF_pfTablesTblBytesOutBlock:
+ val->v.counter64 =
+ e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
+ break;
+ case LEAF_pfTablesTblBytesOutXPass:
+ val->v.counter64 =
+ e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS];
+ break;
+ case LEAF_pfTablesTblPktsInPass:
+ val->v.counter64 =
+ e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS];
+ break;
+ case LEAF_pfTablesTblPktsInBlock:
+ val->v.counter64 =
+ e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK];
+ break;
+ case LEAF_pfTablesTblPktsInXPass:
+ val->v.counter64 =
+ e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS];
+ break;
+ case LEAF_pfTablesTblPktsOutPass:
+ val->v.counter64 =
+ e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS];
+ break;
+ case LEAF_pfTablesTblPktsOutBlock:
+ val->v.counter64 =
+ e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
+ break;
+ case LEAF_pfTablesTblPktsOutXPass:
+ val->v.counter64 =
+ e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS];
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val,
+ u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+ struct pfa_entry *e = NULL;
+
+ if ((time(NULL) - pfa_table_age) > PFA_TABLE_MAXAGE)
+ pfa_refresh();
+
+ switch (op) {
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_GETNEXT:
+ if ((e = NEXT_OBJECT_INT(&pfa_table,
+ &val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ val->var.len = sub + 1;
+ val->var.subs[sub] = e->index;
+ break;
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((e = pfa_table_find(val->var.subs[sub])) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_ROLLBACK:
+ default:
+ abort();
+ }
+
+ switch (which) {
+ case LEAF_pfTablesAddrNetType:
+ if (e->pfas.pfras_a.pfra_af == AF_INET)
+ val->v.integer = pfTablesAddrNetType_ipv4;
+ else if (e->pfas.pfras_a.pfra_af == AF_INET6)
+ val->v.integer = pfTablesAddrNetType_ipv6;
+ else
+ return (SNMP_ERR_GENERR);
+ break;
+ case LEAF_pfTablesAddrNet:
+ if (e->pfas.pfras_a.pfra_af == AF_INET) {
+ return (string_get(val,
+ (u_char *)&e->pfas.pfras_a.pfra_ip4addr, 4));
+ } else if (e->pfas.pfras_a.pfra_af == AF_INET6)
+ return (string_get(val,
+ (u_char *)&e->pfas.pfras_a.pfra_ip6addr, 16));
+ else
+ return (SNMP_ERR_GENERR);
+ break;
+ case LEAF_pfTablesAddrPrefix:
+ val->v.integer = (int32_t) e->pfas.pfras_a.pfra_net;
+ break;
+ case LEAF_pfTablesAddrTZero:
+ val->v.uint32 =
+ (time(NULL) - e->pfas.pfras_tzero) * 100;
+ break;
+ case LEAF_pfTablesAddrBytesInPass:
+ val->v.counter64 =
+ e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_PASS];
+ break;
+ case LEAF_pfTablesAddrBytesInBlock:
+ val->v.counter64 =
+ e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
+ break;
+ case LEAF_pfTablesAddrBytesOutPass:
+ val->v.counter64 =
+ e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_PASS];
+ break;
+ case LEAF_pfTablesAddrBytesOutBlock:
+ val->v.counter64 =
+ e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
+ break;
+ case LEAF_pfTablesAddrPktsInPass:
+ val->v.counter64 =
+ e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_PASS];
+ break;
+ case LEAF_pfTablesAddrPktsInBlock:
+ val->v.counter64 =
+ e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_BLOCK];
+ break;
+ case LEAF_pfTablesAddrPktsOutPass:
+ val->v.counter64 =
+ e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_PASS];
+ break;
+ case LEAF_pfTablesAddrPktsOutBlock:
+ val->v.counter64 =
+ e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
+ break;
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+pf_altq(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+
+ if (!altq_enabled)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
+ if (pfq_refresh() == -1)
+ return (SNMP_ERR_GENERR);
+
+ switch (which) {
+ case LEAF_pfAltqQueueNumber:
+ val->v.uint32 = pfq_table_count;
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+ return (SNMP_ERR_GENERR);
+}
+
+int
+pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+ struct pfq_entry *e = NULL;
+
+ if (!altq_enabled)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
+ pfq_refresh();
+
+ switch (op) {
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_GETNEXT:
+ if ((e = NEXT_OBJECT_INT(&pfq_table,
+ &val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ val->var.len = sub + 1;
+ val->var.subs[sub] = e->index;
+ break;
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((e = pfq_table_find(val->var.subs[sub])) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_ROLLBACK:
+ default:
+ abort();
+ }
+
+ switch (which) {
+ case LEAF_pfAltqQueueDescr:
+ return (string_get(val, e->altq.qname, -1));
+ case LEAF_pfAltqQueueParent:
+ return (string_get(val, e->altq.parent, -1));
+ case LEAF_pfAltqQueueScheduler:
+ val->v.integer = e->altq.scheduler;
+ break;
+ case LEAF_pfAltqQueueBandwidth:
+ val->v.uint32 = e->altq.bandwidth;
+ break;
+ case LEAF_pfAltqQueuePriority:
+ val->v.integer = e->altq.priority;
+ break;
+ case LEAF_pfAltqQueueLimit:
+ val->v.integer = e->altq.qlimit;
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+pf_labels(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ if (op == SNMP_OP_GET) {
+ if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
+ if (pfl_refresh() == -1)
+ return (SNMP_ERR_GENERR);
+
+ switch (which) {
+ case LEAF_pfLabelsLblNumber:
+ val->v.uint32 = pfl_table_count;
+ break;
+
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+ return (SNMP_ERR_GENERR);
+}
+
+int
+pf_lbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
+ u_int sub, u_int __unused vindex, enum snmp_op op)
+{
+ asn_subid_t which = val->var.subs[sub - 1];
+ struct pfl_entry *e = NULL;
+
+ if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
+ pfl_refresh();
+
+ switch (op) {
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_GETNEXT:
+ if ((e = NEXT_OBJECT_INT(&pfl_table,
+ &val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ val->var.len = sub + 1;
+ val->var.subs[sub] = e->index;
+ break;
+ case SNMP_OP_GET:
+ if (val->var.len - sub != 1)
+ return (SNMP_ERR_NOSUCHNAME);
+ if ((e = pfl_table_find(val->var.subs[sub])) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_ROLLBACK:
+ default:
+ abort();
+ }
+
+ switch (which) {
+ case LEAF_pfLabelsLblName:
+ return (string_get(val, e->name, -1));
+ case LEAF_pfLabelsLblEvals:
+ val->v.counter64 = e->evals;
+ break;
+ case LEAF_pfLabelsLblBytesIn:
+ val->v.counter64 = e->bytes[IN];
+ break;
+ case LEAF_pfLabelsLblBytesOut:
+ val->v.counter64 = e->bytes[OUT];
+ break;
+ case LEAF_pfLabelsLblPktsIn:
+ val->v.counter64 = e->pkts[IN];
+ break;
+ case LEAF_pfLabelsLblPktsOut:
+ val->v.counter64 = e->pkts[OUT];
+ break;
+ default:
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+static struct pfi_entry *
+pfi_table_find(u_int idx)
+{
+ struct pfi_entry *e;
+
+ TAILQ_FOREACH(e, &pfi_table, link)
+ if (e->index == idx)
+ return (e);
+ return (NULL);
+}
+
+static struct pfq_entry *
+pfq_table_find(u_int idx)
+{
+ struct pfq_entry *e;
+
+ TAILQ_FOREACH(e, &pfq_table, link)
+ if (e->index == idx)
+ return (e);
+ return (NULL);
+}
+
+static struct pft_entry *
+pft_table_find(u_int idx)
+{
+ struct pft_entry *e;
+
+ TAILQ_FOREACH(e, &pft_table, link)
+ if (e->index == idx)
+ return (e);
+ return (NULL);
+}
+
+static struct pfa_entry *
+pfa_table_find(u_int idx)
+{
+ struct pfa_entry *e;
+
+ TAILQ_FOREACH(e, &pfa_table, link)
+ if (e->index == idx)
+ return (e);
+ return (NULL);
+}
+
+static struct pfl_entry *
+pfl_table_find(u_int idx)
+{
+ struct pfl_entry *e;
+
+ TAILQ_FOREACH(e, &pfl_table, link)
+ if (e->index == idx)
+ return (e);
+
+ return (NULL);
+}
+
+static int
+pfi_refresh(void)
+{
+ struct pfioc_iface io;
+ struct pfi_kif *p = NULL;
+ struct pfi_entry *e;
+ int i, numifs = 1;
+
+ if (started && this_tick <= pf_tick)
+ return (0);
+
+ while (!TAILQ_EMPTY(&pfi_table)) {
+ e = TAILQ_FIRST(&pfi_table);
+ TAILQ_REMOVE(&pfi_table, e, link);
+ free(e);
+ }
+
+ bzero(&io, sizeof(io));
+ io.pfiio_esize = sizeof(struct pfi_kif);
+
+ for (;;) {
+ p = reallocf(p, numifs * sizeof(struct pfi_kif));
+ if (p == NULL) {
+ syslog(LOG_ERR, "pfi_refresh(): reallocf() numifs=%d: %s",
+ numifs, strerror(errno));
+ goto err2;
+ }
+ io.pfiio_size = numifs;
+ io.pfiio_buffer = p;
+
+ if (ioctl(dev, DIOCIGETIFACES, &io)) {
+ syslog(LOG_ERR, "pfi_refresh(): ioctl(): %s",
+ strerror(errno));
+ goto err2;
+ }
+
+ if (numifs >= io.pfiio_size)
+ break;
+
+ numifs = io.pfiio_size;
+ }
+
+ for (i = 0; i < numifs; i++) {
+ e = malloc(sizeof(struct pfi_entry));
+ if (e == NULL)
+ goto err1;
+ e->index = i + 1;
+ memcpy(&e->pfi, p+i, sizeof(struct pfi_kif));
+ TAILQ_INSERT_TAIL(&pfi_table, e, link);
+ }
+
+ pfi_table_age = time(NULL);
+ pfi_table_count = numifs;
+ pf_tick = this_tick;
+
+ free(p);
+ return (0);
+
+err1:
+ while (!TAILQ_EMPTY(&pfi_table)) {
+ e = TAILQ_FIRST(&pfi_table);
+ TAILQ_REMOVE(&pfi_table, e, link);
+ free(e);
+ }
+err2:
+ free(p);
+ return(-1);
+}
+
+static int
+pfq_refresh(void)
+{
+ struct pfioc_altq pa;
+ struct pfq_entry *e;
+ int i, numqs, ticket;
+
+ if (started && this_tick <= pf_tick)
+ return (0);
+
+ while (!TAILQ_EMPTY(&pfq_table)) {
+ e = TAILQ_FIRST(&pfq_table);
+ TAILQ_REMOVE(&pfq_table, e, link);
+ free(e);
+ }
+
+ bzero(&pa, sizeof(pa));
+
+ if (ioctl(dev, DIOCGETALTQS, &pa)) {
+ syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ numqs = pa.nr;
+ ticket = pa.ticket;
+
+ for (i = 0; i < numqs; i++) {
+ e = malloc(sizeof(struct pfq_entry));
+ if (e == NULL) {
+ syslog(LOG_ERR, "pfq_refresh(): "
+ "malloc(): %s",
+ strerror(errno));
+ goto err;
+ }
+ pa.ticket = ticket;
+ pa.nr = i;
+
+ if (ioctl(dev, DIOCGETALTQ, &pa)) {
+ syslog(LOG_ERR, "pfq_refresh(): "
+ "ioctl(DIOCGETALTQ): %s",
+ strerror(errno));
+ goto err;
+ }
+
+ if (pa.altq.qid > 0) {
+ memcpy(&e->altq, &pa.altq, sizeof(struct pf_altq));
+ e->index = pa.altq.qid;
+ pfq_table_count = i;
+ INSERT_OBJECT_INT_LINK_INDEX(e, &pfq_table, link, index);
+ }
+ }
+
+ pfq_table_age = time(NULL);
+ pf_tick = this_tick;
+
+ return (0);
+err:
+ free(e);
+ while (!TAILQ_EMPTY(&pfq_table)) {
+ e = TAILQ_FIRST(&pfq_table);
+ TAILQ_REMOVE(&pfq_table, e, link);
+ free(e);
+ }
+ return(-1);
+}
+
+static int
+pfs_refresh(void)
+{
+ if (started && this_tick <= pf_tick)
+ return (0);
+
+ bzero(&pfs, sizeof(struct pf_status));
+
+ if (ioctl(dev, DIOCGETSTATUS, &pfs)) {
+ syslog(LOG_ERR, "pfs_refresh(): ioctl(): %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ pf_tick = this_tick;
+ return (0);
+}
+
+static int
+pft_refresh(void)
+{
+ struct pfioc_table io;
+ struct pfr_tstats *t = NULL;
+ struct pft_entry *e;
+ int i, numtbls = 1;
+
+ if (started && this_tick <= pf_tick)
+ return (0);
+
+ while (!TAILQ_EMPTY(&pft_table)) {
+ e = TAILQ_FIRST(&pft_table);
+ TAILQ_REMOVE(&pft_table, e, link);
+ free(e);
+ }
+
+ bzero(&io, sizeof(io));
+ io.pfrio_esize = sizeof(struct pfr_tstats);
+
+ for (;;) {
+ t = reallocf(t, numtbls * sizeof(struct pfr_tstats));
+ if (t == NULL) {
+ syslog(LOG_ERR, "pft_refresh(): reallocf() numtbls=%d: %s",
+ numtbls, strerror(errno));
+ goto err2;
+ }
+ io.pfrio_size = numtbls;
+ io.pfrio_buffer = t;
+
+ if (ioctl(dev, DIOCRGETTSTATS, &io)) {
+ syslog(LOG_ERR, "pft_refresh(): ioctl(): %s",
+ strerror(errno));
+ goto err2;
+ }
+
+ if (numtbls >= io.pfrio_size)
+ break;
+
+ numtbls = io.pfrio_size;
+ }
+
+ for (i = 0; i < numtbls; i++) {
+ e = malloc(sizeof(struct pft_entry));
+ if (e == NULL)
+ goto err1;
+ e->index = i + 1;
+ memcpy(&e->pft, t+i, sizeof(struct pfr_tstats));
+ TAILQ_INSERT_TAIL(&pft_table, e, link);
+ }
+
+ pft_table_age = time(NULL);
+ pft_table_count = numtbls;
+ pf_tick = this_tick;
+
+ free(t);
+ return (0);
+err1:
+ while (!TAILQ_EMPTY(&pft_table)) {
+ e = TAILQ_FIRST(&pft_table);
+ TAILQ_REMOVE(&pft_table, e, link);
+ free(e);
+ }
+err2:
+ free(t);
+ return(-1);
+}
+
+static int
+pfa_table_addrs(u_int sidx, struct pfr_table *pt)
+{
+ struct pfioc_table io;
+ struct pfr_astats *t = NULL;
+ struct pfa_entry *e;
+ int i, numaddrs = 1;
+
+ if (pt == NULL)
+ return (-1);
+
+ memset(&io, 0, sizeof(io));
+ strlcpy(io.pfrio_table.pfrt_name, pt->pfrt_name,
+ sizeof(io.pfrio_table.pfrt_name));
+
+ for (;;) {
+ t = reallocf(t, numaddrs * sizeof(struct pfr_astats));
+ if (t == NULL) {
+ syslog(LOG_ERR, "pfa_table_addrs(): reallocf(): %s",
+ strerror(errno));
+ numaddrs = -1;
+ goto error;
+ }
+
+ memset(t, 0, sizeof(*t));
+ io.pfrio_size = numaddrs;
+ io.pfrio_buffer = t;
+ io.pfrio_esize = sizeof(struct pfr_astats);
+
+ if (ioctl(dev, DIOCRGETASTATS, &io)) {
+ syslog(LOG_ERR, "pfa_table_addrs(): ioctl() on %s: %s",
+ pt->pfrt_name, strerror(errno));
+ numaddrs = -1;
+ break;
+ }
+
+ if (numaddrs >= io.pfrio_size)
+ break;
+
+ numaddrs = io.pfrio_size;
+ }
+
+ for (i = 0; i < numaddrs; i++) {
+ if ((t + i)->pfras_a.pfra_af != AF_INET &&
+ (t + i)->pfras_a.pfra_af != AF_INET6) {
+ numaddrs = i;
+ break;
+ }
+
+ e = (struct pfa_entry *)malloc(sizeof(struct pfa_entry));
+ if (e == NULL) {
+ syslog(LOG_ERR, "pfa_table_addrs(): malloc(): %s",
+ strerror(errno));
+ numaddrs = -1;
+ break;
+ }
+ e->index = sidx + i;
+ memcpy(&e->pfas, t + i, sizeof(struct pfr_astats));
+ TAILQ_INSERT_TAIL(&pfa_table, e, link);
+ }
+
+ free(t);
+error:
+ return (numaddrs);
+}
+
+static int
+pfa_refresh(void)
+{
+ struct pfioc_table io;
+ struct pfr_table *pt = NULL, *it = NULL;
+ struct pfa_entry *e;
+ int i, numtbls = 1, cidx, naddrs;
+
+ if (started && this_tick <= pf_tick)
+ return (0);
+
+ while (!TAILQ_EMPTY(&pfa_table)) {
+ e = TAILQ_FIRST(&pfa_table);
+ TAILQ_REMOVE(&pfa_table, e, link);
+ free(e);
+ }
+
+ memset(&io, 0, sizeof(io));
+ io.pfrio_esize = sizeof(struct pfr_table);
+
+ for (;;) {
+ pt = reallocf(pt, numtbls * sizeof(struct pfr_table));
+ if (pt == NULL) {
+ syslog(LOG_ERR, "pfa_refresh(): reallocf() %s",
+ strerror(errno));
+ return (-1);
+ }
+ memset(pt, 0, sizeof(*pt));
+ io.pfrio_size = numtbls;
+ io.pfrio_buffer = pt;
+
+ if (ioctl(dev, DIOCRGETTABLES, &io)) {
+ syslog(LOG_ERR, "pfa_refresh(): ioctl(): %s",
+ strerror(errno));
+ goto err2;
+ }
+
+ if (numtbls >= io.pfrio_size)
+ break;
+
+ numtbls = io.pfrio_size;
+ }
+
+ cidx = 1;
+
+ for (it = pt, i = 0; i < numtbls; it++, i++) {
+ /*
+ * Skip the table if not active - ioctl(DIOCRGETASTATS) will
+ * return ESRCH for this entry anyway.
+ */
+ if (!(it->pfrt_flags & PFR_TFLAG_ACTIVE))
+ continue;
+
+ if ((naddrs = pfa_table_addrs(cidx, it)) < 0)
+ goto err1;
+
+ cidx += naddrs;
+ }
+
+ pfa_table_age = time(NULL);
+ pfa_table_count = cidx;
+ pf_tick = this_tick;
+
+ free(pt);
+ return (0);
+err1:
+ while (!TAILQ_EMPTY(&pfa_table)) {
+ e = TAILQ_FIRST(&pfa_table);
+ TAILQ_REMOVE(&pfa_table, e, link);
+ free(e);
+ }
+
+err2:
+ free(pt);
+ return (-1);
+}
+
+static int
+pfl_scan_ruleset(const char *path)
+{
+ struct pfioc_rule pr;
+ struct pfl_entry *e;
+ u_int32_t nr, i;
+
+ bzero(&pr, sizeof(pr));
+ strlcpy(pr.anchor, path, sizeof(pr.anchor));
+ pr.rule.action = PF_PASS;
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s",
+ strerror(errno));
+ goto err;
+ }
+
+ for (nr = pr.nr, i = 0; i < nr; i++) {
+ pr.nr = i;
+ if (ioctl(dev, DIOCGETRULE, &pr)) {
+ syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULE):"
+ " %s", strerror(errno));
+ goto err;
+ }
+
+ if (pr.rule.label[0]) {
+ e = (struct pfl_entry *)malloc(sizeof(*e));
+ if (e == NULL)
+ goto err;
+
+ strlcpy(e->name, path, sizeof(e->name));
+ if (path[0])
+ strlcat(e->name, "/", sizeof(e->name));
+ strlcat(e->name, pr.rule.label, sizeof(e->name));
+
+ e->evals = pr.rule.evaluations;
+ e->bytes[IN] = pr.rule.bytes[IN];
+ e->bytes[OUT] = pr.rule.bytes[OUT];
+ e->pkts[IN] = pr.rule.packets[IN];
+ e->pkts[OUT] = pr.rule.packets[OUT];
+ e->index = ++pfl_table_count;
+
+ TAILQ_INSERT_TAIL(&pfl_table, e, link);
+ }
+ }
+
+ return (0);
+
+err:
+ return (-1);
+}
+
+static int
+pfl_walk_rulesets(const char *path)
+{
+ struct pfioc_ruleset prs;
+ char newpath[MAXPATHLEN];
+ u_int32_t nr, i;
+
+ if (pfl_scan_ruleset(path))
+ goto err;
+
+ bzero(&prs, sizeof(prs));
+ strlcpy(prs.path, path, sizeof(prs.path));
+ if (ioctl(dev, DIOCGETRULESETS, &prs)) {
+ syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESETS): %s",
+ strerror(errno));
+ goto err;
+ }
+
+ for (nr = prs.nr, i = 0; i < nr; i++) {
+ prs.nr = i;
+ if (ioctl(dev, DIOCGETRULESET, &prs)) {
+ syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESET):"
+ " %s", strerror(errno));
+ goto err;
+ }
+
+ if (strcmp(prs.name, PF_RESERVED_ANCHOR) == 0)
+ continue;
+
+ strlcpy(newpath, path, sizeof(newpath));
+ if (path[0])
+ strlcat(newpath, "/", sizeof(newpath));
+
+ strlcat(newpath, prs.name, sizeof(newpath));
+ if (pfl_walk_rulesets(newpath))
+ goto err;
+ }
+
+ return (0);
+
+err:
+ return (-1);
+}
+
+static int
+pfl_refresh(void)
+{
+ struct pfl_entry *e;
+
+ if (started && this_tick <= pf_tick)
+ return (0);
+
+ while (!TAILQ_EMPTY(&pfl_table)) {
+ e = TAILQ_FIRST(&pfl_table);
+ TAILQ_REMOVE(&pfl_table, e, link);
+ free(e);
+ }
+ pfl_table_count = 0;
+
+ if (pfl_walk_rulesets(""))
+ goto err;
+
+ pfl_table_age = time(NULL);
+ pf_tick = this_tick;
+
+ return (0);
+
+err:
+ while (!TAILQ_EMPTY(&pfl_table)) {
+ e = TAILQ_FIRST(&pfl_table);
+ TAILQ_REMOVE(&pfl_table, e, link);
+ free(e);
+ }
+ pfl_table_count = 0;
+
+ return (-1);
+}
+
+/*
+ * check whether altq support is enabled in kernel
+ */
+
+static int
+altq_is_enabled(int pfdev)
+{
+ struct pfioc_altq pa;
+
+ errno = 0;
+ if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
+ if (errno == ENODEV) {
+ syslog(LOG_INFO, "No ALTQ support in kernel\n"
+ "ALTQ related functions disabled\n");
+ return (0);
+ } else
+ syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",
+ strerror(errno));
+ return (-1);
+ }
+ return (1);
+}
+
+/*
+ * Implement the bsnmpd module interface
+ */
+static int
+pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])
+{
+ module = mod;
+
+ if ((dev = open("/dev/pf", O_RDONLY)) == -1) {
+ syslog(LOG_ERR, "pf_init(): open(): %s\n",
+ strerror(errno));
+ return (-1);
+ }
+
+ if ((altq_enabled = altq_is_enabled(dev)) == -1) {
+ syslog(LOG_ERR, "pf_init(): altq test failed");
+ return (-1);
+ }
+
+ /* Prepare internal state */
+ TAILQ_INIT(&pfi_table);
+ TAILQ_INIT(&pfq_table);
+ TAILQ_INIT(&pft_table);
+ TAILQ_INIT(&pfa_table);
+ TAILQ_INIT(&pfl_table);
+
+ pfi_refresh();
+ if (altq_enabled) {
+ pfq_refresh();
+ }
+
+ pfs_refresh();
+ pft_refresh();
+ pfa_refresh();
+ pfl_refresh();
+
+ started = 1;
+
+ return (0);
+}
+
+static int
+pf_fini(void)
+{
+ struct pfi_entry *i1, *i2;
+ struct pfq_entry *q1, *q2;
+ struct pft_entry *t1, *t2;
+ struct pfa_entry *a1, *a2;
+ struct pfl_entry *l1, *l2;
+
+ /* Empty the list of interfaces */
+ i1 = TAILQ_FIRST(&pfi_table);
+ while (i1 != NULL) {
+ i2 = TAILQ_NEXT(i1, link);
+ free(i1);
+ i1 = i2;
+ }
+
+ /* List of queues */
+ q1 = TAILQ_FIRST(&pfq_table);
+ while (q1 != NULL) {
+ q2 = TAILQ_NEXT(q1, link);
+ free(q1);
+ q1 = q2;
+ }
+
+ /* List of tables */
+ t1 = TAILQ_FIRST(&pft_table);
+ while (t1 != NULL) {
+ t2 = TAILQ_NEXT(t1, link);
+ free(t1);
+ t1 = t2;
+ }
+
+ /* List of table addresses */
+ a1 = TAILQ_FIRST(&pfa_table);
+ while (a1 != NULL) {
+ a2 = TAILQ_NEXT(a1, link);
+ free(a1);
+ a1 = a2;
+ }
+
+ /* And the list of labeled filter rules */
+ l1 = TAILQ_FIRST(&pfl_table);
+ while (l1 != NULL) {
+ l2 = TAILQ_NEXT(l1, link);
+ free(l1);
+ l1 = l2;
+ }
+
+ close(dev);
+ return (0);
+}
+
+static void
+pf_dump(void)
+{
+ pfi_refresh();
+ if (altq_enabled) {
+ pfq_refresh();
+ }
+ pft_refresh();
+ pfa_refresh();
+ pfl_refresh();
+
+ syslog(LOG_ERR, "Dump: pfi_table_age = %jd",
+ (intmax_t)pfi_table_age);
+ syslog(LOG_ERR, "Dump: pfi_table_count = %d",
+ pfi_table_count);
+
+ syslog(LOG_ERR, "Dump: pfq_table_age = %jd",
+ (intmax_t)pfq_table_age);
+ syslog(LOG_ERR, "Dump: pfq_table_count = %d",
+ pfq_table_count);
+
+ syslog(LOG_ERR, "Dump: pft_table_age = %jd",
+ (intmax_t)pft_table_age);
+ syslog(LOG_ERR, "Dump: pft_table_count = %d",
+ pft_table_count);
+
+ syslog(LOG_ERR, "Dump: pfa_table_age = %jd",
+ (intmax_t)pfa_table_age);
+ syslog(LOG_ERR, "Dump: pfa_table_count = %d",
+ pfa_table_count);
+
+ syslog(LOG_ERR, "Dump: pfl_table_age = %jd",
+ (intmax_t)pfl_table_age);
+ syslog(LOG_ERR, "Dump: pfl_table_count = %d",
+ pfl_table_count);
+}
+
+const struct snmp_module config = {
+ .comment = "This module implements a MIB for the pf packet filter.",
+ .init = pf_init,
+ .fini = pf_fini,
+ .tree = pf_ctree,
+ .dump = pf_dump,
+ .tree_size = pf_CTREE_SIZE,
+};
diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def b/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def
new file mode 100644
index 0000000..7b791b3
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def
@@ -0,0 +1,210 @@
+#
+# Copyright (c) 2010 Philip Paeps <philip@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$
+#
+
+(1 internet
+ (4 private
+ (1 enterprises
+ (12325 fokus
+ (1 begemot
+ (200 begemotPf
+ (1 begemotPfObjects
+ (1 pfStatus
+ (1 pfStatusRunning ENUM ( 1 true 2 false ) pf_status GET)
+ (2 pfStatusRuntime TIMETICKS pf_status GET)
+ (3 pfStatusDebug ENUM ( 0 none 1 urgent 2 misc 3 loud ) pf_status GET)
+ (4 pfStatusHostId OCTETSTRING pf_status GET)
+ )
+ (2 pfCounter
+ (1 pfCounterMatch COUNTER64 pf_counter GET)
+ (2 pfCounterBadOffset COUNTER64 pf_counter GET)
+ (3 pfCounterFragment COUNTER64 pf_counter GET)
+ (4 pfCounterShort COUNTER64 pf_counter GET)
+ (5 pfCounterNormalize COUNTER64 pf_counter GET)
+ (6 pfCounterMemDrop COUNTER64 pf_counter GET)
+ )
+ (3 pfStateTable
+ (1 pfStateTableCount UNSIGNED32 pf_statetable GET)
+ (2 pfStateTableSearches COUNTER64 pf_statetable GET)
+ (3 pfStateTableInserts COUNTER64 pf_statetable GET)
+ (4 pfStateTableRemovals COUNTER64 pf_statetable GET)
+ )
+ (4 pfSrcNodes
+ (1 pfSrcNodesCount UNSIGNED32 pf_srcnodes GET)
+ (2 pfSrcNodesSearches COUNTER64 pf_srcnodes GET)
+ (3 pfSrcNodesInserts COUNTER64 pf_srcnodes GET)
+ (4 pfSrcNodesRemovals COUNTER64 pf_srcnodes GET)
+ )
+ (5 pfLimits
+ (1 pfLimitsStates UNSIGNED32 pf_limits GET)
+ (2 pfLimitsSrcNodes UNSIGNED32 pf_limits GET)
+ (3 pfLimitsFrags UNSIGNED32 pf_limits GET)
+ )
+ (6 pfTimeouts
+ (1 pfTimeoutsTcpFirst INTEGER32 pf_timeouts GET)
+ (2 pfTimeoutsTcpOpening INTEGER32 pf_timeouts GET)
+ (3 pfTimeoutsTcpEstablished INTEGER32 pf_timeouts GET)
+ (4 pfTimeoutsTcpClosing INTEGER32 pf_timeouts GET)
+ (5 pfTimeoutsTcpFinWait INTEGER32 pf_timeouts GET)
+ (6 pfTimeoutsTcpClosed INTEGER32 pf_timeouts GET)
+ (7 pfTimeoutsUdpFirst INTEGER32 pf_timeouts GET)
+ (8 pfTimeoutsUdpSingle INTEGER32 pf_timeouts GET)
+ (9 pfTimeoutsUdpMultiple INTEGER32 pf_timeouts GET)
+ (10 pfTimeoutsIcmpFirst INTEGER32 pf_timeouts GET)
+ (11 pfTimeoutsIcmpError INTEGER32 pf_timeouts GET)
+ (12 pfTimeoutsOtherFirst INTEGER32 pf_timeouts GET)
+ (13 pfTimeoutsOtherSingle INTEGER32 pf_timeouts GET)
+ (14 pfTimeoutsOtherMultiple INTEGER32 pf_timeouts GET)
+ (15 pfTimeoutsFragment INTEGER32 pf_timeouts GET)
+ (16 pfTimeoutsInterval INTEGER32 pf_timeouts GET)
+ (17 pfTimeoutsAdaptiveStart INTEGER32 pf_timeouts GET)
+ (18 pfTimeoutsAdaptiveEnd INTEGER32 pf_timeouts GET)
+ (19 pfTimeoutsSrcNode INTEGER32 pf_timeouts GET)
+ )
+ (7 pfLogInterface
+ (1 pfLogInterfaceName OCTETSTRING pf_logif GET)
+ (2 pfLogInterfaceIp4BytesIn COUNTER64 pf_logif GET)
+ (3 pfLogInterfaceIp4BytesOut COUNTER64 pf_logif GET)
+ (4 pfLogInterfaceIp4PktsInPass COUNTER64 pf_logif GET)
+ (5 pfLogInterfaceIp4PktsInDrop COUNTER64 pf_logif GET)
+ (6 pfLogInterfaceIp4PktsOutPass COUNTER64 pf_logif GET)
+ (7 pfLogInterfaceIp4PktsOutDrop COUNTER64 pf_logif GET)
+ (8 pfLogInterfaceIp6BytesIn COUNTER64 pf_logif GET)
+ (9 pfLogInterfaceIp6BytesOut COUNTER64 pf_logif GET)
+ (10 pfLogInterfaceIp6PktsInPass COUNTER64 pf_logif GET)
+ (11 pfLogInterfaceIp6PktsInDrop COUNTER64 pf_logif GET)
+ (12 pfLogInterfaceIp6PktsOutPass COUNTER64 pf_logif GET)
+ (13 pfLogInterfaceIp6PktsOutDrop COUNTER64 pf_logif GET)
+ )
+ (8 pfInterfaces
+ (1 pfInterfacesIfNumber INTEGER32 pf_interfaces GET)
+ (2 pfInterfacesIfTable
+ (1 pfInterfacesIfEntry : INTEGER32 pf_iftable
+ (1 pfInterfacesIfIndex INTEGER32)
+ (2 pfInterfacesIfDescr OCTETSTRING GET)
+ (3 pfInterfacesIfType ENUM ( 0 group 1 instance 2 detached ) GET)
+ (4 pfInterfacesIfTZero TIMETICKS GET)
+ (5 pfInterfacesIfRefsState UNSIGNED32 GET)
+ (6 pfInterfacesIfRefsRule UNSIGNED32 GET)
+ (7 pfInterfacesIf4BytesInPass COUNTER64 GET)
+ (8 pfInterfacesIf4BytesInBlock COUNTER64 GET)
+ (9 pfInterfacesIf4BytesOutPass COUNTER64 GET)
+ (10 pfInterfacesIf4BytesOutBlock COUNTER64 GET)
+ (11 pfInterfacesIf4PktsInPass COUNTER64 GET)
+ (12 pfInterfacesIf4PktsInBlock COUNTER64 GET)
+ (13 pfInterfacesIf4PktsOutPass COUNTER64 GET)
+ (14 pfInterfacesIf4PktsOutBlock COUNTER64 GET)
+ (15 pfInterfacesIf6BytesInPass COUNTER64 GET)
+ (16 pfInterfacesIf6BytesInBlock COUNTER64 GET)
+ (17 pfInterfacesIf6BytesOutPass COUNTER64 GET)
+ (18 pfInterfacesIf6BytesOutBlock COUNTER64 GET)
+ (19 pfInterfacesIf6PktsInPass COUNTER64 GET)
+ (20 pfInterfacesIf6PktsInBlock COUNTER64 GET)
+ (21 pfInterfacesIf6PktsOutPass COUNTER64 GET)
+ (22 pfInterfacesIf6PktsOutBlock COUNTER64 GET)
+ )
+ )
+ )
+ (9 pfTables
+ (1 pfTablesTblNumber INTEGER32 pf_tables GET)
+ (2 pfTablesTblTable
+ (1 pfTablesTblEntry : INTEGER32 pf_tbltable
+ (1 pfTablesTblIndex INTEGER32)
+ (2 pfTablesTblDescr OCTETSTRING GET)
+ (3 pfTablesTblCount INTEGER32 GET)
+ (4 pfTablesTblTZero TIMETICKS GET)
+ (5 pfTablesTblRefsAnchor INTEGER32 GET)
+ (6 pfTablesTblRefsRule INTEGER32 GET)
+ (7 pfTablesTblEvalMatch COUNTER64 GET)
+ (8 pfTablesTblEvalNoMatch COUNTER64 GET)
+ (9 pfTablesTblBytesInPass COUNTER64 GET)
+ (10 pfTablesTblBytesInBlock COUNTER64 GET)
+ (11 pfTablesTblBytesInXPass COUNTER64 GET)
+ (12 pfTablesTblBytesOutPass COUNTER64 GET)
+ (13 pfTablesTblBytesOutBlock COUNTER64 GET)
+ (14 pfTablesTblBytesOutXPass COUNTER64 GET)
+ (15 pfTablesTblPktsInPass COUNTER64 GET)
+ (16 pfTablesTblPktsInBlock COUNTER64 GET)
+ (17 pfTablesTblPktsInXPass COUNTER64 GET)
+ (18 pfTablesTblPktsOutPass COUNTER64 GET)
+ (19 pfTablesTblPktsOutBlock COUNTER64 GET)
+ (20 pfTablesTblPktsOutXPass COUNTER64 GET)
+ )
+ )
+ (3 pfTablesAddrTable
+ (1 pfTablesAddrEntry : INTEGER32 pf_tbladdr
+ (1 pfTablesAddrIndex INTEGER32)
+ (2 pfTablesAddrNetType ENUM ( 0 unknown 1 ipv4 2 ipv6) GET)
+ (3 pfTablesAddrNet OCTETSTRING | InetAddress GET)
+ (4 pfTablesAddrPrefix UNSIGNED32 GET)
+ (5 pfTablesAddrTZero TIMETICKS GET)
+ (6 pfTablesAddrBytesInPass COUNTER64 GET)
+ (7 pfTablesAddrBytesInBlock COUNTER64 GET)
+ (8 pfTablesAddrBytesOutPass COUNTER64 GET)
+ (9 pfTablesAddrBytesOutBlock COUNTER64 GET)
+ (10 pfTablesAddrPktsInPass COUNTER64 GET)
+ (11 pfTablesAddrPktsInBlock COUNTER64 GET)
+ (12 pfTablesAddrPktsOutPass COUNTER64 GET)
+ (13 pfTablesAddrPktsOutBlock COUNTER64 GET)
+ )
+ )
+ )
+ (10 pfAltq
+ (1 pfAltqQueueNumber INTEGER32 pf_altq GET)
+ (2 pfAltqQueueTable
+ (1 pfAltqQueueEntry : INTEGER32 pf_altqq
+ (1 pfAltqQueueIndex INTEGER32)
+ (2 pfAltqQueueDescr OCTETSTRING GET)
+ (3 pfAltqQueueParent OCTETSTRING GET)
+ (4 pfAltqQueueScheduler ENUM ( 1 cbq 8 hfsc 11 priq ) GET)
+ (5 pfAltqQueueBandwidth UNSIGNED32 GET)
+ (6 pfAltqQueuePriority INTEGER32 GET)
+ (7 pfAltqQueueLimit INTEGER32 GET)
+ )
+ )
+ )
+ (11 pfLabels
+ (1 pfLabelsLblNumber INTEGER32 pf_labels GET)
+ (2 pfLabelsLblTable
+ (1 pfLabelsLblEntry : INTEGER pf_lbltable
+ (1 pfLabelsLblIndex INTEGER)
+ (2 pfLabelsLblName OCTETSTRING GET)
+ (3 pfLabelsLblEvals COUNTER64 GET)
+ (4 pfLabelsLblBytesIn COUNTER64 GET)
+ (5 pfLabelsLblBytesOut COUNTER64 GET)
+ (6 pfLabelsLblPktsIn COUNTER64 GET)
+ (7 pfLabelsLblPktsOut COUNTER64 GET)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+)
diff --git a/usr.sbin/bsnmpd/modules/snmp_target/Makefile b/usr.sbin/bsnmpd/modules/snmp_target/Makefile
new file mode 100755
index 0000000..10141e5
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_target/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+#
+# Author: Shteryana Shopova <syrinx@freebsd.org>
+
+CONTRIB= ${.CURDIR}/../../../../contrib/bsnmp
+.PATH: ${CONTRIB}/snmp_target
+
+MOD= target
+SRCS= target_snmp.c
+XSYM= snmpTargetMIB snmpNotificationMIB snmpUDPDomain
+
+MAN= snmp_target.3
+
+CFLAGS+= -I${CONTRIB}/lib -I${CONTRIB}/snmpd -DSNMPTREE_TYPES
+CFLAGS+= -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY -DHAVE_SYS_TREE_H
+
+DEFS= ${MOD}_tree.def
+BMIBS=
+
+.include <bsd.snmpmod.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_usm/Makefile b/usr.sbin/bsnmpd/modules/snmp_usm/Makefile
new file mode 100755
index 0000000..4ae818a
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_usm/Makefile
@@ -0,0 +1,22 @@
+# $FreeBSD$
+#
+# Author: Shteryana Shopova <syrinx@freebsd.org>
+
+CONTRIB= ${.CURDIR}/../../../../contrib/bsnmp
+.PATH: ${CONTRIB}/snmp_usm
+
+MOD= usm
+SRCS= usm_snmp.c
+XSYM= snmpUsmMIB usmNoAuthProtocol usmHMACMD5AuthProtocol \
+ usmHMACSHAAuthProtocol usmNoPrivProtocol usmDESPrivProtocol \
+ usmAesCfb128Protocol usmUserSecurityName
+
+MAN= snmp_usm.3
+
+CFLAGS+= -I${CONTRIB}/lib -I${CONTRIB}/snmpd -DSNMPTREE_TYPES
+CFLAGS+= -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY -DHAVE_SYS_TREE_H
+
+DEFS= ${MOD}_tree.def
+BMIBS=
+
+.include <bsd.snmpmod.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_vacm/Makefile b/usr.sbin/bsnmpd/modules/snmp_vacm/Makefile
new file mode 100755
index 0000000..1be8d62
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_vacm/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+#
+# Author: Shteryana Shopova <syrinx@freebsd.org>
+
+CONTRIB= ${.CURDIR}/../../../../contrib/bsnmp
+.PATH: ${CONTRIB}/snmp_vacm
+
+MOD= vacm
+SRCS= vacm_snmp.c
+XSYM= snmpVacmMIB
+
+MAN= snmp_vacm.3
+
+CFLAGS+= -I${CONTRIB}/lib -I${CONTRIB}/snmpd -DSNMPTREE_TYPES
+CFLAGS+= -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY -DHAVE_SYS_TREE_H
+
+DEFS= ${MOD}_tree.def
+BMIBS=
+
+.include <bsd.snmpmod.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/BEGEMOT-WIRELESS-MIB.txt b/usr.sbin/bsnmpd/modules/snmp_wlan/BEGEMOT-WIRELESS-MIB.txt
new file mode 100644
index 0000000..27f5be7
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/BEGEMOT-WIRELESS-MIB.txt
@@ -0,0 +1,3898 @@
+--
+-- Copyright (C) 2010 The FreeBSD Foundation
+-- All rights reserved.
+--
+-- This documentation was written by Shteryana Sotirova Shopova under
+-- sponsorship from the FreeBSD Foundation.
+--
+-- 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-WIRELESS-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ Counter32, Integer32, TimeTicks, Unsigned32, mib-2
+ FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION, MacAddress, TruthValue, RowStatus,
+ DisplayString
+ FROM SNMPv2-TC
+ InterfaceIndex, ifIndex FROM IF-MIB
+ begemot
+ FROM BEGEMOT-MIB;
+
+begemotWlan MODULE-IDENTITY
+ LAST-UPDATED "201005170000Z"
+ ORGANIZATION "The FreeBSD Foundation"
+ CONTACT-INFO
+ " Shteryana Shopova
+
+ Postal: 12 Andrey Lyapchev Blvd.
+ block 2, ap.19
+ 1797 Sofia
+ Bulgaria
+
+ Fax: N/A
+
+ E-Mail: syrinx@FreeBSD.org"
+ DESCRIPTION
+ "The Begemot MIB for managing IEEE802.11 interfaces."
+ REVISION "201005170000Z"
+ DESCRIPTION
+ "Initial revision."
+ ::= { begemot 210 }
+
+-- ---------------------------------------------------------- --
+-- Textual conventions
+-- ---------------------------------------------------------- --
+WlanMgmtReasonCode ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Enumeration of reason and codes used in IEEE802.11
+ management frames to indicate why an action took place."
+ SYNTAX INTEGER {
+ unspecified(1),
+ authenticationExpire(2),
+ authenticationLeave(3),
+ associationExpire(4),
+ associationTooMany(5),
+ notAuthenticated(6),
+ notAssociated(7),
+ associationLeave(8),
+ associationNotAuthenticated(9),
+-- XXX: TODO - FIXME
+ dissassocPwrcapBad(10),
+ dissassocSuperchanBad(11),
+ ieInvalid(13),
+ micFailure(14),
+ fourWayHandshakeTimeout(15),
+ groupKeyUpdateTimeout(16),
+ ieIn4FourWayDiffers(17),
+ groupCipherInvalid(18),
+ pairwiseCiherInvalid(19),
+ akmpInvalid(20),
+ unsupportedRsnIeVersion(21),
+ invalidRsnIeCap(22),
+ dot1xAuthFailed(23),
+ cipherSuiteRejected(24),
+ unspeciffiedQos(32),
+ insufficientBw(33),
+ tooManyFrames(34),
+ outsideTxOp(35),
+ leavingQbss(36),
+ badMechanism(37),
+ setupNeeded(38),
+ timeout(39)
+ }
+
+WlanMgmtMeshReasonCode ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Enumeration of reason and codes used in IEEE802.11
+ mesh routing management frames to indicate why an
+ action took place."
+ SYNTAX INTEGER {
+-- XXX: TODO - FIXME
+ peerLinkCancelled(2),
+ maxPeers(3),
+ cpViolation(4),
+ closeRcvd(5),
+ maxRetries(6),
+ confirmTimeout(7),
+ invalidGtk(8),
+ inconsistentParams(9),
+ invalidSecurity(10),
+ perrUnspecified(11),
+ perrNoFI(12),
+ perrDestUnreach(13)
+ }
+
+WlanMgmtStatusCode ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Enumeration of reason and codes used in IEEE802.11
+ management frames to indicate what the result of an
+ operation is."
+ SYNTAX INTEGER {
+-- XXX: TODO - FIXME
+ success(0),
+ unspecified(1),
+ capabilitiesInfo(10),
+ notAssociated(11),
+ other(12),
+ algorithm(13),
+ sequence(14),
+ challenge(15),
+ timeout(16),
+ tooMany(17),
+ basicRate(18),
+ spRequired(19),
+ pbccRequired(20),
+ caRequired(21),
+ specMgmtRequired(22),
+ pwrcapRequire(23),
+ superchanRequired(24),
+ shortSlotRequired(25),
+ dssofdmRequired(26),
+ missingHTCaps(27),
+ invalidIE(40),
+ groupCipherInvalid(41),
+ pairwiseCipherInvalid(42),
+ akmpInvalid(43),
+ unsupportedRsnIEVersion(44),
+ invalidRsnIECap(45),
+ cipherSuiteRejected(46)
+ }
+
+WlanRegDomainCode ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Enumeration of regdomain codes."
+ SYNTAX INTEGER {
+ fcc(1),
+ ca(2),
+ etsi(3),
+ etsi2(4),
+ etsi3(5),
+ fcc3(6),
+ japan(7),
+ korea(8),
+ apac(9),
+ apac2(10),
+ apac3(11),
+ row(12),
+ none(13),
+ debug(14),
+ sr9(15),
+ xr9(16),
+ gz901(17)
+ }
+
+WlanIfaceDot11nPduType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Enumeration of values for PDU transmit/receive enabled."
+ SYNTAX INTEGER {
+ disabled(0),
+ rxOnly(1),
+ txOnly(2),
+ txAndRx(3)
+ }
+
+WlanPeerCapabilityFlags ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "A list of capability bits that may be advertised by a peer."
+ SYNTAX BITS {
+ ess(1),
+ ibss(2),
+ cfPollable(3),
+ cfPollRequest(4),
+ privacy(5),
+ shortPreamble(6),
+ pbcc(7),
+ channelAgility(8),
+ shortSlotTime(9),
+ rsn(10),
+ dsssofdm(11)
+ }
+
+WlanIfPhyMode ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "A list of wireless PHY operating modes."
+ SYNTAX INTEGER {
+ auto(1),
+ dot11a(2),
+ dot11b(3),
+ dot11g(4),
+ fh(5),
+ turboA(6),
+ turboG(7),
+ sturboA(8),
+ dot11na(9),
+ dot11ng(10),
+ ofdmHalf(11),
+ ofdmQuarter(12)
+ }
+
+-- ---------------------------------------------------------- --
+-- Subtrees in the Begemot Wireless MIB
+-- ---------------------------------------------------------- --
+begemotWlanNotifications OBJECT IDENTIFIER ::= { begemotWlan 0 }
+
+begemotWlanInterface OBJECT IDENTIFIER ::= { begemotWlan 1 }
+
+begemotWlanScanning OBJECT IDENTIFIER ::= { begemotWlan 2 }
+
+begemotWlanStatistics OBJECT IDENTIFIER ::= { begemotWlan 3 }
+
+begemotWlanWep OBJECT IDENTIFIER ::= { begemotWlan 4 }
+
+begemotWlanMACAccessControl OBJECT IDENTIFIER ::= { begemotWlan 5 }
+
+begemotWlanMeshRouting OBJECT IDENTIFIER ::= { begemotWlan 6 }
+
+-- ---------------------------------------------------------- --
+-- begemotWlanMultimedia OBJECT IDENTIFIER ::= { begemotWlan 7 }
+-- ---------------------------------------------------------- --
+
+-- ---------------------------------------------------------- --
+-- Cloned wireless interfaces' database
+-- ---------------------------------------------------------- --
+wlanInterfaceTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanInterfaceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains the list of cloned wireless
+ interfaces created on the system."
+ ::= { begemotWlanInterface 1 }
+
+wlanInterfaceEntry OBJECT-TYPE
+ SYNTAX WlanInterfaceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information for a cloned wireless interface."
+ INDEX { wlanIfaceName }
+ ::= { wlanInterfaceTable 1 }
+
+WlanInterfaceEntry ::= SEQUENCE {
+ wlanIfaceIndex InterfaceIndex,
+ wlanIfaceName DisplayString,
+ wlanParentIfName DisplayString,
+ wlanIfaceOperatingMode INTEGER,
+ wlanIfaceFlags BITS,
+ wlanIfaceBssid MacAddress,
+ wlanIfaceLocalAddress MacAddress,
+ wlanIfaceStatus RowStatus,
+ wlanIfaceState INTEGER
+}
+
+wlanIfaceIndex OBJECT-TYPE
+ SYNTAX InterfaceIndex
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The ifIndex of this cloned wireless interface."
+ ::= { wlanInterfaceEntry 1 }
+
+wlanIfaceName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE(1..32))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The name of this cloned wireless interface."
+ ::= { wlanInterfaceEntry 2 }
+
+wlanParentIfName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE(1..32))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The name of this cloned wireless interface's parent hardware
+ interface."
+ ::= { wlanInterfaceEntry 3 }
+
+wlanIfaceOperatingMode OBJECT-TYPE
+ SYNTAX INTEGER {
+ ibss(0),
+ station(1),
+ wds(2),
+ adhocDemo(3),
+ hostAp(4),
+ monitor(5),
+ meshPoint(6),
+ tdma(7)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The desired operating mode of the cloned wireless interface."
+ DEFVAL { station }
+ ::= { wlanInterfaceEntry 4 }
+
+wlanIfaceFlags OBJECT-TYPE
+ SYNTAX BITS {
+ uniqueBssid(1),
+ noBeacons(2),
+ wdsLegacy(3)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "Flags per cloned wireless interface used during creation."
+ ::= { wlanInterfaceEntry 5 }
+
+wlanIfaceBssid OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The BSSID assigned to a cloned wireless interface operating in
+ WDS mode."
+ ::= { wlanInterfaceEntry 6 }
+
+wlanIfaceLocalAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The unique local MAC address assigned to the cloned wireless
+ interface during creation."
+ ::= { wlanInterfaceEntry 7 }
+
+wlanIfaceStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This column allows creation or deletion of cloned wireless
+ interfaces."
+ ::= { wlanInterfaceEntry 8 }
+
+wlanIfaceState OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1),
+ down(2)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The operating state of the interface."
+ ::= { wlanInterfaceEntry 9 }
+
+wlanIfParentTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanIfParentEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information about the parent hardware
+ interface of every cloned wireless interface in the system."
+ ::= { begemotWlanInterface 2 }
+
+wlanIfParentEntry OBJECT-TYPE
+ SYNTAX WlanIfParentEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information for the parent hardware interface of a cloned
+ wireless interface."
+ AUGMENTS { wlanInterfaceEntry }
+ ::= { wlanIfParentTable 1 }
+
+WlanIfParentEntry ::= SEQUENCE {
+ wlanIfParentDriverCapabilities BITS,
+ wlanIfParentCryptoCapabilities BITS,
+ wlanIfParentHTCapabilities BITS
+}
+
+wlanIfParentDriverCapabilities OBJECT-TYPE
+ SYNTAX BITS {
+ station(1),
+ ieee8023encap(2),
+ athFastFrames(3),
+ athTurbo(4),
+ ibss(5),
+ pmgt(6),
+ hostAp(7),
+ ahDemo(8),
+ swRetry(9),
+ txPmgt(10),
+ shortSlot(11),
+ shortPreamble(12),
+ monitor(13),
+ dfs(14),
+ mbss(15),
+ wpa1(16),
+ wpa2(17),
+ burst(18),
+ wme(19),
+ wds(20),
+ bgScan(21),
+ txFrag(22),
+ tdma(23)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The driver capabilities of this cloned interface's parent."
+ ::= { wlanIfParentEntry 1 }
+
+wlanIfParentCryptoCapabilities OBJECT-TYPE
+ SYNTAX BITS {
+ wep(1),
+ tkip(2),
+ aes(3),
+ aesCcm(4),
+ tkipMic(5),
+ ckip(6)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The hardware cryptographic capabilities of this cloned
+ interface's parent."
+ ::= { wlanIfParentEntry 2 }
+
+wlanIfParentHTCapabilities OBJECT-TYPE
+ SYNTAX BITS {
+ ldpc(1),
+ chwidth40(2),
+ greenField(3),
+ shortGi20(4),
+ shortGi40(5),
+ txStbc(6),
+ delba(7),
+ amsdu7935(8),
+ dssscck40(9),
+ psmp(10),
+ fortyMHzIntolerant(11),
+ lsigTxOpProt(12),
+ htcAmpdu(13),
+ htcAmsdu(14),
+ htcHt(15),
+ htcSmps(16),
+ htcRifs(17)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The hardware High Throughput capabilities of this cloned
+ interface's parent."
+ ::= { wlanIfParentEntry 3 }
+
+wlanIfaceConfigTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanIfaceConfigEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains a list of configuration parameters per
+ cloned wireless interface. Some of the parameters may not be
+ applicable depending on the underlying device's hardware
+ capabilities and operating mode of the virtual interface."
+ ::= { begemotWlanInterface 3 }
+
+wlanIfaceConfigEntry OBJECT-TYPE
+ SYNTAX WlanIfaceConfigEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of configuration parameters for a cloned wireless interface."
+ AUGMENTS { wlanInterfaceEntry }
+ ::= { wlanIfaceConfigTable 1 }
+
+WlanIfaceConfigEntry ::= SEQUENCE {
+ wlanIfacePacketBurst TruthValue,
+ wlanIfaceCountryCode OCTET STRING,
+ wlanIfaceRegDomain INTEGER,
+ wlanIfaceDesiredSsid OCTET STRING,
+ wlanIfaceDesiredChannel INTEGER,
+ wlanIfaceDynamicFreqSelection TruthValue,
+ wlanIfaceFastFrames TruthValue,
+ wlanIfaceDturbo TruthValue,
+ wlanIfaceTxPower INTEGER,
+ wlanIfaceFragmentThreshold INTEGER,
+ wlanIfaceRTSThreshold INTEGER,
+ wlanIfaceWlanPrivacySubscribe TruthValue,
+-- Parameters for station mode
+ wlanIfaceBgScan TruthValue,
+ wlanIfaceBgScanIdle INTEGER,
+ wlanIfaceBgScanInterval INTEGER,
+ wlanIfaceBeaconMissedThreshold INTEGER,
+ wlanIfaceDesiredBssid MacAddress,
+ wlanIfaceRoamingMode INTEGER,
+-- Additional parameters when operating in host-ap/ad-hoc mode
+ wlanIfaceDot11d TruthValue,
+ wlanIfaceDot11h TruthValue,
+ wlanIfaceDynamicWds TruthValue,
+ wlanIfacePowerSave TruthValue,
+ wlanIfaceApBridge TruthValue,
+ wlanIfaceBeaconInterval INTEGER,
+ wlanIfaceDtimPeriod INTEGER,
+ wlanIfaceHideSsid TruthValue,
+ wlanIfaceInactivityProccess TruthValue,
+ wlanIfaceDot11gProtMode INTEGER,
+ wlanIfaceDot11gPureMode TruthValue,
+ wlanIfaceDot11nPureMode TruthValue,
+ wlanIfaceDot11nAmpdu INTEGER,
+ wlanIfaceDot11nAmpduDensity INTEGER,
+ wlanIfaceDot11nAmpduLimit INTEGER,
+ wlanIfaceDot11nAmsdu INTEGER,
+ wlanIfaceDot11nAmsduLimit INTEGER,
+ wlanIfaceDot11nHighThroughput TruthValue,
+ wlanIfaceDot11nHTCompatible TruthValue,
+ wlanIfaceDot11nHTProtMode INTEGER,
+ wlanIfaceDot11nRIFS TruthValue,
+ wlanIfaceDot11nShortGI TruthValue,
+ wlanIfaceDot11nSMPSMode INTEGER,
+-- Parameters when operating in tdma mode
+ wlanIfaceTdmaSlot INTEGER,
+ wlanIfaceTdmaSlotCount INTEGER,
+ wlanIfaceTdmaSlotLength INTEGER,
+ wlanIfaceTdmaBeaconInterval INTEGER
+}
+
+wlanIfacePacketBurst OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object controls whether packet bursting is
+ enabled on the interface."
+ ::= { wlanIfaceConfigEntry 1 }
+
+wlanIfaceCountryCode OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(3))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object controls the country regulatory
+ constraints for operation of this wireless interface. The first
+ two octets of this string is the two character country code as
+ described in ISO/IEC 3166-1. The third octet shall contain one
+ of the following:
+
+ 1. an ASCII space character, if the regulations under which the
+ interface is operating include all environments in the specified
+ country.
+
+ 2. an ASCII 'O' character, if the country's regulations are for
+ Outdoor environment only.
+
+ 3. an ASCII 'I' character, if the country's regulations are for
+ Indoor environment only."
+ ::= { wlanIfaceConfigEntry 2 }
+
+wlanIfaceRegDomain OBJECT-TYPE
+ SYNTAX WlanRegDomainCode
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object specifies the regulatory domain to use when calculating
+ the regulatory constraints for operation of the interface."
+ ::= { wlanIfaceConfigEntry 3 }
+
+wlanIfaceDesiredSsid OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..32))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The desired SSID for the interface as an ASCII string.
+ Specifying an empty string shall remove the current configured
+ SSID."
+ ::= { wlanIfaceConfigEntry 4 }
+
+wlanIfaceDesiredChannel OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The desired operating channel for this interface. The value of this
+ column is the channel index (wlanIfaceChannelId) of the corresponding
+ entry from the wlanIfaceChannelTable. The interface status must be
+ down so that the current operating channel may be set properly."
+ ::= { wlanIfaceConfigEntry 5 }
+
+wlanIfaceDynamicFreqSelection OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether Dynamic Frequency
+ Selection (DFS) as specified in 802.11h is enabled on an
+ interface that supports 802.11h and DFS."
+ DEFVAL { false }
+ ::= { wlanIfaceConfigEntry 6 }
+
+wlanIfaceFastFrames OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object controls whether use of Atheros Fast
+ Frames is enabled when when communicating with another Fast
+ Frames-capable station. The value is only meaningful for
+ interfaces that support Atheros Fast Frames."
+ ::= { wlanIfaceConfigEntry 7 }
+
+wlanIfaceDturbo OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object controls whether use of Atheros Dynamic
+ Turbo mode is enabled when when communicating with another Dynamic
+ Turbo-capable station. The value is only meaningful for interfaces
+ that support Atheros Dynamic Turbo mode."
+ ::= { wlanIfaceConfigEntry 8 }
+
+wlanIfaceTxPower OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object controls the power used to transmit
+ frames. Accepted values are in units of one tenths of a dBm in
+ steps of .5 dBm, e.g setting the value of this object to 155
+ results in 15.5 dBm transmit power configured on the interface."
+ ::= { wlanIfaceConfigEntry 9 }
+
+wlanIfaceFragmentThreshold OBJECT-TYPE
+ SYNTAX INTEGER (256..2346)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object controls the threshold for which
+ transmitted frames are broken into fragments. Setting the value
+ of this object to 2346 will disable transmit fragmentation."
+ DEFVAL { 2346 }
+ ::= { wlanIfaceConfigEntry 10 }
+
+wlanIfaceRTSThreshold OBJECT-TYPE
+ SYNTAX INTEGER (1..2346)
+ UNITS "bytes"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object controls the threshold for which
+ transmitted frames are preceded by transmission of an RTS
+ control frame. Setting the value of this object to 2346 will
+ disable transmission of RTS frames."
+ DEFVAL { 2346 }
+ ::= { wlanIfaceConfigEntry 11 }
+
+wlanIfaceWlanPrivacySubscribe OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether Wireless Privacy
+ Subscriber support is enabled on the interface."
+ ::= { wlanIfaceConfigEntry 12 }
+
+wlanIfaceBgScan OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether background scanning
+ is enabled for an interface operating in station mode."
+ ::= { wlanIfaceConfigEntry 13 }
+
+wlanIfaceBgScanIdle OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the minimum time a station must
+ be idle before a background scan is initiated on an interface
+ operating in station mode."
+ DEFVAL { 250 }
+ ::= { wlanIfaceConfigEntry 14 }
+
+wlanIfaceBgScanInterval OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "seconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the interval at which background
+ scanning is attempted when operating in station mode."
+ DEFVAL { 300 }
+ ::= { wlanIfaceConfigEntry 15 }
+
+wlanIfaceBeaconMissedThreshold OBJECT-TYPE
+ SYNTAX INTEGER (1..255)
+ UNITS "frames"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the number of consecutive missed
+ beacons before an interface operating in station mode will attempt
+ to search for a new access point."
+ DEFVAL { 7 }
+ ::= { wlanIfaceConfigEntry 16 }
+
+wlanIfaceDesiredBssid OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the MAC address of the desired
+ access point to use when an interface is operating as a station."
+ ::= { wlanIfaceConfigEntry 17 }
+
+wlanIfaceRoamingMode OBJECT-TYPE
+ SYNTAX INTEGER {
+ device(1),
+ auto(2),
+ manual(3)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the desired system behavior
+ when the interface is operating as a station and the communication
+ with the current access point is broken."
+ DEFVAL { auto }
+ ::= { wlanIfaceConfigEntry 18 }
+
+wlanIfaceDot11d OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether 802.11d specification
+ support is enabled."
+ DEFVAL { false }
+ ::= { wlanIfaceConfigEntry 19 }
+
+wlanIfaceDot11h OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether 802.11h support
+ including spectrum management is enabled. The value is only
+ meaningfull for interfaces that support 802.11h specification."
+ DEFVAL { false }
+ ::= { wlanIfaceConfigEntry 20 }
+
+wlanIfaceDynamicWds OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether Dynamic WDS (DWDS)
+ support is enabled. The value is only meaningful for interfaces
+ that support Dynamic WDS."
+ ::= { wlanIfaceConfigEntry 21 }
+
+wlanIfacePowerSave OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether powersave operation
+ is enabled. The value is only meaningful for interfaces that
+ support powersave operation."
+ ::= { wlanIfaceConfigEntry 22 }
+
+wlanIfaceApBridge OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether packets between
+ wireless clients will be passed directly by an interface
+ operating in host ap mode. Disabling it may be useful in
+ situations when traffic between wireless clients needs to be
+ processed with packet filtering."
+ DEFVAL { true }
+ ::= { wlanIfaceConfigEntry 23 }
+
+wlanIfaceBeaconInterval OBJECT-TYPE
+ SYNTAX INTEGER (25..1000)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the interval at with beacon
+ frames are sent when an interface is operating in ad-hoc or ap
+ mode. The beacon interval is specified in TU's (1024 usecs)."
+ DEFVAL { 100 }
+ ::= { wlanIfaceConfigEntry 24 }
+
+wlanIfaceDtimPeriod OBJECT-TYPE
+ SYNTAX INTEGER (1..15)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the DTIM period at which
+ buffered multicast data frames are transmitted by an interface
+ operating in host ap mode. Its value indicates the number of
+ beacon intervals between DTIM."
+ DEFVAL { 1 }
+ ::= { wlanIfaceConfigEntry 25 }
+
+wlanIfaceHideSsid OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether broadcasting of the
+ SSID in beacon frames and responding to undirected probe request
+ frames is enabled for an interface operating in ap mode."
+ DEFVAL { false }
+ ::= { wlanIfaceConfigEntry 26 }
+
+wlanIfaceInactivityProccess OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether inactivity processing
+ for associated station on an interface operating in ap mode is
+ enabled."
+ DEFVAL { true }
+ ::= { wlanIfaceConfigEntry 27 }
+
+wlanIfaceDot11gProtMode OBJECT-TYPE
+ SYNTAX INTEGER {
+ off(1),
+ cts(2),
+ rtscts(3)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the technique used for
+ protecting OFDM frames in a mixed 11b/11g network."
+ ::= { wlanIfaceConfigEntry 28 }
+
+wlanIfaceDot11gPureMode OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether only 802.11g-capable
+ stations will be allowed to associate to an interface operating
+ as access point in 802.11g mode."
+ ::= { wlanIfaceConfigEntry 29 }
+
+wlanIfaceDot11nPureMode OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether only HT-capable
+ stations will be allowed to associate to an interface operating
+ as access point in 802.11n mode."
+ ::= { wlanIfaceConfigEntry 30 }
+
+wlanIfaceDot11nAmpdu OBJECT-TYPE
+ SYNTAX WlanIfaceDot11nPduType
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether sending and
+ receiving of AMPDU frames is enabled on an interface
+ operating in 802.11n mode."
+ DEFVAL { txAndRx }
+ ::= { wlanIfaceConfigEntry 31 }
+
+wlanIfaceDot11nAmpduDensity OBJECT-TYPE
+ SYNTAX INTEGER (0|25|50|100|200|400|800|1600)
+ UNITS "1/100ths-of-microsecond"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the AMPDU density parameter
+ for an interface operating in 802.11n mode."
+ ::= { wlanIfaceConfigEntry 32 }
+
+wlanIfaceDot11nAmpduLimit OBJECT-TYPE
+ SYNTAX INTEGER (8192|16384|32768|65536)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies a limit on the AMPDU packet
+ size for receiving AMPDU frames for an interface operating in
+ 802.11n mode."
+ ::= { wlanIfaceConfigEntry 33 }
+
+wlanIfaceDot11nAmsdu OBJECT-TYPE
+ SYNTAX WlanIfaceDot11nPduType
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether sending and receiving
+ of AMSDU frames is enabled on an interface operating in 802.11n
+ mode."
+ DEFVAL { rxOnly }
+ ::= { wlanIfaceConfigEntry 34 }
+
+wlanIfaceDot11nAmsduLimit OBJECT-TYPE
+ SYNTAX INTEGER (3839|7935)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies a limit on the AMSDU packet
+ size when sending and receiving AMSDU frames for an interface
+ operating in 802.11n mode."
+ ::= { wlanIfaceConfigEntry 35 }
+
+wlanIfaceDot11nHighThroughput OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether use of High Throughput
+ (HT) is enabled for an interface operating in 802.11n mode."
+ DEFVAL { true }
+ ::= { wlanIfaceConfigEntry 36 }
+
+wlanIfaceDot11nHTCompatible OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether use of compatibility
+ support for pre-802.11n devices is enabled for an interface
+ operating in 802.11n mode."
+ DEFVAL { true }
+ ::= { wlanIfaceConfigEntry 37 }
+
+wlanIfaceDot11nHTProtMode OBJECT-TYPE
+ SYNTAX INTEGER {
+ off(1),
+ rts(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the technique used for
+ protecting HT frames in a mixed legacy/HT network for interfaces
+ operating in 802.11n mode."
+ DEFVAL { rts }
+ ::= { wlanIfaceConfigEntry 38 }
+
+wlanIfaceDot11nRIFS OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether Reduced InterFrame
+ Spacing (RIFS) is enabled for an interface operating in 802.11n
+ mode on an HT channel."
+ ::= { wlanIfaceConfigEntry 39 }
+
+wlanIfaceDot11nShortGI OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether use of Short Guard
+ Interval is enabled on an interface operating in 802.11n mode
+ on an HT channel."
+ ::= { wlanIfaceConfigEntry 40 }
+
+wlanIfaceDot11nSMPSMode OBJECT-TYPE
+ SYNTAX INTEGER {
+ disabled(1),
+ static(2),
+ dynamic(3)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies whether use of Spatial Multiplexing
+ Power Save (SMPS) is enabled on an interface operating in 802.11n mode
+ and whether SMPS mode is set to Static or Dynamic. The value is only
+ meaningfull for interfaces that support SMPS."
+ ::= { wlanIfaceConfigEntry 41 }
+
+wlanIfaceTdmaSlot OBJECT-TYPE
+ SYNTAX INTEGER (0..2)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the slot configuration to use
+ when operating in TDMA mode."
+ ::= { wlanIfaceConfigEntry 42 }
+
+wlanIfaceTdmaSlotCount OBJECT-TYPE
+ SYNTAX INTEGER (0..2)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the number of slots to use to
+ setup a BSS for an interface operating in TDMA mode."
+ ::= { wlanIfaceConfigEntry 43 }
+
+wlanIfaceTdmaSlotLength OBJECT-TYPE
+ SYNTAX INTEGER (150..65000)
+ UNITS "microseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies a slot length that each station
+ has when a BSS is setup by an interface operating in TDMA mode."
+ DEFVAL { 10000 }
+ ::= { wlanIfaceConfigEntry 44 }
+
+wlanIfaceTdmaBeaconInterval OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the number of superframes at
+ which a beacon frame is sent to synchronize the TDMA slot timing
+ for interfaces operating in TDMA mode."
+ DEFVAL { 5 }
+ ::= { wlanIfaceConfigEntry 45 }
+
+wlanIfacePeerTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanIfacePeerEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information about the associated stations
+ for an interface operating as an access point, or the stations
+ identified as neighbors in the IBSS for an interface operating in
+ adhoc mode."
+ ::= { begemotWlanInterface 4 }
+
+wlanIfacePeerEntry OBJECT-TYPE
+ SYNTAX WlanIfacePeerEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry that contains information for the associated stations
+ for an interface operating as an access point, or the neighboring
+ stations of an interface in adhoc mode."
+ INDEX { wlanIfaceName, wlanIfacePeerAddress }
+ ::= { wlanIfacePeerTable 1 }
+
+WlanIfacePeerEntry ::= SEQUENCE {
+ wlanIfacePeerAddress MacAddress,
+ wlanIfacePeerAssociationId INTEGER,
+ wlanIfacePeerVlanTag INTEGER,
+ wlanIfacePeerFrequency INTEGER,
+ wlanIfacePeerCurrentTXRate INTEGER,
+ wlanIfacePeerRxSignalStrength INTEGER,
+ wlanIfacePeerIdleTimer INTEGER,
+ wlanIfacePeerTxSequenceNo INTEGER,
+ wlanIfacePeerRxSequenceNo INTEGER,
+ wlanIfacePeerTxPower INTEGER,
+ wlanIfacePeerCapabilities BITS,
+ wlanIfacePeerFlags BITS
+}
+
+wlanIfacePeerAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The MAC address of this peer."
+ ::= { wlanIfacePeerEntry 1 }
+
+wlanIfacePeerAssociationId OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The ID of the associacition with this peer."
+ ::= { wlanIfacePeerEntry 2 }
+
+wlanIfacePeerVlanTag OBJECT-TYPE
+ SYNTAX INTEGER (0..4096)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The Vlan Tag for traffic to/from this peer."
+ ::= { wlanIfacePeerEntry 3 }
+
+wlanIfacePeerFrequency OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The operating frequency for the link with this peer."
+ ::= { wlanIfacePeerEntry 4 }
+
+wlanIfacePeerCurrentTXRate OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The current transmit rate for this peer."
+ ::= { wlanIfacePeerEntry 5 }
+
+wlanIfacePeerRxSignalStrength OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The average receive signal strength for this peer."
+ ::= { wlanIfacePeerEntry 6 }
+
+wlanIfacePeerIdleTimer OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of this peer's inactivity timer."
+ ::= { wlanIfacePeerEntry 7 }
+
+wlanIfacePeerTxSequenceNo OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The last sequence number transmitted to this peer."
+ ::= { wlanIfacePeerEntry 8 }
+
+wlanIfacePeerRxSequenceNo OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The last sequence number received from this peer."
+ ::= { wlanIfacePeerEntry 9 }
+
+wlanIfacePeerTxPower OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The transmit power limit for this peer."
+ ::= { wlanIfacePeerEntry 10 }
+
+wlanIfacePeerCapabilities OBJECT-TYPE
+ SYNTAX WlanPeerCapabilityFlags
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The capabilities advertised by this peer."
+ ::= { wlanIfacePeerEntry 11 }
+
+wlanIfacePeerFlags OBJECT-TYPE
+ SYNTAX BITS {
+ authorizedForData(1),
+ qosEnabled(2),
+ erpEnabled(3),
+ powerSaveMode(4),
+ authRefHeld(5),
+ htEnabled(6),
+ htCompat(7),
+ wpsAssoc(8),
+ tsnAssoc(9),
+ ampduRx(10),
+ ampduTx(11),
+ mimoPowerSave(12),
+ sendRts(13),
+ rifs(14),
+ shortGiHT20(15),
+ shortGiHT40(16),
+ amsduRx(17),
+ amsduTx(18)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The peer state flags."
+ ::= { wlanIfacePeerEntry 12 }
+
+wlanIfaceChannelTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanIfaceChannelEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information about the active channels for
+ the cloned wireless interfaces in the system."
+ ::= { begemotWlanInterface 5 }
+
+wlanIfaceChannelEntry OBJECT-TYPE
+ SYNTAX WlanIfaceChannelEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry that contains active channel information for the wireless
+ interface."
+ INDEX { wlanIfaceName, wlanIfaceChannelId }
+ ::= { wlanIfaceChannelTable 1 }
+
+WlanIfaceChannelEntry ::= SEQUENCE {
+ wlanIfaceChannelId INTEGER,
+ wlanIfaceChannelIeeeId INTEGER,
+ wlanIfaceChannelType INTEGER,
+ wlanIfaceChannelFlags BITS,
+ wlanIfaceChannelFrequency INTEGER,
+ wlanIfaceChannelMaxRegPower INTEGER,
+ wlanIfaceChannelMaxTxPower INTEGER,
+ wlanIfaceChannelMinTxPower INTEGER,
+ wlanIfaceChannelState BITS,
+ wlanIfaceChannelHTExtension INTEGER,
+ wlanIfaceChannelMaxAntennaGain INTEGER
+}
+
+wlanIfaceChannelId OBJECT-TYPE
+ SYNTAX INTEGER (1..1536)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The index of this channel entry."
+ ::= { wlanIfaceChannelEntry 1 }
+
+wlanIfaceChannelIeeeId OBJECT-TYPE
+ SYNTAX INTEGER (1..256)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The channel IEEE ID."
+ ::= { wlanIfaceChannelEntry 2 }
+
+wlanIfaceChannelType OBJECT-TYPE
+ SYNTAX INTEGER {
+ fhss(1),
+ dot11a(2),
+ dot11b(3),
+ dot11g(4),
+ tenMHz(5),
+ fiveMHz(6),
+ turbo(7),
+ ht(8)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The operating channel type for this entry."
+ ::= { wlanIfaceChannelEntry 3 }
+
+wlanIfaceChannelFlags OBJECT-TYPE
+ SYNTAX BITS {
+ turbo(1),
+ cck(2),
+ ofdm(3),
+ spectrum2Ghz(4),
+ spectrum5Ghz(5),
+ passiveScan(6),
+ dynamicCckOfdm(7),
+ gfsk(8),
+ spectrum900Mhz(9),
+ dot11aStaticTurbo(10),
+ halfRate(11),
+ quarterRate(12),
+ ht20(13),
+ ht40u(14),
+ ht40d(15),
+ dfs(16),
+ xmit4ms(17),
+ noAdhoc(18),
+ noHostAp(19),
+ dot11d(20)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The channel flags."
+ ::= { wlanIfaceChannelEntry 4 }
+
+wlanIfaceChannelFrequency OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The channel frequency setting in MHz."
+ ::= { wlanIfaceChannelEntry 5 }
+
+wlanIfaceChannelMaxRegPower OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum regulatory tx power in dBm for this channel."
+ ::= { wlanIfaceChannelEntry 6 }
+
+wlanIfaceChannelMaxTxPower OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum tx power in units of .5 dBm for this channel."
+ ::= { wlanIfaceChannelEntry 7 }
+
+wlanIfaceChannelMinTxPower OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The minimum tx power in units of .5 dBm for this channel."
+ ::= { wlanIfaceChannelEntry 8 }
+
+wlanIfaceChannelState OBJECT-TYPE
+ SYNTAX BITS {
+ radar(1),
+ cacDone(2),
+ interferenceDetected(3),
+ radarClear(4)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The channel dynamic state."
+ ::= { wlanIfaceChannelEntry 9 }
+
+wlanIfaceChannelHTExtension OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The HT40 extension channel number."
+ ::= { wlanIfaceChannelEntry 10 }
+
+wlanIfaceChannelMaxAntennaGain OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum antenna gain in units of .5 dBm."
+ ::= { wlanIfaceChannelEntry 11 }
+
+-- ---------------------------------------------------------- --
+-- The Scan requests/results for cloned wireless interfaces
+-- ---------------------------------------------------------- --
+
+wlanScanConfigTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanScanConfigEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains a configuration for channel scanning
+ initiated via SNMP."
+ ::= { begemotWlanScanning 1 }
+
+wlanScanConfigEntry OBJECT-TYPE
+ SYNTAX WlanScanConfigEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Per cloned wireless interface channel scan configuration data.
+ The entry will be empty if no scans were initiated via SNMP."
+ INDEX { wlanIfaceName }
+ ::= { wlanScanConfigTable 1 }
+
+WlanScanConfigEntry ::= SEQUENCE {
+ wlanScanFlags BITS,
+ wlanScanDuration INTEGER,
+ wlanScanMinChannelDwellTime INTEGER,
+ wlanScanMaxChannelDwellTime INTEGER,
+ wlanScanConfigStatus INTEGER
+}
+
+wlanScanFlags OBJECT-TYPE
+ SYNTAX BITS {
+ noSelection(1),
+ activeScan(2),
+ pickFirst(3),
+ backgroundScan(4),
+ once(5),
+ noBroadcast(6),
+ noAutoSequencing(7),
+ flushCashe(8),
+ chechCashe(9)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Desired flags for the channel scan."
+ ::= { wlanScanConfigEntry 1 }
+
+wlanScanDuration OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The desired duration of the scan. Setting the value of this object
+ to the highest allowed value will initiate an infinite scan."
+ ::= { wlanScanConfigEntry 2 }
+
+wlanScanMinChannelDwellTime OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The minimum channel dwelltime for this scan."
+ ::= { wlanScanConfigEntry 3 }
+
+wlanScanMaxChannelDwellTime OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum channel dwelltime for this scan."
+ ::= { wlanScanConfigEntry 4 }
+
+wlanScanConfigStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(0),
+ notStarted(1),
+ running(2),
+ finished(3),
+ cancel(4)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object is used to initiate or cancel channel scanning on the cloned
+ interface via SNMP. Setting its value to running(2) will initiate channel
+ scanning on the cloned interface, while setting the value to cancel will
+ cancel the current ongoing scan. All other values should be returned in
+ GET operations only."
+ ::= { wlanScanConfigEntry 5 }
+
+wlanScanResultsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanScanResultsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains scan results for a virtual wireless interface."
+ ::= { begemotWlanScanning 2 }
+
+wlanScanResultsEntry OBJECT-TYPE
+ SYNTAX WlanScanResultsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Per virtual wireless interface channel scan results data."
+ INDEX { wlanIfaceName, wlanScanResultID, wlanScanResultBssid }
+ ::= { wlanScanResultsTable 1 }
+
+WlanScanResultsEntry ::= SEQUENCE {
+ wlanScanResultID OCTET STRING,
+ wlanScanResultBssid MacAddress,
+ wlanScanResultChannel INTEGER,
+ wlanScanResultRate INTEGER,
+ wlanScanResultNoise INTEGER,
+ wlanScanResultBeaconInterval INTEGER,
+ wlanScanResultCapabilities BITS
+}
+
+wlanScanResultID OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..32))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The SSID/MESH ID for this scan result entry."
+ ::= { wlanScanResultsEntry 1 }
+
+wlanScanResultBssid OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The BSSID for this scan result entry."
+ ::= { wlanScanResultsEntry 2 }
+
+wlanScanResultChannel OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The operating channel for this scan result entry."
+ ::= { wlanScanResultsEntry 3 }
+
+wlanScanResultRate OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The operating rate of this scan result entry."
+ ::= { wlanScanResultsEntry 4 }
+
+wlanScanResultNoise OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The channel noise for this scan result entry."
+ ::= { wlanScanResultsEntry 5 }
+
+wlanScanResultBeaconInterval OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The beacon interval reported for this scan result entry."
+ ::= { wlanScanResultsEntry 6 }
+
+wlanScanResultCapabilities OBJECT-TYPE
+ SYNTAX WlanPeerCapabilityFlags
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The capabilities advertised for this scan result entry."
+ ::= { wlanScanResultsEntry 7 }
+
+wlanIfRoamParamsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanIfRoamParamsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains the parameters that govern the roaming
+ operation on a wireless interface."
+ ::= { begemotWlanInterface 6 }
+
+wlanIfRoamParamsEntry OBJECT-TYPE
+ SYNTAX WlanIfRoamParamsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry that contains the roaming parameters of a wireless
+ interface."
+ INDEX { wlanIfaceName, wlanIfRoamPhyMode }
+ ::= { wlanIfRoamParamsTable 1 }
+
+WlanIfRoamParamsEntry ::= SEQUENCE {
+ wlanIfRoamPhyMode INTEGER,
+ wlanIfRoamRxSignalStrength INTEGER,
+ wlanIfRoamTxRateThreshold INTEGER
+}
+
+wlanIfRoamPhyMode OBJECT-TYPE
+ SYNTAX WlanIfPhyMode
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The PHY mode for this roaming parameters entry."
+ ::= { wlanIfRoamParamsEntry 1 }
+
+wlanIfRoamRxSignalStrength OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The Receive Signal Strength for this roaming parameters entry."
+ ::= { wlanIfRoamParamsEntry 2 }
+
+wlanIfRoamTxRateThreshold OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The transmit rate threshold value for this roaming parameters
+ entry in Mb/s or MCS."
+ ::= { wlanIfRoamParamsEntry 3 }
+
+wlanIfTxParamsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanIfTxParamsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains the parameters that govern the transmit
+ operation on a wireless interface."
+ ::= { begemotWlanInterface 7 }
+
+wlanIfTxParamsEntry OBJECT-TYPE
+ SYNTAX WlanIfTxParamsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry that contains the transmit parameters of a wireless
+ interface."
+ INDEX { wlanIfaceName, wlanIfTxPhyMode }
+ ::= { wlanIfTxParamsTable 1 }
+
+WlanIfTxParamsEntry ::= SEQUENCE {
+ wlanIfTxPhyMode INTEGER,
+ wlanIfTxUnicastRate INTEGER,
+ wlanIfTxMcastRate INTEGER,
+ wlanIfTxMgmtRate INTEGER,
+ wlanIfTxMaxRetryCount INTEGER
+}
+
+wlanIfTxPhyMode OBJECT-TYPE
+ SYNTAX WlanIfPhyMode
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The PHY mode for this entry."
+ ::= { wlanIfTxParamsEntry 1 }
+
+wlanIfTxUnicastRate OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies a fixed rate for transmitting
+ unicast frames in this phy mode."
+ ::= { wlanIfTxParamsEntry 2 }
+
+wlanIfTxMcastRate OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies a fixed rate for transmitting
+ broadcast and multicast frames in this phy mode."
+ ::= { wlanIfTxParamsEntry 3 }
+
+wlanIfTxMgmtRate OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies a fixed rate for transmitting
+ management and/or control frames in this phy mode."
+ ::= { wlanIfTxParamsEntry 4 }
+
+wlanIfTxMaxRetryCount OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of tries to use when sending unicast frames
+ in this phy mode."
+ ::= { wlanIfTxParamsEntry 5 }
+
+-- ---------------------------------------------------------- --
+-- The Statistics Database for Wireless interfaces
+-- ---------------------------------------------------------- --
+
+wlanIfaceStatisticsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanIfaceStatisticsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains summary statistics for each virtual wireless
+ interface on the managed device."
+ ::= { begemotWlanStatistics 1 }
+
+wlanIfaceStatisticsEntry OBJECT-TYPE
+ SYNTAX WlanIfaceStatisticsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of statistics for each virtual wireless interface."
+ AUGMENTS { wlanInterfaceEntry }
+ ::= { wlanIfaceStatisticsTable 1 }
+
+WlanIfaceStatisticsEntry ::= SEQUENCE {
+ wlanStatsRxBadVersion Counter32,
+ wlanStatsRxTooShort Counter32,
+ wlanStatsRxWrongBssid Counter32,
+ wlanStatsRxDiscardedDups Counter32,
+ wlanStatsRxWrongDir Counter32,
+ wlanStatsRxDiscardMcastEcho Counter32,
+ wlanStatsRxDiscardNoAssoc Counter32,
+ wlanStatsRxWepNoPrivacy Counter32,
+ wlanStatsRxWepUnencrypted Counter32,
+ wlanStatsRxWepFailed Counter32,
+ wlanStatsRxDecapsulationFailed Counter32,
+ wlanStatsRxDiscardMgmt Counter32,
+ wlanStatsRxControl Counter32,
+ wlanStatsRxBeacon Counter32,
+ wlanStatsRxRateSetTooBig Counter32,
+ wlanStatsRxElemMissing Counter32,
+ wlanStatsRxElemTooBig Counter32,
+ wlanStatsRxElemTooSmall Counter32,
+ wlanStatsRxElemUnknown Counter32,
+ wlanStatsRxChannelMismatch Counter32,
+ wlanStatsRxDropped Counter32,
+ wlanStatsRxSsidMismatch Counter32,
+ wlanStatsRxAuthNotSupported Counter32,
+ wlanStatsRxAuthFailed Counter32,
+ wlanStatsRxAuthCM Counter32,
+ wlanStatsRxAssocWrongBssid Counter32,
+ wlanStatsRxAssocNoAuth Counter32,
+ wlanStatsRxAssocCapMismatch Counter32,
+ wlanStatsRxAssocNoRateMatch Counter32,
+ wlanStatsRxBadWpaIE Counter32,
+ wlanStatsRxDeauthenticate Counter32,
+ wlanStatsRxDisassociate Counter32,
+ wlanStatsRxUnknownSubtype Counter32,
+ wlanStatsRxFailedNoBuf Counter32,
+ wlanStatsRxBadAuthRequest Counter32,
+ wlanStatsRxUnAuthorized Counter32,
+ wlanStatsRxBadKeyId Counter32,
+ wlanStatsRxCCMPSeqViolation Counter32,
+ wlanStatsRxCCMPBadFormat Counter32,
+ wlanStatsRxCCMPFailedMIC Counter32,
+ wlanStatsRxTKIPSeqViolation Counter32,
+ wlanStatsRxTKIPBadFormat Counter32,
+ wlanStatsRxTKIPFailedMIC Counter32,
+ wlanStatsRxTKIPFailedICV Counter32,
+ wlanStatsRxDiscardACL Counter32,
+ wlanStatsTxFailedNoBuf Counter32,
+ wlanStatsTxFailedNoNode Counter32,
+ wlanStatsTxUnknownMgmt Counter32,
+ wlanStatsTxBadCipher Counter32,
+ wlanStatsTxNoDefKey Counter32,
+ wlanStatsTxFragmented Counter32,
+ wlanStatsTxFragmentsCreated Counter32,
+ wlanStatsActiveScans Counter32,
+ wlanStatsPassiveScans Counter32,
+ wlanStatsTimeoutInactivity Counter32,
+ wlanStatsCryptoNoMem Counter32,
+ wlanStatsSwCryptoTKIP Counter32,
+ wlanStatsSwCryptoTKIPEnMIC Counter32,
+ wlanStatsSwCryptoTKIPDeMIC Counter32,
+ wlanStatsCryptoTKIPCM Counter32,
+ wlanStatsSwCryptoCCMP Counter32,
+ wlanStatsSwCryptoWEP Counter32,
+ wlanStatsCryptoCipherKeyRejected Counter32,
+ wlanStatsCryptoNoKey Counter32,
+ wlanStatsCryptoDeleteKeyFailed Counter32,
+ wlanStatsCryptoUnknownCipher Counter32,
+ wlanStatsCryptoAttachFailed Counter32,
+ wlanStatsCryptoKeyFailed Counter32,
+ wlanStatsCryptoEnMICFailed Counter32,
+ wlanStatsIBSSCapMismatch Counter32,
+ wlanStatsUnassocStaPSPoll Counter32,
+ wlanStatsBadAidPSPoll Counter32,
+ wlanStatsEmptyPSPoll Counter32,
+ wlanStatsRxFFBadHdr Counter32,
+ wlanStatsRxFFTooShort Counter32,
+ wlanStatsRxFFSplitError Counter32,
+ wlanStatsRxFFDecap Counter32,
+ wlanStatsTxFFEncap Counter32,
+ wlanStatsRxBadBintval Counter32,
+ wlanStatsRxDemicFailed Counter32,
+ wlanStatsRxDefragFailed Counter32,
+ wlanStatsRxMgmt Counter32,
+ wlanStatsRxActionMgmt Counter32,
+ wlanStatsRxAMSDUTooShort Counter32,
+ wlanStatsRxAMSDUSplitError Counter32,
+ wlanStatsRxAMSDUDecap Counter32,
+ wlanStatsTxAMSDUEncap Counter32,
+ wlanStatsAMPDUBadBAR Counter32,
+ wlanStatsAMPDUOowBar Counter32,
+ wlanStatsAMPDUMovedBAR Counter32,
+ wlanStatsAMPDURxBAR Counter32,
+ wlanStatsAMPDURxOor Counter32,
+ wlanStatsAMPDURxCopied Counter32,
+ wlanStatsAMPDURxDropped Counter32,
+ wlanStatsTxDiscardBadState Counter32,
+ wlanStatsTxFailedNoAssoc Counter32,
+ wlanStatsTxClassifyFailed Counter32,
+ wlanStatsDwdsMcastDiscard Counter32,
+ wlanStatsHTAssocRejectNoHT Counter32,
+ wlanStatsHTAssocDowngrade Counter32,
+ wlanStatsHTAssocRateMismatch Counter32,
+ wlanStatsAMPDURxAge Counter32,
+ wlanStatsAMPDUMoved Counter32,
+ wlanStatsADDBADisabledReject Counter32,
+ wlanStatsADDBANoRequest Counter32,
+ wlanStatsADDBABadToken Counter32,
+ wlanStatsADDBABadPolicy Counter32,
+ wlanStatsAMPDUStopped Counter32,
+ wlanStatsAMPDUStopFailed Counter32,
+ wlanStatsAMPDURxReorder Counter32,
+ wlanStatsScansBackground Counter32,
+ wlanLastDeauthReason INTEGER,
+ wlanLastDissasocReason INTEGER,
+ wlanLastAuthFailReason INTEGER,
+ wlanStatsBeaconMissedEvents Counter32,
+ wlanStatsRxDiscardBadStates Counter32,
+ wlanStatsFFFlushed Counter32,
+ wlanStatsTxControlFrames Counter32,
+ wlanStatsAMPDURexmt Counter32,
+ wlanStatsAMPDURexmtFailed Counter32,
+ wlanStatsReset INTEGER
+}
+
+wlanStatsRxBadVersion OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that had bad version."
+ ::= { wlanIfaceStatisticsEntry 1 }
+
+wlanStatsRxTooShort OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that were too short."
+ ::= { wlanIfaceStatisticsEntry 2 }
+
+wlanStatsRxWrongBssid OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface with wrong BSSID."
+ ::= { wlanIfaceStatisticsEntry 3 }
+
+wlanStatsRxDiscardedDups OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of received discarded duplicate frames by this interface."
+ ::= { wlanIfaceStatisticsEntry 4 }
+
+wlanStatsRxWrongDir OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of received frames by this interface that were dropped
+ due to wrong direction."
+ ::= { wlanIfaceStatisticsEntry 5 }
+
+wlanStatsRxDiscardMcastEcho OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of received multicast echo frames discarded by this
+ interface."
+ ::= { wlanIfaceStatisticsEntry 6 }
+
+wlanStatsRxDiscardNoAssoc OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that were dropped
+ since no association existed with the sending station."
+ ::= { wlanIfaceStatisticsEntry 7 }
+
+wlanStatsRxWepNoPrivacy OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that were dropped
+ since they contained WEP information and WEP privacy was off."
+ ::= { wlanIfaceStatisticsEntry 8 }
+
+wlanStatsRxWepUnencrypted OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that were dropped
+ since they contained no WEP information and WEP privacy was on."
+ ::= { wlanIfaceStatisticsEntry 9 }
+
+wlanStatsRxWepFailed OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that were dropped
+ since processing of the WEP information contained in them failed."
+ ::= { wlanIfaceStatisticsEntry 10 }
+
+wlanStatsRxDecapsulationFailed OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of received frames that were discarded by this interface
+ due to decapsulation failure."
+ ::= { wlanIfaceStatisticsEntry 11 }
+
+wlanStatsRxDiscardMgmt OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of received management frames discarded by this interface."
+ ::= { wlanIfaceStatisticsEntry 12 }
+
+wlanStatsRxControl OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of control frames received by this interface."
+ ::= { wlanIfaceStatisticsEntry 13 }
+
+wlanStatsRxBeacon OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of beacon frames received by this interface."
+ ::= { wlanIfaceStatisticsEntry 14 }
+
+wlanStatsRxRateSetTooBig OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface with extended
+ supported rate element."
+ ::= { wlanIfaceStatisticsEntry 15 }
+
+wlanStatsRxElemMissing OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that were missing
+ a required element."
+ ::= { wlanIfaceStatisticsEntry 16 }
+
+wlanStatsRxElemTooBig OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that contained an
+ information element whose size was too big."
+ ::= { wlanIfaceStatisticsEntry 17 }
+
+wlanStatsRxElemTooSmall OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that contained an
+ information element whose size was too small."
+ ::= { wlanIfaceStatisticsEntry 18 }
+
+wlanStatsRxElemUnknown OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that contained an
+ unknown information element."
+ ::= { wlanIfaceStatisticsEntry 19 }
+
+wlanStatsRxChannelMismatch OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface, that were discarded
+ since they were received on a channel different from the one indicated
+ in the DS params element id."
+ ::= { wlanIfaceStatisticsEntry 20 }
+
+wlanStatsRxDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that were dropped due
+ to unknown reason."
+ ::= { wlanIfaceStatisticsEntry 21 }
+
+wlanStatsRxSsidMismatch OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that had a bad SSID."
+ ::= { wlanIfaceStatisticsEntry 22 }
+
+wlanStatsRxAuthNotSupported OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that contained an
+ unknown authentication algorithm."
+ ::= { wlanIfaceStatisticsEntry 23 }
+
+wlanStatsRxAuthFailed OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface for which the
+ authentication failed."
+ ::= { wlanIfaceStatisticsEntry 24 }
+
+wlanStatsRxAuthCM OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface for which the
+ authentication failed due to TKIP countermeasures enabled."
+ ::= { wlanIfaceStatisticsEntry 25 }
+
+wlanStatsRxAssocWrongBssid OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface with association
+ request that had a bad BSSID."
+ ::= { wlanIfaceStatisticsEntry 26 }
+
+wlanStatsRxAssocNoAuth OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface with association
+ request that came from unauthentication node."
+ ::= { wlanIfaceStatisticsEntry 27 }
+
+wlanStatsRxAssocCapMismatch OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface with association
+ request that had bad capabilities set."
+ ::= { wlanIfaceStatisticsEntry 28 }
+
+wlanStatsRxAssocNoRateMatch OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface with association
+ request that had unsupported rate set."
+ ::= { wlanIfaceStatisticsEntry 29 }
+
+wlanStatsRxBadWpaIE OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface with association
+ request that had no or invalid WPA information element."
+ ::= { wlanIfaceStatisticsEntry 30 }
+
+wlanStatsRxDeauthenticate OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of deauthentication requests received by this interface."
+ ::= { wlanIfaceStatisticsEntry 31 }
+
+wlanStatsRxDisassociate OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of deassociation requests received by this interface."
+ ::= { wlanIfaceStatisticsEntry 32 }
+
+wlanStatsRxUnknownSubtype OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that had unknown
+ subtype."
+ ::= { wlanIfaceStatisticsEntry 33 }
+
+wlanStatsRxFailedNoBuf OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that were dropped
+ due to lack of free buffers."
+ ::= { wlanIfaceStatisticsEntry 34 }
+
+wlanStatsRxBadAuthRequest OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface for which
+ authentication failed."
+ ::= { wlanIfaceStatisticsEntry 35 }
+
+wlanStatsRxUnAuthorized OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of non-PAE frames received by this interface prior to
+ authorization."
+ ::= { wlanIfaceStatisticsEntry 36 }
+
+wlanStatsRxBadKeyId OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface with bad key."
+ ::= { wlanIfaceStatisticsEntry 37 }
+
+wlanStatsRxCCMPSeqViolation OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that caused CCMP
+ sequence violation."
+ ::= { wlanIfaceStatisticsEntry 38 }
+
+wlanStatsRxCCMPBadFormat OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that had bad CCMP
+ format."
+ ::= { wlanIfaceStatisticsEntry 39 }
+
+wlanStatsRxCCMPFailedMIC OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames receivbed by this interface for which CCMP
+ decryption failed due to MIC mismatch."
+ ::= { wlanIfaceStatisticsEntry 40 }
+
+wlanStatsRxTKIPSeqViolation OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that caused TKIP
+ sequence violation.."
+ ::= { wlanIfaceStatisticsEntry 41 }
+
+wlanStatsRxTKIPBadFormat OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that were missing
+ TKIP ExtIV."
+ ::= { wlanIfaceStatisticsEntry 42 }
+
+wlanStatsRxTKIPFailedMIC OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface for which TKIP
+ decryption failed due to MIC mismatch."
+ ::= { wlanIfaceStatisticsEntry 43 }
+
+wlanStatsRxTKIPFailedICV OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface for which TKIP
+ decryption failed due to ICV mismatch."
+ ::= { wlanIfaceStatisticsEntry 44 }
+
+wlanStatsRxDiscardACL OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface that were
+ disallowed by ACL."
+ ::= { wlanIfaceStatisticsEntry 45 }
+
+wlanStatsTxFailedNoBuf OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were not transmitted by this interface
+ due to lack of free buffers."
+ ::= { wlanIfaceStatisticsEntry 46 }
+
+wlanStatsTxFailedNoNode OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were queued for transmit on this interface
+ but were not sent since appropriate node for sending was not found."
+ ::= { wlanIfaceStatisticsEntry 47 }
+
+wlanStatsTxUnknownMgmt OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of unknown management frames transmitted by this interface."
+ ::= { wlanIfaceStatisticsEntry 48 }
+
+wlanStatsTxBadCipher OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were queued for transmit on this interface
+ but were not send since the specified key was not setup."
+ ::= { wlanIfaceStatisticsEntry 49 }
+
+wlanStatsTxNoDefKey OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were queued for transmit on this interface
+ but were not send since an appropriate key was not found."
+ ::= { wlanIfaceStatisticsEntry 50 }
+
+wlanStatsTxFragmented OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of fragmented frames transmitted by this interface."
+ ::= { wlanIfaceStatisticsEntry 51 }
+
+wlanStatsTxFragmentsCreated OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of created fragments transmitted by this interface."
+ ::= { wlanIfaceStatisticsEntry 52 }
+
+wlanStatsActiveScans OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of active scans performed by this interface."
+ ::= { wlanIfaceStatisticsEntry 53 }
+
+wlanStatsPassiveScans OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of passive scans performed by this interface."
+ ::= { wlanIfaceStatisticsEntry 54 }
+
+wlanStatsTimeoutInactivity OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times a station/node was dropped by this interface
+ due to inactivity timeout."
+ ::= { wlanIfaceStatisticsEntry 55 }
+
+wlanStatsCryptoNoMem OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number times attaching a crypto protocol to this interface
+ failed due to lack of memory."
+ ::= { wlanIfaceStatisticsEntry 56 }
+
+wlanStatsSwCryptoTKIP OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times TKIP encryption/decryption was handled in
+ software for frames received/transmitted by this interface."
+ ::= { wlanIfaceStatisticsEntry 57 }
+
+wlanStatsSwCryptoTKIPEnMIC OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times TKIP MIC was added in software to frames
+ transmitted by this interface."
+ ::= { wlanIfaceStatisticsEntry 58 }
+
+wlanStatsSwCryptoTKIPDeMIC OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times TKIP MIC was stripped in software from frames
+ received by this interface."
+ ::= { wlanIfaceStatisticsEntry 59 }
+
+wlanStatsCryptoTKIPCM OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames discarded by this interface due to TKIP
+ counter measures."
+ ::= { wlanIfaceStatisticsEntry 60 }
+
+wlanStatsSwCryptoCCMP OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times CCMP encryption/decryption was handled in
+ software for frames received/transmitted by this interface."
+ ::= { wlanIfaceStatisticsEntry 61 }
+
+wlanStatsSwCryptoWEP OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times WEP encryption/decryption was handled in
+ software for frames received/transmitted by this interface."
+ ::= { wlanIfaceStatisticsEntry 62 }
+
+wlanStatsCryptoCipherKeyRejected OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times a key was rejected for this interface."
+ ::= { wlanIfaceStatisticsEntry 63 }
+
+wlanStatsCryptoNoKey OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times key setup for this interface failed."
+ ::= { wlanIfaceStatisticsEntry 64 }
+
+wlanStatsCryptoDeleteKeyFailed OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times key deletion from driver for this interface
+ failed."
+ ::= { wlanIfaceStatisticsEntry 65 }
+
+wlanStatsCryptoUnknownCipher OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times key setup for this interface failed due to
+ invalid cipher."
+ ::= { wlanIfaceStatisticsEntry 66 }
+
+wlanStatsCryptoAttachFailed OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times attaching a cipher for this interface failed."
+ ::= { wlanIfaceStatisticsEntry 67 }
+
+wlanStatsCryptoKeyFailed OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times setting a cipher in the driver for this
+ interface failed."
+ ::= { wlanIfaceStatisticsEntry 68 }
+
+wlanStatsCryptoEnMICFailed OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were discarded by by this interface
+ due to failed enmic."
+ ::= { wlanIfaceStatisticsEntry 69 }
+
+wlanStatsIBSSCapMismatch OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times a BSSID change failed for an interface operating
+ in ad hoc mode due to capabilities mismatch."
+ ::= { wlanIfaceStatisticsEntry 70 }
+
+wlanStatsUnassocStaPSPoll OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of ps-poll frames from unassociated station received
+ by this interface."
+ ::= { wlanIfaceStatisticsEntry 71 }
+
+wlanStatsBadAidPSPoll OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of ps-poll frames with incorrect aid received by this
+ interface."
+ ::= { wlanIfaceStatisticsEntry 72 }
+
+wlanStatsEmptyPSPoll OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of empty ps-poll frames received by this interface."
+ ::= { wlanIfaceStatisticsEntry 73 }
+
+wlanStatsRxFFBadHdr OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of fast frames with bad header received by this interface."
+ ::= { wlanIfaceStatisticsEntry 74 }
+
+wlanStatsRxFFTooShort OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of fast frames received by this interface, for which
+ decapsulation failed."
+ ::= { wlanIfaceStatisticsEntry 75 }
+
+wlanStatsRxFFSplitError OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of fast frames received by this interface, for which
+ decapsulation failed during split."
+ ::= { wlanIfaceStatisticsEntry 76 }
+
+wlanStatsRxFFDecap OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of fast frames received by this interface, that were
+ successfully decapsulated."
+ ::= { wlanIfaceStatisticsEntry 77 }
+
+wlanStatsTxFFEncap OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of encapsulated fast frames transmitted by this interface."
+ ::= { wlanIfaceStatisticsEntry 78 }
+
+wlanStatsRxBadBintval OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames with bogus beacon interval received by this
+ interface."
+ ::= { wlanIfaceStatisticsEntry 79 }
+
+wlanStatsRxDemicFailed OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface for which
+ stripping of the MIC failed."
+ ::= { wlanIfaceStatisticsEntry 80 }
+
+wlanStatsRxDefragFailed OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received by this interface for which
+ defragmentation failed."
+ ::= { wlanIfaceStatisticsEntry 81 }
+
+wlanStatsRxMgmt OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of management frames received by this interface."
+ ::= { wlanIfaceStatisticsEntry 82 }
+
+wlanStatsRxActionMgmt OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of action management frames received by this interface."
+ ::= { wlanIfaceStatisticsEntry 83 }
+
+wlanStatsRxAMSDUTooShort OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MSDU frames received by this interface for which
+ decapsulaiton failed."
+ ::= { wlanIfaceStatisticsEntry 84 }
+
+wlanStatsRxAMSDUSplitError OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MSDU frames received by this interface for which
+ split failed."
+ ::= { wlanIfaceStatisticsEntry 85 }
+
+wlanStatsRxAMSDUDecap OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MSDU frames received by this interface which
+ were successfully decapsulaited."
+ ::= { wlanIfaceStatisticsEntry 86 }
+
+wlanStatsTxAMSDUEncap OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of encapsulated A-MSDU frames transmitted by this
+ interface."
+ ::= { wlanIfaceStatisticsEntry 87 }
+
+wlanStatsAMPDUBadBAR OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MPDU frames that were dropped by this interface
+ source BAR frame processing was disabled."
+ ::= { wlanIfaceStatisticsEntry 88 }
+
+wlanStatsAMPDUOowBar OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MPDU BAR before ADDBA frames received by this
+ interface."
+ ::= { wlanIfaceStatisticsEntry 89 }
+
+wlanStatsAMPDUMovedBAR OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times a BAR moved window occurred."
+ ::= { wlanIfaceStatisticsEntry 90 }
+
+wlanStatsAMPDURxBAR OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MPDU BAR frames received by this interface."
+ ::= { wlanIfaceStatisticsEntry 91 }
+
+wlanStatsAMPDURxOor OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of out-of-order A-MPDU frames by received this interface."
+ ::= { wlanIfaceStatisticsEntry 92 }
+
+wlanStatsAMPDURxCopied OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MPDU frames by copied down this interface."
+ ::= { wlanIfaceStatisticsEntry 93 }
+
+wlanStatsAMPDURxDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MPDU frames by dropped this interface."
+ ::= { wlanIfaceStatisticsEntry 94 }
+
+wlanStatsTxDiscardBadState OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames queued for transmit on this interface that
+ were discarded due to interface state not ready for transmit."
+ ::= { wlanIfaceStatisticsEntry 95 }
+
+wlanStatsTxFailedNoAssoc OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames queued for transmit on this interface that
+ were discarded since the receiving station was not associated."
+ ::= { wlanIfaceStatisticsEntry 96 }
+
+wlanStatsTxClassifyFailed OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames queued for transmit on this interface that
+ were discarded since their priority was not determined."
+ ::= { wlanIfaceStatisticsEntry 97 }
+
+wlanStatsDwdsMcastDiscard OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of multicast over DWDS frames discarded by this interface."
+ ::= { wlanIfaceStatisticsEntry 98 }
+
+wlanStatsHTAssocRejectNoHT OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of management frames received from a non-HT stations
+ that were rejected by this interface."
+ ::= { wlanIfaceStatisticsEntry 99 }
+
+wlanStatsHTAssocDowngrade OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times HT was disallowed for an association on
+ this interface due to WEP or TKIP requested."
+ ::= { wlanIfaceStatisticsEntry 100 }
+
+wlanStatsHTAssocRateMismatch OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times rate mismatch occurred during HT rate set
+ handling on this interface."
+ ::= { wlanIfaceStatisticsEntry 101 }
+
+wlanStatsAMPDURxAge OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MPDU frames sent by this interface due to aging out."
+ ::= { wlanIfaceStatisticsEntry 102 }
+
+wlanStatsAMPDUMoved OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of time A-MPDU MSDU moved window occurred for this
+ interface."
+ ::= { wlanIfaceStatisticsEntry 103 }
+
+wlanStatsADDBADisabledReject OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of received ADDBA frames that were discarded by this
+ interface since ADDBA was disabled."
+ ::= { wlanIfaceStatisticsEntry 104 }
+
+wlanStatsADDBANoRequest OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of received ADDBA responses frames that were discarded
+ by this interface due to no pending ADDBA."
+ ::= { wlanIfaceStatisticsEntry 105 }
+
+wlanStatsADDBABadToken OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of received ADDBA response frames that were discarded
+ by this interface since ADDBA response caused dialogtoken mismatch."
+ ::= { wlanIfaceStatisticsEntry 106 }
+
+wlanStatsADDBABadPolicy OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of received ADDBA response frames that were discarded
+ by this interface since ADDBA response caused policy mismatch."
+ ::= { wlanIfaceStatisticsEntry 107 }
+
+wlanStatsAMPDUStopped OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times a A-MPDU stream stopped on this interface."
+ ::= { wlanIfaceStatisticsEntry 108 }
+
+wlanStatsAMPDUStopFailed OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times a A-MPDU stream stop failed on this interface."
+ ::= { wlanIfaceStatisticsEntry 109 }
+
+wlanStatsAMPDURxReorder OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of received reordered A-MPDU frames on this interface."
+ ::= { wlanIfaceStatisticsEntry 110 }
+
+wlanStatsScansBackground OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of background scans started on this interface."
+ ::= { wlanIfaceStatisticsEntry 111 }
+
+wlanLastDeauthReason OBJECT-TYPE
+ SYNTAX WlanMgmtReasonCode
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The last received deauthenticate reason on this interface."
+ ::= { wlanIfaceStatisticsEntry 112 }
+
+wlanLastDissasocReason OBJECT-TYPE
+ SYNTAX WlanMgmtReasonCode
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The last received disassociate reason on this interface."
+ ::= { wlanIfaceStatisticsEntry 113 }
+
+wlanLastAuthFailReason OBJECT-TYPE
+ SYNTAX WlanMgmtReasonCode
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The last received authentication failed reason on this interface."
+ ::= { wlanIfaceStatisticsEntry 114 }
+
+wlanStatsBeaconMissedEvents OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of beacon miss notification events on this interface."
+ ::= { wlanIfaceStatisticsEntry 115 }
+
+wlanStatsRxDiscardBadStates OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames received on this interface that were discarded
+ due to interface state not ready for receive."
+ ::= { wlanIfaceStatisticsEntry 116 }
+
+wlanStatsFFFlushed OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of fast frames flushed from the stage queue on this
+ interface."
+ ::= { wlanIfaceStatisticsEntry 117 }
+
+wlanStatsTxControlFrames OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of control frames transmitted by this interface."
+ ::= { wlanIfaceStatisticsEntry 118 }
+
+wlanStatsAMPDURexmt OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MPDU frames successfully retransmitted by this
+ interface."
+ ::= { wlanIfaceStatisticsEntry 119 }
+
+wlanStatsAMPDURexmtFailed OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of A-MPDU frames for which retransmission failed on
+ this interface."
+ ::= { wlanIfaceStatisticsEntry 120 }
+
+wlanStatsReset OBJECT-TYPE
+ SYNTAX INTEGER {
+ no-op(1),
+ clear(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object is used to reset the statistics on this
+ interface."
+ ::= { wlanIfaceStatisticsEntry 121 }
+
+-- ---------------------------------------------------------- --
+-- The WEP Configuration Database for Wireless interfaces
+-- ---------------------------------------------------------- --
+
+wlanWepInterfaceTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanWepInterfaceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains WEP configuration for the wireless interfaces
+ on the managed system."
+ ::= { begemotWlanWep 1 }
+
+wlanWepInterfaceEntry OBJECT-TYPE
+ SYNTAX WlanWepInterfaceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "WEP Configuration for wireless interface."
+ INDEX { wlanIfaceName}
+ ::= { wlanWepInterfaceTable 1 }
+
+WlanWepInterfaceEntry ::= SEQUENCE {
+ wlanWepMode INTEGER,
+ wlanWepDefTxKey INTEGER
+}
+
+wlanWepMode OBJECT-TYPE
+ SYNTAX INTEGER {
+ off(0),
+ on(1),
+ mixed(2)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The WEP mode set on the interface."
+ DEFVAL { off }
+ ::= { wlanWepInterfaceEntry 1 }
+
+wlanWepDefTxKey OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The index of the default WEP key for the interface."
+ ::= { wlanWepInterfaceEntry 2 }
+
+wlanWepKeyTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanWepKeyEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains the configured WEP keys for a virtual
+ wireless interface."
+ ::= { begemotWlanWep 2 }
+
+wlanWepKeyEntry OBJECT-TYPE
+ SYNTAX WlanWepKeyEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A configured WEP Key entry."
+ INDEX { wlanIfaceName, wlanWepKeyID }
+ ::= { wlanWepKeyTable 1 }
+
+WlanWepKeyEntry ::= SEQUENCE {
+ wlanWepKeyID INTEGER,
+ wlanWepKeyLength INTEGER,
+ wlanWepKeySet OCTET STRING,
+ wlanWepKeyHash OCTET STRING,
+ wlanWepKeyStatus RowStatus
+}
+
+wlanWepKeyID OBJECT-TYPE
+ SYNTAX INTEGER (1..4)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The WEP Key ID."
+ ::= { wlanWepKeyEntry 1 }
+
+wlanWepKeyLength OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The WEP Key length."
+ ::= { wlanWepKeyEntry 2 }
+
+wlanWepKeySet OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The WEP Key String to configure for this key. When GET is attempted
+ for this column, an empty Octet String is returned."
+ ::= { wlanWepKeyEntry 3 }
+
+wlanWepKeyHash OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The SHA256 hash produced of the WEP Key String."
+ ::= { wlanWepKeyEntry 4 }
+
+wlanWepKeyStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object is used for creating/deleting WEP keys."
+ ::= { wlanWepKeyEntry 5 }
+
+-- ---------------------------------------------------------- --
+-- The MAC Access Control Database for Wireless interfaces
+-- ---------------------------------------------------------- --
+
+wlanMACAccessControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanMACAccessControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains Access Control configuration for wireless
+ interfaces operating as an access point."
+ ::= { begemotWlanMACAccessControl 1 }
+
+wlanMACAccessControlEntry OBJECT-TYPE
+ SYNTAX WlanMACAccessControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The MAC Access Control configuration for a wireless interface
+ operating as an access point."
+ INDEX { wlanIfaceName}
+ ::= { wlanMACAccessControlTable 1 }
+
+WlanMACAccessControlEntry ::= SEQUENCE {
+ wlanMACAccessControlPolicy INTEGER,
+ wlanMACAccessControlNacl Counter32,
+ wlanMACAccessControlFlush INTEGER
+}
+
+wlanMACAccessControlPolicy OBJECT-TYPE
+ SYNTAX INTEGER {
+ open(0),
+ allow(1),
+ deny(2),
+ radius(7)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the MAC Access Control policy
+ for this Host AP interface."
+ DEFVAL { open }
+ ::= { wlanMACAccessControlEntry 1 }
+
+wlanMACAccessControlNacl OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of active MAC Access Control Entries in the Database
+ for this Host AP interface."
+ ::= { wlanMACAccessControlEntry 2 }
+
+wlanMACAccessControlFlush OBJECT-TYPE
+ SYNTAX INTEGER {
+ no-op(0),
+ flush(1)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object is used to flush all entries from the MAC Access
+ Control Database for the specified virtual wireless interface."
+ ::= { wlanMACAccessControlEntry 3 }
+
+wlanMACAccessControlMACTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanMACAccessControlMACEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains Access Control MAC for virtual wireless
+ interfaces operating in Host AP mode."
+ ::= { begemotWlanMACAccessControl 2 }
+
+wlanMACAccessControlMACEntry OBJECT-TYPE
+ SYNTAX WlanMACAccessControlMACEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The MAC Access Control configuration database with MAC addresses
+ for a virtual wireless interface."
+ INDEX { wlanIfaceName, wlanMACAccessControlMAC }
+ ::= { wlanMACAccessControlMACTable 1 }
+
+WlanMACAccessControlMACEntry ::= SEQUENCE {
+ wlanMACAccessControlMAC MacAddress,
+ wlanMACAccessControlMACStatus RowStatus
+}
+
+wlanMACAccessControlMAC OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of this object specifies the station's MAC to which
+ the Access Control policy will be applied."
+ ::= { wlanMACAccessControlMACEntry 1 }
+
+wlanMACAccessControlMACStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The object is used to add or delete MAC entries from the Access
+ Control Database for this interface operating in Host AP mode.
+ To add an entry the value of this object should be set to createAndGo,
+ a value of destroy will remove an existing entry. A GET on this object
+ will always return value active."
+ ::= { wlanMACAccessControlMACEntry 2 }
+
+-- ---------------------------------------------------------- --
+-- The Mesh Routing Database for interfaces operating in mesh mode
+-- ---------------------------------------------------------- --
+
+wlanMeshRoutingConfig OBJECT IDENTIFIER ::= { begemotWlanMeshRouting 1 }
+
+wlanMeshInterface OBJECT IDENTIFIER ::= { begemotWlanMeshRouting 2 }
+
+wlanMeshRoute OBJECT IDENTIFIER ::= { begemotWlanMeshRouting 3 }
+
+wlanMeshStatistics OBJECT IDENTIFIER ::= { begemotWlanMeshRouting 4 }
+
+wlanMeshRouteProtocols OBJECT IDENTIFIER ::= { begemotWlanMeshRouting 5 }
+
+wlanMeshMaxRetries OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Maximum retries during peer link establishment for wireless mesh
+ routing operation."
+ DEFVAL { 2 }
+ ::= { wlanMeshRoutingConfig 1 }
+
+wlanMeshConfirmTimeout OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Confirm state timeout for wireless mesh routing operation."
+ DEFVAL { 40 }
+ ::= { wlanMeshRoutingConfig 2 }
+
+wlanMeshHoldingTimeout OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Holding state timeout for wireless mesh routing operation."
+ DEFVAL { 40 }
+ ::= { wlanMeshRoutingConfig 3 }
+
+wlanMeshRetryTimeout OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Retry timeout for wireless mesh routing operation."
+ DEFVAL { 40 }
+ ::= { wlanMeshRoutingConfig 4 }
+
+wlanMeshInterfaceTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanMeshInterfaceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information for wireless interfaces operating
+ as wireless mesh points."
+ ::= { wlanMeshInterface 1 }
+
+wlanMeshInterfaceEntry OBJECT-TYPE
+ SYNTAX WlanMeshInterfaceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Wireless Mesh Routing information for an interface operating as
+ mesh point."
+ INDEX { wlanIfaceName }
+ ::= { wlanMeshInterfaceTable 1 }
+
+WlanMeshInterfaceEntry ::= SEQUENCE {
+ wlanMeshId OCTET STRING,
+ wlanMeshTTL INTEGER,
+ wlanMeshPeeringEnabled TruthValue,
+ wlanMeshForwardingEnabled TruthValue,
+ wlanMeshMetric INTEGER,
+ wlanMeshPath INTEGER,
+ wlanMeshRoutesFlush INTEGER
+}
+
+wlanMeshId OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(1..32))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The desired Mesh Identifier for the interface."
+ ::= { wlanMeshInterfaceEntry 1 }
+
+wlanMeshTTL OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "hops"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The number of hops a packet may be forwarded before it is discarded."
+ DEFVAL { 31 }
+ ::= { wlanMeshInterfaceEntry 2 }
+
+wlanMeshPeeringEnabled OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Enable or disable peering with neighbor mesh stations for this
+ interface."
+ DEFVAL { true }
+ ::= { wlanMeshInterfaceEntry 3 }
+
+wlanMeshForwardingEnabled OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Enable or disable forwarding packets by this interface."
+ DEFVAL { true }
+ ::= { wlanMeshInterfaceEntry 4 }
+
+wlanMeshMetric OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(0),
+ airtime(1)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The link metric protocol used by the interface."
+ DEFVAL { airtime }
+ ::= { wlanMeshInterfaceEntry 5 }
+
+wlanMeshPath OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(0),
+ hwmp(1)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The path selection protocol used by the interface."
+ DEFVAL { hwmp }
+ ::= { wlanMeshInterfaceEntry 6 }
+
+wlanMeshRoutesFlush OBJECT-TYPE
+ SYNTAX INTEGER {
+ no-op(0),
+ flush(1)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object is used to flush all mesh route entries from the mesh
+ routing table for the specified interface."
+ ::= { wlanMeshInterfaceEntry 7 }
+
+wlanMeshNeighborTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanMeshNeighborEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information for the neighbors of wireless
+ interfaces operating in mesh mode."
+ ::= { wlanMeshInterface 2 }
+
+wlanMeshNeighborEntry OBJECT-TYPE
+ SYNTAX WlanMeshNeighborEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information for all neighbors of a wireless interface operating as
+ a mesh point."
+ INDEX { wlanIfaceName, wlanMeshNeighborAddress }
+ ::= { wlanMeshNeighborTable 1 }
+
+WlanMeshNeighborEntry ::= SEQUENCE {
+ wlanMeshNeighborAddress MacAddress,
+ wlanMeshNeighborFrequency INTEGER,
+ wlanMeshNeighborLocalId INTEGER,
+ wlanMeshNeighborPeerId INTEGER,
+ wlanMeshNeighborPeerState INTEGER,
+ wlanMeshNeighborCurrentTXRate INTEGER,
+ wlanMeshNeighborRxSignalStrength INTEGER,
+ wlanMeshNeighborIdleTimer INTEGER,
+ wlanMeshNeighborTxSequenceNo INTEGER,
+ wlanMeshNeighborRxSequenceNo INTEGER
+}
+
+wlanMeshNeighborAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The Ethernet address of this neighbor."
+ ::= { wlanMeshNeighborEntry 1 }
+
+wlanMeshNeighborFrequency OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The operating frequency for the link with this neighbor."
+ ::= { wlanMeshNeighborEntry 2 }
+
+wlanMeshNeighborLocalId OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The local mesh id for this neighbor."
+ ::= { wlanMeshNeighborEntry 3 }
+
+wlanMeshNeighborPeerId OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The mesh peer id of this neighbor."
+ ::= { wlanMeshNeighborEntry 4 }
+
+wlanMeshNeighborPeerState OBJECT-TYPE
+ SYNTAX INTEGER {
+ idle(0),
+ openTx(1),
+ openRx(2),
+ confirmRx(3),
+ established(4),
+ closing(5)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The current link state for this neighbor."
+ ::= { wlanMeshNeighborEntry 5 }
+
+wlanMeshNeighborCurrentTXRate OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The current transmit rate for this neighbor."
+ ::= { wlanMeshNeighborEntry 6 }
+
+wlanMeshNeighborRxSignalStrength OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The average receive signal strength for this neighbor."
+ ::= { wlanMeshNeighborEntry 7 }
+
+wlanMeshNeighborIdleTimer OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of this neighbor's inactivity timer."
+ ::= { wlanMeshNeighborEntry 8 }
+
+wlanMeshNeighborTxSequenceNo OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The last sequence number transmitted to this neighbor."
+ ::= { wlanMeshNeighborEntry 9 }
+
+wlanMeshNeighborRxSequenceNo OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The last sequence number received from this neighbor."
+ ::= { wlanMeshNeighborEntry 10 }
+
+wlanMeshRouteTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanMeshRouteEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains the mesh routing table for interfaces operating
+ as mesh points, used for forwarding packets on a mesh network."
+ ::= { wlanMeshRoute 1 }
+
+wlanMeshRouteEntry OBJECT-TYPE
+ SYNTAX WlanMeshRouteEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Wireless Mesh Routing Table entries for virtual wireless interfaces."
+ INDEX { wlanIfaceName, wlanMeshRouteDestination }
+ ::= { wlanMeshRouteTable 1 }
+
+WlanMeshRouteEntry ::= SEQUENCE {
+ wlanMeshRouteDestination MacAddress,
+ wlanMeshRouteNextHop MacAddress,
+ wlanMeshRouteHops INTEGER,
+ wlanMeshRouteMetric Unsigned32,
+ wlanMeshRouteLifeTime Unsigned32,
+ wlanMeshRouteLastMseq Unsigned32,
+ wlanMeshRouteFlags BITS,
+ wlanMeshRouteStatus RowStatus
+}
+
+wlanMeshRouteDestination OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The mesh route entry's destination address."
+ ::= { wlanMeshRouteEntry 1 }
+
+wlanMeshRouteNextHop OBJECT-TYPE
+ SYNTAX MacAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The mesh route entry's next hop address."
+ ::= { wlanMeshRouteEntry 2 }
+
+wlanMeshRouteHops OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of hops for this mesh route entry."
+ ::= { wlanMeshRouteEntry 3 }
+
+wlanMeshRouteMetric OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The metric of this mesh route entry."
+ ::= { wlanMeshRouteEntry 4 }
+
+wlanMeshRouteLifeTime OBJECT-TYPE
+ SYNTAX Unsigned32
+ UNITS "seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The life time of this mesh route entry."
+ ::= { wlanMeshRouteEntry 5 }
+
+wlanMeshRouteLastMseq OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The last sequence number seen from this destination."
+ ::= { wlanMeshRouteEntry 6 }
+
+wlanMeshRouteFlags OBJECT-TYPE
+ SYNTAX BITS {
+ valid(1),
+ proxy(2)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The Mesh Route entry's flags."
+ ::= { wlanMeshRouteEntry 7 }
+
+wlanMeshRouteStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The object is used to add or delete entries from the mesh routing
+ table for the virtual wireless interface."
+ ::= { wlanMeshRouteEntry 8 }
+
+wlanMeshStatsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanMeshStatsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains summary statistics for each virtual wireless
+ interface operating as mesh point."
+ ::= { wlanMeshStatistics 1 }
+
+wlanMeshStatsEntry OBJECT-TYPE
+ SYNTAX WlanMeshStatsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of statistics for each virtual wireless interface operating
+ as mesh point."
+ INDEX { wlanIfaceName }
+ ::= { wlanMeshStatsTable 1 }
+
+WlanMeshStatsEntry ::= SEQUENCE {
+ wlanMeshDroppedBadSta Counter32,
+ wlanMeshDroppedNoLink Counter32,
+ wlanMeshNoFwdTtl Counter32,
+ wlanMeshNoFwdBuf Counter32,
+ wlanMeshNoFwdTooShort Counter32,
+ wlanMeshNoFwdDisabled Counter32,
+ wlanMeshNoFwdPathUnknown Counter32,
+ wlanMeshDroppedBadAE Counter32,
+ wlanMeshRouteAddFailed Counter32,
+ wlanMeshDroppedNoProxy Counter32,
+ wlanMeshDroppedMisaligned Counter32
+}
+
+wlanMeshDroppedBadSta OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames dropped by this interface since they were
+ received from a non-mesh station."
+ ::= { wlanMeshStatsEntry 1 }
+
+wlanMeshDroppedNoLink OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames dropped by this interface since no link had
+ been established."
+ ::= { wlanMeshStatsEntry 2 }
+
+wlanMeshNoFwdTtl OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were not forwarded by this interface
+ because of a zero TTL."
+ ::= { wlanMeshStatsEntry 3 }
+
+wlanMeshNoFwdBuf OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were not forwarded by this interface
+ due to lack of free buffers."
+ ::= { wlanMeshStatsEntry 4 }
+
+wlanMeshNoFwdTooShort OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were not forwarded by this interface
+ due to missing headers."
+ ::= { wlanMeshStatsEntry 5 }
+
+wlanMeshNoFwdDisabled OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were not forwarded by this interface
+ since forwarding was disabled."
+ ::= { wlanMeshStatsEntry 6 }
+
+wlanMeshNoFwdPathUnknown OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were not forwarded by this interface
+ since the path was unknown."
+ ::= { wlanMeshStatsEntry 7 }
+
+wlanMeshDroppedBadAE OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were dropped by this interface since
+ the AE was invalid."
+ ::= { wlanMeshStatsEntry 8 }
+
+wlanMeshRouteAddFailed OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an addition of a route to the mesh routing
+ table for this interface failed."
+ ::= { wlanMeshStatsEntry 9 }
+
+wlanMeshDroppedNoProxy OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were dropped by this interface since
+ proxying was not enabled on the interface."
+ ::= { wlanMeshStatsEntry 10 }
+
+wlanMeshDroppedMisaligned OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of frames that were dropped by this interface due to
+ bad alignment."
+ ::= { wlanMeshStatsEntry 11 }
+
+-- ---------------------------------------------------------- --
+-- Subtrees containing data for each supported mesh routing protocol.
+-- ---------------------------------------------------------- --
+
+wlanMeshProtoHWMP OBJECT IDENTIFIER ::= { wlanMeshRouteProtocols 1 }
+
+-- ---------------------------------------------------------- --
+-- Hybrid Wireless Mesh Protocol database.
+-- ---------------------------------------------------------- --
+wlanMeshHWMPConfig OBJECT IDENTIFIER ::= { wlanMeshProtoHWMP 1 }
+
+wlanMeshHWMPInterface OBJECT IDENTIFIER ::= { wlanMeshProtoHWMP 2 }
+
+wlanMeshHWMPStatistics OBJECT IDENTIFIER ::= { wlanMeshProtoHWMP 3 }
+
+wlanHWMPRouteInactiveTimeout OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The HWMP Route inactivity timeout."
+ DEFVAL { 5000 }
+ ::= { wlanMeshHWMPConfig 1 }
+
+wlanHWMPRootAnnounceInterval OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The HWMP Root Announcement interval."
+ DEFVAL { 1000 }
+ ::= { wlanMeshHWMPConfig 2 }
+
+wlanHWMPRootInterval OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The HWMP Root interval."
+ DEFVAL { 2000 }
+ ::= { wlanMeshHWMPConfig 3 }
+
+wlanHWMPRootTimeout OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The root PREQ timeout."
+ DEFVAL { 5000 }
+ ::= { wlanMeshHWMPConfig 4 }
+
+wlanHWMPPathLifetime OBJECT-TYPE
+ SYNTAX INTEGER
+ UNITS "milliseconds"
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The HWMP path entry lifetime."
+ DEFVAL { 500 }
+ ::= { wlanMeshHWMPConfig 5 }
+
+wlanHWMPReplyForwardBit OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "A non-zero value for this object specifies that RF bit shall be
+ set on generated PREQs."
+ DEFVAL { 1 }
+ ::= { wlanMeshHWMPConfig 6 }
+
+wlanHWMPTargetOnlyBit OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "A non-zero value for this object specifies that TO bit shall be
+ set on generated PREQs."
+ DEFVAL { 0 }
+ ::= { wlanMeshHWMPConfig 7 }
+
+wlanHWMPInterfaceTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanHWMPInterfaceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains information for wireless interfaces
+ operating in mesh mode."
+ ::= { wlanMeshHWMPInterface 1 }
+
+wlanHWMPInterfaceEntry OBJECT-TYPE
+ SYNTAX WlanHWMPInterfaceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Wireless Mesh Routing HWMP information for a wireless interface."
+ INDEX { wlanIfaceName }
+ ::= { wlanHWMPInterfaceTable 1 }
+
+WlanHWMPInterfaceEntry ::= SEQUENCE {
+ wlanHWMPRootMode INTEGER,
+ wlanHWMPMaxHops INTEGER
+}
+
+wlanHWMPRootMode OBJECT-TYPE
+ SYNTAX INTEGER {
+ disabled(1),
+ normal(2),
+ proactive(3),
+ rann(4)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object is used to configure whether the interface will operate
+ as root node and specify root node mode."
+ DEFVAL { disabled }
+ ::= { wlanHWMPInterfaceEntry 1 }
+
+wlanHWMPMaxHops OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of hops allowed on an HMWP path for this interface."
+ DEFVAL { 31 }
+ ::= { wlanHWMPInterfaceEntry 2 }
+
+wlanMeshHWMPStatsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WlanMeshHWMPStatsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table that contains summary statistics for HWMP operation on an
+ interface operating as mesh point."
+ ::= { wlanMeshHWMPStatistics 1 }
+
+wlanMeshHWMPStatsEntry OBJECT-TYPE
+ SYNTAX WlanMeshHWMPStatsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of HWMP statistics for each wlan interface operating as HWMP
+ mesh point."
+ INDEX { wlanIfaceName }
+ ::= { wlanMeshHWMPStatsTable 1 }
+
+WlanMeshHWMPStatsEntry ::= SEQUENCE {
+ wlanMeshHWMPWrongSeqNo Counter32,
+ wlanMeshHWMPTxRootPREQ Counter32,
+ wlanMeshHWMPTxRootRANN Counter32,
+ wlanMeshHWMPProxy Counter32
+}
+
+wlanMeshHWMPWrongSeqNo OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of HWMP frames with wrong sequence number received by
+ this interface."
+ ::= { wlanMeshHWMPStatsEntry 1 }
+
+wlanMeshHWMPTxRootPREQ OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of HWMP Root PREQ frames sent by this interface."
+ ::= { wlanMeshHWMPStatsEntry 2 }
+
+wlanMeshHWMPTxRootRANN OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of HWMP Root RANN frames sent by this interface."
+ ::= { wlanMeshHWMPStatsEntry 3 }
+
+wlanMeshHWMPProxy OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "frames"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of HWMP PREP frames discarded by this interface due to
+ the HWMP route being marked as proxy."
+ ::= { wlanMeshHWMPStatsEntry 4 }
+
+END
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile b/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile
new file mode 100644
index 0000000..6a53d46
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile
@@ -0,0 +1,15 @@
+#
+# $FreeBSD$
+#
+
+MOD= wlan
+SRCS= wlan_snmp.c wlan_sys.c
+CFLAGS+= -DSNMPTREE_TYPES
+
+XSYM= begemotWlan
+
+BMIBS= BEGEMOT-WIRELESS-MIB.txt
+MAN= snmp_${MOD}.3
+DEFS= ${MOD}_tree.def
+
+.include <bsd.snmpmod.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/snmp_wlan.3 b/usr.sbin/bsnmpd/modules/snmp_wlan/snmp_wlan.3
new file mode 100644
index 0000000..6c6af47
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/snmp_wlan.3
@@ -0,0 +1,160 @@
+.\"-
+.\" Copyright (C) 2010 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Shteryana Sotirova Shopova under
+.\" sponsorship from the FreeBSD Foundation.
+.\"
+.\" 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 June 28, 2010
+.Dt SNMP_WLAN 3
+.Os
+.Sh NAME
+.Nm snmp_wlan
+.Nd "wireless networking module for"
+.Xr bsnmpd 1
+.Sh LIBRARY
+.Pq begemotSnmpdModulePath."wlan" = "/usr/lib/snmp_wlan.so"
+.Sh DESCRIPTION
+The
+.Nm snmp_wlan
+module implements a private BEGEMOT-WIRELESS-MIB, which allows
+management of virtual wireless interfaces. The MIB defines objects similar to the
+state data and configuration capabilities of
+.Xr ifconfig 8
+for configuring virtual wireless interfaces.
+Therefore one should consider adding write communities or loading the
+.Nm
+module on systems where security is crucial.
+.Sh IMPLEMENTATION NOTES
+A short description of the Tables and interesting objects in the MIB follows.
+.Bl -tag -width "XXXXXXXXX"
+.It Va wlanInterfaceTable
+The table is used for creation and deletion of virtual wireless interfaces. To
+add a new interface, a SET should be executed on the
+.Va wlanIfaceName
+column with
+value the desired name of the interface. Next the parent interface must be set
+via
+.Va wlanParentIfName
+column. Any optional parameters may be set
+via the
+.Va wlanIfaceOperatingMode ,
+.Va wlanIfaceFlags ,
+.Va wlanIfaceBssid
+and
+.Va wlanIfaceLocalAddress
+columns.
+To finally create the interface in the system, a SET with value of active(1) to
+.Va wlanIfaceStatus
+column should be executed.
+To destroy a wireless interface a SET with value of destroy(6) to the relevant
+.Va wlanIfaceStatus
+column should be executed.
+.It Va wlanIfParentTable
+The table contains information about the hardware capabilities of the parent of
+a wireless interface.
+.It Va wlanIfaceConfigTable
+The table is used to get or set various configuration parameters for a virtual
+wireless interface. Depending on the operating mode of the interface and the
+hardware capabilities of the underlying hardware interface, not all parameters
+and values may be supported.
+.It Va wlanIfacePeerTable
+The table contains information about the associated stations for interfaces
+operating as access points, or the stations identified as neighbors in the IBSS
+for interfaces operating in adhoc mode.
+.It Va wlanIfaceChannelTable
+Information about the active channels for the wireless interfaces in the system.
+.It Va wlanIfRoamParamsTable
+The parameters that govern the roaming operation on the wireless interfaces.
+.It Va wlanIfTxParamsTable
+The parameters that govern the transmit operation on the wireless interfaces.
+.It Va wlanScanConfigTable
+The table that contains a configuration for channel scanning initiated via SNMP.
+.It Va wlanScanResultsTable
+The table contains the scan results from the last scan for each wireless
+interface on the system.
+.It Va wlanIfaceStatisticsTable
+Summary statistics for each wireless interface on the system.
+.It Va wlanWepInterfaceTable
+WEP configuration for the wireless interfaces on the system.
+.It Va wlanMACAccessControlTable
+Access Control configuration for wireless interfaces operating as access points.
+.It Va wlanMACAccessControlMACTable
+The table with Access Control MAC entries for which the configured Access
+Control Policy on wireless interfaces operating in Host AP mode is applied.
+.Va wlanMACAccessControlMACStatus
+column is used to add or delete MAC ACL entries. A set with value createAndGo(4)
+will add new entry, while with value destroy(6) will delete an existing one.
+.It Va wlanMeshRoutingConfig
+The subtree contains system configuration related to Wireless Mesh Routing.
+.It Va wlanMeshInterfaceTable
+The table contains information for wireless interfaces operating as wireless
+mesh points.
+.It Va wlanMeshNeighborTable
+The table contains information for the neighbors of wireless interfaces
+operating in mesh mode.
+.It Va wlanMeshRouteTable
+The mesh routing table for interfaces operating as mesh points, used for
+forwarding packets on a mesh network.
+.Va wlanMeshRouteStatus
+column is used to add or delete entries in the mesh routing table for an
+interface. A set with value createAndGo(4) will add new entry, while with value
+destroy(6) will delete an existing one.
+.It Va wlanMeshStatsTable
+Summary statistics for each virtual wireless interface operating as mesh point.
+.It Va wlanMeshHWMPConfig
+The subtree contains system configuration related to Hybrid Wireless Mesh
+Protocol.
+.It Va wlanHWMPInterfaceTable
+The table contains HWMP information for wireless interfaces operating in mesh
+mode.
+.It Va wlanMeshHWMPStatsTable
+Summary statistics for HWMP operation on interfaces operating as mesh points.
+.El
+.Sh RESTRICTIONS
+Not all information or configuration in the MIBs is currently available in FreeBSD.
+The values of the following variables carry no information:
+.Bl -tag -width "XXXXXXXXX"
+.It Va wlanStatsReset
+.El
+.Sh FILES
+.Bl -tag -width "XXXXXXXXX"
+.It Pa /usr/share/snmp/defs/wlan_tree.def
+The description of the MIB tree implemented by
+.Nm .
+.It Pa /usr/share/snmp/mibs/BEGEMOT-WIRELESS-MIB.txt
+The private BEGEMOT-WIRELESS-MIB that is implemented by this module.
+.El
+.Sh SEE ALSO
+.Xr bsnmpd 1 ,
+.Xr gensnmptree 1 ,
+.Xr wlan 4 ,
+.Xr wlan_acl 4 ,
+.Xr wlan_wep 4 ,
+.Xr ifconfig 8 ,
+.Xr snmpmod 3
+.Sh AUTHORS
+.An Shteryana Shopova Aq syrinx@FreeBSD.org
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c
new file mode 100644
index 0000000..ec94ac6
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c
@@ -0,0 +1,4513 @@
+/*-
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Shteryana Sotirova Shopova under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * 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 <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_ioctl.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 "wlan_tree.h"
+#include "wlan_snmp.h"
+#include "wlan_oid.h"
+
+static struct lmodule *wlan_module;
+
+/* For the registration. */
+static const struct asn_oid oid_wlan = OIDX_begemotWlan;
+/* The registration. */
+static uint reg_wlan;
+
+/* Periodic timer for polling the module's data. */
+static void *wlan_data_timer;
+
+/*
+ * Poll data from kernel every 15 minutes unless explicitly requested by an
+ * SNMP client.
+ * XXX: make that configurable.
+ */
+static int wlan_poll_ticks = (15 * 60) * 100;
+
+/* The age of each table. */
+#define WLAN_LIST_MAXAGE 5
+
+static time_t wlan_iflist_age;
+static time_t wlan_peerlist_age;
+static time_t wlan_chanlist_age;
+static time_t wlan_roamlist_age;
+static time_t wlan_tx_paramlist_age;
+static time_t wlan_scanlist_age;
+static time_t wlan_maclist_age;
+static time_t wlan_mrlist_age;
+
+/*
+ * The list of all virtual wireless interfaces - sorted by name.
+ */
+SLIST_HEAD(wlan_ifaces, wlan_iface);
+static struct wlan_ifaces wlan_ifaces = SLIST_HEAD_INITIALIZER(wlan_ifaces);
+
+static struct wlan_config wlan_config;
+
+/* Forward declarations */
+static int bits_get(struct snmp_value *, const u_char *, ssize_t);
+
+static int wlan_add_wif(struct wlan_iface *);
+static void wlan_delete_wif(struct wlan_iface *);
+static int wlan_attach_newif(struct mibif *);
+static int wlan_iface_create(struct wlan_iface *);
+static int wlan_iface_destroy(struct wlan_iface *);
+static struct wlan_iface * wlan_new_wif(char *);
+
+static void wlan_free_interface(struct wlan_iface *);
+static void wlan_free_iflist(void);
+static void wlan_free_peerlist(struct wlan_iface *);
+static void wlan_scan_free_results(struct wlan_iface *);
+static void wlan_mac_free_maclist(struct wlan_iface *);
+static void wlan_mesh_free_routes(struct wlan_iface *);
+
+static int wlan_update_interface(struct wlan_iface *);
+static void wlan_update_interface_list(void);
+static void wlan_update_peers(void);
+static void wlan_update_channels(void);
+static void wlan_update_roam_params(void);
+static void wlan_update_tx_params(void);
+static void wlan_scan_update_results(void);
+static void wlan_mac_update_aclmacs(void);
+static void wlan_mesh_update_routes(void);
+
+static struct wlan_iface * wlan_find_interface(const char *);
+static struct wlan_peer * wlan_find_peer(struct wlan_iface *, uint8_t *);
+static struct ieee80211_channel* wlan_find_channel(struct wlan_iface *,
+ uint32_t);
+static struct wlan_scan_result * wlan_scan_find_result(struct wlan_iface *,
+ uint8_t *, uint8_t *);
+static struct wlan_mac_mac * wlan_mac_find_mac(struct wlan_iface *,
+ uint8_t *);
+static struct wlan_mesh_route * wlan_mesh_find_route(struct wlan_iface *,
+ uint8_t *);
+
+static struct wlan_iface * wlan_first_interface(void);
+static struct wlan_iface * wlan_next_interface(struct wlan_iface *);
+static struct wlan_iface * wlan_mesh_first_interface(void);
+static struct wlan_iface * wlan_mesh_next_interface(struct wlan_iface *);
+
+static struct wlan_iface * wlan_get_interface(const struct asn_oid *, uint);
+static struct wlan_iface * wlan_get_snmp_interface(const struct asn_oid *,
+ uint);
+static struct wlan_peer * wlan_get_peer(const struct asn_oid *, uint,
+ struct wlan_iface **);
+static struct ieee80211_channel *wlan_get_channel(const struct asn_oid *, uint,
+ struct wlan_iface **);
+static struct ieee80211_roamparam *wlan_get_roam_param(const struct asn_oid *,
+ uint, struct wlan_iface **);
+static struct ieee80211_txparam *wlan_get_tx_param(const struct asn_oid *,
+ uint, struct wlan_iface **, uint32_t *);
+static struct wlan_scan_result *wlan_get_scanr(const struct asn_oid *, uint,
+ struct wlan_iface **);
+static struct wlan_mac_mac * wlan_get_acl_mac(const struct asn_oid *,
+ uint, struct wlan_iface **);
+static struct wlan_iface * wlan_mesh_get_iface(const struct asn_oid *, uint);
+static struct wlan_peer * wlan_mesh_get_peer(const struct asn_oid *, uint,
+ struct wlan_iface **);
+static struct wlan_mesh_route * wlan_mesh_get_route(const struct asn_oid *,
+ uint, struct wlan_iface **);
+
+static struct wlan_iface * wlan_get_next_interface(const struct asn_oid *,
+ uint);
+static struct wlan_iface * wlan_get_next_snmp_interface(const struct
+ asn_oid *, uint);
+static struct wlan_peer * wlan_get_next_peer(const struct asn_oid *, uint,
+ struct wlan_iface **);
+static struct ieee80211_channel *wlan_get_next_channel(const struct asn_oid *,
+ uint, struct wlan_iface **);
+static struct ieee80211_roamparam *wlan_get_next_roam_param(const struct
+ asn_oid *, uint sub, struct wlan_iface **, uint32_t *);
+static struct ieee80211_txparam *wlan_get_next_tx_param(const struct asn_oid *,
+ uint, struct wlan_iface **, uint32_t *);
+static struct wlan_scan_result *wlan_get_next_scanr(const struct asn_oid *,
+ uint , struct wlan_iface **);
+static struct wlan_mac_mac * wlan_get_next_acl_mac(const struct asn_oid *,
+ uint, struct wlan_iface **);
+static struct wlan_iface * wlan_mesh_get_next_iface(const struct asn_oid *,
+ uint);
+static struct wlan_peer * wlan_mesh_get_next_peer(const struct asn_oid *,
+ uint, struct wlan_iface **);
+static struct wlan_mesh_route * wlan_mesh_get_next_route(const struct asn_oid *,
+ uint sub, struct wlan_iface **);
+
+static uint8_t *wlan_get_ifname(const struct asn_oid *, uint, uint8_t *);
+static int wlan_mac_index_decode(const struct asn_oid *, uint, char *,
+ uint8_t *);
+static int wlan_channel_index_decode(const struct asn_oid *, uint,
+ char *, uint32_t *);
+static int wlan_phy_index_decode(const struct asn_oid *, uint, char *,
+ uint32_t *);
+static int wlan_scanr_index_decode(const struct asn_oid *oid, uint sub,
+ char *wname, uint8_t *ssid, uint8_t *bssid);
+
+static void wlan_append_ifindex(struct asn_oid *, uint,
+ const struct wlan_iface *);
+static void wlan_append_mac_index(struct asn_oid *, uint, char *, uint8_t *);
+static void wlan_append_channel_index(struct asn_oid *, uint,
+ const struct wlan_iface *, const struct ieee80211_channel *);
+static void wlan_append_phy_index(struct asn_oid *, uint, char *, uint32_t);
+static void wlan_append_scanr_index(struct asn_oid *, uint, char *,
+ uint8_t *, uint8_t *);
+
+static int wlan_acl_mac_set_status(struct snmp_context *,
+ struct snmp_value *, uint);
+static int wlan_mesh_route_set_status(struct snmp_context *,
+ struct snmp_value *, uint);
+
+static int32_t wlan_get_channel_type(struct ieee80211_channel *);
+static int wlan_scan_compare_result(struct wlan_scan_result *,
+ struct wlan_scan_result *);
+static int wlan_mac_delete_mac(struct wlan_iface *, struct wlan_mac_mac *);
+static int wlan_mesh_delete_route(struct wlan_iface *,
+ struct wlan_mesh_route *);
+
+/*
+ * The module's GET/SET data hooks per each table or group of objects as
+ * required by bsnmpd(1).
+ */
+int
+op_wlan_iface(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
+ uint32_t iidx __unused, enum snmp_op op)
+{
+ int rc;
+ char wname[IFNAMSIZ];
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_get_snmp_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ if ((wif = wlan_get_next_snmp_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ break;
+
+ case SNMP_OP_SET:
+ if ((wif = wlan_get_snmp_interface(&val->var, sub)) == NULL) {
+ if (val->var.subs[sub - 1] != LEAF_wlanIfaceName)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (wlan_get_ifname(&val->var, sub, wname) == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+ if ((wif = wlan_new_wif(wname)) == NULL)
+ return (SNMP_ERR_GENERR);
+ wif->internal = 1;
+ }
+ if (wif->status == RowStatus_active &&
+ val->var.subs[sub - 1] != LEAF_wlanIfaceStatus &&
+ val->var.subs[sub - 1] != LEAF_wlanIfaceState)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfaceIndex:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case LEAF_wlanIfaceName:
+ if (val->v.octetstring.len >= IFNAMSIZ)
+ return (SNMP_ERR_INCONS_VALUE);
+ if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL)
+ return (SNMP_ERR_GENERR);
+ strlcpy(ctx->scratch->ptr1, wif->wname, IFNAMSIZ);
+ memcpy(wif->wname, val->v.octetstring.octets,
+ val->v.octetstring.len);
+ wif->wname[val->v.octetstring.len] = '\0';
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_wlanParentIfName:
+ if (val->v.octetstring.len >= IFNAMSIZ)
+ return (SNMP_ERR_INCONS_VALUE);
+ if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL)
+ return (SNMP_ERR_GENERR);
+ strlcpy(ctx->scratch->ptr1, wif->pname, IFNAMSIZ);
+ memcpy(wif->pname, val->v.octetstring.octets,
+ val->v.octetstring.len);
+ wif->pname[val->v.octetstring.len] = '\0';
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_wlanIfaceOperatingMode:
+ ctx->scratch->int1 = wif->mode;
+ wif->mode = val->v.integer;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_wlanIfaceFlags:
+ if (val->v.octetstring.len > sizeof(wif->flags))
+ return (SNMP_ERR_INCONS_VALUE);
+ ctx->scratch->ptr1 = malloc(sizeof(wif->flags));
+ if (ctx->scratch->ptr1 == NULL)
+ return (SNMP_ERR_GENERR);
+ memcpy(ctx->scratch->ptr1, (uint8_t *)&wif->flags,
+ sizeof(wif->flags));
+ memcpy((uint8_t *)&wif->flags, val->v.octetstring.octets,
+ sizeof(wif->flags));
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_wlanIfaceBssid:
+ if (val->v.octetstring.len != IEEE80211_ADDR_LEN)
+ return (SNMP_ERR_INCONS_VALUE);
+ ctx->scratch->ptr1 = malloc(IEEE80211_ADDR_LEN);
+ if (ctx->scratch->ptr1 == NULL)
+ return (SNMP_ERR_GENERR);
+ memcpy(ctx->scratch->ptr1, wif->dbssid,
+ IEEE80211_ADDR_LEN);
+ memcpy(wif->dbssid, val->v.octetstring.octets,
+ IEEE80211_ADDR_LEN);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_wlanIfaceLocalAddress:
+ if (val->v.octetstring.len != IEEE80211_ADDR_LEN)
+ return (SNMP_ERR_INCONS_VALUE);
+ ctx->scratch->ptr1 = malloc(IEEE80211_ADDR_LEN);
+ if (ctx->scratch->ptr1 == NULL)
+ return (SNMP_ERR_GENERR);
+ memcpy(ctx->scratch->ptr1, wif->dlmac,
+ IEEE80211_ADDR_LEN);
+ memcpy(wif->dlmac, val->v.octetstring.octets,
+ IEEE80211_ADDR_LEN);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_wlanIfaceStatus:
+ ctx->scratch->int1 = wif->status;
+ wif->status = val->v.integer;
+ if (wif->status == RowStatus_active) {
+ rc = wlan_iface_create(wif); /* XXX */
+ if (rc != SNMP_ERR_NOERROR) {
+ wif->status = ctx->scratch->int1;
+ return (rc);
+ }
+ } else if (wif->status == RowStatus_destroy)
+ return (wlan_iface_destroy(wif));
+ else
+ wif->status = RowStatus_notReady;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_wlanIfaceState:
+ ctx->scratch->int1 = wif->state;
+ wif->state = val->v.integer;
+ if (wif->status == RowStatus_active)
+ if (wlan_config_state(wif, 1) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ if ((wif = wlan_get_snmp_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfaceName:
+ strlcpy(wif->wname, ctx->scratch->ptr1, IFNAMSIZ);
+ free(ctx->scratch->ptr1);
+ break;
+
+ case LEAF_wlanParentIfName:
+ strlcpy(wif->pname, ctx->scratch->ptr1, IFNAMSIZ);
+ free(ctx->scratch->ptr1);
+ break;
+
+ case LEAF_wlanIfaceOperatingMode:
+ wif->mode = ctx->scratch->int1;
+ break;
+
+ case LEAF_wlanIfaceFlags:
+ memcpy((uint8_t *)&wif->flags, ctx->scratch->ptr1,
+ sizeof(wif->flags));
+ free(ctx->scratch->ptr1);
+ break;
+
+ case LEAF_wlanIfaceBssid:
+ memcpy(wif->dbssid, ctx->scratch->ptr1,
+ IEEE80211_ADDR_LEN);
+ free(ctx->scratch->ptr1);
+ break;
+
+ case LEAF_wlanIfaceLocalAddress:
+ memcpy(wif->dlmac, ctx->scratch->ptr1,
+ IEEE80211_ADDR_LEN);
+ free(ctx->scratch->ptr1);
+ break;
+
+ case LEAF_wlanIfaceStatus:
+ wif->status = ctx->scratch->int1;
+ if (ctx->scratch->int1 == RowStatus_active)
+ return (SNMP_ERR_GENERR); /* XXX: FIXME */
+ else if (wif->internal != 0)
+ return (wlan_iface_destroy(wif));
+ break;
+
+ case LEAF_wlanIfaceState:
+ wif->state = ctx->scratch->int1;
+ if (wif->status == RowStatus_active)
+ if (wlan_config_state(wif, 1) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfaceName:
+ case LEAF_wlanParentIfName:
+ case LEAF_wlanIfaceFlags:
+ case LEAF_wlanIfaceBssid:
+ case LEAF_wlanIfaceLocalAddress:
+ free(ctx->scratch->ptr1);
+ /* FALLTHROUGH */
+ default:
+ return (SNMP_ERR_NOERROR);
+ }
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfaceIndex:
+ val->v.integer = wif->index;
+ return (SNMP_ERR_NOERROR);
+ case LEAF_wlanIfaceName:
+ return (string_get(val, wif->wname, -1));
+ case LEAF_wlanParentIfName:
+ return (string_get(val, wif->pname, -1));
+ case LEAF_wlanIfaceOperatingMode:
+ val->v.integer = wif->mode;
+ return (SNMP_ERR_NOERROR);
+ case LEAF_wlanIfaceFlags:
+ return (bits_get(val, (uint8_t *)&wif->flags,
+ sizeof(wif->flags)));
+ case LEAF_wlanIfaceBssid:
+ return (string_get(val, wif->dbssid, IEEE80211_ADDR_LEN));
+ case LEAF_wlanIfaceLocalAddress:
+ return (string_get(val, wif->dlmac, IEEE80211_ADDR_LEN));
+ case LEAF_wlanIfaceStatus:
+ val->v.integer = wif->status;
+ return (SNMP_ERR_NOERROR);
+ case LEAF_wlanIfaceState:
+ val->v.integer = wif->state;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ abort();
+}
+
+int
+op_wlan_if_parent(struct snmp_context *ctx __unused, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+ case SNMP_OP_GETNEXT:
+ if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ break;
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_COMMIT:
+ /* FALLTHROUGH */
+ case SNMP_OP_ROLLBACK:
+ /* FALLTHROUGH */
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfParentDriverCapabilities:
+ return (bits_get(val, (uint8_t *)&wif->drivercaps,
+ sizeof(wif->drivercaps)));
+ case LEAF_wlanIfParentCryptoCapabilities:
+ return (bits_get(val, (uint8_t *)&wif->cryptocaps,
+ sizeof(wif->cryptocaps)));
+ case LEAF_wlanIfParentHTCapabilities:
+ return (bits_get(val, (uint8_t *)&wif->htcaps,
+ sizeof(wif->htcaps)));
+ }
+
+ abort();
+}
+
+int
+op_wlan_iface_config(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ int intval, vlen, rc;
+ char *strval;
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get_config;
+
+ case SNMP_OP_GETNEXT:
+ if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ goto get_config;
+
+ case SNMP_OP_SET:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ intval = val->v.integer;
+ strval = NULL;
+ vlen = 0;
+
+ /* Simple sanity checks & save old data. */
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfaceCountryCode:
+ if (val->v.octetstring.len != WLAN_COUNTRY_CODE_SIZE)
+ return (SNMP_ERR_INCONS_VALUE);
+ break;
+ case LEAF_wlanIfaceDesiredSsid:
+ if (val->v.octetstring.len > IEEE80211_NWID_LEN)
+ return (SNMP_ERR_INCONS_VALUE);
+ break;
+ case LEAF_wlanIfaceDesiredBssid:
+ if (val->v.octetstring.len != IEEE80211_ADDR_LEN)
+ return (SNMP_ERR_INCONS_VALUE);
+ break;
+ case LEAF_wlanIfacePacketBurst:
+ ctx->scratch->int1 = wif->packet_burst;
+ break;
+ case LEAF_wlanIfaceRegDomain:
+ ctx->scratch->int1 = wif->reg_domain;
+ break;
+ case LEAF_wlanIfaceDesiredChannel:
+ ctx->scratch->int1 = wif->desired_channel;
+ break;
+ case LEAF_wlanIfaceDynamicFreqSelection:
+ ctx->scratch->int1 = wif->dyn_frequency;
+ break;
+ case LEAF_wlanIfaceFastFrames:
+ ctx->scratch->int1 = wif->fast_frames;
+ break;
+ case LEAF_wlanIfaceDturbo:
+ ctx->scratch->int1 = wif->dturbo;
+ break;
+ case LEAF_wlanIfaceTxPower:
+ ctx->scratch->int1 = wif->tx_power;
+ break;
+ case LEAF_wlanIfaceFragmentThreshold:
+ ctx->scratch->int1 = wif->frag_threshold;
+ break;
+ case LEAF_wlanIfaceRTSThreshold:
+ ctx->scratch->int1 = wif->rts_threshold;
+ break;
+ case LEAF_wlanIfaceWlanPrivacySubscribe:
+ ctx->scratch->int1 = wif->priv_subscribe;
+ break;
+ case LEAF_wlanIfaceBgScan:
+ ctx->scratch->int1 = wif->bg_scan;
+ break;
+ case LEAF_wlanIfaceBgScanIdle:
+ ctx->scratch->int1 = wif->bg_scan_idle;
+ break;
+ case LEAF_wlanIfaceBgScanInterval:
+ ctx->scratch->int1 = wif->bg_scan_interval;
+ break;
+ case LEAF_wlanIfaceBeaconMissedThreshold:
+ ctx->scratch->int1 = wif->beacons_missed;
+ break;
+ case LEAF_wlanIfaceRoamingMode:
+ ctx->scratch->int1 = wif->roam_mode;
+ break;
+ case LEAF_wlanIfaceDot11d:
+ ctx->scratch->int1 = wif->dot11d;
+ break;
+ case LEAF_wlanIfaceDot11h:
+ ctx->scratch->int1 = wif->dot11h;
+ break;
+ case LEAF_wlanIfaceDynamicWds:
+ ctx->scratch->int1 = wif->dynamic_wds;
+ break;
+ case LEAF_wlanIfacePowerSave:
+ ctx->scratch->int1 = wif->power_save;
+ break;
+ case LEAF_wlanIfaceApBridge:
+ ctx->scratch->int1 = wif->ap_bridge;
+ break;
+ case LEAF_wlanIfaceBeaconInterval:
+ ctx->scratch->int1 = wif->beacon_interval;
+ break;
+ case LEAF_wlanIfaceDtimPeriod:
+ ctx->scratch->int1 = wif->dtim_period;
+ break;
+ case LEAF_wlanIfaceHideSsid:
+ ctx->scratch->int1 = wif->hide_ssid;
+ break;
+ case LEAF_wlanIfaceInactivityProccess:
+ ctx->scratch->int1 = wif->inact_process;
+ break;
+ case LEAF_wlanIfaceDot11gProtMode:
+ ctx->scratch->int1 = wif->do11g_protect;
+ break;
+ case LEAF_wlanIfaceDot11gPureMode:
+ ctx->scratch->int1 = wif->dot11g_pure;
+ break;
+ case LEAF_wlanIfaceDot11nPureMode:
+ ctx->scratch->int1 = wif->dot11n_pure;
+ break;
+ case LEAF_wlanIfaceDot11nAmpdu:
+ ctx->scratch->int1 = wif->ampdu;
+ break;
+ case LEAF_wlanIfaceDot11nAmpduDensity:
+ ctx->scratch->int1 = wif->ampdu_density;
+ break;
+ case LEAF_wlanIfaceDot11nAmpduLimit:
+ ctx->scratch->int1 = wif->ampdu_limit;
+ break;
+ case LEAF_wlanIfaceDot11nAmsdu:
+ ctx->scratch->int1 = wif->amsdu;
+ break;
+ case LEAF_wlanIfaceDot11nAmsduLimit:
+ ctx->scratch->int1 = wif->amsdu_limit;
+ break;
+ case LEAF_wlanIfaceDot11nHighThroughput:
+ ctx->scratch->int1 = wif->ht_enabled;
+ break;
+ case LEAF_wlanIfaceDot11nHTCompatible:
+ ctx->scratch->int1 = wif->ht_compatible;
+ break;
+ case LEAF_wlanIfaceDot11nHTProtMode:
+ ctx->scratch->int1 = wif->ht_prot_mode;
+ break;
+ case LEAF_wlanIfaceDot11nRIFS:
+ ctx->scratch->int1 = wif->rifs;
+ break;
+ case LEAF_wlanIfaceDot11nShortGI:
+ ctx->scratch->int1 = wif->short_gi;
+ break;
+ case LEAF_wlanIfaceDot11nSMPSMode:
+ ctx->scratch->int1 = wif->smps_mode;
+ break;
+ case LEAF_wlanIfaceTdmaSlot:
+ ctx->scratch->int1 = wif->tdma_slot;
+ break;
+ case LEAF_wlanIfaceTdmaSlotCount:
+ ctx->scratch->int1 = wif->tdma_slot_count;
+ break;
+ case LEAF_wlanIfaceTdmaSlotLength:
+ ctx->scratch->int1 = wif->tdma_slot_length;
+ break;
+ case LEAF_wlanIfaceTdmaBeaconInterval:
+ ctx->scratch->int1 = wif->tdma_binterval;
+ break;
+ default:
+ abort();
+ }
+
+ if (val->syntax != SNMP_SYNTAX_OCTETSTRING)
+ goto set_config;
+
+ ctx->scratch->int1 = val->v.octetstring.len;
+ ctx->scratch->ptr1 = malloc(val->v.octetstring.len + 1);
+ if (ctx->scratch->ptr1 == NULL)
+ return (SNMP_ERR_GENERR); /* XXX */
+ if (val->var.subs[sub - 1] == LEAF_wlanIfaceDesiredSsid)
+ strlcpy(ctx->scratch->ptr1, val->v.octetstring.octets,
+ val->v.octetstring.len + 1);
+ else
+ memcpy(ctx->scratch->ptr1, val->v.octetstring.octets,
+ val->v.octetstring.len);
+ strval = val->v.octetstring.octets;
+ vlen = val->v.octetstring.len;
+ goto set_config;
+
+ case SNMP_OP_ROLLBACK:
+ intval = ctx->scratch->int1;
+ strval = NULL;
+ vlen = 0;
+
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfaceCountryCode:
+ case LEAF_wlanIfaceDesiredSsid:
+ case LEAF_wlanIfaceDesiredBssid:
+ strval = ctx->scratch->ptr1;
+ vlen = ctx->scratch->int1;
+ break;
+ default:
+ break;
+ }
+ goto set_config;
+
+ case SNMP_OP_COMMIT:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfaceCountryCode:
+ case LEAF_wlanIfaceDesiredSsid:
+ case LEAF_wlanIfaceDesiredBssid:
+ free(ctx->scratch->ptr1);
+ /* FALLTHROUGH */
+ default:
+ return (SNMP_ERR_NOERROR);
+ }
+ }
+ abort();
+
+get_config:
+
+ if (wlan_config_get_ioctl(wif, val->var.subs[sub - 1]) < 0)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfacePacketBurst:
+ val->v.integer = wif->packet_burst;
+ break;
+ case LEAF_wlanIfaceCountryCode:
+ return (string_get(val, wif->country_code,
+ WLAN_COUNTRY_CODE_SIZE));
+ case LEAF_wlanIfaceRegDomain:
+ val->v.integer = wif->reg_domain;
+ break;
+ case LEAF_wlanIfaceDesiredSsid:
+ return (string_get(val, wif->desired_ssid, -1));
+ case LEAF_wlanIfaceDesiredChannel:
+ val->v.integer = wif->desired_channel;
+ break;
+ case LEAF_wlanIfaceDynamicFreqSelection:
+ val->v.integer = wif->dyn_frequency;
+ break;
+ case LEAF_wlanIfaceFastFrames:
+ val->v.integer = wif->fast_frames;
+ break;
+ case LEAF_wlanIfaceDturbo:
+ val->v.integer = wif->dturbo;
+ break;
+ case LEAF_wlanIfaceTxPower:
+ val->v.integer = wif->tx_power;
+ break;
+ case LEAF_wlanIfaceFragmentThreshold:
+ val->v.integer = wif->frag_threshold;
+ break;
+ case LEAF_wlanIfaceRTSThreshold:
+ val->v.integer = wif->rts_threshold;
+ break;
+ case LEAF_wlanIfaceWlanPrivacySubscribe:
+ val->v.integer = wif->priv_subscribe;
+ break;
+ case LEAF_wlanIfaceBgScan:
+ val->v.integer = wif->bg_scan;
+ break;
+ case LEAF_wlanIfaceBgScanIdle:
+ val->v.integer = wif->bg_scan_idle;
+ break;
+ case LEAF_wlanIfaceBgScanInterval:
+ val->v.integer = wif->bg_scan_interval;
+ break;
+ case LEAF_wlanIfaceBeaconMissedThreshold:
+ val->v.integer = wif->beacons_missed;
+ break;
+ case LEAF_wlanIfaceDesiredBssid:
+ return (string_get(val, wif->desired_bssid,
+ IEEE80211_ADDR_LEN));
+ case LEAF_wlanIfaceRoamingMode:
+ val->v.integer = wif->roam_mode;
+ break;
+ case LEAF_wlanIfaceDot11d:
+ val->v.integer = wif->dot11d;
+ break;
+ case LEAF_wlanIfaceDot11h:
+ val->v.integer = wif->dot11h;
+ break;
+ case LEAF_wlanIfaceDynamicWds:
+ val->v.integer = wif->dynamic_wds;
+ break;
+ case LEAF_wlanIfacePowerSave:
+ val->v.integer = wif->power_save;
+ break;
+ case LEAF_wlanIfaceApBridge:
+ val->v.integer = wif->ap_bridge;
+ break;
+ case LEAF_wlanIfaceBeaconInterval:
+ val->v.integer = wif->beacon_interval;
+ break;
+ case LEAF_wlanIfaceDtimPeriod:
+ val->v.integer = wif->dtim_period;
+ break;
+ case LEAF_wlanIfaceHideSsid:
+ val->v.integer = wif->hide_ssid;
+ break;
+ case LEAF_wlanIfaceInactivityProccess:
+ val->v.integer = wif->inact_process;
+ break;
+ case LEAF_wlanIfaceDot11gProtMode:
+ val->v.integer = wif->do11g_protect;
+ break;
+ case LEAF_wlanIfaceDot11gPureMode:
+ val->v.integer = wif->dot11g_pure;
+ break;
+ case LEAF_wlanIfaceDot11nPureMode:
+ val->v.integer = wif->dot11n_pure;
+ break;
+ case LEAF_wlanIfaceDot11nAmpdu:
+ val->v.integer = wif->ampdu;
+ break;
+ case LEAF_wlanIfaceDot11nAmpduDensity:
+ val->v.integer = wif->ampdu_density;
+ break;
+ case LEAF_wlanIfaceDot11nAmpduLimit:
+ val->v.integer = wif->ampdu_limit;
+ break;
+ case LEAF_wlanIfaceDot11nAmsdu:
+ val->v.integer = wif->amsdu;
+ break;
+ case LEAF_wlanIfaceDot11nAmsduLimit:
+ val->v.integer = wif->amsdu_limit;
+ break;
+ case LEAF_wlanIfaceDot11nHighThroughput:
+ val->v.integer = wif->ht_enabled;
+ break;
+ case LEAF_wlanIfaceDot11nHTCompatible:
+ val->v.integer = wif->ht_compatible;
+ break;
+ case LEAF_wlanIfaceDot11nHTProtMode:
+ val->v.integer = wif->ht_prot_mode;
+ break;
+ case LEAF_wlanIfaceDot11nRIFS:
+ val->v.integer = wif->rifs;
+ break;
+ case LEAF_wlanIfaceDot11nShortGI:
+ val->v.integer = wif->short_gi;
+ break;
+ case LEAF_wlanIfaceDot11nSMPSMode:
+ val->v.integer = wif->smps_mode;
+ break;
+ case LEAF_wlanIfaceTdmaSlot:
+ val->v.integer = wif->tdma_slot;
+ break;
+ case LEAF_wlanIfaceTdmaSlotCount:
+ val->v.integer = wif->tdma_slot_count;
+ break;
+ case LEAF_wlanIfaceTdmaSlotLength:
+ val->v.integer = wif->tdma_slot_length;
+ break;
+ case LEAF_wlanIfaceTdmaBeaconInterval:
+ val->v.integer = wif->tdma_binterval;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+
+set_config:
+ rc = wlan_config_set_ioctl(wif, val->var.subs[sub - 1], intval,
+ strval, vlen);
+
+ if (op == SNMP_OP_ROLLBACK) {
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfaceCountryCode:
+ case LEAF_wlanIfaceDesiredSsid:
+ case LEAF_wlanIfaceDesiredBssid:
+ free(ctx->scratch->ptr1);
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+ }
+
+ if (rc < 0)
+ return (SNMP_ERR_GENERR);
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_if_peer(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
+ uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_peer *wip;
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+ wlan_update_peers();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wip = wlan_get_peer(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+ case SNMP_OP_GETNEXT:
+ if ((wip = wlan_get_next_peer(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_mac_index(&val->var, sub, wif->wname, wip->pmac);
+ break;
+ case SNMP_OP_SET:
+ if ((wip = wlan_get_peer(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (val->var.subs[sub - 1] != LEAF_wlanIfacePeerVlanTag)
+ return (SNMP_ERR_GENERR);
+ ctx->scratch->int1 = wip->vlan;
+ if (wlan_peer_set_vlan(wif, wip, val->v.integer) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+ case SNMP_OP_ROLLBACK:
+ if ((wip = wlan_get_peer(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (val->var.subs[sub - 1] != LEAF_wlanIfacePeerVlanTag)
+ return (SNMP_ERR_GENERR);
+ if (wlan_peer_set_vlan(wif, wip, ctx->scratch->int1) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfacePeerAddress:
+ return (string_get(val, wip->pmac, IEEE80211_ADDR_LEN));
+ case LEAF_wlanIfacePeerAssociationId:
+ val->v.integer = wip->associd;
+ break;
+ case LEAF_wlanIfacePeerVlanTag:
+ val->v.integer = wip->vlan;
+ break;
+ case LEAF_wlanIfacePeerFrequency:
+ val->v.integer = wip->frequency;
+ break;
+ case LEAF_wlanIfacePeerCurrentTXRate:
+ val->v.integer = wip->txrate;
+ break;
+ case LEAF_wlanIfacePeerRxSignalStrength:
+ val->v.integer = wip->rssi;
+ break;
+ case LEAF_wlanIfacePeerIdleTimer:
+ val->v.integer = wip->idle;
+ break;
+ case LEAF_wlanIfacePeerTxSequenceNo:
+ val->v.integer = wip->txseqs;
+ break;
+ case LEAF_wlanIfacePeerRxSequenceNo:
+ val->v.integer = wip->rxseqs;
+ break;
+ case LEAF_wlanIfacePeerTxPower:
+ val->v.integer = wip->txpower;
+ break;
+ case LEAF_wlanIfacePeerCapabilities:
+ return (bits_get(val, (uint8_t *)&wip->capinfo,
+ sizeof(wip->capinfo)));
+ case LEAF_wlanIfacePeerFlags:
+ return (bits_get(val, (uint8_t *)&wip->state,
+ sizeof(wip->state)));
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_channels(struct snmp_context *ctx __unused, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ int32_t bits;
+ struct ieee80211_channel *channel;
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+ wlan_update_channels();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((channel = wlan_get_channel(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+ case SNMP_OP_GETNEXT:
+ channel = wlan_get_next_channel(&val->var, sub, &wif);
+ if (channel == NULL || wif == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_channel_index(&val->var, sub, wif, channel);
+ break;
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_COMMIT:
+ /* FALLTHROUGH */
+ case SNMP_OP_ROLLBACK:
+ /* FALLTHROUGH */
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfaceChannelIeeeId:
+ val->v.integer = channel->ic_ieee;
+ break;
+ case LEAF_wlanIfaceChannelType:
+ val->v.integer = wlan_get_channel_type(channel);
+ break;
+ case LEAF_wlanIfaceChannelFlags:
+ bits = wlan_channel_flags_to_snmp(channel->ic_flags);
+ return (bits_get(val, (uint8_t *)&bits, sizeof(bits)));
+ case LEAF_wlanIfaceChannelFrequency:
+ val->v.integer = channel->ic_freq;
+ break;
+ case LEAF_wlanIfaceChannelMaxRegPower:
+ val->v.integer = channel->ic_maxregpower;
+ break;
+ case LEAF_wlanIfaceChannelMaxTxPower:
+ val->v.integer = channel->ic_maxpower;
+ break;
+ case LEAF_wlanIfaceChannelMinTxPower:
+ val->v.integer = channel->ic_minpower;
+ break;
+ case LEAF_wlanIfaceChannelState:
+ bits = wlan_channel_state_to_snmp(channel->ic_state);
+ return (bits_get(val, (uint8_t *)&bits, sizeof(bits)));
+ case LEAF_wlanIfaceChannelHTExtension:
+ val->v.integer = channel->ic_extieee;
+ break;
+ case LEAF_wlanIfaceChannelMaxAntennaGain:
+ val->v.integer = channel->ic_maxantgain;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_roam_params(struct snmp_context *ctx __unused, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ uint32_t phy;
+ struct ieee80211_roamparam *rparam;
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+ wlan_update_roam_params();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ rparam = wlan_get_roam_param(&val->var, sub, &wif);
+ if (rparam == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+ case SNMP_OP_GETNEXT:
+ rparam = wlan_get_next_roam_param(&val->var, sub, &wif, &phy);
+ if (rparam == NULL || wif == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_phy_index(&val->var, sub, wif->wname, phy);
+ break;
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_COMMIT:
+ /* FALLTHROUGH */
+ case SNMP_OP_ROLLBACK:
+ /* FALLTHROUGH */
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfRoamRxSignalStrength:
+ val->v.integer = rparam->rssi/2;
+ break;
+ case LEAF_wlanIfRoamTxRateThreshold:
+ val->v.integer = rparam->rate/2;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_tx_params(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ uint32_t phy;
+ struct ieee80211_txparam *txparam;
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+ wlan_update_tx_params();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ txparam = wlan_get_tx_param(&val->var, sub, &wif, &phy);
+ if (txparam == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get_txparams;
+
+ case SNMP_OP_GETNEXT:
+ txparam = wlan_get_next_tx_param(&val->var, sub, &wif, &phy);
+ if (txparam == NULL || wif == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_phy_index(&val->var, sub, wif->wname, phy);
+ goto get_txparams;
+
+ case SNMP_OP_SET:
+ txparam = wlan_get_tx_param(&val->var, sub, &wif, &phy);
+ if (txparam == NULL || wif == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfTxUnicastRate:
+ ctx->scratch->int1 = txparam->ucastrate;
+ txparam->ucastrate = val->v.integer * 2;
+ break;
+ case LEAF_wlanIfTxMcastRate:
+ ctx->scratch->int1 = txparam->mcastrate;
+ txparam->mcastrate = val->v.integer * 2;
+ break;
+ case LEAF_wlanIfTxMgmtRate:
+ ctx->scratch->int1 = txparam->mgmtrate;
+ txparam->mgmtrate = val->v.integer * 2;
+ break;
+ case LEAF_wlanIfTxMaxRetryCount:
+ ctx->scratch->int1 = txparam->maxretry;
+ txparam->maxretry = val->v.integer;
+ break;
+ default:
+ abort();
+ }
+ if (wlan_set_tx_params(wif, phy) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ txparam = wlan_get_tx_param(&val->var, sub, &wif, &phy);
+ if (txparam == NULL || wif == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfTxUnicastRate:
+ txparam->ucastrate = ctx->scratch->int1;
+ break;
+ case LEAF_wlanIfTxMcastRate:
+ txparam->mcastrate = ctx->scratch->int1;
+ break;
+ case LEAF_wlanIfTxMgmtRate:
+ txparam->mgmtrate = ctx->scratch->int1;
+ break;
+ case LEAF_wlanIfTxMaxRetryCount:
+ txparam->maxretry = ctx->scratch->int1;
+ break;
+ default:
+ abort();
+ }
+ if (wlan_set_tx_params(wif, phy) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+ default:
+ abort();
+ }
+
+get_txparams:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanIfTxUnicastRate:
+ val->v.integer = txparam->ucastrate / 2;
+ break;
+ case LEAF_wlanIfTxMcastRate:
+ val->v.integer = txparam->mcastrate / 2;
+ break;
+ case LEAF_wlanIfTxMgmtRate:
+ val->v.integer = txparam->mgmtrate / 2;
+ break;
+ case LEAF_wlanIfTxMaxRetryCount:
+ val->v.integer = txparam->maxretry;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_scan_config(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ break;
+
+ case SNMP_OP_SET:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (wif->scan_status == wlanScanConfigStatus_running
+ && val->var.subs[sub - 1] != LEAF_wlanScanConfigStatus)
+ return (SNMP_ERR_INCONS_VALUE);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanScanFlags:
+ ctx->scratch->int1 = wif->scan_flags;
+ wif->scan_flags = val->v.integer;
+ break;
+ case LEAF_wlanScanDuration:
+ ctx->scratch->int1 = wif->scan_duration;
+ wif->scan_duration = val->v.integer;
+ break;
+ case LEAF_wlanScanMinChannelDwellTime:
+ ctx->scratch->int1 = wif->scan_mindwell;
+ wif->scan_mindwell = val->v.integer;
+ break;
+ case LEAF_wlanScanMaxChannelDwellTime:
+ ctx->scratch->int1 = wif->scan_maxdwell;
+ wif->scan_maxdwell = val->v.integer;
+ break;
+ case LEAF_wlanScanConfigStatus:
+ if (val->v.integer == wlanScanConfigStatus_running ||
+ val->v.integer == wlanScanConfigStatus_cancel) {
+ ctx->scratch->int1 = wif->scan_status;
+ wif->scan_status = val->v.integer;
+ break;
+ }
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (val->var.subs[sub - 1] == LEAF_wlanScanConfigStatus)
+ if (wif->scan_status == wlanScanConfigStatus_running)
+ (void)wlan_set_scan_config(wif); /* XXX */
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanScanFlags:
+ wif->scan_flags = ctx->scratch->int1;
+ break;
+ case LEAF_wlanScanDuration:
+ wif->scan_duration = ctx->scratch->int1;
+ break;
+ case LEAF_wlanScanMinChannelDwellTime:
+ wif->scan_mindwell = ctx->scratch->int1;
+ break;
+ case LEAF_wlanScanMaxChannelDwellTime:
+ wif->scan_maxdwell = ctx->scratch->int1;
+ break;
+ case LEAF_wlanScanConfigStatus:
+ wif->scan_status = ctx->scratch->int1;
+ break;
+ }
+ return (SNMP_ERR_NOERROR);
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanScanFlags:
+ val->v.integer = wif->scan_flags;
+ break;
+ case LEAF_wlanScanDuration:
+ val->v.integer = wif->scan_duration;
+ break;
+ case LEAF_wlanScanMinChannelDwellTime:
+ val->v.integer = wif->scan_mindwell;
+ break;
+ case LEAF_wlanScanMaxChannelDwellTime:
+ val->v.integer = wif->scan_maxdwell;
+ break;
+ case LEAF_wlanScanConfigStatus:
+ val->v.integer = wif->scan_status;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_scan_results(struct snmp_context *ctx __unused, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_scan_result *sr;
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+ wlan_scan_update_results();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((sr = wlan_get_scanr(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ if ((sr = wlan_get_next_scanr(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_scanr_index(&val->var, sub, wif->wname, sr->ssid,
+ sr->bssid);
+ break;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_COMMIT:
+ /* FALLTHROUGH */
+ case SNMP_OP_ROLLBACK:
+ /* FALLTHROUGH */
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanScanResultID:
+ return (string_get(val, sr->ssid, -1));
+ case LEAF_wlanScanResultBssid:
+ return (string_get(val, sr->bssid, IEEE80211_ADDR_LEN));
+ case LEAF_wlanScanResultChannel:
+ val->v.integer = sr->opchannel; /* XXX */
+ break;
+ case LEAF_wlanScanResultRate:
+ val->v.integer = sr->rssi;
+ break;
+ case LEAF_wlanScanResultNoise:
+ val->v.integer = sr->noise;
+ break;
+ case LEAF_wlanScanResultBeaconInterval:
+ val->v.integer = sr->bintval;
+ break;
+ case LEAF_wlanScanResultCapabilities:
+ return (bits_get(val, &sr->capinfo, sizeof(sr->capinfo)));
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_iface_stats(struct snmp_context *ctx __unused, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+ case SNMP_OP_GETNEXT:
+ if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ break;
+ case SNMP_OP_SET:
+ /* XXX: LEAF_wlanStatsReset */
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_COMMIT:
+ /* FALLTHROUGH */
+ case SNMP_OP_ROLLBACK:
+ /* FALLTHROUGH */
+ default:
+ abort();
+ }
+
+ if (wlan_get_stats(wif) < 0)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanStatsRxBadVersion:
+ val->v.uint32 = wif->stats.is_rx_badversion;
+ break;
+ case LEAF_wlanStatsRxTooShort:
+ val->v.uint32 = wif->stats.is_rx_tooshort;
+ break;
+ case LEAF_wlanStatsRxWrongBssid:
+ val->v.uint32 = wif->stats.is_rx_wrongbss;
+ break;
+ case LEAF_wlanStatsRxDiscardedDups:
+ val->v.uint32 = wif->stats.is_rx_dup;
+ break;
+ case LEAF_wlanStatsRxWrongDir:
+ val->v.uint32 = wif->stats.is_rx_wrongdir;
+ break;
+ case LEAF_wlanStatsRxDiscardMcastEcho:
+ val->v.uint32 = wif->stats.is_rx_mcastecho;
+ break;
+ case LEAF_wlanStatsRxDiscardNoAssoc:
+ val->v.uint32 = wif->stats.is_rx_notassoc;
+ break;
+ case LEAF_wlanStatsRxWepNoPrivacy:
+ val->v.uint32 = wif->stats.is_rx_noprivacy;
+ break;
+ case LEAF_wlanStatsRxWepUnencrypted:
+ val->v.uint32 = wif->stats.is_rx_unencrypted;
+ break;
+ case LEAF_wlanStatsRxWepFailed:
+ val->v.uint32 = wif->stats.is_rx_wepfail;
+ break;
+ case LEAF_wlanStatsRxDecapsulationFailed:
+ val->v.uint32 = wif->stats.is_rx_decap;
+ break;
+ case LEAF_wlanStatsRxDiscardMgmt:
+ val->v.uint32 = wif->stats.is_rx_mgtdiscard;
+ break;
+ case LEAF_wlanStatsRxControl:
+ val->v.uint32 = wif->stats.is_rx_ctl;
+ break;
+ case LEAF_wlanStatsRxBeacon:
+ val->v.uint32 = wif->stats.is_rx_beacon;
+ break;
+ case LEAF_wlanStatsRxRateSetTooBig:
+ val->v.uint32 = wif->stats.is_rx_rstoobig;
+ break;
+ case LEAF_wlanStatsRxElemMissing:
+ val->v.uint32 = wif->stats.is_rx_elem_missing;
+ break;
+ case LEAF_wlanStatsRxElemTooBig:
+ val->v.uint32 = wif->stats.is_rx_elem_toobig;
+ break;
+ case LEAF_wlanStatsRxElemTooSmall:
+ val->v.uint32 = wif->stats.is_rx_elem_toosmall;
+ break;
+ case LEAF_wlanStatsRxElemUnknown:
+ val->v.uint32 = wif->stats.is_rx_elem_unknown;
+ break;
+ case LEAF_wlanStatsRxChannelMismatch:
+ val->v.uint32 = wif->stats.is_rx_chanmismatch;
+ break;
+ case LEAF_wlanStatsRxDropped:
+ val->v.uint32 = wif->stats.is_rx_nodealloc;
+ break;
+ case LEAF_wlanStatsRxSsidMismatch:
+ val->v.uint32 = wif->stats.is_rx_ssidmismatch;
+ break;
+ case LEAF_wlanStatsRxAuthNotSupported:
+ val->v.uint32 = wif->stats.is_rx_auth_unsupported;
+ break;
+ case LEAF_wlanStatsRxAuthFailed:
+ val->v.uint32 = wif->stats.is_rx_auth_fail;
+ break;
+ case LEAF_wlanStatsRxAuthCM:
+ val->v.uint32 = wif->stats.is_rx_auth_countermeasures;
+ break;
+ case LEAF_wlanStatsRxAssocWrongBssid:
+ val->v.uint32 = wif->stats.is_rx_assoc_bss;
+ break;
+ case LEAF_wlanStatsRxAssocNoAuth:
+ val->v.uint32 = wif->stats.is_rx_assoc_notauth;
+ break;
+ case LEAF_wlanStatsRxAssocCapMismatch:
+ val->v.uint32 = wif->stats.is_rx_assoc_capmismatch;
+ break;
+ case LEAF_wlanStatsRxAssocNoRateMatch:
+ val->v.uint32 = wif->stats.is_rx_assoc_norate;
+ break;
+ case LEAF_wlanStatsRxBadWpaIE:
+ val->v.uint32 = wif->stats.is_rx_assoc_badwpaie;
+ break;
+ case LEAF_wlanStatsRxDeauthenticate:
+ val->v.uint32 = wif->stats.is_rx_deauth;
+ break;
+ case LEAF_wlanStatsRxDisassociate:
+ val->v.uint32 = wif->stats.is_rx_disassoc;
+ break;
+ case LEAF_wlanStatsRxUnknownSubtype:
+ val->v.uint32 = wif->stats.is_rx_badsubtype;
+ break;
+ case LEAF_wlanStatsRxFailedNoBuf:
+ val->v.uint32 = wif->stats.is_rx_nobuf;
+ break;
+ case LEAF_wlanStatsRxBadAuthRequest:
+ val->v.uint32 = wif->stats.is_rx_bad_auth;
+ break;
+ case LEAF_wlanStatsRxUnAuthorized:
+ val->v.uint32 = wif->stats.is_rx_unauth;
+ break;
+ case LEAF_wlanStatsRxBadKeyId:
+ val->v.uint32 = wif->stats.is_rx_badkeyid;
+ break;
+ case LEAF_wlanStatsRxCCMPSeqViolation:
+ val->v.uint32 = wif->stats.is_rx_ccmpreplay;
+ break;
+ case LEAF_wlanStatsRxCCMPBadFormat:
+ val->v.uint32 = wif->stats.is_rx_ccmpformat;
+ break;
+ case LEAF_wlanStatsRxCCMPFailedMIC:
+ val->v.uint32 = wif->stats.is_rx_ccmpmic;
+ break;
+ case LEAF_wlanStatsRxTKIPSeqViolation:
+ val->v.uint32 = wif->stats.is_rx_tkipreplay;
+ break;
+ case LEAF_wlanStatsRxTKIPBadFormat:
+ val->v.uint32 = wif->stats.is_rx_tkipformat;
+ break;
+ case LEAF_wlanStatsRxTKIPFailedMIC:
+ val->v.uint32 = wif->stats.is_rx_tkipmic;
+ break;
+ case LEAF_wlanStatsRxTKIPFailedICV:
+ val->v.uint32 = wif->stats.is_rx_tkipicv;
+ break;
+ case LEAF_wlanStatsRxDiscardACL:
+ val->v.uint32 = wif->stats.is_rx_acl;
+ break;
+ case LEAF_wlanStatsTxFailedNoBuf:
+ val->v.uint32 = wif->stats.is_tx_nobuf;
+ break;
+ case LEAF_wlanStatsTxFailedNoNode:
+ val->v.uint32 = wif->stats.is_tx_nonode;
+ break;
+ case LEAF_wlanStatsTxUnknownMgmt:
+ val->v.uint32 = wif->stats.is_tx_unknownmgt;
+ break;
+ case LEAF_wlanStatsTxBadCipher:
+ val->v.uint32 = wif->stats.is_tx_badcipher;
+ break;
+ case LEAF_wlanStatsTxNoDefKey:
+ val->v.uint32 = wif->stats.is_tx_nodefkey;
+ break;
+ case LEAF_wlanStatsTxFragmented:
+ val->v.uint32 = wif->stats.is_tx_fragframes;
+ break;
+ case LEAF_wlanStatsTxFragmentsCreated:
+ val->v.uint32 = wif->stats.is_tx_frags;
+ break;
+ case LEAF_wlanStatsActiveScans:
+ val->v.uint32 = wif->stats.is_scan_active;
+ break;
+ case LEAF_wlanStatsPassiveScans:
+ val->v.uint32 = wif->stats.is_scan_passive;
+ break;
+ case LEAF_wlanStatsTimeoutInactivity:
+ val->v.uint32 = wif->stats.is_node_timeout;
+ break;
+ case LEAF_wlanStatsCryptoNoMem:
+ val->v.uint32 = wif->stats.is_crypto_nomem;
+ break;
+ case LEAF_wlanStatsSwCryptoTKIP:
+ val->v.uint32 = wif->stats.is_crypto_tkip;
+ break;
+ case LEAF_wlanStatsSwCryptoTKIPEnMIC:
+ val->v.uint32 = wif->stats.is_crypto_tkipenmic;
+ break;
+ case LEAF_wlanStatsSwCryptoTKIPDeMIC:
+ val->v.uint32 = wif->stats.is_crypto_tkipdemic;
+ break;
+ case LEAF_wlanStatsCryptoTKIPCM:
+ val->v.uint32 = wif->stats.is_crypto_tkipcm;
+ break;
+ case LEAF_wlanStatsSwCryptoCCMP:
+ val->v.uint32 = wif->stats.is_crypto_ccmp;
+ break;
+ case LEAF_wlanStatsSwCryptoWEP:
+ val->v.uint32 = wif->stats.is_crypto_wep;
+ break;
+ case LEAF_wlanStatsCryptoCipherKeyRejected:
+ val->v.uint32 = wif->stats.is_crypto_setkey_cipher;
+ break;
+ case LEAF_wlanStatsCryptoNoKey:
+ val->v.uint32 = wif->stats.is_crypto_setkey_nokey;
+ break;
+ case LEAF_wlanStatsCryptoDeleteKeyFailed:
+ val->v.uint32 = wif->stats.is_crypto_delkey;
+ break;
+ case LEAF_wlanStatsCryptoUnknownCipher:
+ val->v.uint32 = wif->stats.is_crypto_badcipher;
+ break;
+ case LEAF_wlanStatsCryptoAttachFailed:
+ val->v.uint32 = wif->stats.is_crypto_attachfail;
+ break;
+ case LEAF_wlanStatsCryptoKeyFailed:
+ val->v.uint32 = wif->stats.is_crypto_keyfail;
+ break;
+ case LEAF_wlanStatsCryptoEnMICFailed:
+ val->v.uint32 = wif->stats.is_crypto_enmicfail;
+ break;
+ case LEAF_wlanStatsIBSSCapMismatch:
+ val->v.uint32 = wif->stats.is_ibss_capmismatch;
+ break;
+ case LEAF_wlanStatsUnassocStaPSPoll:
+ val->v.uint32 = wif->stats.is_ps_unassoc;
+ break;
+ case LEAF_wlanStatsBadAidPSPoll:
+ val->v.uint32 = wif->stats.is_ps_badaid;
+ break;
+ case LEAF_wlanStatsEmptyPSPoll:
+ val->v.uint32 = wif->stats.is_ps_qempty;
+ break;
+ case LEAF_wlanStatsRxFFBadHdr:
+ val->v.uint32 = wif->stats.is_ff_badhdr;
+ break;
+ case LEAF_wlanStatsRxFFTooShort:
+ val->v.uint32 = wif->stats.is_ff_tooshort;
+ break;
+ case LEAF_wlanStatsRxFFSplitError:
+ val->v.uint32 = wif->stats.is_ff_split;
+ break;
+ case LEAF_wlanStatsRxFFDecap:
+ val->v.uint32 = wif->stats.is_ff_decap;
+ break;
+ case LEAF_wlanStatsTxFFEncap:
+ val->v.uint32 = wif->stats.is_ff_encap;
+ break;
+ case LEAF_wlanStatsRxBadBintval:
+ val->v.uint32 = wif->stats.is_rx_badbintval;
+ break;
+ case LEAF_wlanStatsRxDemicFailed:
+ val->v.uint32 = wif->stats.is_rx_demicfail;
+ break;
+ case LEAF_wlanStatsRxDefragFailed:
+ val->v.uint32 = wif->stats.is_rx_defrag;
+ break;
+ case LEAF_wlanStatsRxMgmt:
+ val->v.uint32 = wif->stats.is_rx_mgmt;
+ break;
+ case LEAF_wlanStatsRxActionMgmt:
+ val->v.uint32 = wif->stats.is_rx_action;
+ break;
+ case LEAF_wlanStatsRxAMSDUTooShort:
+ val->v.uint32 = wif->stats.is_amsdu_tooshort;
+ break;
+ case LEAF_wlanStatsRxAMSDUSplitError:
+ val->v.uint32 = wif->stats.is_amsdu_split;
+ break;
+ case LEAF_wlanStatsRxAMSDUDecap:
+ val->v.uint32 = wif->stats.is_amsdu_decap;
+ break;
+ case LEAF_wlanStatsTxAMSDUEncap:
+ val->v.uint32 = wif->stats.is_amsdu_encap;
+ break;
+ case LEAF_wlanStatsAMPDUBadBAR:
+ val->v.uint32 = wif->stats.is_ampdu_bar_bad;
+ break;
+ case LEAF_wlanStatsAMPDUOowBar:
+ val->v.uint32 = wif->stats.is_ampdu_bar_oow;
+ break;
+ case LEAF_wlanStatsAMPDUMovedBAR:
+ val->v.uint32 = wif->stats.is_ampdu_bar_move;
+ break;
+ case LEAF_wlanStatsAMPDURxBAR:
+ val->v.uint32 = wif->stats.is_ampdu_bar_rx;
+ break;
+ case LEAF_wlanStatsAMPDURxOor:
+ val->v.uint32 = wif->stats.is_ampdu_rx_oor;
+ break;
+ case LEAF_wlanStatsAMPDURxCopied:
+ val->v.uint32 = wif->stats.is_ampdu_rx_copy;
+ break;
+ case LEAF_wlanStatsAMPDURxDropped:
+ val->v.uint32 = wif->stats.is_ampdu_rx_drop;
+ break;
+ case LEAF_wlanStatsTxDiscardBadState:
+ val->v.uint32 = wif->stats.is_tx_badstate;
+ break;
+ case LEAF_wlanStatsTxFailedNoAssoc:
+ val->v.uint32 = wif->stats.is_tx_notassoc;
+ break;
+ case LEAF_wlanStatsTxClassifyFailed:
+ val->v.uint32 = wif->stats.is_tx_classify;
+ break;
+ case LEAF_wlanStatsDwdsMcastDiscard:
+ val->v.uint32 = wif->stats.is_dwds_mcast;
+ break;
+ case LEAF_wlanStatsHTAssocRejectNoHT:
+ val->v.uint32 = wif->stats.is_ht_assoc_nohtcap;
+ break;
+ case LEAF_wlanStatsHTAssocDowngrade:
+ val->v.uint32 = wif->stats.is_ht_assoc_downgrade;
+ break;
+ case LEAF_wlanStatsHTAssocRateMismatch:
+ val->v.uint32 = wif->stats.is_ht_assoc_norate;
+ break;
+ case LEAF_wlanStatsAMPDURxAge:
+ val->v.uint32 = wif->stats.is_ampdu_rx_age;
+ break;
+ case LEAF_wlanStatsAMPDUMoved:
+ val->v.uint32 = wif->stats.is_ampdu_rx_move;
+ break;
+ case LEAF_wlanStatsADDBADisabledReject:
+ val->v.uint32 = wif->stats.is_addba_reject;
+ break;
+ case LEAF_wlanStatsADDBANoRequest:
+ val->v.uint32 = wif->stats.is_addba_norequest;
+ break;
+ case LEAF_wlanStatsADDBABadToken:
+ val->v.uint32 = wif->stats.is_addba_badtoken;
+ break;
+ case LEAF_wlanStatsADDBABadPolicy:
+ val->v.uint32 = wif->stats.is_addba_badpolicy;
+ break;
+ case LEAF_wlanStatsAMPDUStopped:
+ val->v.uint32 = wif->stats.is_ampdu_stop;
+ break;
+ case LEAF_wlanStatsAMPDUStopFailed:
+ val->v.uint32 = wif->stats.is_ampdu_stop_failed;
+ break;
+ case LEAF_wlanStatsAMPDURxReorder:
+ val->v.uint32 = wif->stats.is_ampdu_rx_reorder;
+ break;
+ case LEAF_wlanStatsScansBackground:
+ val->v.uint32 = wif->stats.is_scan_bg;
+ break;
+ case LEAF_wlanLastDeauthReason:
+ val->v.uint32 = wif->stats.is_rx_deauth_code;
+ break;
+ case LEAF_wlanLastDissasocReason:
+ val->v.uint32 = wif->stats.is_rx_disassoc_code;
+ break;
+ case LEAF_wlanLastAuthFailReason:
+ val->v.uint32 = wif->stats.is_rx_authfail_code;
+ break;
+ case LEAF_wlanStatsBeaconMissedEvents:
+ val->v.uint32 = wif->stats.is_beacon_miss;
+ break;
+ case LEAF_wlanStatsRxDiscardBadStates:
+ val->v.uint32 = wif->stats.is_rx_badstate;
+ break;
+ case LEAF_wlanStatsFFFlushed:
+ val->v.uint32 = wif->stats.is_ff_flush;
+ break;
+ case LEAF_wlanStatsTxControlFrames:
+ val->v.uint32 = wif->stats.is_tx_ctl;
+ break;
+ case LEAF_wlanStatsAMPDURexmt:
+ val->v.uint32 = wif->stats.is_ampdu_rexmt;
+ break;
+ case LEAF_wlanStatsAMPDURexmtFailed:
+ val->v.uint32 = wif->stats.is_ampdu_rexmt_fail;
+ break;
+ case LEAF_wlanStatsReset:
+ val->v.uint32 = wlanStatsReset_no_op;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_wep_iface(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
+ !wif->wepsupported)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ /* XXX: filter wif->wepsupported */
+ if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ break;
+
+ case SNMP_OP_SET:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
+ !wif->wepsupported)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanWepMode:
+ if (val->v.integer < wlanWepMode_off ||
+ val->v.integer > wlanWepMode_mixed)
+ return (SNMP_ERR_INCONS_VALUE);
+ ctx->scratch->int1 = wif->wepmode;
+ wif->wepmode = val->v.integer;
+ if (wlan_set_wepmode(wif) < 0) {
+ wif->wepmode = ctx->scratch->int1;
+ return (SNMP_ERR_GENERR);
+ }
+ break;
+ case LEAF_wlanWepDefTxKey:
+ if (val->v.integer < 0 ||
+ val->v.integer > IEEE80211_WEP_NKID)
+ return (SNMP_ERR_INCONS_VALUE);
+ ctx->scratch->int1 = wif->weptxkey;
+ wif->weptxkey = val->v.integer;
+ if (wlan_set_weptxkey(wif) < 0) {
+ wif->weptxkey = ctx->scratch->int1;
+ return (SNMP_ERR_GENERR);
+ }
+ break;
+ default:
+ abort();
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanWepMode:
+ wif->wepmode = ctx->scratch->int1;
+ if (wlan_set_wepmode(wif) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+ case LEAF_wlanWepDefTxKey:
+ wif->weptxkey = ctx->scratch->int1;
+ if (wlan_set_weptxkey(wif) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+ default:
+ abort();
+ }
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanWepMode:
+ if (wlan_get_wepmode(wif) < 0)
+ return (SNMP_ERR_GENERR);
+ val->v.integer = wif->wepmode;
+ break;
+ case LEAF_wlanWepDefTxKey:
+ if (wlan_get_weptxkey(wif) < 0)
+ return (SNMP_ERR_GENERR);
+ val->v.integer = wif->weptxkey;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_wep_key(struct snmp_context *ctx __unused,
+ struct snmp_value *val __unused, uint32_t sub __unused,
+ uint32_t iidx __unused, enum snmp_op op __unused)
+{
+ return (SNMP_ERR_NOSUCHNAME);
+}
+
+int
+op_wlan_mac_access_control(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
+ !wif->macsupported)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ /* XXX: filter wif->macsupported */
+ if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ break;
+
+ case SNMP_OP_SET:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
+ !wif->macsupported)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMACAccessControlPolicy:
+ ctx->scratch->int1 = wif->mac_policy;
+ wif->mac_policy = val->v.integer;
+ break;
+ case LEAF_wlanMACAccessControlNacl:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case LEAF_wlanMACAccessControlFlush:
+ break;
+ default:
+ abort();
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMACAccessControlPolicy:
+ if (wlan_set_mac_policy(wif) < 0) {
+ wif->mac_policy = ctx->scratch->int1;
+ return (SNMP_ERR_GENERR);
+ }
+ break;
+ case LEAF_wlanMACAccessControlFlush:
+ if (wlan_flush_mac_mac(wif) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+ default:
+ abort();
+ }
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (val->var.subs[sub - 1] == LEAF_wlanMACAccessControlPolicy)
+ wif->mac_policy = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+
+ if (wlan_get_mac_policy(wif) < 0)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMACAccessControlPolicy:
+ val->v.integer = wif->mac_policy;
+ break;
+ case LEAF_wlanMACAccessControlNacl:
+ val->v.integer = wif->mac_nacls;
+ break;
+ case LEAF_wlanMACAccessControlFlush:
+ val->v.integer = wlanMACAccessControlFlush_no_op;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_mac_acl_mac(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_iface *wif;
+ struct wlan_mac_mac *macl;
+
+ wlan_update_interface_list();
+ wlan_mac_update_aclmacs();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((macl = wlan_get_acl_mac(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ if ((macl = wlan_get_next_acl_mac(&val->var, sub, &wif))
+ == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_mac_index(&val->var, sub, wif->wname, macl->mac);
+ break;
+
+ case SNMP_OP_SET:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMACAccessControlMAC:
+ return (SNMP_ERR_INCONS_NAME);
+ case LEAF_wlanMACAccessControlMACStatus:
+ return(wlan_acl_mac_set_status(ctx, val, sub));
+ default:
+ abort();
+ }
+
+ case SNMP_OP_COMMIT:
+ if ((macl = wlan_get_acl_mac(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (val->v.integer == RowStatus_destroy &&
+ wlan_mac_delete_mac(wif, macl) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ if ((macl = wlan_get_acl_mac(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (ctx->scratch->int1 == RowStatus_destroy &&
+ wlan_mac_delete_mac(wif, macl) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMACAccessControlMAC:
+ return (string_get(val, macl->mac, IEEE80211_ADDR_LEN));
+ case LEAF_wlanMACAccessControlMACStatus:
+ val->v.integer = macl->mac_status;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_mesh_config(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ int which;
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshMaxRetries:
+ which = WLAN_MESH_MAX_RETRIES;
+ break;
+ case LEAF_wlanMeshHoldingTimeout:
+ which = WLAN_MESH_HOLDING_TO;
+ break;
+ case LEAF_wlanMeshConfirmTimeout:
+ which = WLAN_MESH_CONFIRM_TO;
+ break;
+ case LEAF_wlanMeshRetryTimeout:
+ which = WLAN_MESH_RETRY_TO;
+ break;
+ default:
+ abort();
+ }
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (wlan_do_sysctl(&wlan_config, which, 0) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_SET:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshRetryTimeout :
+ ctx->scratch->int1 = wlan_config.mesh_retryto;
+ wlan_config.mesh_retryto = val->v.integer;
+ break;
+ case LEAF_wlanMeshHoldingTimeout:
+ ctx->scratch->int1 = wlan_config.mesh_holdingto;
+ wlan_config.mesh_holdingto = val->v.integer;
+ break;
+ case LEAF_wlanMeshConfirmTimeout:
+ ctx->scratch->int1 = wlan_config.mesh_confirmto;
+ wlan_config.mesh_confirmto = val->v.integer;
+ break;
+ case LEAF_wlanMeshMaxRetries:
+ ctx->scratch->int1 = wlan_config.mesh_maxretries;
+ wlan_config.mesh_maxretries = val->v.integer;
+ break;
+ }
+ if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshRetryTimeout:
+ wlan_config.mesh_retryto = ctx->scratch->int1;
+ break;
+ case LEAF_wlanMeshConfirmTimeout:
+ wlan_config.mesh_confirmto = ctx->scratch->int1;
+ break;
+ case LEAF_wlanMeshHoldingTimeout:
+ wlan_config.mesh_holdingto= ctx->scratch->int1;
+ break;
+ case LEAF_wlanMeshMaxRetries:
+ wlan_config.mesh_maxretries = ctx->scratch->int1;
+ break;
+ }
+ if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshRetryTimeout:
+ val->v.integer = wlan_config.mesh_retryto;
+ break;
+ case LEAF_wlanMeshHoldingTimeout:
+ val->v.integer = wlan_config.mesh_holdingto;
+ break;
+ case LEAF_wlanMeshConfirmTimeout:
+ val->v.integer = wlan_config.mesh_confirmto;
+ break;
+ case LEAF_wlanMeshMaxRetries:
+ val->v.integer = wlan_config.mesh_maxretries;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_mesh_iface(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ int rc;
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ break;
+
+ case SNMP_OP_SET:
+ if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshId:
+ if (val->v.octetstring.len > IEEE80211_NWID_LEN)
+ return (SNMP_ERR_INCONS_VALUE);
+ ctx->scratch->ptr1 = malloc(val->v.octetstring.len + 1);
+ if (ctx->scratch->ptr1 == NULL)
+ return (SNMP_ERR_GENERR);
+ strlcpy(ctx->scratch->ptr1, wif->desired_ssid,
+ val->v.octetstring.len + 1);
+ ctx->scratch->int1 = strlen(wif->desired_ssid);
+ memcpy(wif->desired_ssid, val->v.octetstring.octets,
+ val->v.octetstring.len);
+ wif->desired_ssid[val->v.octetstring.len] = '\0';
+ break;
+ case LEAF_wlanMeshTTL:
+ ctx->scratch->int1 = wif->mesh_ttl;
+ wif->mesh_ttl = val->v.integer;
+ break;
+ case LEAF_wlanMeshPeeringEnabled:
+ ctx->scratch->int1 = wif->mesh_peering;
+ wif->mesh_peering = val->v.integer;
+ break;
+ case LEAF_wlanMeshForwardingEnabled:
+ ctx->scratch->int1 = wif->mesh_forwarding;
+ wif->mesh_forwarding = val->v.integer;
+ break;
+ case LEAF_wlanMeshMetric:
+ ctx->scratch->int1 = wif->mesh_metric;
+ wif->mesh_metric = val->v.integer;
+ break;
+ case LEAF_wlanMeshPath:
+ ctx->scratch->int1 = wif->mesh_path;
+ wif->mesh_path = val->v.integer;
+ break;
+ case LEAF_wlanMeshRoutesFlush:
+ if (val->v.integer != wlanMeshRoutesFlush_flush)
+ return (SNMP_ERR_INCONS_VALUE);
+ return (SNMP_ERR_NOERROR);
+ default:
+ abort();
+ }
+ if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
+ rc = wlan_config_set_dssid(wif,
+ val->v.octetstring.octets, val->v.octetstring.len);
+ else
+ rc = wlan_mesh_config_set(wif, val->var.subs[sub - 1]);
+ if (rc < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (val->var.subs[sub - 1] == LEAF_wlanMeshRoutesFlush &&
+ wlan_mesh_flush_routes(wif) < 0)
+ return (SNMP_ERR_GENERR);
+ if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
+ free(ctx->scratch->ptr1);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshId:
+ strlcpy(wif->desired_ssid, ctx->scratch->ptr1,
+ IEEE80211_NWID_LEN);
+ free(ctx->scratch->ptr1);
+ break;
+ case LEAF_wlanMeshTTL:
+ wif->mesh_ttl = ctx->scratch->int1;
+ break;
+ case LEAF_wlanMeshPeeringEnabled:
+ wif->mesh_peering = ctx->scratch->int1;
+ break;
+ case LEAF_wlanMeshForwardingEnabled:
+ wif->mesh_forwarding = ctx->scratch->int1;
+ break;
+ case LEAF_wlanMeshMetric:
+ wif->mesh_metric = ctx->scratch->int1;
+ break;
+ case LEAF_wlanMeshPath:
+ wif->mesh_path = ctx->scratch->int1;
+ break;
+ case LEAF_wlanMeshRoutesFlush:
+ return (SNMP_ERR_NOERROR);
+ default:
+ abort();
+ }
+ if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
+ rc = wlan_config_set_dssid(wif, wif->desired_ssid,
+ strlen(wif->desired_ssid));
+ else
+ rc = wlan_mesh_config_set(wif, val->var.subs[sub - 1]);
+ if (rc < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+
+ if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
+ rc = wlan_config_get_dssid(wif);
+ else
+ rc = wlan_mesh_config_get(wif, val->var.subs[sub - 1]);
+ if (rc < 0)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshId:
+ return (string_get(val, wif->desired_ssid, -1));
+ case LEAF_wlanMeshTTL:
+ val->v.integer = wif->mesh_ttl;
+ break;
+ case LEAF_wlanMeshPeeringEnabled:
+ val->v.integer = wif->mesh_peering;
+ break;
+ case LEAF_wlanMeshForwardingEnabled:
+ val->v.integer = wif->mesh_forwarding;
+ break;
+ case LEAF_wlanMeshMetric:
+ val->v.integer = wif->mesh_metric;
+ break;
+ case LEAF_wlanMeshPath:
+ val->v.integer = wif->mesh_path;
+ break;
+ case LEAF_wlanMeshRoutesFlush:
+ val->v.integer = wlanMeshRoutesFlush_no_op;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_mesh_neighbor(struct snmp_context *ctx __unused, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_peer *wip;
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+ wlan_update_peers();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wip = wlan_mesh_get_peer(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+ case SNMP_OP_GETNEXT:
+ wip = wlan_mesh_get_next_peer(&val->var, sub, &wif);
+ if (wip == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_mac_index(&val->var, sub, wif->wname,
+ wip->pmac);
+ break;
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_COMMIT:
+ /* FALLTHROUGH */
+ case SNMP_OP_ROLLBACK:
+ /* FALLTHROUGH */
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshNeighborAddress:
+ return (string_get(val, wip->pmac, IEEE80211_ADDR_LEN));
+ case LEAF_wlanMeshNeighborFrequency:
+ val->v.integer = wip->frequency;
+ break;
+ case LEAF_wlanMeshNeighborLocalId:
+ val->v.integer = wip->local_id;
+ break;
+ case LEAF_wlanMeshNeighborPeerId:
+ val->v.integer = wip->peer_id;
+ break;
+ case LEAF_wlanMeshNeighborPeerState:
+ return (bits_get(val, (uint8_t *)&wip->state,
+ sizeof(wip->state)));
+ case LEAF_wlanMeshNeighborCurrentTXRate:
+ val->v.integer = wip->txrate;
+ break;
+ case LEAF_wlanMeshNeighborRxSignalStrength:
+ val->v.integer = wip->rssi;
+ break;
+ case LEAF_wlanMeshNeighborIdleTimer:
+ val->v.integer = wip->idle;
+ break;
+ case LEAF_wlanMeshNeighborTxSequenceNo:
+ val->v.integer = wip->txseqs;
+ break;
+ case LEAF_wlanMeshNeighborRxSequenceNo:
+ val->v.integer = wip->rxseqs;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_mesh_route(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_mesh_route *wmr;
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+ wlan_mesh_update_routes();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wmr = wlan_mesh_get_route(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ wmr = wlan_mesh_get_next_route(&val->var, sub, &wif);
+ if (wmr == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_mac_index(&val->var, sub, wif->wname,
+ wmr->imroute.imr_dest);
+ break;
+
+ case SNMP_OP_SET:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshRouteDestination:
+ return (SNMP_ERR_INCONS_NAME);
+ case LEAF_wlanMeshRouteStatus:
+ return(wlan_mesh_route_set_status(ctx, val, sub));
+ default:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ abort();
+
+ case SNMP_OP_COMMIT:
+ if ((wmr = wlan_mesh_get_route(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (val->v.integer == RowStatus_destroy &&
+ wlan_mesh_delete_route(wif, wmr) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ if ((wmr = wlan_mesh_get_route(&val->var, sub, &wif)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ if (ctx->scratch->int1 == RowStatus_destroy &&
+ wlan_mesh_delete_route(wif, wmr) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshRouteDestination:
+ return (string_get(val, wmr->imroute.imr_dest,
+ IEEE80211_ADDR_LEN));
+ case LEAF_wlanMeshRouteNextHop:
+ return (string_get(val, wmr->imroute.imr_nexthop,
+ IEEE80211_ADDR_LEN));
+ case LEAF_wlanMeshRouteHops:
+ val->v.integer = wmr->imroute.imr_nhops;
+ break;
+ case LEAF_wlanMeshRouteMetric:
+ val->v.integer = wmr->imroute.imr_metric;
+ break;
+ case LEAF_wlanMeshRouteLifeTime:
+ val->v.integer = wmr->imroute.imr_lifetime;
+ break;
+ case LEAF_wlanMeshRouteLastMseq:
+ val->v.integer = wmr->imroute.imr_lastmseq;
+ break;
+ case LEAF_wlanMeshRouteFlags:
+ val->v.integer = 0;
+ if ((wmr->imroute.imr_flags &
+ IEEE80211_MESHRT_FLAGS_VALID) != 0)
+ val->v.integer |= (0x1 << wlanMeshRouteFlags_valid);
+ if ((wmr->imroute.imr_flags &
+ IEEE80211_MESHRT_FLAGS_PROXY) != 0)
+ val->v.integer |= (0x1 << wlanMeshRouteFlags_proxy);
+ return (bits_get(val, (uint8_t *)&val->v.integer,
+ sizeof(val->v.integer)));
+ case LEAF_wlanMeshRouteStatus:
+ val->v.integer = wmr->mroute_status;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_mesh_stats(struct snmp_context *ctx __unused, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+ case SNMP_OP_GETNEXT:
+ if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ break;
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_COMMIT:
+ /* FALLTHROUGH */
+ case SNMP_OP_ROLLBACK:
+ /* FALLTHROUGH */
+ default:
+ abort();
+ }
+
+ if (wlan_get_stats(wif) < 0)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshDroppedBadSta:
+ val->v.uint32 = wif->stats.is_mesh_wrongmesh;
+ break;
+ case LEAF_wlanMeshDroppedNoLink:
+ val->v.uint32 = wif->stats.is_mesh_nolink;
+ break;
+ case LEAF_wlanMeshNoFwdTtl:
+ val->v.uint32 = wif->stats.is_mesh_fwd_ttl;
+ break;
+ case LEAF_wlanMeshNoFwdBuf:
+ val->v.uint32 = wif->stats.is_mesh_fwd_nobuf;
+ break;
+ case LEAF_wlanMeshNoFwdTooShort:
+ val->v.uint32 = wif->stats.is_mesh_fwd_tooshort;
+ break;
+ case LEAF_wlanMeshNoFwdDisabled:
+ val->v.uint32 = wif->stats.is_mesh_fwd_disabled;
+ break;
+ case LEAF_wlanMeshNoFwdPathUnknown:
+ val->v.uint32 = wif->stats.is_mesh_fwd_nopath;
+ break;
+ case LEAF_wlanMeshDroppedBadAE:
+ val->v.uint32 = wif->stats.is_mesh_badae;
+ break;
+ case LEAF_wlanMeshRouteAddFailed:
+ val->v.uint32 = wif->stats.is_mesh_rtaddfailed;
+ break;
+ case LEAF_wlanMeshDroppedNoProxy:
+ val->v.uint32 = wif->stats.is_mesh_notproxy;
+ break;
+ case LEAF_wlanMeshDroppedMisaligned:
+ val->v.uint32 = wif->stats.is_rx_badalign;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_hwmp_config(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ int which;
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanHWMPRouteInactiveTimeout:
+ which = WLAN_HWMP_INACTIVITY_TO;
+ break;
+ case LEAF_wlanHWMPRootAnnounceInterval:
+ which = WLAN_HWMP_RANN_INT;
+ break;
+ case LEAF_wlanHWMPRootInterval:
+ which = WLAN_HWMP_ROOT_INT;
+ break;
+ case LEAF_wlanHWMPRootTimeout:
+ which = WLAN_HWMP_ROOT_TO;
+ break;
+ case LEAF_wlanHWMPPathLifetime:
+ which = WLAN_HWMP_PATH_LIFETIME;
+ break;
+ case LEAF_wlanHWMPReplyForwardBit:
+ which = WLAN_HWMP_REPLY_FORWARD;
+ break;
+ case LEAF_wlanHWMPTargetOnlyBit:
+ which = WLAN_HWMP_TARGET_ONLY;
+ break;
+ default:
+ abort();
+ }
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if (wlan_do_sysctl(&wlan_config, which, 0) < 0)
+ return (SNMP_ERR_GENERR);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_SET:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanHWMPRouteInactiveTimeout:
+ ctx->scratch->int1 = wlan_config.hwmp_inact;
+ wlan_config.hwmp_inact = val->v.integer;
+ break;
+ case LEAF_wlanHWMPRootAnnounceInterval:
+ ctx->scratch->int1 = wlan_config.hwmp_rannint;
+ wlan_config.hwmp_rannint = val->v.integer;
+ break;
+ case LEAF_wlanHWMPRootInterval:
+ ctx->scratch->int1 = wlan_config.hwmp_rootint;
+ wlan_config.hwmp_rootint = val->v.integer;
+ break;
+ case LEAF_wlanHWMPRootTimeout:
+ ctx->scratch->int1 = wlan_config.hwmp_roottimeout;
+ wlan_config.hwmp_roottimeout = val->v.integer;
+ break;
+ case LEAF_wlanHWMPPathLifetime:
+ ctx->scratch->int1 = wlan_config.hwmp_pathlifetime;
+ wlan_config.hwmp_pathlifetime = val->v.integer;
+ break;
+ case LEAF_wlanHWMPReplyForwardBit:
+ ctx->scratch->int1 = wlan_config.hwmp_replyforward;
+ wlan_config.hwmp_replyforward = val->v.integer;
+ break;
+ case LEAF_wlanHWMPTargetOnlyBit:
+ ctx->scratch->int1 = wlan_config.hwmp_targetonly;
+ wlan_config.hwmp_targetonly = val->v.integer;
+ break;
+ }
+ if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanHWMPRouteInactiveTimeout:
+ wlan_config.hwmp_inact = ctx->scratch->int1;
+ break;
+ case LEAF_wlanHWMPRootAnnounceInterval:
+ wlan_config.hwmp_rannint = ctx->scratch->int1;
+ break;
+ case LEAF_wlanHWMPRootInterval:
+ wlan_config.hwmp_rootint = ctx->scratch->int1;
+ break;
+ case LEAF_wlanHWMPRootTimeout:
+ wlan_config.hwmp_roottimeout = ctx->scratch->int1;
+ break;
+ case LEAF_wlanHWMPPathLifetime:
+ wlan_config.hwmp_pathlifetime = ctx->scratch->int1;
+ break;
+ case LEAF_wlanHWMPReplyForwardBit:
+ wlan_config.hwmp_replyforward = ctx->scratch->int1;
+ break;
+ case LEAF_wlanHWMPTargetOnlyBit:
+ wlan_config.hwmp_targetonly = ctx->scratch->int1;
+ break;
+ }
+ if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanHWMPRouteInactiveTimeout:
+ val->v.integer = wlan_config.hwmp_inact;
+ break;
+ case LEAF_wlanHWMPRootAnnounceInterval:
+ val->v.integer = wlan_config.hwmp_rannint;
+ break;
+ case LEAF_wlanHWMPRootInterval:
+ val->v.integer = wlan_config.hwmp_rootint;
+ break;
+ case LEAF_wlanHWMPRootTimeout:
+ val->v.integer = wlan_config.hwmp_roottimeout;
+ break;
+ case LEAF_wlanHWMPPathLifetime:
+ val->v.integer = wlan_config.hwmp_pathlifetime;
+ break;
+ case LEAF_wlanHWMPReplyForwardBit:
+ val->v.integer = wlan_config.hwmp_replyforward;
+ break;
+ case LEAF_wlanHWMPTargetOnlyBit:
+ val->v.integer = wlan_config.hwmp_targetonly;
+ break;
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_hwmp_iface(struct snmp_context *ctx, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_GETNEXT:
+ if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ break;
+
+ case SNMP_OP_SET:
+ if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanHWMPRootMode:
+ ctx->scratch->int1 = wif->hwmp_root_mode;
+ wif->hwmp_root_mode = val->v.integer;
+ break;
+ case LEAF_wlanHWMPMaxHops:
+ ctx->scratch->int1 = wif->hwmp_max_hops;
+ wif->hwmp_max_hops = val->v.integer;
+ break;
+ default:
+ abort();
+ }
+ if (wlan_hwmp_config_set(wif, val->var.subs[sub - 1]) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_ROLLBACK:
+ if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanHWMPRootMode:
+ wif->hwmp_root_mode = ctx->scratch->int1;
+ break;
+ case LEAF_wlanHWMPMaxHops:
+ wif->hwmp_max_hops = ctx->scratch->int1;
+ break;
+ default:
+ abort();
+ }
+ if (wlan_hwmp_config_set(wif, val->var.subs[sub - 1]) < 0)
+ return (SNMP_ERR_GENERR);
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+
+ if (wlan_hwmp_config_get(wif, val->var.subs[sub - 1]) < 0)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanHWMPRootMode:
+ val->v.integer = wif->hwmp_root_mode;
+ break;
+ case LEAF_wlanHWMPMaxHops:
+ val->v.integer = wif->hwmp_max_hops;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+op_wlan_hwmp_stats(struct snmp_context *ctx __unused, struct snmp_value *val,
+ uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
+{
+ struct wlan_iface *wif;
+
+ wlan_update_interface_list();
+
+ switch (op) {
+ case SNMP_OP_GET:
+ if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+ case SNMP_OP_GETNEXT:
+ if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ wlan_append_ifindex(&val->var, sub, wif);
+ break;
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+ case SNMP_OP_COMMIT:
+ /* FALLTHROUGH */
+ case SNMP_OP_ROLLBACK:
+ /* FALLTHROUGH */
+ default:
+ abort();
+ }
+
+ if (wlan_get_stats(wif) < 0)
+ return (SNMP_ERR_GENERR);
+
+ switch (val->var.subs[sub - 1]) {
+ case LEAF_wlanMeshHWMPWrongSeqNo:
+ val->v.uint32 = wif->stats.is_hwmp_wrongseq;
+ break;
+ case LEAF_wlanMeshHWMPTxRootPREQ:
+ val->v.uint32 = wif->stats.is_hwmp_rootreqs;
+ break;
+ case LEAF_wlanMeshHWMPTxRootRANN:
+ val->v.uint32 = wif->stats.is_hwmp_rootrann;
+ break;
+ case LEAF_wlanMeshHWMPProxy:
+ val->v.uint32 = wif->stats.is_hwmp_proxy;
+ break;
+ default:
+ abort();
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Encode BITS type for a response packet - XXX: this belongs to the snmp lib.
+ */
+static int
+bits_get(struct snmp_value *value, const u_char *ptr, ssize_t len)
+{
+ int size;
+
+ if (ptr == NULL) {
+ value->v.octetstring.len = 0;
+ value->v.octetstring.octets = NULL;
+ return (SNMP_ERR_NOERROR);
+ }
+
+ /* Determine length - up to 8 octets supported so far. */
+ for (size = len; size > 0; size--)
+ if (ptr[size - 1] != 0)
+ break;
+ if (size == 0)
+ size = 1;
+
+ value->v.octetstring.len = (u_long)size;
+ if ((value->v.octetstring.octets = malloc((size_t)size)) == NULL)
+ return (SNMP_ERR_RES_UNAVAIL);
+ memcpy(value->v.octetstring.octets, ptr, (size_t)size);
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Calls for adding/updating/freeing/etc of wireless interfaces.
+ */
+static void
+wlan_free_interface(struct wlan_iface *wif)
+{
+ wlan_free_peerlist(wif);
+ free(wif->chanlist);
+ wlan_scan_free_results(wif);
+ wlan_mac_free_maclist(wif);
+ wlan_mesh_free_routes(wif);
+ free(wif);
+}
+
+static void
+wlan_free_iflist(void)
+{
+ struct wlan_iface *w;
+
+ while ((w = SLIST_FIRST(&wlan_ifaces)) != NULL) {
+ SLIST_REMOVE_HEAD(&wlan_ifaces, w_if);
+ wlan_free_interface(w);
+ }
+}
+
+static struct wlan_iface *
+wlan_find_interface(const char *wname)
+{
+ struct wlan_iface *wif;
+
+ SLIST_FOREACH(wif, &wlan_ifaces, w_if)
+ if (strcmp(wif->wname, wname) == 0) {
+ if (wif->status != RowStatus_active)
+ return (NULL);
+ break;
+ }
+
+ return (wif);
+}
+
+static struct wlan_iface *
+wlan_first_interface(void)
+{
+ return (SLIST_FIRST(&wlan_ifaces));
+}
+
+static struct wlan_iface *
+wlan_next_interface(struct wlan_iface *wif)
+{
+ if (wif == NULL)
+ return (NULL);
+
+ return (SLIST_NEXT(wif, w_if));
+}
+
+/*
+ * Add a new interface to the list - sorted by name.
+ */
+static int
+wlan_add_wif(struct wlan_iface *wif)
+{
+ int cmp;
+ struct wlan_iface *temp, *prev;
+
+ if ((prev = SLIST_FIRST(&wlan_ifaces)) == NULL ||
+ strcmp(wif->wname, prev->wname) < 0) {
+ SLIST_INSERT_HEAD(&wlan_ifaces, wif, w_if);
+ return (0);
+ }
+
+ SLIST_FOREACH(temp, &wlan_ifaces, w_if) {
+ if ((cmp = strcmp(wif->wname, temp->wname)) <= 0)
+ break;
+ prev = temp;
+ }
+
+ if (temp == NULL)
+ SLIST_INSERT_AFTER(prev, wif, w_if);
+ else if (cmp > 0)
+ SLIST_INSERT_AFTER(temp, wif, w_if);
+ else {
+ syslog(LOG_ERR, "Wlan iface %s already in list", wif->wname);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static struct wlan_iface *
+wlan_new_wif(char *wname)
+{
+ struct wlan_iface *wif;
+
+ /* Make sure it's not in the list. */
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif))
+ if (strcmp(wname, wif->wname) == 0) {
+ wif->internal = 0;
+ return (wif);
+ }
+
+ if ((wif = (struct wlan_iface *)malloc(sizeof(*wif))) == NULL)
+ return (NULL);
+
+ memset(wif, 0, sizeof(struct wlan_iface));
+ strlcpy(wif->wname, wname, IFNAMSIZ);
+ wif->status = RowStatus_notReady;
+ wif->state = wlanIfaceState_down;
+ wif->mode = WlanIfaceOperatingModeType_station;
+
+ if (wlan_add_wif(wif) < 0) {
+ free(wif);
+ return (NULL);
+ }
+
+ return (wif);
+}
+
+static void
+wlan_delete_wif(struct wlan_iface *wif)
+{
+ SLIST_REMOVE(&wlan_ifaces, wif, wlan_iface, w_if);
+ wlan_free_interface(wif);
+}
+
+static int
+wlan_attach_newif(struct mibif *mif)
+{
+ struct wlan_iface *wif;
+
+ if (mif->mib.ifmd_data.ifi_type != IFT_ETHER ||
+ wlan_check_media(mif->name) != IFM_IEEE80211)
+ return (0);
+
+ if ((wif = wlan_new_wif(mif->name)) == NULL)
+ return (-1);
+
+ (void)wlan_get_opmode(wif);
+ wif->index = mif->index;
+ wif->status = RowStatus_active;
+ (void)wlan_update_interface(wif);
+
+ return (0);
+}
+
+static int
+wlan_iface_create(struct wlan_iface *wif)
+{
+ int rc;
+
+ if ((rc = wlan_clone_create(wif)) == SNMP_ERR_NOERROR) {
+ /*
+ * The rest of the info will be updated once the
+ * snmp_mibII module notifies us of the interface.
+ */
+ wif->status = RowStatus_active;
+ if (wif->state == wlanIfaceState_up)
+ (void)wlan_config_state(wif, 1);
+ }
+
+ return (rc);
+}
+
+static int
+wlan_iface_destroy(struct wlan_iface *wif)
+{
+ int rc = SNMP_ERR_NOERROR;
+
+ if (wif->internal == 0)
+ rc = wlan_clone_destroy(wif);
+
+ if (rc == SNMP_ERR_NOERROR)
+ wlan_delete_wif(wif);
+
+ return (rc);
+}
+
+static int
+wlan_update_interface(struct wlan_iface *wif)
+{
+ int i;
+
+ (void)wlan_config_state(wif, 0);
+ (void)wlan_get_driver_caps(wif);
+ for (i = LEAF_wlanIfacePacketBurst;
+ i <= LEAF_wlanIfaceTdmaBeaconInterval; i++)
+ (void)wlan_config_get_ioctl(wif, i);
+ (void)wlan_get_stats(wif);
+ /*
+ * XXX: wlan_get_channel_list() not needed -
+ * fetched with wlan_get_driver_caps()
+ */
+ (void)wlan_get_channel_list(wif);
+ (void)wlan_get_roam_params(wif);
+ (void)wlan_get_tx_params(wif);
+ (void)wlan_get_scan_results(wif);
+ (void)wlan_get_wepmode(wif);
+ (void)wlan_get_weptxkey(wif);
+ (void)wlan_get_mac_policy(wif);
+ (void)wlan_get_mac_acl_macs(wif);
+ (void)wlan_get_peerinfo(wif);
+
+ if (wif->mode == WlanIfaceOperatingModeType_meshPoint) {
+ for (i = LEAF_wlanMeshTTL; i <= LEAF_wlanMeshPath; i++)
+ (void)wlan_mesh_config_get(wif, i);
+ (void)wlan_mesh_get_routelist(wif);
+ for (i = LEAF_wlanHWMPRootMode; i <= LEAF_wlanHWMPMaxHops; i++)
+ (void)wlan_hwmp_config_get(wif, i);
+ }
+
+ return (0);
+}
+
+static void
+wlan_update_interface_list(void)
+{
+ struct wlan_iface *wif, *twif;
+
+ if ((time(NULL) - wlan_iflist_age) <= WLAN_LIST_MAXAGE)
+ return;
+
+ /*
+ * The snmp_mibII module would have notified us for new interfaces,
+ * so only check if any have been deleted.
+ */
+ SLIST_FOREACH_SAFE(wif, &wlan_ifaces, w_if, twif)
+ if (wif->status == RowStatus_active && wlan_get_opmode(wif) < 0)
+ wlan_delete_wif(wif);
+
+ wlan_iflist_age = time(NULL);
+}
+
+static void
+wlan_append_ifindex(struct asn_oid *oid, uint sub, const struct wlan_iface *w)
+{
+ uint32_t i;
+
+ oid->len = sub + strlen(w->wname) + 1;
+ oid->subs[sub] = strlen(w->wname);
+ for (i = 1; i <= strlen(w->wname); i++)
+ oid->subs[sub + i] = w->wname[i - 1];
+}
+
+static uint8_t *
+wlan_get_ifname(const struct asn_oid *oid, uint sub, uint8_t *wname)
+{
+ uint32_t i;
+
+ memset(wname, 0, IFNAMSIZ);
+
+ if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ wname[i] = oid->subs[sub + i + 1];
+ wname[i] = '\0';
+
+ return (wname);
+}
+
+static struct wlan_iface *
+wlan_get_interface(const struct asn_oid *oid, uint sub)
+{
+ uint8_t wname[IFNAMSIZ];
+
+ if (wlan_get_ifname(oid, sub, wname) == NULL)
+ return (NULL);
+
+ return (wlan_find_interface(wname));
+}
+
+static struct wlan_iface *
+wlan_get_next_interface(const struct asn_oid *oid, uint sub)
+{
+ uint32_t i;
+ uint8_t wname[IFNAMSIZ];
+ struct wlan_iface *wif;
+
+ if (oid->len - sub == 0) {
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif))
+ if (wif->status == RowStatus_active)
+ break;
+ return (wif);
+ }
+
+ if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ memset(wname, 0, IFNAMSIZ);
+ for (i = 0; i < oid->subs[sub]; i++)
+ wname[i] = oid->subs[sub + i + 1];
+ wname[i] = '\0';
+ if ((wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ while ((wif = wlan_next_interface(wif)) != NULL)
+ if (wif->status == RowStatus_active)
+ break;
+
+ return (wif);
+}
+
+static struct wlan_iface *
+wlan_get_snmp_interface(const struct asn_oid *oid, uint sub)
+{
+ uint8_t wname[IFNAMSIZ];
+ struct wlan_iface *wif;
+
+ if (wlan_get_ifname(oid, sub, wname) == NULL)
+ return (NULL);
+
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif))
+ if (strcmp(wif->wname, wname) == 0)
+ break;
+
+ return (wif);
+}
+
+static struct wlan_iface *
+wlan_get_next_snmp_interface(const struct asn_oid *oid, uint sub)
+{
+ uint32_t i;
+ uint8_t wname[IFNAMSIZ];
+ struct wlan_iface *wif;
+
+ if (oid->len - sub == 0)
+ return (wlan_first_interface());
+
+ if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ memset(wname, 0, IFNAMSIZ);
+ for (i = 0; i < oid->subs[sub]; i++)
+ wname[i] = oid->subs[sub + i + 1];
+ wname[i] = '\0';
+
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif))
+ if (strcmp(wif->wname, wname) == 0)
+ break;
+
+ return (wlan_next_interface(wif));
+}
+
+/*
+ * Decode/Append an index for tables indexed by the wireless interface
+ * name and a MAC address - ACL MACs and Mesh Routes.
+ */
+static int
+wlan_mac_index_decode(const struct asn_oid *oid, uint sub,
+ char *wname, uint8_t *mac)
+{
+ uint32_t i;
+ int mac_off;
+
+ if (oid->len - sub != oid->subs[sub] + 2 + IEEE80211_ADDR_LEN
+ || oid->subs[sub] >= IFNAMSIZ)
+ return (-1);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ wname[i] = oid->subs[sub + i + 1];
+ wname[i] = '\0';
+
+ mac_off = sub + oid->subs[sub] + 1;
+ if (oid->subs[mac_off] != IEEE80211_ADDR_LEN)
+ return (-1);
+ for (i = 0; i < IEEE80211_ADDR_LEN; i++)
+ mac[i] = oid->subs[mac_off + i + 1];
+
+ return (0);
+}
+
+static void
+wlan_append_mac_index(struct asn_oid *oid, uint sub, char *wname, uint8_t *mac)
+{
+ uint32_t i;
+
+ oid->len = sub + strlen(wname) + IEEE80211_ADDR_LEN + 2;
+ oid->subs[sub] = strlen(wname);
+ for (i = 1; i <= strlen(wname); i++)
+ oid->subs[sub + i] = wname[i - 1];
+
+ sub += strlen(wname) + 1;
+ oid->subs[sub] = IEEE80211_ADDR_LEN;
+ for (i = 1; i <= IEEE80211_ADDR_LEN; i++)
+ oid->subs[sub + i] = mac[i - 1];
+}
+
+/*
+ * Decode/Append an index for tables indexed by the wireless interface
+ * name and the PHY mode - Roam and TX params.
+ */
+static int
+wlan_phy_index_decode(const struct asn_oid *oid, uint sub, char *wname,
+ uint32_t *phy)
+{
+ uint32_t i;
+
+ if (oid->len - sub != oid->subs[sub] + 2 || oid->subs[sub] >= IFNAMSIZ)
+ return (-1);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ wname[i] = oid->subs[sub + i + 1];
+ wname[i] = '\0';
+
+ *phy = oid->subs[sub + oid->subs[sub] + 1];
+ return (0);
+}
+
+static void
+wlan_append_phy_index(struct asn_oid *oid, uint sub, char *wname, uint32_t phy)
+{
+ uint32_t i;
+
+ oid->len = sub + strlen(wname) + 2;
+ oid->subs[sub] = strlen(wname);
+ for (i = 1; i <= strlen(wname); i++)
+ oid->subs[sub + i] = wname[i - 1];
+ oid->subs[sub + strlen(wname) + 1] = phy;
+}
+
+/*
+ * Calls for manipulating the peerlist of a wireless interface.
+ */
+static void
+wlan_free_peerlist(struct wlan_iface *wif)
+{
+ struct wlan_peer *wip;
+
+ while ((wip = SLIST_FIRST(&wif->peerlist)) != NULL) {
+ SLIST_REMOVE_HEAD(&wif->peerlist, wp);
+ free(wip);
+ }
+
+ SLIST_INIT(&wif->peerlist);
+}
+
+static struct wlan_peer *
+wlan_find_peer(struct wlan_iface *wif, uint8_t *peermac)
+{
+ struct wlan_peer *wip;
+
+ SLIST_FOREACH(wip, &wif->peerlist, wp)
+ if (memcmp(wip->pmac, peermac, IEEE80211_ADDR_LEN) == 0)
+ break;
+
+ return (wip);
+}
+
+struct wlan_peer *
+wlan_new_peer(const uint8_t *pmac)
+{
+ struct wlan_peer *wip;
+
+ if ((wip = (struct wlan_peer *)malloc(sizeof(*wip))) == NULL)
+ return (NULL);
+
+ memset(wip, 0, sizeof(struct wlan_peer));
+ memcpy(wip->pmac, pmac, IEEE80211_ADDR_LEN);
+
+ return (wip);
+}
+
+void
+wlan_free_peer(struct wlan_peer *wip)
+{
+ free(wip);
+}
+
+int
+wlan_add_peer(struct wlan_iface *wif, struct wlan_peer *wip)
+{
+ struct wlan_peer *temp, *prev;
+
+ SLIST_FOREACH(temp, &wif->peerlist, wp)
+ if (memcmp(temp->pmac, wip->pmac, IEEE80211_ADDR_LEN) == 0)
+ return (-1);
+
+ if ((prev = SLIST_FIRST(&wif->peerlist)) == NULL ||
+ memcmp(wip->pmac, prev->pmac, IEEE80211_ADDR_LEN) < 0) {
+ SLIST_INSERT_HEAD(&wif->peerlist, wip, wp);
+ return (0);
+ }
+
+ SLIST_FOREACH(temp, &wif->peerlist, wp) {
+ if (memcmp(wip->pmac, temp->pmac, IEEE80211_ADDR_LEN) < 0)
+ break;
+ prev = temp;
+ }
+
+ SLIST_INSERT_AFTER(prev, wip, wp);
+ return (0);
+}
+
+static void
+wlan_update_peers(void)
+{
+ struct wlan_iface *wif;
+
+ if ((time(NULL) - wlan_peerlist_age) <= WLAN_LIST_MAXAGE)
+ return;
+
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif)) {
+ if (wif->status != RowStatus_active)
+ continue;
+ wlan_free_peerlist(wif);
+ (void)wlan_get_peerinfo(wif);
+ }
+ wlan_peerlist_age = time(NULL);
+}
+
+static struct wlan_peer *
+wlan_get_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
+{
+ char wname[IFNAMSIZ];
+ uint8_t pmac[IEEE80211_ADDR_LEN];
+
+ if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0)
+ return (NULL);
+
+ if ((*wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ return (wlan_find_peer(*wif, pmac));
+}
+
+static struct wlan_peer *
+wlan_get_next_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
+{
+ char wname[IFNAMSIZ];
+ char pmac[IEEE80211_ADDR_LEN];
+ struct wlan_peer *wip;
+
+ if (oid->len - sub == 0) {
+ for (*wif = wlan_first_interface(); *wif != NULL;
+ *wif = wlan_next_interface(*wif)) {
+ if ((*wif)->mode ==
+ WlanIfaceOperatingModeType_meshPoint)
+ continue;
+ wip = SLIST_FIRST(&(*wif)->peerlist);
+ if (wip != NULL)
+ return (wip);
+ }
+ return (NULL);
+ }
+
+ if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0 ||
+ (*wif = wlan_find_interface(wname)) == NULL ||
+ (wip = wlan_find_peer(*wif, pmac)) == NULL)
+ return (NULL);
+
+ if ((wip = SLIST_NEXT(wip, wp)) != NULL)
+ return (wip);
+
+ while ((*wif = wlan_next_interface(*wif)) != NULL) {
+ if ((*wif)->mode == WlanIfaceOperatingModeType_meshPoint)
+ continue;
+ if ((wip = SLIST_FIRST(&(*wif)->peerlist)) != NULL)
+ break;
+ }
+
+ return (wip);
+}
+
+/*
+ * Calls for manipulating the active channel list of a wireless interface.
+ */
+static void
+wlan_update_channels(void)
+{
+ struct wlan_iface *wif;
+
+ if ((time(NULL) - wlan_chanlist_age) <= WLAN_LIST_MAXAGE)
+ return;
+
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif)) {
+ if (wif->status != RowStatus_active)
+ continue;
+ (void)wlan_get_channel_list(wif);
+ }
+ wlan_chanlist_age = time(NULL);
+}
+
+static int
+wlan_channel_index_decode(const struct asn_oid *oid, uint sub, char *wname,
+ uint32_t *cindex)
+{
+ uint32_t i;
+ if (oid->len - sub != oid->subs[sub] + 2 || oid->subs[sub] >= IFNAMSIZ)
+ return (-1);
+
+ for (i = 0; i < oid->subs[sub]; i++)
+ wname[i] = oid->subs[sub + i + 1];
+ wname[i] = '\0';
+
+ *cindex = oid->subs[sub + oid->subs[sub] + 1];
+
+ return (0);
+}
+
+static void
+wlan_append_channel_index(struct asn_oid *oid, uint sub,
+ const struct wlan_iface *wif, const struct ieee80211_channel *channel)
+{
+ uint32_t i;
+
+ oid->len = sub + strlen(wif->wname) + 2;
+ oid->subs[sub] = strlen(wif->wname);
+ for (i = 1; i <= strlen(wif->wname); i++)
+ oid->subs[sub + i] = wif->wname[i - 1];
+ oid->subs[sub + strlen(wif->wname) + 1] = (channel - wif->chanlist) + 1;
+}
+
+static int32_t
+wlan_get_channel_type(struct ieee80211_channel *c)
+{
+ if (IEEE80211_IS_CHAN_FHSS(c))
+ return (WlanChannelType_fhss);
+ if (IEEE80211_IS_CHAN_A(c))
+ return (WlanChannelType_dot11a);
+ if (IEEE80211_IS_CHAN_B(c))
+ return (WlanChannelType_dot11b);
+ if (IEEE80211_IS_CHAN_ANYG(c))
+ return (WlanChannelType_dot11g);
+ if (IEEE80211_IS_CHAN_HALF(c))
+ return (WlanChannelType_tenMHz);
+ if (IEEE80211_IS_CHAN_QUARTER(c))
+ return (WlanChannelType_fiveMHz);
+ if (IEEE80211_IS_CHAN_TURBO(c))
+ return (WlanChannelType_turbo);
+ if (IEEE80211_IS_CHAN_HT(c))
+ return (WlanChannelType_ht);
+
+ return (-1);
+}
+
+static struct ieee80211_channel *
+wlan_find_channel(struct wlan_iface *wif, uint32_t cindex)
+{
+ if (wif->chanlist == NULL || cindex > wif->nchannels)
+ return (NULL);
+
+ return (wif->chanlist + cindex - 1);
+}
+
+static struct ieee80211_channel *
+wlan_get_channel(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
+{
+ uint32_t cindex;
+ char wname[IFNAMSIZ];
+
+ if (wlan_channel_index_decode(oid, sub, wname, &cindex) < 0)
+ return (NULL);
+
+ if ((*wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ return (wlan_find_channel(*wif, cindex));
+}
+
+static struct ieee80211_channel *
+wlan_get_next_channel(const struct asn_oid *oid, uint sub,
+ struct wlan_iface **wif)
+{
+ uint32_t cindex;
+ char wname[IFNAMSIZ];
+
+ if (oid->len - sub == 0) {
+ for (*wif = wlan_first_interface(); *wif != NULL;
+ *wif = wlan_next_interface(*wif)) {
+ if ((*wif)->status != RowStatus_active)
+ continue;
+ if ((*wif)->nchannels != 0 && (*wif)->chanlist != NULL)
+ return ((*wif)->chanlist);
+ }
+ return (NULL);
+ }
+
+ if (wlan_channel_index_decode(oid, sub, wname, &cindex) < 0)
+ return (NULL);
+
+ if ((*wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ if (cindex < (*wif)->nchannels)
+ return ((*wif)->chanlist + cindex);
+
+ while ((*wif = wlan_next_interface(*wif)) != NULL)
+ if ((*wif)->status == RowStatus_active)
+ if ((*wif)->nchannels != 0 && (*wif)->chanlist != NULL)
+ return ((*wif)->chanlist);
+
+ return (NULL);
+}
+
+/*
+ * Calls for manipulating the roam params of a wireless interface.
+ */
+static void
+wlan_update_roam_params(void)
+{
+ struct wlan_iface *wif;
+
+ if ((time(NULL) - wlan_roamlist_age) <= WLAN_LIST_MAXAGE)
+ return;
+
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif)) {
+ if (wif->status != RowStatus_active)
+ continue;
+ (void)wlan_get_roam_params(wif);
+ }
+ wlan_roamlist_age = time(NULL);
+}
+
+static struct ieee80211_roamparam *
+wlan_get_roam_param(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
+{
+ uint32_t phy;
+ char wname[IFNAMSIZ];
+
+ if (wlan_phy_index_decode(oid, sub, wname, &phy) < 0)
+ return (NULL);
+
+ if ((*wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ if (phy == 0 || phy > IEEE80211_MODE_MAX)
+ return (NULL);
+
+ return ((*wif)->roamparams.params + phy - 1);
+}
+
+static struct ieee80211_roamparam *
+wlan_get_next_roam_param(const struct asn_oid *oid, uint sub,
+ struct wlan_iface **wif, uint32_t *phy)
+{
+ char wname[IFNAMSIZ];
+
+ if (oid->len - sub == 0) {
+ for (*wif = wlan_first_interface(); *wif != NULL;
+ *wif = wlan_next_interface(*wif)) {
+ if ((*wif)->status != RowStatus_active)
+ continue;
+ *phy = 1;
+ return ((*wif)->roamparams.params);
+ }
+ return (NULL);
+ }
+
+ if (wlan_phy_index_decode(oid, sub, wname, phy) < 0)
+ return (NULL);
+
+ if (*phy == 0 || (*wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ if (++(*phy) <= IEEE80211_MODE_MAX)
+ return ((*wif)->roamparams.params + *phy - 1);
+
+ *phy = 1;
+ while ((*wif = wlan_next_interface(*wif)) != NULL)
+ if ((*wif)->status == RowStatus_active)
+ return ((*wif)->roamparams.params);
+
+ return (NULL);
+}
+
+/*
+ * Calls for manipulating the tx params of a wireless interface.
+ */
+static void
+wlan_update_tx_params(void)
+{
+ struct wlan_iface *wif;
+
+ if ((time(NULL) - wlan_tx_paramlist_age) <= WLAN_LIST_MAXAGE)
+ return;
+
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif)) {
+ if (wif->status != RowStatus_active)
+ continue;
+ (void)wlan_get_tx_params(wif);
+ }
+
+ wlan_tx_paramlist_age = time(NULL);
+}
+
+static struct ieee80211_txparam *
+wlan_get_tx_param(const struct asn_oid *oid, uint sub, struct wlan_iface **wif,
+ uint32_t *phy)
+{
+ char wname[IFNAMSIZ];
+
+ if (wlan_phy_index_decode(oid, sub, wname, phy) < 0)
+ return (NULL);
+
+ if ((*wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ if (*phy == 0 || *phy > IEEE80211_MODE_MAX)
+ return (NULL);
+
+ return ((*wif)->txparams.params + *phy - 1);
+}
+
+static struct ieee80211_txparam *
+wlan_get_next_tx_param(const struct asn_oid *oid, uint sub,
+ struct wlan_iface **wif, uint32_t *phy)
+{
+ char wname[IFNAMSIZ];
+
+ if (oid->len - sub == 0) {
+ for (*wif = wlan_first_interface(); *wif != NULL;
+ *wif = wlan_next_interface(*wif)) {
+ if ((*wif)->status != RowStatus_active)
+ continue;
+ *phy = 1;
+ return ((*wif)->txparams.params);
+ }
+ return (NULL);
+ }
+
+ if (wlan_phy_index_decode(oid, sub, wname, phy) < 0)
+ return (NULL);
+
+ if (*phy == 0 || (*wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ if (++(*phy) <= IEEE80211_MODE_MAX)
+ return ((*wif)->txparams.params + *phy - 1);
+
+ *phy = 1;
+ while ((*wif = wlan_next_interface(*wif)) != NULL)
+ if ((*wif)->status == RowStatus_active)
+ return ((*wif)->txparams.params);
+
+ return (NULL);
+}
+
+/*
+ * Calls for manipulating the scan results for a wireless interface.
+ */
+static void
+wlan_scan_free_results(struct wlan_iface *wif)
+{
+ struct wlan_scan_result *sr;
+
+ while ((sr = SLIST_FIRST(&wif->scanlist)) != NULL) {
+ SLIST_REMOVE_HEAD(&wif->scanlist, wsr);
+ free(sr);
+ }
+
+ SLIST_INIT(&wif->scanlist);
+}
+
+static struct wlan_scan_result *
+wlan_scan_find_result(struct wlan_iface *wif, uint8_t *ssid, uint8_t *bssid)
+{
+ struct wlan_scan_result *sr;
+
+ SLIST_FOREACH(sr, &wif->scanlist, wsr)
+ if (strlen(ssid) == strlen(sr->ssid) &&
+ strcmp(sr->ssid, ssid) == 0 &&
+ memcmp(sr->bssid, bssid, IEEE80211_ADDR_LEN) == 0)
+ break;
+
+ return (sr);
+}
+
+struct wlan_scan_result *
+wlan_scan_new_result(const uint8_t *ssid, const uint8_t *bssid)
+{
+ struct wlan_scan_result *sr;
+
+ sr = (struct wlan_scan_result *)malloc(sizeof(*sr));
+ if (sr == NULL)
+ return (NULL);
+
+ memset(sr, 0, sizeof(*sr));
+ if (ssid[0] != '\0')
+ strlcpy(sr->ssid, ssid, IEEE80211_NWID_LEN + 1);
+ memcpy(sr->bssid, bssid, IEEE80211_ADDR_LEN);
+
+ return (sr);
+}
+
+void
+wlan_scan_free_result(struct wlan_scan_result *sr)
+{
+ free(sr);
+}
+
+static int
+wlan_scan_compare_result(struct wlan_scan_result *sr1,
+ struct wlan_scan_result *sr2)
+{
+ uint32_t i;
+
+ if (strlen(sr1->ssid) < strlen(sr2->ssid))
+ return (-1);
+ if (strlen(sr1->ssid) > strlen(sr2->ssid))
+ return (1);
+
+ for (i = 0; i < strlen(sr1->ssid) && i < strlen(sr2->ssid); i++) {
+ if (sr1->ssid[i] < sr2->ssid[i])
+ return (-1);
+ if (sr1->ssid[i] > sr2->ssid[i])
+ return (1);
+ }
+
+ for (i = 0; i < IEEE80211_ADDR_LEN; i++) {
+ if (sr1->bssid[i] < sr2->bssid[i])
+ return (-1);
+ if (sr1->bssid[i] > sr2->bssid[i])
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+wlan_scan_add_result(struct wlan_iface *wif, struct wlan_scan_result *sr)
+{
+ struct wlan_scan_result *prev, *temp;
+
+ SLIST_FOREACH(temp, &wif->scanlist, wsr)
+ if (strlen(temp->ssid) == strlen(sr->ssid) &&
+ strcmp(sr->ssid, temp->ssid) == 0 &&
+ memcmp(sr->bssid, temp->bssid, IEEE80211_ADDR_LEN) == 0)
+ return (-1);
+
+ if ((prev = SLIST_FIRST(&wif->scanlist)) == NULL ||
+ wlan_scan_compare_result(sr, prev) < 0) {
+ SLIST_INSERT_HEAD(&wif->scanlist, sr, wsr);
+ return (0);
+ }
+
+ SLIST_FOREACH(temp, &wif->scanlist, wsr) {
+ if (wlan_scan_compare_result(sr, temp) < 0)
+ break;
+ prev = temp;
+ }
+
+ SLIST_INSERT_AFTER(prev, sr, wsr);
+ return (0);
+}
+
+static void
+wlan_scan_update_results(void)
+{
+ struct wlan_iface *wif;
+
+ if ((time(NULL) - wlan_scanlist_age) <= WLAN_LIST_MAXAGE)
+ return;
+
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif)) {
+ if (wif->status != RowStatus_active)
+ continue;
+ wlan_scan_free_results(wif);
+ (void)wlan_get_scan_results(wif);
+ }
+ wlan_scanlist_age = time(NULL);
+}
+
+static int
+wlan_scanr_index_decode(const struct asn_oid *oid, uint sub,
+ char *wname, uint8_t *ssid, uint8_t *bssid)
+{
+ uint32_t i;
+ int offset;
+
+ if (oid->subs[sub] >= IFNAMSIZ)
+ return (-1);
+ for (i = 0; i < oid->subs[sub]; i++)
+ wname[i] = oid->subs[sub + i + 1];
+ wname[oid->subs[sub]] = '\0';
+
+ offset = sub + oid->subs[sub] + 1;
+ if (oid->subs[offset] > IEEE80211_NWID_LEN)
+ return (-1);
+ for (i = 0; i < oid->subs[offset]; i++)
+ ssid[i] = oid->subs[offset + i + 1];
+ ssid[i] = '\0';
+
+ offset = sub + oid->subs[sub] + oid->subs[offset] + 2;
+ if (oid->subs[offset] != IEEE80211_ADDR_LEN)
+ return (-1);
+ for (i = 0; i < IEEE80211_ADDR_LEN; i++)
+ bssid[i] = oid->subs[offset + i + 1];
+
+ return (0);
+}
+
+static void
+wlan_append_scanr_index(struct asn_oid *oid, uint sub, char *wname,
+ uint8_t *ssid, uint8_t *bssid)
+{
+ uint32_t i;
+
+ oid->len = sub + strlen(wname) + strlen(ssid) + IEEE80211_ADDR_LEN + 3;
+ oid->subs[sub] = strlen(wname);
+ for (i = 1; i <= strlen(wname); i++)
+ oid->subs[sub + i] = wname[i - 1];
+
+ sub += strlen(wname) + 1;
+ oid->subs[sub] = strlen(ssid);
+ for (i = 1; i <= strlen(ssid); i++)
+ oid->subs[sub + i] = ssid[i - 1];
+
+ sub += strlen(ssid) + 1;
+ oid->subs[sub] = IEEE80211_ADDR_LEN;
+ for (i = 1; i <= IEEE80211_ADDR_LEN; i++)
+ oid->subs[sub + i] = bssid[i - 1];
+}
+
+static struct wlan_scan_result *
+wlan_get_scanr(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
+{
+ char wname[IFNAMSIZ];
+ uint8_t ssid[IEEE80211_NWID_LEN + 1];
+ uint8_t bssid[IEEE80211_ADDR_LEN];
+
+ if (wlan_scanr_index_decode(oid, sub, wname, ssid, bssid) < 0)
+ return (NULL);
+
+ if ((*wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ return (wlan_scan_find_result(*wif, ssid, bssid));
+}
+
+static struct wlan_scan_result *
+wlan_get_next_scanr(const struct asn_oid *oid, uint sub,
+ struct wlan_iface **wif)
+{
+ char wname[IFNAMSIZ];
+ uint8_t ssid[IEEE80211_NWID_LEN + 1];
+ uint8_t bssid[IEEE80211_ADDR_LEN];
+ struct wlan_scan_result *sr;
+
+ if (oid->len - sub == 0) {
+ for (*wif = wlan_first_interface(); *wif != NULL;
+ *wif = wlan_next_interface(*wif)) {
+ sr = SLIST_FIRST(&(*wif)->scanlist);
+ if (sr != NULL)
+ return (sr);
+ }
+ return (NULL);
+ }
+
+ if (wlan_scanr_index_decode(oid, sub, wname, ssid, bssid) < 0 ||
+ (*wif = wlan_find_interface(wname)) == NULL ||
+ (sr = wlan_scan_find_result(*wif, ssid, bssid)) == NULL)
+ return (NULL);
+
+ if ((sr = SLIST_NEXT(sr, wsr)) != NULL)
+ return (sr);
+
+ while ((*wif = wlan_next_interface(*wif)) != NULL)
+ if ((sr = SLIST_FIRST(&(*wif)->scanlist)) != NULL)
+ break;
+
+ return (sr);
+}
+
+/*
+ * MAC Access Control.
+ */
+static void
+wlan_mac_free_maclist(struct wlan_iface *wif)
+{
+ struct wlan_mac_mac *wmm;
+
+ while ((wmm = SLIST_FIRST(&wif->mac_maclist)) != NULL) {
+ SLIST_REMOVE_HEAD(&wif->mac_maclist, wm);
+ free(wmm);
+ }
+
+ SLIST_INIT(&wif->mac_maclist);
+}
+
+static struct wlan_mac_mac *
+wlan_mac_find_mac(struct wlan_iface *wif, uint8_t *mac)
+{
+ struct wlan_mac_mac *wmm;
+
+ SLIST_FOREACH(wmm, &wif->mac_maclist, wm)
+ if (memcmp(wmm->mac, mac, IEEE80211_ADDR_LEN) == 0)
+ break;
+
+ return (wmm);
+}
+
+struct wlan_mac_mac *
+wlan_mac_new_mac(const uint8_t *mac)
+{
+ struct wlan_mac_mac *wmm;
+
+ if ((wmm = (struct wlan_mac_mac *)malloc(sizeof(*wmm))) == NULL)
+ return (NULL);
+
+ memset(wmm, 0, sizeof(*wmm));
+ memcpy(wmm->mac, mac, IEEE80211_ADDR_LEN);
+ wmm->mac_status = RowStatus_notReady;
+
+ return (wmm);
+}
+
+void
+wlan_mac_free_mac(struct wlan_mac_mac *wmm)
+{
+ free(wmm);
+}
+
+int
+wlan_mac_add_mac(struct wlan_iface *wif, struct wlan_mac_mac *wmm)
+{
+ struct wlan_mac_mac *temp, *prev;
+
+ SLIST_FOREACH(temp, &wif->mac_maclist, wm)
+ if (memcmp(temp->mac, wmm->mac, IEEE80211_ADDR_LEN) == 0)
+ return (-1);
+
+ if ((prev = SLIST_FIRST(&wif->mac_maclist)) == NULL ||
+ memcmp(wmm->mac, prev->mac,IEEE80211_ADDR_LEN) < 0) {
+ SLIST_INSERT_HEAD(&wif->mac_maclist, wmm, wm);
+ return (0);
+ }
+
+ SLIST_FOREACH(temp, &wif->mac_maclist, wm) {
+ if (memcmp(wmm->mac, temp->mac, IEEE80211_ADDR_LEN) < 0)
+ break;
+ prev = temp;
+ }
+
+ SLIST_INSERT_AFTER(prev, wmm, wm);
+ return (0);
+}
+
+static int
+wlan_mac_delete_mac(struct wlan_iface *wif, struct wlan_mac_mac *wmm)
+{
+ if (wmm->mac_status == RowStatus_active &&
+ wlan_del_mac_acl_mac(wif, wmm) < 0)
+ return (-1);
+
+ SLIST_REMOVE(&wif->mac_maclist, wmm, wlan_mac_mac, wm);
+ free(wmm);
+
+ return (0);
+}
+
+static void
+wlan_mac_update_aclmacs(void)
+{
+ struct wlan_iface *wif;
+ struct wlan_mac_mac *wmm, *twmm;
+
+ if ((time(NULL) - wlan_maclist_age) <= WLAN_LIST_MAXAGE)
+ return;
+
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif)) {
+ if (wif->status != RowStatus_active)
+ continue;
+ /*
+ * Nuke old entries - XXX - they are likely not to
+ * change often - reconsider.
+ */
+ SLIST_FOREACH_SAFE(wmm, &wif->mac_maclist, wm, twmm)
+ if (wmm->mac_status == RowStatus_active) {
+ SLIST_REMOVE(&wif->mac_maclist, wmm,
+ wlan_mac_mac, wm);
+ wlan_mac_free_mac(wmm);
+ }
+ (void)wlan_get_mac_acl_macs(wif);
+ }
+ wlan_maclist_age = time(NULL);
+}
+
+static struct wlan_mac_mac *
+wlan_get_acl_mac(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
+{
+ char wname[IFNAMSIZ];
+ char mac[IEEE80211_ADDR_LEN];
+
+ if (wlan_mac_index_decode(oid, sub, wname, mac) < 0)
+ return (NULL);
+
+ if ((*wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ return (wlan_mac_find_mac(*wif, mac));
+}
+
+static struct wlan_mac_mac *
+wlan_get_next_acl_mac(const struct asn_oid *oid, uint sub,
+ struct wlan_iface **wif)
+{
+ char wname[IFNAMSIZ];
+ char mac[IEEE80211_ADDR_LEN];
+ struct wlan_mac_mac *wmm;
+
+ if (oid->len - sub == 0) {
+ for (*wif = wlan_first_interface(); *wif != NULL;
+ *wif = wlan_next_interface(*wif)) {
+ wmm = SLIST_FIRST(&(*wif)->mac_maclist);
+ if (wmm != NULL)
+ return (wmm);
+ }
+ return (NULL);
+ }
+
+ if (wlan_mac_index_decode(oid, sub, wname, mac) < 0 ||
+ (*wif = wlan_find_interface(wname)) == NULL ||
+ (wmm = wlan_mac_find_mac(*wif, mac)) == NULL)
+ return (NULL);
+
+ if ((wmm = SLIST_NEXT(wmm, wm)) != NULL)
+ return (wmm);
+
+ while ((*wif = wlan_next_interface(*wif)) != NULL)
+ if ((wmm = SLIST_FIRST(&(*wif)->mac_maclist)) != NULL)
+ break;
+
+ return (wmm);
+}
+
+static int
+wlan_acl_mac_set_status(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub)
+{
+ char wname[IFNAMSIZ];
+ uint8_t mac[IEEE80211_ADDR_LEN];
+ struct wlan_iface *wif;
+ struct wlan_mac_mac *macl;
+
+ if (wlan_mac_index_decode(&val->var, sub, wname, mac) < 0)
+ return (SNMP_ERR_GENERR);
+ macl = wlan_get_acl_mac(&val->var, sub, &wif);
+
+ switch (val->v.integer) {
+ case RowStatus_createAndGo:
+ if (macl != NULL)
+ return (SNMP_ERR_INCONS_NAME);
+ break;
+ case RowStatus_destroy:
+ if (macl == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ ctx->scratch->int1 = RowStatus_active;
+ return (SNMP_ERR_NOERROR);
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+
+
+ if (wif == NULL || !wif->macsupported)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if ((macl = wlan_mac_new_mac((const uint8_t *)mac)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ ctx->scratch->int1 = RowStatus_destroy;
+
+ if (wlan_mac_add_mac(wif, macl) < 0) {
+ wlan_mac_free_mac(macl);
+ return (SNMP_ERR_GENERR);
+ }
+
+ ctx->scratch->int1 = RowStatus_destroy;
+ if (wlan_add_mac_acl_mac(wif, macl) < 0) {
+ (void)wlan_mac_delete_mac(wif, macl);
+ return (SNMP_ERR_GENERR);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Wireless interfaces operating as mesh points.
+ */
+static struct wlan_iface *
+wlan_mesh_first_interface(void)
+{
+ struct wlan_iface *wif;
+
+ SLIST_FOREACH(wif, &wlan_ifaces, w_if)
+ if (wif->mode == WlanIfaceOperatingModeType_meshPoint &&
+ wif->status == RowStatus_active)
+ break;
+
+ return (wif);
+}
+
+static struct wlan_iface *
+wlan_mesh_next_interface(struct wlan_iface *wif)
+{
+ struct wlan_iface *nwif;
+
+ while ((nwif = wlan_next_interface(wif)) != NULL) {
+ if (nwif->mode == WlanIfaceOperatingModeType_meshPoint &&
+ nwif->status == RowStatus_active)
+ break;
+ wif = nwif;
+ }
+
+ return (nwif);
+}
+
+static struct wlan_iface *
+wlan_mesh_get_iface(const struct asn_oid *oid, uint sub)
+{
+ struct wlan_iface *wif;
+
+ if ((wif = wlan_get_interface(oid, sub)) == NULL)
+ return (NULL);
+
+ if (wif->mode != WlanIfaceOperatingModeType_meshPoint)
+ return (NULL);
+
+ return (wif);
+}
+
+static struct wlan_iface *
+wlan_mesh_get_next_iface(const struct asn_oid *oid, uint sub)
+{
+ uint32_t i;
+ uint8_t wname[IFNAMSIZ];
+ struct wlan_iface *wif;
+
+ if (oid->len - sub == 0)
+ return (wlan_mesh_first_interface());
+
+ if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
+ return (NULL);
+
+ memset(wname, 0, IFNAMSIZ);
+ for (i = 0; i < oid->subs[sub]; i++)
+ wname[i] = oid->subs[sub + i + 1];
+ wname[i] = '\0';
+
+ if ((wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ return (wlan_mesh_next_interface(wif));
+}
+
+/*
+ * The neighbors of wireless interfaces operating as mesh points.
+ */
+static struct wlan_peer *
+wlan_mesh_get_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
+{
+ char wname[IFNAMSIZ];
+ uint8_t pmac[IEEE80211_ADDR_LEN];
+
+ if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0)
+ return (NULL);
+
+ if ((*wif = wlan_find_interface(wname)) == NULL ||
+ (*wif)->mode != WlanIfaceOperatingModeType_meshPoint)
+ return (NULL);
+
+ return (wlan_find_peer(*wif, pmac));
+}
+
+static struct wlan_peer *
+wlan_mesh_get_next_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
+{
+ char wname[IFNAMSIZ];
+ char pmac[IEEE80211_ADDR_LEN];
+ struct wlan_peer *wip;
+
+ if (oid->len - sub == 0) {
+ for (*wif = wlan_mesh_first_interface(); *wif != NULL;
+ *wif = wlan_mesh_next_interface(*wif)) {
+ wip = SLIST_FIRST(&(*wif)->peerlist);
+ if (wip != NULL)
+ return (wip);
+ }
+ return (NULL);
+ }
+
+ if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0 ||
+ (*wif = wlan_find_interface(wname)) == NULL ||
+ (*wif)->mode != WlanIfaceOperatingModeType_meshPoint ||
+ (wip = wlan_find_peer(*wif, pmac)) == NULL)
+ return (NULL);
+
+ if ((wip = SLIST_NEXT(wip, wp)) != NULL)
+ return (wip);
+
+ while ((*wif = wlan_mesh_next_interface(*wif)) != NULL)
+ if ((wip = SLIST_FIRST(&(*wif)->peerlist)) != NULL)
+ break;
+
+ return (wip);
+}
+
+/*
+ * Mesh routing table.
+ */
+static void
+wlan_mesh_free_routes(struct wlan_iface *wif)
+{
+ struct wlan_mesh_route *wmr;
+
+ while ((wmr = SLIST_FIRST(&wif->mesh_routelist)) != NULL) {
+ SLIST_REMOVE_HEAD(&wif->mesh_routelist, wr);
+ free(wmr);
+ }
+
+ SLIST_INIT(&wif->mesh_routelist);
+}
+
+static struct wlan_mesh_route *
+wlan_mesh_find_route(struct wlan_iface *wif, uint8_t *dstmac)
+{
+ struct wlan_mesh_route *wmr;
+
+ if (wif->mode != WlanIfaceOperatingModeType_meshPoint)
+ return (NULL);
+
+ SLIST_FOREACH(wmr, &wif->mesh_routelist, wr)
+ if (memcmp(wmr->imroute.imr_dest, dstmac,
+ IEEE80211_ADDR_LEN) == 0)
+ break;
+
+ return (wmr);
+}
+
+struct wlan_mesh_route *
+wlan_mesh_new_route(const uint8_t *dstmac)
+{
+ struct wlan_mesh_route *wmr;
+
+ if ((wmr = (struct wlan_mesh_route *)malloc(sizeof(*wmr))) == NULL)
+ return (NULL);
+
+ memset(wmr, 0, sizeof(*wmr));
+ memcpy(wmr->imroute.imr_dest, dstmac, IEEE80211_ADDR_LEN);
+ wmr->mroute_status = RowStatus_notReady;
+
+ return (wmr);
+}
+
+void
+wlan_mesh_free_route(struct wlan_mesh_route *wmr)
+{
+ free(wmr);
+}
+
+int
+wlan_mesh_add_rtentry(struct wlan_iface *wif, struct wlan_mesh_route *wmr)
+{
+ struct wlan_mesh_route *temp, *prev;
+
+ SLIST_FOREACH(temp, &wif->mesh_routelist, wr)
+ if (memcmp(temp->imroute.imr_dest, wmr->imroute.imr_dest,
+ IEEE80211_ADDR_LEN) == 0)
+ return (-1);
+
+ if ((prev = SLIST_FIRST(&wif->mesh_routelist)) == NULL ||
+ memcmp(wmr->imroute.imr_dest, prev->imroute.imr_dest,
+ IEEE80211_ADDR_LEN) < 0) {
+ SLIST_INSERT_HEAD(&wif->mesh_routelist, wmr, wr);
+ return (0);
+ }
+
+ SLIST_FOREACH(temp, &wif->mesh_routelist, wr) {
+ if (memcmp(wmr->imroute.imr_dest, temp->imroute.imr_dest,
+ IEEE80211_ADDR_LEN) < 0)
+ break;
+ prev = temp;
+ }
+
+ SLIST_INSERT_AFTER(prev, wmr, wr);
+ return (0);
+}
+
+static int
+wlan_mesh_delete_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr)
+{
+ if (wmr->mroute_status == RowStatus_active &&
+ wlan_mesh_del_route(wif, wmr) < 0)
+ return (-1);
+
+ SLIST_REMOVE(&wif->mesh_routelist, wmr, wlan_mesh_route, wr);
+ free(wmr);
+
+ return (0);
+}
+
+static void
+wlan_mesh_update_routes(void)
+{
+ struct wlan_iface *wif;
+ struct wlan_mesh_route *wmr, *twmr;
+
+ if ((time(NULL) - wlan_mrlist_age) <= WLAN_LIST_MAXAGE)
+ return;
+
+ for (wif = wlan_mesh_first_interface(); wif != NULL;
+ wif = wlan_mesh_next_interface(wif)) {
+ /*
+ * Nuke old entries - XXX - they are likely not to
+ * change often - reconsider.
+ */
+ SLIST_FOREACH_SAFE(wmr, &wif->mesh_routelist, wr, twmr)
+ if (wmr->mroute_status == RowStatus_active) {
+ SLIST_REMOVE(&wif->mesh_routelist, wmr,
+ wlan_mesh_route, wr);
+ wlan_mesh_free_route(wmr);
+ }
+ (void)wlan_mesh_get_routelist(wif);
+ }
+ wlan_mrlist_age = time(NULL);
+}
+
+static struct wlan_mesh_route *
+wlan_mesh_get_route(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
+{
+ char wname[IFNAMSIZ];
+ char dstmac[IEEE80211_ADDR_LEN];
+
+ if (wlan_mac_index_decode(oid, sub, wname, dstmac) < 0)
+ return (NULL);
+
+ if ((*wif = wlan_find_interface(wname)) == NULL)
+ return (NULL);
+
+ return (wlan_mesh_find_route(*wif, dstmac));
+}
+
+static struct wlan_mesh_route *
+wlan_mesh_get_next_route(const struct asn_oid *oid, uint sub,
+ struct wlan_iface **wif)
+{
+ char wname[IFNAMSIZ];
+ char dstmac[IEEE80211_ADDR_LEN];
+ struct wlan_mesh_route *wmr;
+
+ if (oid->len - sub == 0) {
+ for (*wif = wlan_mesh_first_interface(); *wif != NULL;
+ *wif = wlan_mesh_next_interface(*wif)) {
+ wmr = SLIST_FIRST(&(*wif)->mesh_routelist);
+ if (wmr != NULL)
+ return (wmr);
+ }
+ return (NULL);
+ }
+
+ if (wlan_mac_index_decode(oid, sub, wname, dstmac) < 0 ||
+ (*wif = wlan_find_interface(wname)) == NULL ||
+ (wmr = wlan_mesh_find_route(*wif, dstmac)) == NULL)
+ return (NULL);
+
+ if ((wmr = SLIST_NEXT(wmr, wr)) != NULL)
+ return (wmr);
+
+ while ((*wif = wlan_mesh_next_interface(*wif)) != NULL)
+ if ((wmr = SLIST_FIRST(&(*wif)->mesh_routelist)) != NULL)
+ break;
+
+ return (wmr);
+}
+
+static int
+wlan_mesh_route_set_status(struct snmp_context *ctx, struct snmp_value *val,
+ uint sub)
+{
+ char wname[IFNAMSIZ];
+ char mac[IEEE80211_ADDR_LEN];
+ struct wlan_mesh_route *wmr;
+ struct wlan_iface *wif;
+
+ if (wlan_mac_index_decode(&val->var, sub, wname, mac) < 0)
+ return (SNMP_ERR_GENERR);
+ wmr = wlan_mesh_get_route(&val->var, sub, &wif);
+
+ switch (val->v.integer) {
+ case RowStatus_createAndGo:
+ if (wmr != NULL)
+ return (SNMP_ERR_INCONS_NAME);
+ break;
+ case RowStatus_destroy:
+ if (wmr == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ ctx->scratch->int1 = RowStatus_active;
+ return (SNMP_ERR_NOERROR);
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+
+ if ((wif = wlan_find_interface(wname)) == NULL)
+ return (SNMP_ERR_INCONS_NAME);
+
+ if ((wmr = wlan_mesh_new_route(mac)) == NULL)
+ return (SNMP_ERR_GENERR);
+
+ if (wlan_mesh_add_rtentry(wif, wmr) < 0) {
+ wlan_mesh_free_route(wmr);
+ return (SNMP_ERR_GENERR);
+ }
+
+ ctx->scratch->int1 = RowStatus_destroy;
+ if (wlan_mesh_add_route(wif, wmr) < 0) {
+ (void)wlan_mesh_delete_route(wif, wmr);
+ return (SNMP_ERR_GENERR);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Wlan snmp module initialization hook.
+ * Returns 0 on success, < 0 on error.
+ */
+static int
+wlan_init(struct lmodule * mod __unused, int argc __unused,
+ char *argv[] __unused)
+{
+ if (wlan_kmodules_load() < 0)
+ return (-1);
+
+ if (wlan_ioctl_init() < 0)
+ return (-1);
+
+ /* Register for new interface creation notifications. */
+ if (mib_register_newif(wlan_attach_newif, wlan_module)) {
+ syslog(LOG_ERR, "Cannot register newif function: %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Wlan snmp module finalization hook.
+ */
+static int
+wlan_fini(void)
+{
+ mib_unregister_newif(wlan_module);
+ or_unregister(reg_wlan);
+
+ /* XXX: Cleanup! */
+ wlan_free_iflist();
+
+ return (0);
+}
+
+/*
+ * Refetch all available data from the kernel.
+ */
+static void
+wlan_update_data(void *arg __unused)
+{
+}
+
+/*
+ * Wlan snmp module start operation.
+ */
+static void
+wlan_start(void)
+{
+ struct mibif *ifp;
+
+ reg_wlan = or_register(&oid_wlan,
+ "The MIB module for managing wireless networking.", wlan_module);
+
+ /* Add the existing wlan interfaces. */
+ for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
+ wlan_attach_newif(ifp);
+
+ wlan_data_timer = timer_start_repeat(wlan_poll_ticks,
+ wlan_poll_ticks, wlan_update_data, NULL, wlan_module);
+}
+
+/*
+ * Dump the Wlan snmp module data on SIGUSR1.
+ */
+static void
+wlan_dump(void)
+{
+ /* XXX: Print some debug info to syslog. */
+ struct wlan_iface *wif;
+
+ for (wif = wlan_first_interface(); wif != NULL;
+ wif = wlan_next_interface(wif))
+ syslog(LOG_ERR, "wlan iface %s", wif->wname);
+}
+
+const char wlan_comment[] = \
+"This module implements the BEGEMOT MIB for wireless networking.";
+
+const struct snmp_module config = {
+ .comment = wlan_comment,
+ .init = wlan_init,
+ .fini = wlan_fini,
+ .start = wlan_start,
+ .tree = wlan_ctree,
+ .dump = wlan_dump,
+ .tree_size = wlan_CTREE_SIZE,
+};
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.h b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.h
new file mode 100644
index 0000000..9e184f5
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.h
@@ -0,0 +1,286 @@
+/*-
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Shteryana Sotirova Shopova under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * 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$
+ */
+
+#define WLAN_IFMODE_MAX WlanIfaceOperatingModeType_tdma
+#define WLAN_COUNTRY_CODE_SIZE 3
+#define WLAN_BGSCAN_IDLE_MIN 100 /* XXX */
+#define WLAN_SCAN_VALID_MIN 10 /* XXX */
+#define WLAN_TDMA_MAXSLOTS 2 /* XXX */
+
+struct wlan_iface;
+
+struct wlan_peer {
+ uint8_t pmac[IEEE80211_ADDR_LEN]; /* key */
+ uint16_t associd;
+ uint16_t vlan;
+ uint16_t frequency;
+ uint32_t fflags;
+ uint8_t txrate;
+ int8_t rssi;
+ uint16_t idle;
+ uint16_t txseqs;
+ uint16_t rxseqs;
+ uint16_t txpower;
+ uint8_t capinfo;
+ uint32_t state;
+ uint16_t local_id;
+ uint16_t peer_id;
+ SLIST_ENTRY(wlan_peer) wp;
+};
+
+SLIST_HEAD(wlan_peerlist, wlan_peer);
+
+struct wlan_scan_result {
+ uint8_t ssid[IEEE80211_NWID_LEN + 1];
+ uint8_t bssid[IEEE80211_ADDR_LEN];
+ uint8_t opchannel;
+ int8_t rssi;
+ uint16_t frequency;
+ int8_t noise;
+ uint16_t bintval;
+ uint8_t capinfo;
+ struct wlan_iface *pwif;
+ SLIST_ENTRY(wlan_scan_result) wsr;
+};
+
+SLIST_HEAD(wlan_scanlist, wlan_scan_result);
+
+struct wlan_mac_mac {
+ uint8_t mac[IEEE80211_ADDR_LEN];
+ enum RowStatus mac_status;
+ SLIST_ENTRY(wlan_mac_mac) wm;
+};
+
+SLIST_HEAD(wlan_maclist, wlan_mac_mac);
+
+struct wlan_mesh_route {
+ struct ieee80211req_mesh_route imroute;
+ enum RowStatus mroute_status;
+ SLIST_ENTRY(wlan_mesh_route) wr;
+};
+
+SLIST_HEAD(wlan_mesh_routes, wlan_mesh_route);
+
+struct wlan_iface {
+ char wname[IFNAMSIZ];
+ uint32_t index;
+ char pname[IFNAMSIZ];
+ enum WlanIfaceOperatingModeType mode;
+ uint32_t flags;
+ uint8_t dbssid[IEEE80211_ADDR_LEN];
+ uint8_t dlmac[IEEE80211_ADDR_LEN];
+ enum RowStatus status;
+ enum wlanIfaceState state;
+ uint8_t internal;
+
+ uint32_t drivercaps;
+ uint32_t cryptocaps;
+ uint32_t htcaps;
+
+ uint32_t packet_burst;
+ uint8_t country_code[WLAN_COUNTRY_CODE_SIZE];
+ enum WlanRegDomainCode reg_domain;
+ uint8_t desired_ssid[IEEE80211_NWID_LEN + 1];
+ uint32_t desired_channel;
+ enum TruthValue dyn_frequency;
+ enum TruthValue fast_frames;
+ enum TruthValue dturbo;
+ int32_t tx_power;
+ int32_t frag_threshold;
+ int32_t rts_threshold;
+ enum TruthValue priv_subscribe;
+ enum TruthValue bg_scan;
+ int32_t bg_scan_idle;
+ int32_t bg_scan_interval;
+ int32_t beacons_missed;
+ uint8_t desired_bssid[IEEE80211_ADDR_LEN];
+ enum wlanIfaceRoamingMode roam_mode;
+ enum TruthValue dot11d;
+ enum TruthValue dot11h;
+ enum TruthValue dynamic_wds;
+ enum TruthValue power_save;
+ enum TruthValue ap_bridge;
+ int32_t beacon_interval;
+ int32_t dtim_period;
+ enum TruthValue hide_ssid;
+ enum TruthValue inact_process;
+ enum wlanIfaceDot11gProtMode do11g_protect;
+ enum TruthValue dot11g_pure;
+ enum TruthValue dot11n_pure;
+ enum WlanIfaceDot11nPduType ampdu;
+ int32_t ampdu_density;
+ int32_t ampdu_limit;
+ enum WlanIfaceDot11nPduType amsdu;
+ int32_t amsdu_limit;
+ enum TruthValue ht_enabled;
+ enum TruthValue ht_compatible;
+ enum wlanIfaceDot11nHTProtMode ht_prot_mode;
+ enum TruthValue rifs;
+ enum TruthValue short_gi;
+ enum wlanIfaceDot11nSMPSMode smps_mode;
+ int32_t tdma_slot;
+ int32_t tdma_slot_count;
+ int32_t tdma_slot_length;
+ int32_t tdma_binterval;
+
+ struct wlan_peerlist peerlist;
+ struct ieee80211_stats stats;
+ uint32_t nchannels;
+ struct ieee80211_channel *chanlist;
+ struct ieee80211_roamparams_req roamparams;
+ struct ieee80211_txparams_req txparams;
+
+ uint32_t scan_flags;
+ uint32_t scan_duration;
+ uint32_t scan_mindwell;
+ uint32_t scan_maxdwell;
+ enum wlanScanConfigStatus scan_status;
+ struct wlan_scanlist scanlist;
+
+ uint8_t wepsupported;
+ enum wlanWepMode wepmode;
+ int32_t weptxkey;
+
+ uint8_t macsupported;
+ enum wlanMACAccessControlPolicy mac_policy;
+ uint32_t mac_nacls;
+ struct wlan_maclist mac_maclist;
+
+ uint32_t mesh_ttl;
+ enum wlanMeshPeeringEnabled mesh_peering;
+ enum wlanMeshForwardingEnabled mesh_forwarding;
+ enum wlanMeshMetric mesh_metric;
+ enum wlanMeshPath mesh_path;
+ enum wlanHWMPRootMode hwmp_root_mode;
+ uint32_t hwmp_max_hops;
+ struct wlan_mesh_routes mesh_routelist;
+
+ SLIST_ENTRY(wlan_iface) w_if;
+};
+
+enum wlan_syscl {
+ WLAN_MESH_RETRY_TO = 0,
+ WLAN_MESH_HOLDING_TO,
+ WLAN_MESH_CONFIRM_TO,
+ WLAN_MESH_MAX_RETRIES,
+ WLAN_HWMP_TARGET_ONLY,
+ WLAN_HWMP_REPLY_FORWARD,
+ WLAN_HWMP_PATH_LIFETIME,
+ WLAN_HWMP_ROOT_TO,
+ WLAN_HWMP_ROOT_INT,
+ WLAN_HWMP_RANN_INT,
+ WLAN_HWMP_INACTIVITY_TO,
+ WLAN_SYSCTL_MAX
+};
+
+struct wlan_config {
+ int32_t mesh_retryto;
+ int32_t mesh_holdingto;
+ int32_t mesh_confirmto;
+ int32_t mesh_maxretries;
+ int32_t hwmp_targetonly;
+ int32_t hwmp_replyforward;
+ int32_t hwmp_pathlifetime;
+ int32_t hwmp_roottimeout;
+ int32_t hwmp_rootint;
+ int32_t hwmp_rannint;
+ int32_t hwmp_inact;
+};
+
+int wlan_ioctl_init(void);
+int wlan_kmodules_load(void);
+int wlan_check_media(char *);
+int wlan_config_state(struct wlan_iface *, uint8_t);
+int wlan_get_opmode(struct wlan_iface *wif);
+int wlan_get_local_addr(struct wlan_iface *wif);
+int wlan_get_parent(struct wlan_iface *wif);
+int wlan_get_driver_caps(struct wlan_iface *wif);
+uint8_t wlan_channel_state_to_snmp(uint8_t cstate);
+uint32_t wlan_channel_flags_to_snmp(uint32_t cflags);
+int wlan_get_channel_list(struct wlan_iface *wif);
+int wlan_get_roam_params(struct wlan_iface *wif);
+int wlan_get_tx_params(struct wlan_iface *wif);
+int wlan_set_tx_params(struct wlan_iface *wif, int32_t pmode);
+int wlan_clone_create(struct wlan_iface *);
+int wlan_clone_destroy(struct wlan_iface *wif);
+int wlan_config_get_dssid(struct wlan_iface *wif);
+int wlan_config_set_dssid(struct wlan_iface *wif, char *ssid, int slen);
+int wlan_config_get_ioctl(struct wlan_iface *wif, int which);
+int wlan_config_set_ioctl(struct wlan_iface *wif, int which, int val,
+ char *strval, int len);
+int wlan_set_scan_config(struct wlan_iface *wif);
+int wlan_get_scan_results(struct wlan_iface *wif);
+int wlan_get_stats(struct wlan_iface *wif);
+int wlan_get_wepmode(struct wlan_iface *wif);
+int wlan_set_wepmode(struct wlan_iface *wif);
+int wlan_get_weptxkey(struct wlan_iface *wif);
+int wlan_set_weptxkey(struct wlan_iface *wif);
+int wlan_get_wepkeys(struct wlan_iface *wif);
+int wlan_set_wepkeys(struct wlan_iface *wif);
+int wlan_get_mac_policy(struct wlan_iface *wif);
+int wlan_set_mac_policy(struct wlan_iface *wif);
+int wlan_flush_mac_mac(struct wlan_iface *wif);
+int wlan_get_mac_acl_macs(struct wlan_iface *wif);
+int wlan_add_mac_acl_mac(struct wlan_iface *wif, struct wlan_mac_mac *mmac);
+int wlan_del_mac_acl_mac(struct wlan_iface *wif, struct wlan_mac_mac *mmac);
+
+int32_t wlan_do_sysctl(struct wlan_config *cfg, enum wlan_syscl which, int set);
+int wlan_mesh_config_get(struct wlan_iface *wif, int which);
+int wlan_mesh_config_set(struct wlan_iface *wif, int which);
+int wlan_mesh_flush_routes(struct wlan_iface *wif);
+int wlan_mesh_add_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr);
+int wlan_mesh_del_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr);
+int wlan_mesh_get_routelist(struct wlan_iface *wif);
+int wlan_hwmp_config_get(struct wlan_iface *wif, int which);
+int wlan_hwmp_config_set(struct wlan_iface *wif, int which);
+
+/* XXX: static */
+
+int wlan_peer_set_vlan(struct wlan_iface *wif, struct wlan_peer *wip, int vlan);
+int wlan_get_peerinfo(struct wlan_iface *wif);
+
+/* XXX*/
+struct wlan_peer *wlan_new_peer(const uint8_t *pmac);
+void wlan_free_peer(struct wlan_peer *wip);
+int wlan_add_peer(struct wlan_iface *wif, struct wlan_peer *wip);
+
+struct wlan_scan_result * wlan_scan_new_result(const uint8_t *ssid,
+ const uint8_t *bssid);
+void wlan_scan_free_result(struct wlan_scan_result *sr);
+int wlan_scan_add_result(struct wlan_iface *wif, struct wlan_scan_result *sr);
+
+struct wlan_mac_mac *wlan_mac_new_mac(const uint8_t *mac);
+void wlan_mac_free_mac(struct wlan_mac_mac *wmm);
+int wlan_mac_add_mac(struct wlan_iface *wif, struct wlan_mac_mac *wmm);
+
+struct wlan_mesh_route *wlan_mesh_new_route(const uint8_t *dstmac);
+int wlan_mesh_add_rtentry(struct wlan_iface *wif, struct wlan_mesh_route *wmr);
+void wlan_mesh_free_route(struct wlan_mesh_route *wmr);
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_sys.c b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_sys.c
new file mode 100644
index 0000000..739f11f
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_sys.c
@@ -0,0 +1,3145 @@
+/*-
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+
+ * This software was developed by Shteryana Sotirova Shopova under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * 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 <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/linker.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_ioctl.h>
+#include <net80211/ieee80211_regdomain.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 "wlan_tree.h"
+#include "wlan_snmp.h"
+
+static int sock = -1;
+
+static int wlan_ioctl(char *, uint16_t, int *, void *, size_t *, int);
+static int wlan_kmod_load(const char *);
+static uint32_t wlan_drivercaps_to_snmp(uint32_t);
+static uint32_t wlan_cryptocaps_to_snmp(uint32_t);
+static uint32_t wlan_htcaps_to_snmp(uint32_t);
+static uint32_t wlan_peerstate_to_snmp(uint32_t);
+static uint32_t wlan_peercaps_to_snmp(uint32_t );
+static uint32_t wlan_channel_flags_to_snmp_phy(uint32_t);
+static uint32_t wlan_regdomain_to_snmp(int);
+static uint32_t wlan_snmp_to_scan_flags(int);
+static int wlan_config_snmp2ioctl(int);
+static int wlan_snmp_to_regdomain(enum WlanRegDomainCode);
+static int wlan_config_get_country(struct wlan_iface *);
+static int wlan_config_set_country(struct wlan_iface *, char *, int);
+static int wlan_config_get_dchannel(struct wlan_iface *wif);
+static int wlan_config_set_dchannel(struct wlan_iface *wif, uint32_t);
+static int wlan_config_get_bssid(struct wlan_iface *);
+static int wlan_config_set_bssid(struct wlan_iface *, uint8_t *);
+static void wlan_config_set_snmp_intval(struct wlan_iface *, int, int);
+static int wlan_config_snmp2value(int, int, int *);
+static int wlan_config_check(struct wlan_iface *, int);
+static int wlan_config_get_intval(struct wlan_iface *, int);
+static int wlan_config_set_intval(struct wlan_iface *, int, int);
+static int wlan_add_new_scan_result(struct wlan_iface *,
+ const struct ieee80211req_scan_result *, uint8_t *);
+static int wlan_add_mac_macinfo(struct wlan_iface *,
+ const struct ieee80211req_maclist *);
+static struct wlan_peer *wlan_add_peerinfo(const struct ieee80211req_sta_info *);
+
+int
+wlan_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 needed modules in kernel if not already there.
+ */
+enum wlan_kmodules {
+ WLAN_KMOD = 0,
+ WLAN_KMOD_ACL,
+ WLAN_KMOD_WEP,
+ WLAN_KMODS_MAX
+};
+
+static const char *wmod_names[] = {
+ "wlan",
+ "wlan_wlan_acl",
+ "wlan_wep",
+ NULL
+};
+
+static int
+wlan_kmod_load(const char *modname)
+{
+ int fileid, modid;
+ struct module_stat mstat;
+
+ mstat.version = sizeof(struct module_stat);
+ for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
+ for (modid = kldfirstmod(fileid); modid > 0;
+ modid = modfnext(modid)) {
+ if (modstat(modid, &mstat) < 0)
+ continue;
+ if (strcmp(modname, mstat.name) == 0)
+ return (0);
+ }
+ }
+
+ /* Not present - load it. */
+ if (kldload(modname) < 0) {
+ syslog(LOG_ERR, "failed to load %s kernel module - %s", modname,
+ strerror(errno));
+ return (-1);
+ }
+
+ return (1);
+}
+
+int
+wlan_kmodules_load(void)
+{
+ if (wlan_kmod_load(wmod_names[WLAN_KMOD]) < 0)
+ return (-1);
+
+ if (wlan_kmod_load(wmod_names[WLAN_KMOD_ACL]) > 0)
+ syslog(LOG_NOTICE, "SNMP wlan loaded %s module",
+ wmod_names[WLAN_KMOD_ACL]);
+
+ if (wlan_kmod_load(wmod_names[WLAN_KMOD_WEP]) > 0)
+ syslog(LOG_NOTICE, "SNMP wlan loaded %s module",
+ wmod_names[WLAN_KMOD_WEP]);
+
+ return (0);
+}
+
+/* XXX: FIXME */
+static int
+wlan_ioctl(char *wif_name, uint16_t req_type, int *val, void *arg,
+ size_t *argsize, int set)
+{
+ struct ieee80211req ireq;
+
+ memset(&ireq, 0, sizeof(struct ieee80211req));
+ strlcpy(ireq.i_name, wif_name, IFNAMSIZ);
+
+ ireq.i_type = req_type;
+ ireq.i_val = *val;
+ ireq.i_len = *argsize;
+ ireq.i_data = arg;
+
+ if (ioctl(sock, set ? SIOCS80211 : SIOCG80211, &ireq) < 0) {
+ syslog(LOG_ERR, "iface %s - %s param: ioctl(%d) "
+ "failed: %s", wif_name, set ? "set" : "get",
+ req_type, strerror(errno));
+ return (-1);
+ }
+
+ *argsize = ireq.i_len;
+ *val = ireq.i_val;
+
+ return (0);
+}
+
+int
+wlan_check_media(char *ifname)
+{
+ struct ifmediareq ifmr;
+
+ memset(&ifmr, 0, sizeof(struct ifmediareq));
+ strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
+
+ if (ioctl(sock, SIOCGIFMEDIA, &ifmr) < 0 || ifmr.ifm_count == 0)
+ return (0); /* Interface doesn't support SIOCGIFMEDIA. */
+
+ if ((ifmr.ifm_status & IFM_AVALID) == 0)
+ return (0);
+
+ return (IFM_TYPE(ifmr.ifm_active));
+}
+
+int
+wlan_get_opmode(struct wlan_iface *wif)
+{
+ struct ifmediareq ifmr;
+
+ memset(&ifmr, 0, sizeof(struct ifmediareq));
+ strlcpy(ifmr.ifm_name, wif->wname, sizeof(ifmr.ifm_name));
+
+ if (ioctl(sock, SIOCGIFMEDIA, &ifmr) < 0) {
+ if (errno == ENXIO)
+ return (-1);
+ wif->mode = WlanIfaceOperatingModeType_station;
+ return (0);
+ }
+
+ if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
+ if (ifmr.ifm_current & IFM_FLAG0)
+ wif->mode = WlanIfaceOperatingModeType_adhocDemo;
+ else
+ wif->mode = WlanIfaceOperatingModeType_ibss;
+ } else if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+ wif->mode = WlanIfaceOperatingModeType_hostAp;
+ else if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+ wif->mode = WlanIfaceOperatingModeType_monitor;
+ else if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
+ wif->mode = WlanIfaceOperatingModeType_meshPoint;
+ else if (ifmr.ifm_current & IFM_IEEE80211_WDS)
+ wif->mode = WlanIfaceOperatingModeType_wds;
+
+ return (0);
+}
+
+int
+wlan_config_state(struct wlan_iface *wif, uint8_t set)
+{
+ int flags;
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, wif->wname);
+
+ if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "set %s status: ioctl(SIOCGIFFLAGS) "
+ "failed: %s", wif->wname, strerror(errno));
+ return (-1);
+ }
+
+ if (set == 0) {
+ if ((ifr.ifr_flags & IFF_UP) != 0)
+ wif->state = wlanIfaceState_up;
+ else
+ wif->state = wlanIfaceState_down;
+ return (0);
+ }
+
+ flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
+
+ if (wif->state == wlanIfaceState_up)
+ 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 %s %s: ioctl(SIOCSIFFLAGS) failed: %s",
+ wif->wname, wif->state == wlanIfaceState_up?"up":"down",
+ strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+wlan_get_local_addr(struct wlan_iface *wif)
+{
+ int len;
+ char ifname[IFNAMSIZ];
+ struct ifaddrs *ifap, *ifa;
+ struct sockaddr_dl sdl;
+
+ if (getifaddrs(&ifap) != 0) {
+ syslog(LOG_ERR, "wlan get mac: getifaddrs() failed - %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ memcpy(&sdl, ifa->ifa_addr, sizeof(struct sockaddr_dl));
+ if (sdl.sdl_alen > IEEE80211_ADDR_LEN)
+ continue;
+ if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
+ len = IFNAMSIZ - 1;
+ memcpy(ifname, sdl.sdl_data, len);
+ ifname[len] = '\0';
+ if (strcmp(wif->wname, ifname) == 0)
+ break;
+ }
+
+ freeifaddrs(ifap);
+ return (0);
+}
+
+int
+wlan_get_parent(struct wlan_iface *wif __unused)
+{
+ /* XXX: There's no way to fetch this from the kernel. */
+ return (0);
+}
+
+/* XXX */
+#define IEEE80211_C_STA 0x00000001 /* CAPABILITY: STA available */
+#define IEEE80211_C_8023ENCAP 0x00000002 /* CAPABILITY: 802.3 encap */
+#define IEEE80211_C_FF 0x00000040 /* CAPABILITY: ATH FF avail */
+#define IEEE80211_C_TURBOP 0x00000080 /* CAPABILITY: ATH Turbo avail*/
+#define IEEE80211_C_IBSS 0x00000100 /* CAPABILITY: IBSS available */
+#define IEEE80211_C_PMGT 0x00000200 /* CAPABILITY: Power mgmt */
+#define IEEE80211_C_HOSTAP 0x00000400 /* CAPABILITY: HOSTAP avail */
+#define IEEE80211_C_AHDEMO 0x00000800 /* CAPABILITY: Old Adhoc Demo */
+#define IEEE80211_C_SWRETRY 0x00001000 /* CAPABILITY: sw tx retry */
+#define IEEE80211_C_TXPMGT 0x00002000 /* CAPABILITY: tx power mgmt */
+#define IEEE80211_C_SHSLOT 0x00004000 /* CAPABILITY: short slottime */
+#define IEEE80211_C_SHPREAMBLE 0x00008000 /* CAPABILITY: short preamble */
+#define IEEE80211_C_MONITOR 0x00010000 /* CAPABILITY: monitor mode */
+#define IEEE80211_C_DFS 0x00020000 /* CAPABILITY: DFS/radar avail*/
+#define IEEE80211_C_MBSS 0x00040000 /* CAPABILITY: MBSS available */
+/* 0x7c0000 available */
+#define IEEE80211_C_WPA1 0x00800000 /* CAPABILITY: WPA1 avail */
+#define IEEE80211_C_WPA2 0x01000000 /* CAPABILITY: WPA2 avail */
+#define IEEE80211_C_WPA 0x01800000 /* CAPABILITY: WPA1+WPA2 avail*/
+#define IEEE80211_C_BURST 0x02000000 /* CAPABILITY: frame bursting */
+#define IEEE80211_C_WME 0x04000000 /* CAPABILITY: WME avail */
+#define IEEE80211_C_WDS 0x08000000 /* CAPABILITY: 4-addr support */
+/* 0x10000000 reserved */
+#define IEEE80211_C_BGSCAN 0x20000000 /* CAPABILITY: bg scanning */
+#define IEEE80211_C_TXFRAG 0x40000000 /* CAPABILITY: tx fragments */
+#define IEEE80211_C_TDMA 0x80000000 /* CAPABILITY: TDMA avail */
+
+static uint32_t
+wlan_drivercaps_to_snmp(uint32_t dcaps)
+{
+ uint32_t scaps = 0;
+
+ if ((dcaps & IEEE80211_C_STA) != 0)
+ scaps |= (0x1 << WlanDriverCaps_station);
+ if ((dcaps & IEEE80211_C_8023ENCAP) != 0)
+ scaps |= (0x1 << WlanDriverCaps_ieee8023encap);
+ if ((dcaps & IEEE80211_C_FF) != 0)
+ scaps |= (0x1 << WlanDriverCaps_athFastFrames);
+ if ((dcaps & IEEE80211_C_TURBOP) != 0)
+ scaps |= (0x1 << WlanDriverCaps_athTurbo);
+ if ((dcaps & IEEE80211_C_IBSS) != 0)
+ scaps |= (0x1 << WlanDriverCaps_ibss);
+ if ((dcaps & IEEE80211_C_PMGT) != 0)
+ scaps |= (0x1 << WlanDriverCaps_pmgt);
+ if ((dcaps & IEEE80211_C_HOSTAP) != 0)
+ scaps |= (0x1 << WlanDriverCaps_hostAp);
+ if ((dcaps & IEEE80211_C_AHDEMO) != 0)
+ scaps |= (0x1 << WlanDriverCaps_ahDemo);
+ if ((dcaps & IEEE80211_C_SWRETRY) != 0)
+ scaps |= (0x1 << WlanDriverCaps_swRetry);
+ if ((dcaps & IEEE80211_C_TXPMGT) != 0)
+ scaps |= (0x1 << WlanDriverCaps_txPmgt);
+ if ((dcaps & IEEE80211_C_SHSLOT) != 0)
+ scaps |= (0x1 << WlanDriverCaps_shortSlot);
+ if ((dcaps & IEEE80211_C_SHPREAMBLE) != 0)
+ scaps |= (0x1 << WlanDriverCaps_shortPreamble);
+ if ((dcaps & IEEE80211_C_MONITOR) != 0)
+ scaps |= (0x1 << WlanDriverCaps_monitor);
+ if ((dcaps & IEEE80211_C_DFS) != 0)
+ scaps |= (0x1 << WlanDriverCaps_dfs);
+ if ((dcaps & IEEE80211_C_MBSS) != 0)
+ scaps |= (0x1 << WlanDriverCaps_mbss);
+ if ((dcaps & IEEE80211_C_WPA1) != 0)
+ scaps |= (0x1 << WlanDriverCaps_wpa1);
+ if ((dcaps & IEEE80211_C_WPA2) != 0)
+ scaps |= (0x1 << WlanDriverCaps_wpa2);
+ if ((dcaps & IEEE80211_C_BURST) != 0)
+ scaps |= (0x1 << WlanDriverCaps_burst);
+ if ((dcaps & IEEE80211_C_WME) != 0)
+ scaps |= (0x1 << WlanDriverCaps_wme);
+ if ((dcaps & IEEE80211_C_WDS) != 0)
+ scaps |= (0x1 << WlanDriverCaps_wds);
+ if ((dcaps & IEEE80211_C_BGSCAN) != 0)
+ scaps |= (0x1 << WlanDriverCaps_bgScan);
+ if ((dcaps & IEEE80211_C_TXFRAG) != 0)
+ scaps |= (0x1 << WlanDriverCaps_txFrag);
+ if ((dcaps & IEEE80211_C_TDMA) != 0)
+ scaps |= (0x1 << WlanDriverCaps_tdma);
+
+ return (scaps);
+}
+
+static uint32_t
+wlan_cryptocaps_to_snmp(uint32_t ccaps)
+{
+ uint32_t scaps = 0;
+
+#if NOT_YET
+ if ((ccaps & IEEE80211_CRYPTO_WEP) != 0)
+ scaps |= (0x1 << wlanCryptoCaps_wep);
+ if ((ccaps & IEEE80211_CRYPTO_TKIP) != 0)
+ scaps |= (0x1 << wlanCryptoCaps_tkip);
+ if ((ccaps & IEEE80211_CRYPTO_AES_OCB) != 0)
+ scaps |= (0x1 << wlanCryptoCaps_aes);
+ if ((ccaps & IEEE80211_CRYPTO_AES_CCM) != 0)
+ scaps |= (0x1 << wlanCryptoCaps_aesCcm);
+ if ((ccaps & IEEE80211_CRYPTO_TKIPMIC) != 0)
+ scaps |= (0x1 << wlanCryptoCaps_tkipMic);
+ if ((ccaps & IEEE80211_CRYPTO_CKIP) != 0)
+ scaps |= (0x1 << wlanCryptoCaps_ckip);
+#else /* !NOT_YET */
+ scaps = ccaps;
+#endif
+ return (scaps);
+}
+
+#define IEEE80211_HTC_AMPDU 0x00010000 /* CAPABILITY: A-MPDU tx */
+#define IEEE80211_HTC_AMSDU 0x00020000 /* CAPABILITY: A-MSDU tx */
+/* NB: HT40 is implied by IEEE80211_HTCAP_CHWIDTH40 */
+#define IEEE80211_HTC_HT 0x00040000 /* CAPABILITY: HT operation */
+#define IEEE80211_HTC_SMPS 0x00080000 /* CAPABILITY: MIMO power save*/
+#define IEEE80211_HTC_RIFS 0x00100000 /* CAPABILITY: RIFS support */
+
+static uint32_t
+wlan_htcaps_to_snmp(uint32_t hcaps)
+{
+ uint32_t scaps = 0;
+
+ if ((hcaps & IEEE80211_HTCAP_LDPC) != 0)
+ scaps |= (0x1 << WlanHTCaps_ldpc);
+ if ((hcaps & IEEE80211_HTCAP_CHWIDTH40) != 0)
+ scaps |= (0x1 << WlanHTCaps_chwidth40);
+ if ((hcaps & IEEE80211_HTCAP_GREENFIELD) != 0)
+ scaps |= (0x1 << WlanHTCaps_greenField);
+ if ((hcaps & IEEE80211_HTCAP_SHORTGI20) != 0)
+ scaps |= (0x1 << WlanHTCaps_shortGi20);
+ if ((hcaps & IEEE80211_HTCAP_SHORTGI40) != 0)
+ scaps |= (0x1 << WlanHTCaps_shortGi40);
+ if ((hcaps & IEEE80211_HTCAP_TXSTBC) != 0)
+ scaps |= (0x1 << WlanHTCaps_txStbc);
+ if ((hcaps & IEEE80211_HTCAP_DELBA) != 0)
+ scaps |= (0x1 << WlanHTCaps_delba);
+ if ((hcaps & IEEE80211_HTCAP_MAXAMSDU_7935) != 0)
+ scaps |= (0x1 << WlanHTCaps_amsdu7935);
+ if ((hcaps & IEEE80211_HTCAP_DSSSCCK40) != 0)
+ scaps |= (0x1 << WlanHTCaps_dssscck40);
+ if ((hcaps & IEEE80211_HTCAP_PSMP) != 0)
+ scaps |= (0x1 << WlanHTCaps_psmp);
+ if ((hcaps & IEEE80211_HTCAP_40INTOLERANT) != 0)
+ scaps |= (0x1 << WlanHTCaps_fortyMHzIntolerant);
+ if ((hcaps & IEEE80211_HTCAP_LSIGTXOPPROT) != 0)
+ scaps |= (0x1 << WlanHTCaps_lsigTxOpProt);
+ if ((hcaps & IEEE80211_HTC_AMPDU) != 0)
+ scaps |= (0x1 << WlanHTCaps_htcAmpdu);
+ if ((hcaps & IEEE80211_HTC_AMSDU) != 0)
+ scaps |= (0x1 << WlanHTCaps_htcAmsdu);
+ if ((hcaps & IEEE80211_HTC_HT) != 0)
+ scaps |= (0x1 << WlanHTCaps_htcHt);
+ if ((hcaps & IEEE80211_HTC_SMPS) != 0)
+ scaps |= (0x1 << WlanHTCaps_htcSmps);
+ if ((hcaps & IEEE80211_HTC_RIFS) != 0)
+ scaps |= (0x1 << WlanHTCaps_htcRifs);
+
+ return (scaps);
+}
+
+/* XXX: Not here? */
+#define WLAN_SET_TDMA_OPMODE(w) do { \
+ if ((w)->mode == WlanIfaceOperatingModeType_adhocDemo && \
+ ((w)->drivercaps & WlanDriverCaps_tdma) != 0) \
+ (w)->mode = WlanIfaceOperatingModeType_tdma; \
+} while (0)
+int
+wlan_get_driver_caps(struct wlan_iface *wif)
+{
+ int val = 0;
+ size_t argsize;
+ struct ieee80211_devcaps_req dc;
+
+ memset(&dc, 0, sizeof(struct ieee80211_devcaps_req));
+ argsize = sizeof(struct ieee80211_devcaps_req);
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_DEVCAPS, &val, &dc,
+ &argsize, 0) < 0)
+ return (-1);
+
+ wif->drivercaps = wlan_drivercaps_to_snmp(dc.dc_drivercaps);
+ wif->cryptocaps = wlan_cryptocaps_to_snmp(dc.dc_cryptocaps);
+ wif->htcaps = wlan_htcaps_to_snmp(dc.dc_htcaps);
+
+ WLAN_SET_TDMA_OPMODE(wif);
+
+ argsize = dc.dc_chaninfo.ic_nchans * sizeof(struct ieee80211_channel);
+ wif->chanlist = (struct ieee80211_channel *)malloc(argsize);
+ if (wif->chanlist == NULL)
+ return (0);
+
+ memcpy(wif->chanlist, dc.dc_chaninfo.ic_chans, argsize);
+ wif->nchannels = dc.dc_chaninfo.ic_nchans;
+
+ return (0);
+}
+
+uint8_t
+wlan_channel_state_to_snmp(uint8_t cstate)
+{
+ uint8_t cs = 0;
+
+ if ((cstate & IEEE80211_CHANSTATE_RADAR) != 0)
+ cs |= (0x1 << WlanIfaceChannelStateType_radar);
+ if ((cstate & IEEE80211_CHANSTATE_CACDONE) != 0)
+ cs |= (0x1 << WlanIfaceChannelStateType_cacDone);
+ if ((cstate & IEEE80211_CHANSTATE_CWINT) != 0)
+ cs |= (0x1 << WlanIfaceChannelStateType_interferenceDetected);
+ if ((cstate & IEEE80211_CHANSTATE_NORADAR) != 0)
+ cs |= (0x1 << WlanIfaceChannelStateType_radarClear);
+
+ return (cs);
+}
+
+uint32_t
+wlan_channel_flags_to_snmp(uint32_t cflags)
+{
+ uint32_t cf = 0;
+
+ if ((cflags & IEEE80211_CHAN_TURBO) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_turbo);
+ if ((cflags & IEEE80211_CHAN_CCK) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_cck);
+ if ((cflags & IEEE80211_CHAN_OFDM) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_ofdm);
+ if ((cflags & IEEE80211_CHAN_2GHZ) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_spectrum2Ghz);
+ if ((cflags & IEEE80211_CHAN_5GHZ) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_spectrum5Ghz);
+ if ((cflags & IEEE80211_CHAN_PASSIVE) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_passiveScan);
+ if ((cflags & IEEE80211_CHAN_DYN) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_dynamicCckOfdm);
+ if ((cflags & IEEE80211_CHAN_GFSK) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_gfsk);
+ if ((cflags & IEEE80211_CHAN_GSM) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_spectrum900Mhz);
+ if ((cflags & IEEE80211_CHAN_STURBO) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_dot11aStaticTurbo);
+ if ((cflags & IEEE80211_CHAN_HALF) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_halfRate);
+ if ((cflags & IEEE80211_CHAN_QUARTER) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_quarterRate);
+ if ((cflags & IEEE80211_CHAN_HT20) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_ht20);
+ if ((cflags & IEEE80211_CHAN_HT40U) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_ht40u);
+ if ((cflags & IEEE80211_CHAN_HT40D) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_ht40d);
+ if ((cflags & IEEE80211_CHAN_DFS) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_dfs);
+ if ((cflags & IEEE80211_CHAN_4MSXMIT) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_xmit4ms);
+ if ((cflags & IEEE80211_CHAN_NOADHOC) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_noAdhoc);
+ if ((cflags & IEEE80211_CHAN_NOHOSTAP) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_noHostAp);
+ if ((cflags & IEEE80211_CHAN_11D) != 0)
+ cf |= (0x1 << WlanIfaceChannelFlagsType_dot11d);
+
+ return (cf);
+}
+
+/* XXX: */
+#define WLAN_SNMP_MAX_CHANS 256
+int
+wlan_get_channel_list(struct wlan_iface *wif)
+{
+ int val = 0;
+ uint32_t i, nchans;
+ size_t argsize;
+ struct ieee80211req_chaninfo *chaninfo;
+ struct ieee80211req_chanlist active;
+ const struct ieee80211_channel *c;
+
+ argsize = sizeof(struct ieee80211req_chaninfo) +
+ sizeof(struct ieee80211_channel) * WLAN_SNMP_MAX_CHANS;
+ chaninfo = (struct ieee80211req_chaninfo *)malloc(argsize);
+ if (chaninfo == NULL)
+ return (-1);
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_CHANINFO, &val, chaninfo,
+ &argsize, 0) < 0)
+ return (-1);
+
+ argsize = sizeof(active);
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_CHANLIST, &val, &active,
+ &argsize, 0) < 0)
+ goto error;
+
+ for (i = 0, nchans = 0; i < chaninfo->ic_nchans; i++) {
+ c = &chaninfo->ic_chans[i];
+ if (!isset(active.ic_channels, c->ic_ieee))
+ continue;
+ nchans++;
+ }
+ wif->chanlist = (struct ieee80211_channel *)reallocf(wif->chanlist,
+ nchans * sizeof(*c));
+ if (wif->chanlist == NULL)
+ goto error;
+ wif->nchannels = nchans;
+ for (i = 0, nchans = 0; i < chaninfo->ic_nchans; i++) {
+ c = &chaninfo->ic_chans[i];
+ if (!isset(active.ic_channels, c->ic_ieee))
+ continue;
+ memcpy(wif->chanlist + nchans, c, sizeof (*c));
+ nchans++;
+ }
+
+ free(chaninfo);
+ return (0);
+error:
+ wif->nchannels = 0;
+ free(chaninfo);
+ return (-1);
+}
+
+static enum WlanIfPhyMode
+wlan_channel_flags_to_snmp_phy(uint32_t cflags)
+{
+ /* XXX: recheck */
+ if ((cflags & IEEE80211_CHAN_A) != 0)
+ return (WlanIfPhyMode_dot11a);
+ if ((cflags & IEEE80211_CHAN_B) != 0)
+ return (WlanIfPhyMode_dot11b);
+ if ((cflags & IEEE80211_CHAN_G) != 0 ||
+ (cflags & IEEE80211_CHAN_PUREG) != 0)
+ return (WlanIfPhyMode_dot11g);
+ if ((cflags & IEEE80211_CHAN_FHSS) != 0)
+ return (WlanIfPhyMode_fh);
+ if ((cflags & IEEE80211_CHAN_TURBO) != 0 &&
+ (cflags & IEEE80211_CHAN_A) != 0)
+ return (WlanIfPhyMode_turboA);
+ if ((cflags & IEEE80211_CHAN_TURBO) != 0 &&
+ (cflags & IEEE80211_CHAN_G) != 0)
+ return (WlanIfPhyMode_turboG);
+ if ((cflags & IEEE80211_CHAN_STURBO) != 0)
+ return (WlanIfPhyMode_sturboA);
+ if ((cflags & IEEE80211_CHAN_HALF) != 0)
+ return (WlanIfPhyMode_ofdmHalf);
+ if ((cflags & IEEE80211_CHAN_QUARTER) != 0)
+ return (WlanIfPhyMode_ofdmQuarter);
+
+ return (WlanIfPhyMode_auto);
+}
+
+int
+wlan_get_roam_params(struct wlan_iface *wif)
+{
+ int val = 0;
+ size_t argsize;
+
+ argsize = sizeof(struct ieee80211_roamparams_req);
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_ROAM, &val,
+ &wif->roamparams, &argsize, 0) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+wlan_get_tx_params(struct wlan_iface *wif)
+{
+ int val = 0;
+ size_t argsize;
+
+ /*
+ * XXX: Reset IEEE80211_RATE_MCS bit on IEEE80211_MODE_11NA
+ * and IEEE80211_MODE_11NG modes.
+ */
+ argsize = sizeof(struct ieee80211_txparams_req);
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_TXPARAMS, &val,
+ &wif->txparams, &argsize, 0) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+wlan_set_tx_params(struct wlan_iface *wif, int32_t pmode __unused)
+{
+ int val = 0;
+ size_t argsize;
+
+ /*
+ * XXX: Set IEEE80211_RATE_MCS bit on IEEE80211_MODE_11NA
+ * and IEEE80211_MODE_11NG modes.
+ */
+ argsize = sizeof(struct ieee80211_txparams_req);
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_TXPARAMS, &val,
+ &wif->txparams, &argsize, 1) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+wlan_clone_create(struct wlan_iface *wif)
+{
+ struct ifreq ifr;
+ struct ieee80211_clone_params wcp;
+ static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
+
+ memset(&wcp, 0, sizeof(wcp));
+ memset(&ifr, 0, sizeof(ifr));
+
+ /* Sanity checks. */
+ if (wif == NULL || wif->pname[0] == '\0' || wif->mode > WLAN_IFMODE_MAX)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ if (wif->mode == WlanIfaceOperatingModeType_wds &&
+ memcmp(wif->dbssid, zerobssid, IEEE80211_ADDR_LEN) == 0)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ strlcpy(wcp.icp_parent, wif->pname, IFNAMSIZ);
+ if ((wif->flags & WlanIfaceFlagsType_uniqueBssid) != 0)
+ wcp.icp_flags |= IEEE80211_CLONE_BSSID;
+ if ((wif->flags & WlanIfaceFlagsType_noBeacons) != 0)
+ wcp.icp_flags |= IEEE80211_CLONE_NOBEACONS;
+ if (wif->mode == WlanIfaceOperatingModeType_wds &&
+ (wif->flags & WlanIfaceFlagsType_wdsLegacy) != 0)
+ wcp.icp_flags |= IEEE80211_CLONE_WDSLEGACY;
+
+ switch (wif->mode) {
+ case WlanIfaceOperatingModeType_ibss:
+ wcp.icp_opmode = IEEE80211_M_IBSS;
+ break;
+ case WlanIfaceOperatingModeType_station:
+ wcp.icp_opmode = IEEE80211_M_STA;
+ break;
+ case WlanIfaceOperatingModeType_wds:
+ wcp.icp_opmode = IEEE80211_M_WDS;
+ break;
+ case WlanIfaceOperatingModeType_adhocDemo:
+ wcp.icp_opmode = IEEE80211_M_AHDEMO;
+ break;
+ case WlanIfaceOperatingModeType_hostAp:
+ wcp.icp_opmode = IEEE80211_M_HOSTAP;
+ break;
+ case WlanIfaceOperatingModeType_monitor:
+ wcp.icp_opmode = IEEE80211_M_MONITOR;
+ break;
+ case WlanIfaceOperatingModeType_meshPoint:
+ wcp.icp_opmode = IEEE80211_M_MBSS;
+ break;
+ case WlanIfaceOperatingModeType_tdma:
+ wcp.icp_opmode = IEEE80211_M_AHDEMO;
+ wcp.icp_flags |= IEEE80211_CLONE_TDMA;
+ break;
+ }
+
+ memcpy(wcp.icp_bssid, wif->dbssid, IEEE80211_ADDR_LEN);
+ if (memcmp(wif->dlmac, zerobssid, IEEE80211_ADDR_LEN) != 0) {
+ memcpy(wcp.icp_macaddr, wif->dlmac, IEEE80211_ADDR_LEN);
+ wcp.icp_flags |= IEEE80211_CLONE_MACADDR;
+ }
+
+ strlcpy(ifr.ifr_name, wif->wname, IFNAMSIZ);
+ ifr.ifr_data = (caddr_t) &wcp;
+
+ if (ioctl(sock, SIOCIFCREATE2, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "wlan clone create: ioctl(SIOCIFCREATE2) "
+ "failed: %s", strerror(errno));
+ return (SNMP_ERR_GENERR);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+int
+wlan_clone_destroy(struct wlan_iface *wif)
+{
+ struct ifreq ifr;
+
+ if (wif == NULL)
+ return (SNMP_ERR_INCONS_VALUE);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, wif->wname);
+
+ if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
+ syslog(LOG_ERR, "wlan clone destroy: ioctl(SIOCIFDESTROY) "
+ "failed: %s", strerror(errno));
+ return (SNMP_ERR_GENERR);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+static int
+wlan_config_snmp2ioctl(int which)
+{
+ int op;
+
+ switch (which) {
+ case LEAF_wlanIfacePacketBurst:
+ op = IEEE80211_IOC_BURST;
+ break;
+ case LEAF_wlanIfaceCountryCode:
+ op = IEEE80211_IOC_REGDOMAIN;
+ break;
+ case LEAF_wlanIfaceRegDomain:
+ op = IEEE80211_IOC_REGDOMAIN;
+ break;
+ case LEAF_wlanIfaceDesiredSsid:
+ op = IEEE80211_IOC_SSID;
+ break;
+ case LEAF_wlanIfaceDesiredChannel:
+ op = IEEE80211_IOC_CURCHAN;
+ break;
+ case LEAF_wlanIfaceDynamicFreqSelection:
+ op = IEEE80211_IOC_DFS;
+ break;
+ case LEAF_wlanIfaceFastFrames:
+ op = IEEE80211_IOC_FF;
+ break;
+ case LEAF_wlanIfaceDturbo:
+ op = IEEE80211_IOC_TURBOP;
+ break;
+ case LEAF_wlanIfaceTxPower:
+ op = IEEE80211_IOC_TXPOWER;
+ break;
+ case LEAF_wlanIfaceFragmentThreshold:
+ op = IEEE80211_IOC_FRAGTHRESHOLD;
+ break;
+ case LEAF_wlanIfaceRTSThreshold:
+ op = IEEE80211_IOC_RTSTHRESHOLD;
+ break;
+ case LEAF_wlanIfaceWlanPrivacySubscribe:
+ op = IEEE80211_IOC_WPS;
+ break;
+ case LEAF_wlanIfaceBgScan:
+ op = IEEE80211_IOC_BGSCAN;
+ break;
+ case LEAF_wlanIfaceBgScanIdle:
+ op = IEEE80211_IOC_BGSCAN_IDLE;
+ break;
+ case LEAF_wlanIfaceBgScanInterval:
+ op = IEEE80211_IOC_BGSCAN_INTERVAL;
+ break;
+ case LEAF_wlanIfaceBeaconMissedThreshold:
+ op = IEEE80211_IOC_BMISSTHRESHOLD;
+ break;
+ case LEAF_wlanIfaceDesiredBssid:
+ op = IEEE80211_IOC_BSSID;
+ break;
+ case LEAF_wlanIfaceRoamingMode:
+ op = IEEE80211_IOC_ROAMING;
+ break;
+ case LEAF_wlanIfaceDot11d:
+ op = IEEE80211_IOC_DOTD;
+ break;
+ case LEAF_wlanIfaceDot11h:
+ op = IEEE80211_IOC_DOTH;
+ break;
+ case LEAF_wlanIfaceDynamicWds:
+ op = IEEE80211_IOC_DWDS;
+ break;
+ case LEAF_wlanIfacePowerSave:
+ op = IEEE80211_IOC_POWERSAVE;
+ break;
+ case LEAF_wlanIfaceApBridge:
+ op = IEEE80211_IOC_APBRIDGE;
+ break;
+ case LEAF_wlanIfaceBeaconInterval:
+ op = IEEE80211_IOC_BEACON_INTERVAL;
+ break;
+ case LEAF_wlanIfaceDtimPeriod:
+ op = IEEE80211_IOC_DTIM_PERIOD;
+ break;
+ case LEAF_wlanIfaceHideSsid:
+ op = IEEE80211_IOC_HIDESSID;
+ break;
+ case LEAF_wlanIfaceInactivityProccess:
+ op = IEEE80211_IOC_INACTIVITY;
+ break;
+ case LEAF_wlanIfaceDot11gProtMode:
+ op = IEEE80211_IOC_PROTMODE;
+ break;
+ case LEAF_wlanIfaceDot11gPureMode:
+ op = IEEE80211_IOC_PUREG;
+ break;
+ case LEAF_wlanIfaceDot11nPureMode:
+ op = IEEE80211_IOC_PUREN;
+ break;
+ case LEAF_wlanIfaceDot11nAmpdu:
+ op = IEEE80211_IOC_AMPDU;
+ break;
+ case LEAF_wlanIfaceDot11nAmpduDensity:
+ op = IEEE80211_IOC_AMPDU_DENSITY;
+ break;
+ case LEAF_wlanIfaceDot11nAmpduLimit:
+ op = IEEE80211_IOC_AMPDU_LIMIT;
+ break;
+ case LEAF_wlanIfaceDot11nAmsdu:
+ op = IEEE80211_IOC_AMSDU;
+ break;
+ case LEAF_wlanIfaceDot11nAmsduLimit:
+ op = IEEE80211_IOC_AMSDU_LIMIT;
+ break;
+ case LEAF_wlanIfaceDot11nHighThroughput:
+ op = IEEE80211_IOC_HTCONF;
+ break;
+ case LEAF_wlanIfaceDot11nHTCompatible:
+ op = IEEE80211_IOC_HTCOMPAT;
+ break;
+ case LEAF_wlanIfaceDot11nHTProtMode:
+ op = IEEE80211_IOC_HTPROTMODE;
+ break;
+ case LEAF_wlanIfaceDot11nRIFS:
+ op = IEEE80211_IOC_RIFS;
+ break;
+ case LEAF_wlanIfaceDot11nShortGI:
+ op = IEEE80211_IOC_SHORTGI;
+ break;
+ case LEAF_wlanIfaceDot11nSMPSMode:
+ op = IEEE80211_IOC_SMPS;
+ break;
+ case LEAF_wlanIfaceTdmaSlot:
+ op = IEEE80211_IOC_TDMA_SLOT;
+ break;
+ case LEAF_wlanIfaceTdmaSlotCount:
+ op = IEEE80211_IOC_TDMA_SLOTCNT;
+ break;
+ case LEAF_wlanIfaceTdmaSlotLength:
+ op = IEEE80211_IOC_TDMA_SLOTLEN;
+ break;
+ case LEAF_wlanIfaceTdmaBeaconInterval:
+ op = IEEE80211_IOC_TDMA_BINTERVAL;
+ break;
+ default:
+ op = -1;
+ }
+
+ return (op);
+}
+
+static enum WlanRegDomainCode
+wlan_regdomain_to_snmp(int which)
+{
+ enum WlanRegDomainCode reg_domain;
+
+ switch (which) {
+ case SKU_FCC:
+ reg_domain = WlanRegDomainCode_fcc;
+ break;
+ case SKU_CA:
+ reg_domain = WlanRegDomainCode_ca;
+ break;
+ case SKU_ETSI:
+ reg_domain = WlanRegDomainCode_etsi;
+ break;
+ case SKU_ETSI2:
+ reg_domain = WlanRegDomainCode_etsi2;
+ break;
+ case SKU_ETSI3:
+ reg_domain = WlanRegDomainCode_etsi3;
+ break;
+ case SKU_FCC3:
+ reg_domain = WlanRegDomainCode_fcc3;
+ break;
+ case SKU_JAPAN:
+ reg_domain = WlanRegDomainCode_japan;
+ break;
+ case SKU_KOREA:
+ reg_domain = WlanRegDomainCode_korea;
+ break;
+ case SKU_APAC:
+ reg_domain = WlanRegDomainCode_apac;
+ break;
+ case SKU_APAC2:
+ reg_domain = WlanRegDomainCode_apac2;
+ break;
+ case SKU_APAC3:
+ reg_domain = WlanRegDomainCode_apac3;
+ break;
+ case SKU_ROW:
+ reg_domain = WlanRegDomainCode_row;
+ break;
+ case SKU_NONE:
+ reg_domain = WlanRegDomainCode_none;
+ break;
+ case SKU_DEBUG:
+ reg_domain = WlanRegDomainCode_debug;
+ break;
+ case SKU_SR9:
+ reg_domain = WlanRegDomainCode_sr9;
+ break;
+ case SKU_XR9:
+ reg_domain = WlanRegDomainCode_xr9;
+ break;
+ case SKU_GZ901:
+ reg_domain = WlanRegDomainCode_gz901;
+ break;
+ case 0:
+ reg_domain = WlanRegDomainCode_none;
+ break;
+ default:
+ syslog(LOG_ERR, "unknown regdomain (0x%x) ", which);
+ reg_domain = WlanRegDomainCode_none;
+ break;
+ }
+
+ return (reg_domain);
+}
+
+static int
+wlan_snmp_to_regdomain(enum WlanRegDomainCode regdomain)
+{
+ int which;
+
+ switch (regdomain) {
+ case WlanRegDomainCode_fcc:
+ which = SKU_FCC;
+ break;
+ case WlanRegDomainCode_ca:
+ which = SKU_CA;
+ break;
+ case WlanRegDomainCode_etsi:
+ which = SKU_ETSI;
+ break;
+ case WlanRegDomainCode_etsi2:
+ which = SKU_ETSI2;
+ break;
+ case WlanRegDomainCode_etsi3:
+ which = SKU_ETSI3;
+ break;
+ case WlanRegDomainCode_fcc3:
+ which = SKU_FCC3;
+ break;
+ case WlanRegDomainCode_japan:
+ which = SKU_JAPAN;
+ break;
+ case WlanRegDomainCode_korea:
+ which = SKU_KOREA;
+ break;
+ case WlanRegDomainCode_apac:
+ which = SKU_APAC;
+ break;
+ case WlanRegDomainCode_apac2:
+ which = SKU_APAC2;
+ break;
+ case WlanRegDomainCode_apac3:
+ which = SKU_APAC3;
+ break;
+ case WlanRegDomainCode_row:
+ which = SKU_ROW;
+ break;
+ case WlanRegDomainCode_none:
+ which = SKU_NONE;
+ break;
+ case WlanRegDomainCode_debug:
+ which = SKU_DEBUG;
+ break;
+ case WlanRegDomainCode_sr9:
+ which = SKU_SR9;
+ break;
+ case WlanRegDomainCode_xr9:
+ which = SKU_XR9;
+ break;
+ case WlanRegDomainCode_gz901:
+ which = SKU_GZ901;
+ break;
+ default:
+ syslog(LOG_ERR, "unknown snmp regdomain (0x%x) ", regdomain);
+ which = SKU_NONE;
+ break;
+ }
+
+ return (which);
+}
+
+static int
+wlan_config_get_country(struct wlan_iface *wif)
+{
+ int val = 0;
+ size_t argsize;
+ struct ieee80211_regdomain regdomain;
+
+ memset(&regdomain, 0, sizeof(regdomain));
+ argsize = sizeof(regdomain);
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_REGDOMAIN, &val, &regdomain,
+ &argsize, 0) < 0)
+ return (-1);
+
+ wif->reg_domain = wlan_regdomain_to_snmp(regdomain.regdomain);
+ wif->country_code[0] = regdomain.isocc[0];
+ wif->country_code[1] = regdomain.isocc[1];
+ wif->country_code[2] = regdomain.location;
+
+ return (0);
+}
+
+static int
+wlan_config_set_country(struct wlan_iface *wif, char *ccode, int rdomain)
+{
+ int val = 0, txpowermax;
+ uint32_t i;
+ size_t argsize = 0;
+ struct ieee80211_regdomain_req *regdomain;
+
+ if (wlan_get_channel_list(wif) < 0)
+ return (-1);
+
+ if (wif->nchannels == 0) {
+ syslog(LOG_ERR, "iface %s - set regdomain failed", wif->wname);
+ return (-1);
+ }
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_TXPOWMAX, &txpowermax, 0,
+ &argsize, 0) < 0)
+ return (-1);
+
+ regdomain = malloc(IEEE80211_REGDOMAIN_SIZE(wif->nchannels));
+ if (regdomain == NULL)
+ return (-1);
+ memset(regdomain, 0, IEEE80211_REGDOMAIN_SIZE(wif->nchannels));
+ argsize = IEEE80211_REGDOMAIN_SIZE(wif->nchannels);
+
+ /* XXX: recheck with how this is done by ifconfig(8) */
+ regdomain->rd.regdomain = wlan_snmp_to_regdomain(rdomain);
+ regdomain->rd.isocc[0] = ccode[0];
+ regdomain->rd.isocc[1] = ccode[1];
+ regdomain->rd.location = ccode[2];
+
+ /* XXX: fill the channel list properly */
+ regdomain->chaninfo.ic_nchans = wif->nchannels;
+ memcpy(regdomain->chaninfo.ic_chans, wif->chanlist,
+ wif->nchannels * sizeof(struct ieee80211_channel));
+ for (i = 0; i < wif->nchannels; i++)
+ regdomain->chaninfo.ic_chans[i].ic_maxregpower = txpowermax;
+
+ wif->state = wlanIfaceState_down;
+ if (wlan_config_state(wif, 1) < 0 ||
+ wlan_ioctl(wif->wname, IEEE80211_IOC_REGDOMAIN, &val, regdomain,
+ &argsize, 1) < 0) {
+ free(regdomain);
+ return (-1);
+ }
+
+ wif->state = wlanIfaceState_up;
+ (void)wlan_config_state(wif, 1);
+ wif->reg_domain = wlan_regdomain_to_snmp(regdomain->rd.regdomain);
+ wif->country_code[0] = regdomain->rd.isocc[0];
+ wif->country_code[1] = regdomain->rd.isocc[1];
+ wif->country_code[2] = regdomain->rd.location;
+ free(regdomain);
+
+ return (0);
+}
+
+int
+wlan_config_get_dssid(struct wlan_iface *wif)
+{
+ int val = -1;
+ size_t argsize = IEEE80211_NWID_LEN + 1;
+ char ssid[IEEE80211_NWID_LEN + 1];
+
+ memset(ssid, 0, IEEE80211_NWID_LEN + 1);
+
+ if (wlan_ioctl(wif->wname,
+ (wif->mode == WlanIfaceOperatingModeType_meshPoint) ?
+ IEEE80211_IOC_MESH_ID : IEEE80211_IOC_SSID, &val, ssid,
+ &argsize, 0) < 0)
+ return (-1);
+
+ if (argsize > IEEE80211_NWID_LEN)
+ argsize = IEEE80211_NWID_LEN;
+ memcpy(wif->desired_ssid, ssid, argsize);
+ wif->desired_ssid[argsize] = '\0';
+
+ return (0);
+}
+
+int
+wlan_config_set_dssid(struct wlan_iface *wif, char *ssid, int slen)
+{
+ int val = 0;
+ size_t argsize = slen;
+
+ if (wlan_ioctl(wif->wname,
+ (wif->mode == WlanIfaceOperatingModeType_meshPoint) ?
+ IEEE80211_IOC_MESH_ID : IEEE80211_IOC_SSID, &val, ssid,
+ &argsize, 1) < 0)
+ return (-1);
+
+ if (argsize > IEEE80211_NWID_LEN)
+ argsize = IEEE80211_NWID_LEN;
+ memcpy(wif->desired_ssid, ssid, argsize);
+ wif->desired_ssid[argsize] = '\0';
+
+ return (0);
+}
+
+static int
+wlan_config_get_dchannel(struct wlan_iface *wif)
+{
+ uint32_t i = 0;
+ int val = 0;
+ size_t argsize = sizeof(struct ieee80211_channel);
+ struct ieee80211_channel chan;
+
+ if (wlan_get_channel_list(wif) < 0)
+ return (-1);
+
+ memset(&chan, 0, sizeof(chan));
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_CURCHAN, &val, &chan,
+ &argsize, 0) < 0)
+ return (-1);
+
+ for (i = 0; i < wif->nchannels; i++)
+ if (chan.ic_ieee == wif->chanlist[i].ic_ieee &&
+ chan.ic_flags == wif->chanlist[i].ic_flags) {
+ wif->desired_channel = i + 1;
+ break;
+ }
+
+ return (0);
+}
+
+static int
+wlan_config_set_dchannel(struct wlan_iface *wif, uint32_t dchannel)
+{
+ int val = 0;
+ size_t argsize = sizeof(struct ieee80211_channel);
+ struct ieee80211_channel chan;
+
+ if (wlan_get_channel_list(wif) < 0)
+ return (-1);
+
+ if (dchannel > wif->nchannels)
+ return (-1);
+
+ memcpy(&chan, wif->chanlist + dchannel - 1, sizeof(chan));
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_CURCHAN, &val, &chan,
+ &argsize, 1) < 0)
+ return (-1);
+
+ wif->desired_channel = dchannel;
+
+ return (0);
+}
+
+static int
+wlan_config_get_bssid(struct wlan_iface *wif)
+{
+ int val = 0;
+ size_t argsize = IEEE80211_ADDR_LEN;
+ char bssid[IEEE80211_ADDR_LEN];
+
+ memset(bssid, 0, IEEE80211_ADDR_LEN);
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_BSSID, &val, bssid,
+ &argsize, 0) < 0 || argsize != IEEE80211_ADDR_LEN)
+ return (-1);
+
+ memcpy(wif->desired_bssid, bssid, IEEE80211_ADDR_LEN);
+
+ return (0);
+}
+
+static int
+wlan_config_set_bssid(struct wlan_iface *wif, uint8_t *bssid)
+{
+ int val = 0;
+ size_t argsize = IEEE80211_ADDR_LEN;
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_BSSID, &val, bssid,
+ &argsize, 1) < 0 || argsize != IEEE80211_ADDR_LEN)
+ return (-1);
+
+ memcpy(wif->desired_bssid, bssid, IEEE80211_ADDR_LEN);
+
+ return (0);
+}
+
+/*
+ * Convert the value returned by the kernel to the appropriate SNMP
+ * representation and set the corresponding interface member accordingly.
+ */
+static void
+wlan_config_set_snmp_intval(struct wlan_iface *wif, int op, int val)
+{
+ switch (op) {
+ case IEEE80211_IOC_BURST:
+ if (val == 0)
+ wif->packet_burst = TruthValue_false;
+ else
+ wif->packet_burst = TruthValue_true;
+ break;
+ case IEEE80211_IOC_DFS:
+ if (val == 0)
+ wif->dyn_frequency = TruthValue_false;
+ else
+ wif->dyn_frequency = TruthValue_true;
+ break;
+ case IEEE80211_IOC_FF:
+ if (val == 0)
+ wif->fast_frames = TruthValue_false;
+ else
+ wif->fast_frames = TruthValue_true;
+ break;
+ case IEEE80211_IOC_TURBOP:
+ if (val == 0)
+ wif->dturbo = TruthValue_false;
+ else
+ wif->dturbo = TruthValue_true;
+ break;
+ case IEEE80211_IOC_TXPOWER:
+ wif->tx_power = val / 2;
+ break;
+ case IEEE80211_IOC_FRAGTHRESHOLD:
+ wif->frag_threshold = val;
+ break;
+ case IEEE80211_IOC_RTSTHRESHOLD:
+ wif->rts_threshold = val;
+ break;
+ case IEEE80211_IOC_WPS:
+ if (val == 0)
+ wif->priv_subscribe = TruthValue_false;
+ else
+ wif->priv_subscribe = TruthValue_true;
+ break;
+ case IEEE80211_IOC_BGSCAN:
+ if (val == 0)
+ wif->bg_scan = TruthValue_false;
+ else
+ wif->bg_scan = TruthValue_true;
+ break;
+ case IEEE80211_IOC_BGSCAN_IDLE:
+ wif->bg_scan_idle = val;
+ break;
+ case IEEE80211_IOC_BGSCAN_INTERVAL:
+ wif->bg_scan_interval = val;
+ break;
+ case IEEE80211_IOC_BMISSTHRESHOLD:
+ wif->beacons_missed = val;
+ break;
+ case IEEE80211_IOC_ROAMING:
+ switch (val) {
+ case IEEE80211_ROAMING_DEVICE:
+ wif->roam_mode = wlanIfaceRoamingMode_device;
+ break;
+ case IEEE80211_ROAMING_MANUAL:
+ wif->roam_mode = wlanIfaceRoamingMode_manual;
+ break;
+ case IEEE80211_ROAMING_AUTO:
+ /* FALTHROUGH */
+ default:
+ wif->roam_mode = wlanIfaceRoamingMode_auto;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_DOTD:
+ if (val == 0)
+ wif->dot11d = TruthValue_false;
+ else
+ wif->dot11d = TruthValue_true;
+ break;
+ case IEEE80211_IOC_DOTH:
+ if (val == 0)
+ wif->dot11h = TruthValue_false;
+ else
+ wif->dot11h = TruthValue_true;
+ break;
+ case IEEE80211_IOC_DWDS:
+ if (val == 0)
+ wif->dynamic_wds = TruthValue_false;
+ else
+ wif->dynamic_wds = TruthValue_true;
+ break;
+ case IEEE80211_IOC_POWERSAVE:
+ if (val == 0)
+ wif->power_save = TruthValue_false;
+ else
+ wif->power_save = TruthValue_true;
+ break;
+ case IEEE80211_IOC_APBRIDGE:
+ if (val == 0)
+ wif->ap_bridge = TruthValue_false;
+ else
+ wif->ap_bridge = TruthValue_true;
+ break;
+ case IEEE80211_IOC_BEACON_INTERVAL:
+ wif->beacon_interval = val;
+ break;
+ case IEEE80211_IOC_DTIM_PERIOD:
+ wif->dtim_period = val;
+ break;
+ case IEEE80211_IOC_HIDESSID:
+ if (val == 0)
+ wif->hide_ssid = TruthValue_false;
+ else
+ wif->hide_ssid = TruthValue_true;
+ break;
+ case IEEE80211_IOC_INACTIVITY:
+ if (val == 0)
+ wif->inact_process = TruthValue_false;
+ else
+ wif->inact_process = TruthValue_true;
+ break;
+ case IEEE80211_IOC_PROTMODE:
+ switch (val) {
+ case IEEE80211_PROTMODE_CTS:
+ wif->do11g_protect = wlanIfaceDot11gProtMode_cts;
+ break;
+ case IEEE80211_PROTMODE_RTSCTS:
+ wif->do11g_protect = wlanIfaceDot11gProtMode_rtscts;
+ break;
+ case IEEE80211_PROTMODE_OFF:
+ /* FALLTHROUGH */
+ default:
+ wif->do11g_protect = wlanIfaceDot11gProtMode_off;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_PUREG:
+ if (val == 0)
+ wif->dot11g_pure = TruthValue_false;
+ else
+ wif->dot11g_pure = TruthValue_true;
+ break;
+ case IEEE80211_IOC_PUREN:
+ if (val == 0)
+ wif->dot11n_pure = TruthValue_false;
+ else
+ wif->dot11n_pure = TruthValue_true;
+ break;
+ case IEEE80211_IOC_AMPDU:
+ switch (val) {
+ case 0:
+ wif->ampdu = WlanIfaceDot11nPduType_disabled;
+ break;
+ case 1:
+ wif->ampdu = WlanIfaceDot11nPduType_txOnly;
+ break;
+ case 2:
+ wif->ampdu = WlanIfaceDot11nPduType_rxOnly;
+ break;
+ case 3:
+ /* FALLTHROUGH */
+ default:
+ wif->ampdu = WlanIfaceDot11nPduType_txAndRx;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_AMPDU_DENSITY:
+ switch (val) {
+ case IEEE80211_HTCAP_MPDUDENSITY_025:
+ wif->ampdu_density = 25;
+ break;
+ case IEEE80211_HTCAP_MPDUDENSITY_05:
+ wif->ampdu_density = 50;
+ break;
+ case IEEE80211_HTCAP_MPDUDENSITY_1:
+ wif->ampdu_density = 100;
+ break;
+ case IEEE80211_HTCAP_MPDUDENSITY_2:
+ wif->ampdu_density = 200;
+ break;
+ case IEEE80211_HTCAP_MPDUDENSITY_4:
+ wif->ampdu_density = 400;
+ break;
+ case IEEE80211_HTCAP_MPDUDENSITY_8:
+ wif->ampdu_density = 800;
+ break;
+ case IEEE80211_HTCAP_MPDUDENSITY_16:
+ wif->ampdu_density = 1600;
+ break;
+ case IEEE80211_HTCAP_MPDUDENSITY_NA:
+ default:
+ wif->ampdu_density = 0;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_AMPDU_LIMIT:
+ switch (val) {
+ case IEEE80211_HTCAP_MAXRXAMPDU_8K:
+ wif->ampdu_limit = 8192;
+ break;
+ case IEEE80211_HTCAP_MAXRXAMPDU_16K:
+ wif->ampdu_limit = 16384;
+ break;
+ case IEEE80211_HTCAP_MAXRXAMPDU_32K:
+ wif->ampdu_limit = 32768;
+ break;
+ case IEEE80211_HTCAP_MAXRXAMPDU_64K:
+ default:
+ wif->ampdu_limit = 65536;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_AMSDU:
+ switch (val) {
+ case 0:
+ wif->amsdu = WlanIfaceDot11nPduType_disabled;
+ break;
+ case 1:
+ wif->amsdu = WlanIfaceDot11nPduType_txOnly;
+ break;
+ case 3:
+ wif->amsdu = WlanIfaceDot11nPduType_txAndRx;
+ break;
+ case 2:
+ default:
+ /* FALLTHROUGH */
+ wif->amsdu = WlanIfaceDot11nPduType_rxOnly;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_AMSDU_LIMIT:
+ wif->amsdu_limit = val;
+ break;
+ case IEEE80211_IOC_HTCONF:
+ if (val == 0) /* XXX */
+ wif->ht_enabled = TruthValue_false;
+ else
+ wif->ht_enabled = TruthValue_true;
+ break;
+ case IEEE80211_IOC_HTCOMPAT:
+ if (val == 0)
+ wif->ht_compatible = TruthValue_false;
+ else
+ wif->ht_compatible = TruthValue_true;
+ break;
+ case IEEE80211_IOC_HTPROTMODE:
+ if (val == IEEE80211_PROTMODE_RTSCTS)
+ wif->ht_prot_mode = wlanIfaceDot11nHTProtMode_rts;
+ else
+ wif->ht_prot_mode = wlanIfaceDot11nHTProtMode_off;
+ break;
+ case IEEE80211_IOC_RIFS:
+ if (val == 0)
+ wif->rifs = TruthValue_false;
+ else
+ wif->rifs = TruthValue_true;
+ break;
+ case IEEE80211_IOC_SHORTGI:
+ if (val == 0)
+ wif->short_gi = TruthValue_false;
+ else
+ wif->short_gi = TruthValue_true;
+ break;
+ case IEEE80211_IOC_SMPS:
+ switch (val) {
+ case IEEE80211_HTCAP_SMPS_DYNAMIC:
+ wif->smps_mode = wlanIfaceDot11nSMPSMode_dynamic;
+ break;
+ case IEEE80211_HTCAP_SMPS_ENA:
+ wif->smps_mode = wlanIfaceDot11nSMPSMode_static;
+ break;
+ case IEEE80211_HTCAP_SMPS_OFF:
+ /* FALLTHROUGH */
+ default:
+ wif->smps_mode = wlanIfaceDot11nSMPSMode_disabled;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_TDMA_SLOT:
+ wif->tdma_slot = val;
+ break;
+ case IEEE80211_IOC_TDMA_SLOTCNT:
+ wif->tdma_slot_count = val;
+ break;
+ case IEEE80211_IOC_TDMA_SLOTLEN:
+ wif->tdma_slot_length = val;
+ break;
+ case IEEE80211_IOC_TDMA_BINTERVAL:
+ wif->tdma_binterval = val;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * Convert an SNMP value to the kernel equivalent and also do sanity check
+ * for each specific type.
+ */
+static int
+wlan_config_snmp2value(int which, int sval, int *value)
+{
+ *value = 0;
+
+ switch (which) {
+ case IEEE80211_IOC_BURST:
+ case IEEE80211_IOC_DFS:
+ case IEEE80211_IOC_FF:
+ case IEEE80211_IOC_TURBOP:
+ case IEEE80211_IOC_WPS:
+ case IEEE80211_IOC_BGSCAN:
+ case IEEE80211_IOC_DOTD:
+ case IEEE80211_IOC_DOTH:
+ case IEEE80211_IOC_DWDS:
+ case IEEE80211_IOC_POWERSAVE:
+ case IEEE80211_IOC_APBRIDGE:
+ case IEEE80211_IOC_HIDESSID:
+ case IEEE80211_IOC_INACTIVITY:
+ case IEEE80211_IOC_PUREG:
+ case IEEE80211_IOC_PUREN:
+ case IEEE80211_IOC_HTCONF:
+ case IEEE80211_IOC_HTCOMPAT:
+ case IEEE80211_IOC_RIFS:
+ if (sval == TruthValue_true)
+ *value = 1;
+ else if (sval != TruthValue_false)
+ return (SNMP_ERR_INCONS_VALUE);
+ break;
+ case IEEE80211_IOC_REGDOMAIN:
+ break;
+ case IEEE80211_IOC_SSID:
+ break;
+ case IEEE80211_IOC_CURCHAN:
+ break;
+ case IEEE80211_IOC_TXPOWER:
+ *value = sval * 2;
+ break;
+ case IEEE80211_IOC_FRAGTHRESHOLD:
+ if (sval < IEEE80211_FRAG_MIN || sval > IEEE80211_FRAG_MAX)
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ case IEEE80211_IOC_RTSTHRESHOLD:
+ if (sval < IEEE80211_RTS_MIN || sval > IEEE80211_RTS_MAX)
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ case IEEE80211_IOC_BGSCAN_IDLE:
+ if (sval < WLAN_BGSCAN_IDLE_MIN)
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ case IEEE80211_IOC_BGSCAN_INTERVAL:
+ if (sval < WLAN_SCAN_VALID_MIN)
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ case IEEE80211_IOC_BMISSTHRESHOLD:
+ if (sval < IEEE80211_HWBMISS_MIN || sval > IEEE80211_HWBMISS_MAX)
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ case IEEE80211_IOC_BSSID:
+ break;
+ case IEEE80211_IOC_ROAMING:
+ switch (sval) {
+ case wlanIfaceRoamingMode_device:
+ *value = IEEE80211_ROAMING_DEVICE;
+ break;
+ case wlanIfaceRoamingMode_manual:
+ *value = IEEE80211_ROAMING_MANUAL;
+ break;
+ case wlanIfaceRoamingMode_auto:
+ *value = IEEE80211_ROAMING_AUTO;
+ break;
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+ break;
+ case IEEE80211_IOC_BEACON_INTERVAL:
+ if (sval < IEEE80211_BINTVAL_MIN || sval > IEEE80211_BINTVAL_MAX)
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ case IEEE80211_IOC_DTIM_PERIOD:
+ if (sval < IEEE80211_DTIM_MIN || sval > IEEE80211_DTIM_MAX)
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ case IEEE80211_IOC_PROTMODE:
+ switch (sval) {
+ case wlanIfaceDot11gProtMode_cts:
+ *value = IEEE80211_PROTMODE_CTS;
+ break;
+ case wlanIfaceDot11gProtMode_rtscts:
+ *value = IEEE80211_PROTMODE_RTSCTS;
+ break;
+ case wlanIfaceDot11gProtMode_off:
+ *value = IEEE80211_PROTMODE_OFF;
+ break;
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+ break;
+ case IEEE80211_IOC_AMPDU:
+ switch (sval) {
+ case WlanIfaceDot11nPduType_disabled:
+ break;
+ case WlanIfaceDot11nPduType_txOnly:
+ *value = 1;
+ break;
+ case WlanIfaceDot11nPduType_rxOnly:
+ *value = 2;
+ break;
+ case WlanIfaceDot11nPduType_txAndRx:
+ *value = 3;
+ break;
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+ break;
+ case IEEE80211_IOC_AMPDU_DENSITY:
+ switch (sval) {
+ case 0:
+ *value = IEEE80211_HTCAP_MPDUDENSITY_NA;
+ break;
+ case 25:
+ *value = IEEE80211_HTCAP_MPDUDENSITY_025;
+ break;
+ case 50:
+ *value = IEEE80211_HTCAP_MPDUDENSITY_05;
+ break;
+ case 100:
+ *value = IEEE80211_HTCAP_MPDUDENSITY_1;
+ break;
+ case 200:
+ *value = IEEE80211_HTCAP_MPDUDENSITY_2;
+ break;
+ case 400:
+ *value = IEEE80211_HTCAP_MPDUDENSITY_4;
+ break;
+ case 800:
+ *value = IEEE80211_HTCAP_MPDUDENSITY_8;
+ break;
+ case 1600:
+ *value = IEEE80211_HTCAP_MPDUDENSITY_16;
+ break;
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+ break;
+ case IEEE80211_IOC_AMPDU_LIMIT:
+ switch (sval) {
+ case 8192:
+ *value = IEEE80211_HTCAP_MAXRXAMPDU_8K;
+ break;
+ case 16384:
+ *value = IEEE80211_HTCAP_MAXRXAMPDU_16K;
+ break;
+ case 32768:
+ *value = IEEE80211_HTCAP_MAXRXAMPDU_32K;
+ break;
+ case 65536:
+ *value = IEEE80211_HTCAP_MAXRXAMPDU_64K;
+ break;
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+ break;
+ case IEEE80211_IOC_AMSDU:
+ switch (sval) {
+ case WlanIfaceDot11nPduType_disabled:
+ break;
+ case WlanIfaceDot11nPduType_txOnly:
+ *value = 1;
+ break;
+ case WlanIfaceDot11nPduType_rxOnly:
+ *value = 2;
+ break;
+ case WlanIfaceDot11nPduType_txAndRx:
+ *value = 3;
+ break;
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+ break;
+ case IEEE80211_IOC_AMSDU_LIMIT:
+ if (sval == 3839 || sval == 0)
+ *value = IEEE80211_HTCAP_MAXAMSDU_3839;
+ else if (sval == 7935)
+ *value = IEEE80211_HTCAP_MAXAMSDU_7935;
+ else
+ return (SNMP_ERR_INCONS_VALUE);
+ break;
+ case IEEE80211_IOC_HTPROTMODE:
+ switch (sval) {
+ case wlanIfaceDot11nHTProtMode_rts:
+ *value = IEEE80211_PROTMODE_RTSCTS;
+ break;
+ case wlanIfaceDot11nHTProtMode_off:
+ break;
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+ break;
+ case IEEE80211_IOC_SHORTGI:
+ if (sval == TruthValue_true)
+ *value = IEEE80211_HTCAP_SHORTGI20 |
+ IEEE80211_HTCAP_SHORTGI40;
+ else if (sval != TruthValue_false)
+ return (SNMP_ERR_INCONS_VALUE);
+ break;
+ case IEEE80211_IOC_SMPS:
+ switch (sval) {
+ case wlanIfaceDot11nSMPSMode_disabled:
+ *value = IEEE80211_HTCAP_SMPS_OFF;
+ break;
+ case wlanIfaceDot11nSMPSMode_static:
+ *value = IEEE80211_HTCAP_SMPS_ENA;
+ break;
+ case wlanIfaceDot11nSMPSMode_dynamic:
+ *value = IEEE80211_HTCAP_SMPS_DYNAMIC;
+ break;
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+ break;
+ case IEEE80211_IOC_TDMA_SLOT:
+ if (sval < 0 || sval > WLAN_TDMA_MAXSLOTS) /* XXX */
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ case IEEE80211_IOC_TDMA_SLOTCNT:
+ if (sval < 0 || sval > WLAN_TDMA_MAXSLOTS) /* XXX */
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ case IEEE80211_IOC_TDMA_SLOTLEN:
+ if (sval < 2*100 || sval > 0xfffff) /* XXX */
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ case IEEE80211_IOC_TDMA_BINTERVAL:
+ if (sval < 1) /* XXX */
+ return (SNMP_ERR_INCONS_VALUE);
+ *value = sval;
+ break;
+ default:
+ return (SNMP_ERR_INCONS_VALUE);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Sanity checks for the wlanIfaceConfigTable.
+ */
+static int
+wlan_config_check(struct wlan_iface *wif, int op)
+{
+ switch (op) {
+ case IEEE80211_IOC_BURST:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_burst)) == 0) {
+ wif->packet_burst = TruthValue_false;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_DFS:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_dfs)) == 0) {
+ wif->dyn_frequency = TruthValue_false;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_FF:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_athFastFrames))
+ == 0) {
+ wif->fast_frames = TruthValue_false;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_TURBOP:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_athTurbo)) == 0) {
+ wif->dturbo = TruthValue_false;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_TXPOWER:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_txPmgt)) == 0) {
+ wif->tx_power = 0;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_FRAGTHRESHOLD:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_txFrag)) == 0) {
+ wif->frag_threshold = IEEE80211_FRAG_MAX;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_DWDS:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_wds)) == 0) {
+ wif->dynamic_wds = TruthValue_false;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_POWERSAVE:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_pmgt)) == 0) {
+ wif->power_save = TruthValue_false;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_BEACON_INTERVAL:
+ if (wif->mode != WlanIfaceOperatingModeType_hostAp &&
+ wif->mode != WlanIfaceOperatingModeType_meshPoint &&
+ wif->mode != WlanIfaceOperatingModeType_ibss) {
+ wif->beacon_interval = 100; /* XXX */
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_DTIM_PERIOD:
+ if (wif->mode != WlanIfaceOperatingModeType_hostAp &&
+ wif->mode != WlanIfaceOperatingModeType_meshPoint &&
+ wif->mode != WlanIfaceOperatingModeType_ibss) {
+ wif->dtim_period = 1; /* XXX */
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_PUREN:
+ if ((wif->htcaps & (0x1 << WlanHTCaps_htcHt)) == 0) {
+ wif->dot11n_pure = TruthValue_false;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_AMPDU:
+ if ((wif->htcaps & (0x1 << WlanHTCaps_htcAmpdu)) == 0) {
+ wif->ampdu = WlanIfaceDot11nPduType_disabled;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_AMSDU:
+ if ((wif->htcaps & (0x1 << WlanHTCaps_htcAmsdu)) == 0) {
+ wif->amsdu = WlanIfaceDot11nPduType_disabled;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_RIFS:
+ if ((wif->htcaps & (0x1 << WlanHTCaps_htcRifs)) == 0) {
+ wif->rifs = TruthValue_false;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_SHORTGI:
+ if ((wif->htcaps & (0x1 << WlanHTCaps_shortGi20 |
+ 0x1 << WlanHTCaps_shortGi40)) == 0) {
+ wif->short_gi = TruthValue_false;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_SMPS:
+ if ((wif->htcaps & (0x1 << WlanHTCaps_htcSmps)) == 0) {
+ wif->smps_mode = wlanIfaceDot11nSMPSMode_disabled;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_TDMA_SLOT:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) {
+ wif->tdma_slot = 0;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_TDMA_SLOTCNT:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) {
+ wif->tdma_slot_count = 0;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_TDMA_SLOTLEN:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) {
+ wif->tdma_slot_length = 0;
+ return (-1);
+ }
+ break;
+ case IEEE80211_IOC_TDMA_BINTERVAL:
+ if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) {
+ wif->tdma_binterval = 0;
+ return (-1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static int
+wlan_config_get_intval(struct wlan_iface *wif, int op)
+{
+ int val = 0;
+ size_t argsize = 0;
+
+ if (wlan_config_check(wif, op) < 0)
+ return (0);
+ if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 0) < 0)
+ return (-1);
+ wlan_config_set_snmp_intval(wif, op, val);
+
+ return (0);
+}
+
+static int
+wlan_config_set_intval(struct wlan_iface *wif, int op, int sval)
+{
+ size_t argsize = 0;
+ int val;
+
+ if (wlan_config_check(wif, op) < 0)
+ return (-1);
+ if (wlan_config_snmp2value(op, sval, &val) != SNMP_ERR_NOERROR)
+ return (-1);
+ if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 1) < 0)
+ return (-1);
+ wlan_config_set_snmp_intval(wif, op, val);
+
+ return (0);
+}
+
+int
+wlan_config_get_ioctl(struct wlan_iface *wif, int which)
+{
+ int op;
+
+ switch (which) {
+ case LEAF_wlanIfaceCountryCode:
+ /* FALLTHROUGH */
+ case LEAF_wlanIfaceRegDomain:
+ return (wlan_config_get_country(wif));
+ case LEAF_wlanIfaceDesiredSsid:
+ return (wlan_config_get_dssid(wif));
+ case LEAF_wlanIfaceDesiredChannel:
+ return (wlan_config_get_dchannel(wif));
+ case LEAF_wlanIfaceDesiredBssid:
+ return (wlan_config_get_bssid(wif));
+ default:
+ op = wlan_config_snmp2ioctl(which);
+ return (wlan_config_get_intval(wif, op));
+ }
+
+ return (-1);
+}
+
+int
+wlan_config_set_ioctl(struct wlan_iface *wif, int which, int val,
+ char *strval, int len)
+{
+ int op;
+
+ switch (which) {
+ case LEAF_wlanIfaceCountryCode:
+ return (wlan_config_set_country(wif, strval,
+ wif->reg_domain));
+ case LEAF_wlanIfaceRegDomain:
+ return (wlan_config_set_country(wif, wif->country_code,
+ val));
+ case LEAF_wlanIfaceDesiredSsid:
+ return (wlan_config_set_dssid(wif, strval, len));
+ case LEAF_wlanIfaceDesiredChannel:
+ return (wlan_config_set_dchannel(wif, val));
+ case LEAF_wlanIfaceDesiredBssid:
+ return (wlan_config_set_bssid(wif, strval));
+ default:
+ op = wlan_config_snmp2ioctl(which);
+ return (wlan_config_set_intval(wif, op, val));
+ }
+
+ return (-1);
+}
+
+static uint32_t
+wlan_snmp_to_scan_flags(int flags)
+{
+ int sr_flags = 0;
+
+ if ((flags & (0x1 << WlanScanFlagsType_noSelection)) != 0)
+ sr_flags |= IEEE80211_IOC_SCAN_NOPICK;
+ if ((flags & (0x1 << WlanScanFlagsType_activeScan)) != 0)
+ sr_flags |= IEEE80211_IOC_SCAN_ACTIVE;
+ if ((flags & (0x1 << WlanScanFlagsType_pickFirst)) != 0)
+ sr_flags |= IEEE80211_IOC_SCAN_PICK1ST;
+ if ((flags & (0x1 << WlanScanFlagsType_backgroundScan)) != 0)
+ sr_flags |= IEEE80211_IOC_SCAN_BGSCAN;
+ if ((flags & (0x1 << WlanScanFlagsType_once)) != 0)
+ sr_flags |= IEEE80211_IOC_SCAN_ONCE;
+ if ((flags & (0x1 << WlanScanFlagsType_noBroadcast)) != 0)
+ sr_flags |= IEEE80211_IOC_SCAN_NOBCAST;
+ if ((flags & (0x1 << WlanScanFlagsType_noAutoSequencing)) != 0)
+ sr_flags |= IEEE80211_IOC_SCAN_NOJOIN;
+ if ((flags & (0x1 << WlanScanFlagsType_flushCashe)) != 0)
+ sr_flags |= IEEE80211_IOC_SCAN_FLUSH;
+ if ((flags & (0x1 << WlanScanFlagsType_chechCashe)) != 0)
+ sr_flags |= IEEE80211_IOC_SCAN_CHECK;
+
+ return (sr_flags);
+}
+
+int
+wlan_set_scan_config(struct wlan_iface *wif)
+{
+ int val = 0;
+ size_t argsize;
+ struct ieee80211_scan_req sr;
+
+
+ memset(&sr, 0, sizeof(sr));
+ argsize = sizeof(struct ieee80211_scan_req);
+ sr.sr_flags = wlan_snmp_to_scan_flags(wif->scan_flags);
+ sr.sr_flags |= IEEE80211_IOC_SCAN_BGSCAN;
+ sr.sr_duration = wif->scan_duration;
+ sr.sr_mindwell = wif->scan_mindwell;
+ sr.sr_maxdwell = wif->scan_maxdwell;
+ sr.sr_nssid = 0;
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_SCAN_REQ,
+ &val, &sr, &argsize, 1) < 0)
+ return (-1);
+
+ wif->scan_status = wlanScanConfigStatus_running;
+ return (0);
+}
+
+static uint32_t
+wlan_peercaps_to_snmp(uint32_t pcaps)
+{
+ uint32_t scaps = 0;
+
+ if ((pcaps & IEEE80211_CAPINFO_ESS) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_ess);
+ if ((pcaps & IEEE80211_CAPINFO_IBSS) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_ibss);
+ if ((pcaps & IEEE80211_CAPINFO_CF_POLLABLE) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_cfPollable);
+ if ((pcaps & IEEE80211_CAPINFO_CF_POLLREQ) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_cfPollRequest);
+ if ((pcaps & IEEE80211_CAPINFO_PRIVACY) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_privacy);
+ if ((pcaps & IEEE80211_CAPINFO_SHORT_PREAMBLE) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_shortPreamble);
+ if ((pcaps & IEEE80211_CAPINFO_PBCC) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_pbcc);
+ if ((pcaps & IEEE80211_CAPINFO_CHNL_AGILITY) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_channelAgility);
+ if ((pcaps & IEEE80211_CAPINFO_SHORT_SLOTTIME) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_shortSlotTime);
+ if ((pcaps & IEEE80211_CAPINFO_RSN) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_rsn);
+ if ((pcaps & IEEE80211_CAPINFO_DSSSOFDM) != 0)
+ scaps |= (0x1 << WlanPeerCapabilityFlags_dsssofdm);
+
+ return (scaps);
+}
+
+static int
+wlan_add_new_scan_result(struct wlan_iface *wif,
+ const struct ieee80211req_scan_result *isr, uint8_t *ssid)
+{
+ struct wlan_scan_result *sr;
+
+ if ((sr = wlan_scan_new_result(ssid, isr->isr_bssid)) == NULL)
+ return (-1);
+
+ sr->opchannel = wlan_channel_flags_to_snmp_phy(isr->isr_flags);
+ sr->rssi = isr->isr_rssi;
+ sr->frequency = isr->isr_freq;
+ sr->noise = isr->isr_noise;
+ sr->bintval = isr->isr_intval;
+ sr->capinfo = wlan_peercaps_to_snmp(isr->isr_capinfo);
+
+ if (wlan_scan_add_result(wif, sr) < 0) {
+ wlan_scan_free_result(sr);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+wlan_get_scan_results(struct wlan_iface *wif)
+{
+ int ssidlen, val = 0;
+ uint8_t buf[24 * 1024];
+ size_t argsize;
+ const uint8_t *cp, *idp;
+ uint8_t ssid[IEEE80211_NWID_LEN + 1];
+ struct ieee80211req_scan_result isr;
+
+ argsize = sizeof(buf);
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_SCAN_RESULTS, &val, &buf,
+ &argsize, 0) < 0)
+ return (-1);
+
+ if (argsize < sizeof(struct ieee80211req_scan_result))
+ return (0);
+
+ cp = buf;
+ do {
+ memcpy(&isr, cp, sizeof(struct ieee80211req_scan_result));
+ memset(ssid, 0, IEEE80211_NWID_LEN + 1);
+
+ if (isr.isr_meshid_len) {
+ idp = cp + isr.isr_ie_off + isr.isr_ssid_len;
+ ssidlen = isr.isr_meshid_len;
+ } else {
+ idp = cp + isr.isr_ie_off;
+ ssidlen = isr.isr_ssid_len;
+ }
+ if (ssidlen > IEEE80211_NWID_LEN)
+ ssidlen = IEEE80211_NWID_LEN;
+ memcpy(ssid, idp, ssidlen);
+ ssid[IEEE80211_NWID_LEN] = '\0';
+ (void)wlan_add_new_scan_result(wif, &isr, ssid);
+ cp += isr.isr_len;
+ argsize -= isr.isr_len;
+ } while (argsize >= sizeof(struct ieee80211req_scan_result));
+
+ return (0);
+}
+
+int
+wlan_get_stats(struct wlan_iface *wif)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ strlcpy(ifr.ifr_name, wif->wname, IFNAMSIZ);
+
+ ifr.ifr_data = (caddr_t) &wif->stats;
+
+ if (ioctl(sock, SIOCG80211STATS, &ifr) < 0) {
+ syslog(LOG_ERR, "iface %s - ioctl(SIOCG80211STATS) failed: %s",
+ wif->wname, strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+wlan_get_wepmode(struct wlan_iface *wif)
+{
+ int val = 0;
+ size_t argsize = 0;
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEP, &val, NULL,
+ &argsize, 0) < 0 || val == IEEE80211_WEP_NOSUP) {
+ wif->wepsupported = 0; /* XXX */
+ wif->wepmode = wlanWepMode_off;
+ wif->weptxkey = 0;
+ return (-1);
+ }
+
+ wif->wepsupported = 1;
+
+ switch (val) {
+ case IEEE80211_WEP_ON:
+ wif->wepmode = wlanWepMode_on;
+ break;
+ case IEEE80211_WEP_MIXED:
+ wif->wepmode = wlanWepMode_mixed;
+ break;
+ case IEEE80211_WEP_OFF:
+ /* FALLTHROUGH */
+ default:
+ wif->wepmode = wlanWepMode_off;
+ break;
+ }
+
+ return (0);
+}
+
+int
+wlan_set_wepmode(struct wlan_iface *wif)
+{
+ int val;
+ size_t argsize = 0;
+
+ if (!wif->wepsupported)
+ return (-1);
+
+ switch (wif->wepmode) {
+ case wlanWepMode_off:
+ val = IEEE80211_WEP_OFF;
+ break;
+ case wlanWepMode_on:
+ val = IEEE80211_WEP_ON;
+ break;
+ case wlanWepMode_mixed:
+ val = IEEE80211_WEP_MIXED;
+ break;
+ default:
+ return (-1);
+ }
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEP, &val, NULL,
+ &argsize, 1) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+wlan_get_weptxkey(struct wlan_iface *wif)
+{
+ int val;
+ size_t argsize = 0;
+
+ if (!wif->wepsupported)
+ return (0);
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEPTXKEY, &val, NULL,
+ &argsize, 0) < 0)
+ return (-1);
+
+ if (val == IEEE80211_KEYIX_NONE)
+ wif->weptxkey = 0;
+ else
+ wif->weptxkey = val + 1;
+
+ return (0);
+}
+
+int
+wlan_set_weptxkey(struct wlan_iface *wif)
+{
+ int val;
+ size_t argsize = 0;
+
+ if (!wif->wepsupported)
+ return (0);
+
+ if (wif->weptxkey >= IEEE80211_WEP_NKID)
+ return (-1);
+
+ if (wif->weptxkey == 0)
+ val = IEEE80211_KEYIX_NONE;
+ else
+ val = wif->weptxkey - 1;
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEPTXKEY, &val, NULL,
+ &argsize, 1) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+wlan_get_wepkeys(struct wlan_iface *wif __unused)
+{
+ /* XXX: should they be visible via SNMP */
+ return (0);
+}
+
+int
+wlan_set_wepkeys(struct wlan_iface *wif __unused)
+{
+ /* XXX: should they be configurable via SNMP */
+ return (0);
+}
+
+int
+wlan_get_mac_policy(struct wlan_iface *wif)
+{
+ int val = IEEE80211_MACCMD_POLICY;
+ size_t argsize = 0;
+ struct ieee80211req ireq;
+
+ memset(&ireq, 0, sizeof(struct ieee80211req));
+ strlcpy(ireq.i_name, wif->wname, IFNAMSIZ);
+ ireq.i_type = IEEE80211_IOC_MACCMD;
+ ireq.i_val = IEEE80211_MACCMD_POLICY;
+
+ if (ioctl(sock, SIOCG80211, &ireq) < 0) {
+ if (errno != EINVAL) {
+ syslog(LOG_ERR, "iface %s - get param: ioctl(%d) "
+ "failed: %s", wif->wname, ireq.i_type,
+ strerror(errno));
+ wif->macsupported = 0;
+ return (-1);
+ } else {
+ wif->macsupported = 1;
+ wif->mac_policy = wlanMACAccessControlPolicy_open;
+ return (0);
+ }
+
+ }
+
+ wif->macsupported = 1;
+
+ switch (val) {
+ case IEEE80211_MACCMD_POLICY_ALLOW:
+ wif->mac_policy = wlanMACAccessControlPolicy_allow;
+ break;
+ case IEEE80211_MACCMD_POLICY_DENY:
+ wif->mac_policy = wlanMACAccessControlPolicy_deny;
+ break;
+ case IEEE80211_MACCMD_POLICY_RADIUS:
+ wif->mac_policy = wlanMACAccessControlPolicy_radius;
+ break;
+ case IEEE80211_MACCMD_POLICY_OPEN:
+ /* FALLTHROUGH */
+ default:
+ wif->mac_policy = wlanMACAccessControlPolicy_open;
+ break;
+ }
+
+ argsize = 0;
+ val = IEEE80211_MACCMD_LIST;
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, NULL,
+ &argsize, 0) < 0)
+ return (-1);
+
+ wif->mac_nacls = argsize / sizeof(struct ieee80211req_maclist *);
+ return (0);
+}
+
+int
+wlan_set_mac_policy(struct wlan_iface *wif)
+{
+ int val;
+ size_t argsize = 0;
+
+ if (!wif->macsupported)
+ return (-1);
+
+ switch (wif->mac_policy) {
+ case wlanMACAccessControlPolicy_allow:
+ val = IEEE80211_MACCMD_POLICY_ALLOW;
+ break;
+ case wlanMACAccessControlPolicy_deny:
+ val = IEEE80211_MACCMD_POLICY_DENY;
+ break;
+ case wlanMACAccessControlPolicy_radius:
+ val = IEEE80211_MACCMD_POLICY_RADIUS;
+ break;
+ case wlanMACAccessControlPolicy_open:
+ val = IEEE80211_MACCMD_POLICY_OPEN;
+ break;
+ default:
+ return (-1);
+ }
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, NULL,
+ &argsize, 1) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+wlan_flush_mac_mac(struct wlan_iface *wif)
+{
+ int val = IEEE80211_MACCMD_FLUSH;
+ size_t argsize = 0;
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, NULL,
+ &argsize, 1) < 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+wlan_add_mac_macinfo(struct wlan_iface *wif,
+ const struct ieee80211req_maclist *ml)
+{
+ struct wlan_mac_mac *mmac;
+
+ if ((mmac = wlan_mac_new_mac(ml->ml_macaddr)) == NULL)
+ return (-1);
+
+ mmac->mac_status = RowStatus_active;
+ if (wlan_mac_add_mac(wif, mmac) < 0) {
+ wlan_mac_free_mac(mmac);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+wlan_get_mac_acl_macs(struct wlan_iface *wif)
+{
+ int i, nacls, val = IEEE80211_MACCMD_LIST;
+ size_t argsize = 0;
+ uint8_t *data;
+ struct ieee80211req ireq;
+ const struct ieee80211req_maclist *acllist;
+
+ if (wif->mac_policy == wlanMACAccessControlPolicy_radius) {
+ wif->mac_nacls = 0;
+ return (0);
+ }
+
+ memset(&ireq, 0, sizeof(struct ieee80211req));
+ strlcpy(ireq.i_name, wif->wname, IFNAMSIZ);
+ ireq.i_type = IEEE80211_IOC_MACCMD;
+ ireq.i_val = IEEE80211_MACCMD_LIST;
+
+
+ if (ioctl(sock, SIOCG80211, &ireq) < 0) {
+ if (errno != EINVAL) {
+ syslog(LOG_ERR, "iface %s - get param: ioctl(%d) "
+ "failed: %s", wif->wname, ireq.i_type,
+ strerror(errno));
+ wif->macsupported = 0;
+ return (-1);
+ }
+ }
+
+ if (argsize == 0) {
+ wif->mac_nacls = 0;
+ return (0);
+ }
+
+ if ((data = (uint8_t *)malloc(argsize)) == NULL)
+ return (-1);
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, data,
+ &argsize, 0) < 0)
+ return (-1);
+
+ nacls = argsize / sizeof(*acllist);
+ acllist = (struct ieee80211req_maclist *) data;
+ for (i = 0; i < nacls; i++)
+ (void)wlan_add_mac_macinfo(wif, acllist + i);
+
+ wif->mac_nacls = nacls;
+ return (0);
+}
+
+int
+wlan_add_mac_acl_mac(struct wlan_iface *wif, struct wlan_mac_mac *mmac)
+{
+ int val = 0;
+ size_t argsize = IEEE80211_ADDR_LEN;
+ struct ieee80211req_mlme mlme;
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_ADDMAC, &val,
+ mmac->mac, &argsize, 1) < 0)
+ return (-1);
+
+ mmac->mac_status = RowStatus_active;
+
+ /* If policy is deny, try to kick the station just in case. */
+ if (wif->mac_policy != wlanMACAccessControlPolicy_deny)
+ return (0);
+
+ memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
+ memcpy(mlme.im_macaddr, mmac->mac, IEEE80211_ADDR_LEN);
+ argsize = sizeof(struct ieee80211req_mlme);
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_MLME, &val, &mlme,
+ &argsize, 1) < 0 && errno != ENOENT)
+ return (-1);
+
+ return (0);
+}
+
+int
+wlan_del_mac_acl_mac(struct wlan_iface *wif, struct wlan_mac_mac *mmac)
+{
+ int val = 0;
+ size_t argsize = IEEE80211_ADDR_LEN;
+ struct ieee80211req_mlme mlme;
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_DELMAC, &val,
+ mmac->mac, &argsize, 1) < 0)
+ return (-1);
+
+ mmac->mac_status = RowStatus_active;
+
+ /* If policy is allow, try to kick the station just in case. */
+ if (wif->mac_policy != wlanMACAccessControlPolicy_allow)
+ return (0);
+
+ memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
+ memcpy(mlme.im_macaddr, mmac->mac, IEEE80211_ADDR_LEN);
+ argsize = sizeof(struct ieee80211req_mlme);
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_MLME, &val, &mlme,
+ &argsize, 1) < 0 && errno != ENOENT)
+ return (-1);
+
+ return (0);
+}
+
+int
+wlan_peer_set_vlan(struct wlan_iface *wif, struct wlan_peer *wip, int vlan)
+{
+ int val = 0;
+ size_t argsize;
+ struct ieee80211req_sta_vlan vreq;
+
+ memcpy(vreq.sv_macaddr, wip->pmac, IEEE80211_ADDR_LEN);
+ vreq.sv_vlan = vlan;
+ argsize = sizeof(struct ieee80211req_sta_vlan);
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_STA_VLAN,
+ &val, &vreq, &argsize, 1) < 0)
+ return (-1);
+
+ wip->vlan = vlan;
+
+ return (0);
+}
+
+/* XXX */
+#ifndef IEEE80211_NODE_AUTH
+#define IEEE80211_NODE_AUTH 0x000001 /* authorized for data */
+#define IEEE80211_NODE_QOS 0x000002 /* QoS enabled */
+#define IEEE80211_NODE_ERP 0x000004 /* ERP enabled */
+#define IEEE80211_NODE_PWR_MGT 0x000010 /* power save mode enabled */
+#define IEEE80211_NODE_AREF 0x000020 /* authentication ref held */
+#define IEEE80211_NODE_HT 0x000040 /* HT enabled */
+#define IEEE80211_NODE_HTCOMPAT 0x000080 /* HT setup w/ vendor OUI's */
+#define IEEE80211_NODE_WPS 0x000100 /* WPS association */
+#define IEEE80211_NODE_TSN 0x000200 /* TSN association */
+#define IEEE80211_NODE_AMPDU_RX 0x000400 /* AMPDU rx enabled */
+#define IEEE80211_NODE_AMPDU_TX 0x000800 /* AMPDU tx enabled */
+#define IEEE80211_NODE_MIMO_PS 0x001000 /* MIMO power save enabled */
+#define IEEE80211_NODE_MIMO_RTS 0x002000 /* send RTS in MIMO PS */
+#define IEEE80211_NODE_RIFS 0x004000 /* RIFS enabled */
+#define IEEE80211_NODE_SGI20 0x008000 /* Short GI in HT20 enabled */
+#define IEEE80211_NODE_SGI40 0x010000 /* Short GI in HT40 enabled */
+#define IEEE80211_NODE_ASSOCID 0x020000 /* xmit requires associd */
+#define IEEE80211_NODE_AMSDU_RX 0x040000 /* AMSDU rx enabled */
+#define IEEE80211_NODE_AMSDU_TX 0x080000 /* AMSDU tx enabled */
+#endif
+
+static uint32_t
+wlan_peerstate_to_snmp(uint32_t pstate)
+{
+ uint32_t sstate = 0;
+
+ if ((pstate & IEEE80211_NODE_AUTH) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_authorizedForData);
+ if ((pstate & IEEE80211_NODE_QOS) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_qosEnabled);
+ if ((pstate & IEEE80211_NODE_ERP) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_erpEnabled);
+ if ((pstate & IEEE80211_NODE_PWR_MGT) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_powerSaveMode);
+ if ((pstate & IEEE80211_NODE_AREF) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_authRefHeld);
+ if ((pstate & IEEE80211_NODE_HT) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_htEnabled);
+ if ((pstate & IEEE80211_NODE_HTCOMPAT) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_htCompat);
+ if ((pstate & IEEE80211_NODE_WPS) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_wpsAssoc);
+ if ((pstate & IEEE80211_NODE_TSN) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_tsnAssoc);
+ if ((pstate & IEEE80211_NODE_AMPDU_RX) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_ampduRx);
+ if ((pstate & IEEE80211_NODE_AMPDU_TX) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_ampduTx);
+ if ((pstate & IEEE80211_NODE_MIMO_PS) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_mimoPowerSave);
+ if ((pstate & IEEE80211_NODE_MIMO_RTS) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_sendRts);
+ if ((pstate & IEEE80211_NODE_RIFS) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_rifs);
+ if ((pstate & IEEE80211_NODE_SGI20) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_shortGiHT20);
+ if ((pstate & IEEE80211_NODE_SGI40) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_shortGiHT40);
+ if ((pstate & IEEE80211_NODE_AMSDU_RX) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_amsduRx);
+ if ((pstate & IEEE80211_NODE_AMSDU_TX) != 0)
+ sstate |= (0x1 << WlanIfacePeerFlagsType_amsduTx);
+
+ return (sstate);
+}
+
+static struct wlan_peer *
+wlan_add_peerinfo(const struct ieee80211req_sta_info *si)
+{
+ struct wlan_peer *wip;
+
+ if ((wip = wlan_new_peer(si->isi_macaddr))== NULL)
+ return (NULL);
+
+ wip->associd = IEEE80211_AID(si->isi_associd);
+ wip->vlan = si->isi_vlan;
+ wip->frequency = si->isi_freq;
+ wip->fflags = si->isi_flags;
+ wip->txrate = si->isi_txrate;
+ wip->rssi = si->isi_rssi;
+ wip->idle = si->isi_inact;
+ wip->txseqs = si->isi_txseqs[0]; /* XXX */
+ wip->rxseqs = si->isi_rxseqs[0]; /* XXX */
+ wip->txpower = si->isi_txpower;
+ wip->capinfo = wlan_peercaps_to_snmp(si->isi_capinfo);
+ wip->state = wlan_peerstate_to_snmp(si->isi_state);
+ wip->local_id = si->isi_localid;
+ wip->peer_id = si->isi_peerid;
+
+ return (wip);
+}
+
+int
+wlan_get_peerinfo(struct wlan_iface *wif)
+{
+ union {
+ struct ieee80211req_sta_req req;
+ uint8_t buf[24 * 1024];
+ } u;
+ const uint8_t *cp;
+ int val = 0;
+ size_t len;
+ struct ieee80211req_sta_info si;
+ struct wlan_peer *wip;
+
+ /* Get all stations - broadcast address */
+ (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
+ len = sizeof(u);
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_STA_INFO,
+ & val, &u, &len, 0) < 0)
+ return (-1);
+
+ if (len < sizeof(struct ieee80211req_sta_info))
+ return (-1);
+
+ cp = (const uint8_t *) u.req.info;
+ do {
+ memcpy(&si, cp, sizeof(struct ieee80211req_sta_info));
+ if ((wip = wlan_add_peerinfo(&si)) != NULL &&
+ wlan_add_peer(wif, wip) < 0)
+ wlan_free_peer(wip);
+ cp += si.isi_len, len -= si.isi_len;
+ } while (len >= sizeof(struct ieee80211req_sta_info));
+
+ return (0);
+}
+
+/************************************************************************
+ * Wireless MESH & HWMP sysctl config.
+ */
+const char wlan_sysctl_name[] = "net.wlan.";
+
+static const char *wlan_sysctl[] = {
+ "mesh.retrytimeout",
+ "mesh.holdingtimeout",
+ "mesh.confirmtimeout",
+ "mesh.maxretries",
+ "hwmp.targetonly",
+ "hwmp.replyforward",
+ "hwmp.pathlifetime",
+ "hwmp.roottimeout",
+ "hwmp.rootint",
+ "hwmp.rannint",
+ "hwmp.inact",
+};
+
+int32_t
+wlan_do_sysctl(struct wlan_config *cfg, enum wlan_syscl which, int set)
+{
+ char mib_name[100];
+ int val, sval;
+ size_t len, vlen;
+
+ if (set) {
+ vlen = sizeof(sval);
+ switch (which) {
+ case WLAN_MESH_RETRY_TO:
+ sval = cfg->mesh_retryto;
+ break;
+ case WLAN_MESH_HOLDING_TO:
+ sval = cfg->mesh_holdingto;
+ break;
+ case WLAN_MESH_CONFIRM_TO:
+ sval = cfg->mesh_confirmto;
+ break;
+ case WLAN_MESH_MAX_RETRIES:
+ sval = cfg->mesh_maxretries;
+ break;
+ case WLAN_HWMP_TARGET_ONLY:
+ sval = cfg->hwmp_targetonly;
+ break;
+ case WLAN_HWMP_REPLY_FORWARD:
+ sval = cfg->hwmp_replyforward;
+ break;
+ case WLAN_HWMP_PATH_LIFETIME:
+ sval = cfg->hwmp_pathlifetime;
+ break;
+ case WLAN_HWMP_ROOT_TO:
+ sval = cfg->hwmp_roottimeout;
+ break;
+ case WLAN_HWMP_ROOT_INT:
+ sval = cfg->hwmp_rootint;
+ break;
+ case WLAN_HWMP_RANN_INT:
+ sval = cfg->hwmp_rannint;
+ break;
+ case WLAN_HWMP_INACTIVITY_TO:
+ sval = cfg->hwmp_inact;
+ break;
+ default:
+ return (-1);
+ }
+ } else {
+ if (which >= WLAN_SYSCTL_MAX)
+ return (-1);
+ vlen = 0;
+ }
+
+ strlcpy(mib_name, wlan_sysctl_name, sizeof(mib_name));
+ strlcat(mib_name, wlan_sysctl[which], sizeof(mib_name));
+ len = sizeof (val);
+
+ if (sysctlbyname(mib_name, &val, &len, (set? &sval : NULL), vlen) < 0) {
+ syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_name,
+ strerror(errno));
+ return (-1);
+ }
+
+ switch (which) {
+ case WLAN_MESH_RETRY_TO:
+ cfg->mesh_retryto = val;
+ break;
+ case WLAN_MESH_HOLDING_TO:
+ cfg->mesh_holdingto = val;
+ break;
+ case WLAN_MESH_CONFIRM_TO:
+ cfg->mesh_confirmto = val;
+ break;
+ case WLAN_MESH_MAX_RETRIES:
+ cfg->mesh_maxretries = val;
+ break;
+ case WLAN_HWMP_TARGET_ONLY:
+ cfg->hwmp_targetonly = val;
+ break;
+ case WLAN_HWMP_REPLY_FORWARD:
+ cfg->hwmp_replyforward = val;
+ break;
+ case WLAN_HWMP_PATH_LIFETIME:
+ cfg->hwmp_pathlifetime = val;
+ break;
+ case WLAN_HWMP_ROOT_TO:
+ cfg->hwmp_roottimeout = val;
+ break;
+ case WLAN_HWMP_ROOT_INT:
+ cfg->hwmp_rootint = val;
+ break;
+ case WLAN_HWMP_RANN_INT:
+ cfg->hwmp_rannint = val;
+ break;
+ case WLAN_HWMP_INACTIVITY_TO:
+ cfg->hwmp_inact = val;
+ break;
+ default:
+ /* NOTREACHED */
+ abort();
+ }
+
+ return (0);
+}
+
+int
+wlan_mesh_config_get(struct wlan_iface *wif, int which)
+{
+ int op, val = 0;
+ size_t argsize = 0;
+ uint8_t data[32], *pd = NULL;
+
+ switch (which) {
+ case LEAF_wlanMeshTTL:
+ op = IEEE80211_IOC_MESH_TTL;
+ break;
+ case LEAF_wlanMeshPeeringEnabled:
+ op = IEEE80211_IOC_MESH_AP;
+ break;
+ case LEAF_wlanMeshForwardingEnabled:
+ op = IEEE80211_IOC_MESH_FWRD;
+ break;
+ case LEAF_wlanMeshMetric:
+ op = IEEE80211_IOC_MESH_PR_METRIC;
+ pd = data;
+ argsize = sizeof(data);
+ break;
+ case LEAF_wlanMeshPath:
+ op = IEEE80211_IOC_MESH_PR_PATH;
+ pd = data;
+ argsize = sizeof(data);
+ break;
+ case LEAF_wlanMeshRoutesFlush:
+ return (0);
+ default:
+ return (-1);
+ }
+
+ if (wlan_ioctl(wif->wname, op, &val, pd, &argsize, 0) < 0)
+ return (-1);
+
+ switch (which) {
+ case LEAF_wlanMeshTTL:
+ wif->mesh_ttl = val;
+ break;
+ case LEAF_wlanMeshPeeringEnabled:
+ if (val)
+ wif->mesh_peering = wlanMeshPeeringEnabled_true;
+ else
+ wif->mesh_peering = wlanMeshPeeringEnabled_false;
+ break;
+ case LEAF_wlanMeshForwardingEnabled:
+ if (val)
+ wif->mesh_forwarding = wlanMeshForwardingEnabled_true;
+ else
+ wif->mesh_forwarding = wlanMeshForwardingEnabled_false;
+ break;
+ case LEAF_wlanMeshMetric:
+ data[argsize] = '\0';
+ if (strcmp(data, "AIRTIME") == 0)
+ wif->mesh_metric = wlanMeshMetric_airtime;
+ else
+ wif->mesh_metric = wlanMeshMetric_unknown;
+ break;
+ case LEAF_wlanMeshPath:
+ data[argsize] = '\0';
+ if (strcmp(data, "HWMP") == 0)
+ wif->mesh_path = wlanMeshPath_hwmp;
+ else
+ wif->mesh_path = wlanMeshPath_unknown;
+ }
+
+ return (0);
+}
+
+int
+wlan_mesh_config_set(struct wlan_iface *wif, int which)
+{
+ int op, val = 0;
+ size_t argsize = 0;
+ uint8_t data[32], *pd = NULL;
+
+ switch (which) {
+ case LEAF_wlanMeshTTL:
+ op = IEEE80211_IOC_MESH_TTL;
+ val = wif->mesh_ttl;
+ break;
+ case LEAF_wlanMeshPeeringEnabled:
+ op = IEEE80211_IOC_MESH_AP;
+ if (wif->mesh_peering == wlanMeshPeeringEnabled_true)
+ val = 1;
+ break;
+ case LEAF_wlanMeshForwardingEnabled:
+ if (wif->mesh_forwarding == wlanMeshForwardingEnabled_true)
+ val = 1;
+ op = IEEE80211_IOC_MESH_FWRD;
+ break;
+ case LEAF_wlanMeshMetric:
+ op = IEEE80211_IOC_MESH_PR_METRIC;
+ if (wif->mesh_metric == wlanMeshMetric_airtime)
+ strcpy(data, "AIRTIME");
+ else
+ return (-1);
+ pd = data;
+ argsize = sizeof(data);
+ break;
+ case LEAF_wlanMeshPath:
+ op = IEEE80211_IOC_MESH_PR_PATH;
+ if (wif->mesh_path == wlanMeshPath_hwmp)
+ strcpy(data, "HWMP");
+ else
+ return (-1);
+ pd = data;
+ argsize = sizeof(data);
+ break;
+ default:
+ return (-1);
+ }
+
+ if (wlan_ioctl(wif->wname, op, &val, pd, &argsize, 1) < 0)
+ return (-1);
+
+ return(0);
+}
+
+int
+wlan_mesh_flush_routes(struct wlan_iface *wif)
+{
+ int val = IEEE80211_MESH_RTCMD_FLUSH;
+ size_t argsize = 0;
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val, NULL,
+ &argsize, 1) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+wlan_mesh_add_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr)
+{
+ int val = IEEE80211_MESH_RTCMD_ADD;
+ size_t argsize = IEEE80211_ADDR_LEN;
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val,
+ wmr->imroute.imr_dest, &argsize, 1) < 0)
+ return (-1);
+
+ wmr->mroute_status = RowStatus_active;
+
+ return (0);
+}
+
+int
+wlan_mesh_del_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr)
+{
+ int val = IEEE80211_MESH_RTCMD_DELETE;
+ size_t argsize = IEEE80211_ADDR_LEN;
+
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val,
+ wmr->imroute.imr_dest, &argsize, 1) < 0)
+ return (-1);
+
+ wmr->mroute_status = RowStatus_destroy;
+
+ return (0);
+}
+
+int
+wlan_mesh_get_routelist(struct wlan_iface *wif)
+{
+ int i, nroutes, val = IEEE80211_MESH_RTCMD_LIST;
+ size_t argsize;
+ struct ieee80211req_mesh_route routes[128];
+ struct ieee80211req_mesh_route *rt;
+ struct wlan_mesh_route *wmr;
+
+ argsize = sizeof(routes);
+ if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val, routes,
+ &argsize, 0) < 0) /* XXX: ENOMEM? */
+ return (-1);
+
+ nroutes = argsize / sizeof(*rt);
+ for (i = 0; i < nroutes; i++) {
+ rt = routes + i;
+ if ((wmr = wlan_mesh_new_route(rt->imr_dest)) == NULL)
+ return (-1);
+ memcpy(&wmr->imroute, rt, sizeof(*rt));
+ wmr->mroute_status = RowStatus_active;
+ if (wlan_mesh_add_rtentry(wif, wmr) < 0)
+ wlan_mesh_free_route(wmr);
+ }
+
+ return (0);
+}
+
+int
+wlan_hwmp_config_get(struct wlan_iface *wif, int which)
+{
+ int op, val = 0;
+ size_t argsize = 0;
+
+ switch (which) {
+ case LEAF_wlanHWMPRootMode:
+ op = IEEE80211_IOC_HWMP_ROOTMODE;
+ break;
+ case LEAF_wlanHWMPMaxHops:
+ op = IEEE80211_IOC_HWMP_MAXHOPS;
+ break;
+ default:
+ return (-1);
+ }
+
+ if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 0) < 0)
+ return (-1);
+
+ switch (which) {
+ case LEAF_wlanHWMPRootMode:
+ switch (val) {
+ case IEEE80211_HWMP_ROOTMODE_NORMAL:
+ wif->hwmp_root_mode = wlanHWMPRootMode_normal;
+ break;
+ case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
+ wif->hwmp_root_mode = wlanHWMPRootMode_proactive;
+ break;
+ case IEEE80211_HWMP_ROOTMODE_RANN:
+ wif->hwmp_root_mode = wlanHWMPRootMode_rann;
+ break;
+ case IEEE80211_HWMP_ROOTMODE_DISABLED:
+ default:
+ wif->hwmp_root_mode = wlanHWMPRootMode_disabled;
+ break;
+ }
+ break;
+ case LEAF_wlanHWMPMaxHops:
+ wif->hwmp_max_hops = val;
+ break;
+ }
+
+ return (0);
+}
+
+int
+wlan_hwmp_config_set(struct wlan_iface *wif, int which)
+{
+ int op, val = 0;
+ size_t argsize = 0;
+
+ switch (which) {
+ case LEAF_wlanHWMPRootMode:
+ op = IEEE80211_IOC_HWMP_ROOTMODE;
+ switch (wif->hwmp_root_mode) {
+ case wlanHWMPRootMode_disabled:
+ val = IEEE80211_HWMP_ROOTMODE_DISABLED;
+ break;
+ case wlanHWMPRootMode_normal:
+ val = IEEE80211_HWMP_ROOTMODE_NORMAL;
+ break;
+ case wlanHWMPRootMode_proactive:
+ val = IEEE80211_HWMP_ROOTMODE_PROACTIVE;
+ break;
+ case wlanHWMPRootMode_rann:
+ val = IEEE80211_HWMP_ROOTMODE_RANN;
+ break;
+ default:
+ return (-1);
+ }
+ break;
+ case LEAF_wlanHWMPMaxHops:
+ op = IEEE80211_IOC_HWMP_MAXHOPS;
+ val = wif->hwmp_max_hops;
+ break;
+ default:
+ return (-1);
+ }
+
+ if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 1) < 0)
+ return (-1);
+
+ return (0);
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_tree.def b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_tree.def
new file mode 100644
index 0000000..e0ae2a0
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_tree.def
@@ -0,0 +1,677 @@
+#-
+# Copyright (C) 2010 The FreeBSD Foundation
+# All rights reserved.
+#
+# This software was developed by Shteryana Sotirova Shopova under
+# sponsorship from the FreeBSD Foundation.
+#
+# 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$
+#
+
+#include "tc.def"
+
+typedef RowStatus ENUM (
+ 1 active
+ 2 notInService
+ 3 notReady
+ 4 createAndGo
+ 5 createAndWait
+ 6 destroy
+)
+
+typedef TruthValue ENUM (
+ 1 true
+ 2 false
+)
+
+typedef WlanRegDomainCode ENUM (
+ 1 fcc
+ 2 ca
+ 3 etsi
+ 4 etsi2
+ 5 etsi3
+ 6 fcc3
+ 7 japan
+ 8 korea
+ 9 apac
+ 10 apac2
+ 11 apac3
+ 12 row
+ 13 none
+ 14 debug
+ 15 sr9
+ 16 xr9
+ 17 gz901
+)
+
+typedef WlanMgmtReasonCode ENUM (
+ 1 unspecified
+ 2 authenticationExpire
+ 3 authenticationLeave
+ 4 associationExpire
+ 5 associationTooMany
+ 6 notAuthenticated
+ 7 notAssociated
+ 8 associationLeave
+ 9 associationNotAuthenticated
+ 10 dissassocPwrcapBad
+ 11 dissassocSuperchanBad
+ 13 ieInvalid
+ 14 micFailure
+ 15 fourWayHandshakeTimeout
+ 16 groupKeyUpdateTimeout
+ 17 ieIn4FourWayDiffers
+ 18 groupCipherInvalid
+ 19 pairwiseCiherInvalid
+ 20 akmpInvalid
+ 21 unsupportedRsnIeVersion
+ 22 invalidRsnIeCap
+ 23 dot1xAuthFailed
+ 24 cipherSuiteRejected
+ 32 unspeciffiedQos
+ 33 insufficientBw
+ 34 tooManyFrames
+ 35 outsideTxOp
+ 36 leavingQbss
+ 37 badMechanism
+ 38 setupNeeded
+ 39 timeout
+)
+
+typedef WlanIfaceOperatingModeType ENUM (
+ 0 ibss
+ 1 station
+ 2 wds
+ 3 adhocDemo
+ 4 hostAp
+ 5 monitor
+ 6 meshPoint
+ 7 tdma
+)
+
+typedef WlanIfaceFlagsType BITS (
+ 1 uniqueBssid
+ 2 noBeacons
+ 3 wdsLegacy
+)
+
+typedef WlanDriverCaps BITS (
+ 1 station
+ 2 ieee8023encap
+ 3 athFastFrames
+ 4 athTurbo
+ 5 ibss
+ 6 pmgt
+ 7 hostAp
+ 8 ahDemo
+ 9 swRetry
+ 10 txPmgt
+ 11 shortSlot
+ 12 shortPreamble
+ 13 monitor
+ 14 dfs
+ 15 mbss
+ 16 wpa1
+ 17 wpa2
+ 18 burst
+ 19 wme
+ 20 wds
+ 21 bgScan
+ 22 txFrag
+ 23 tdma
+)
+
+typedef WlanCryptoCaps BITS (
+ 1 wep
+ 2 tkip
+ 3 aes
+ 4 aesCcm
+ 5 tkipMic
+ 6 ckip
+)
+
+typedef WlanHTCaps BITS (
+ 1 ldpc
+ 2 chwidth40
+ 3 greenField
+ 4 shortGi20
+ 5 shortGi40
+ 6 txStbc
+ 7 delba
+ 8 amsdu7935
+ 9 dssscck40
+ 10 psmp
+ 11 fortyMHzIntolerant
+ 12 lsigTxOpProt
+ 13 htcAmpdu
+ 14 htcAmsdu
+ 15 htcHt
+ 16 htcSmps
+ 17 htcRifs
+)
+
+typedef WlanIfaceDot11nPduType ENUM (
+ 0 disabled
+ 1 rxOnly
+ 2 txOnly
+ 3 txAndRx
+)
+
+typedef WlanPeerCapabilityFlags BITS (
+ 1 ess
+ 2 ibss
+ 3 cfPollable
+ 4 cfPollRequest
+ 5 privacy
+ 6 shortPreamble
+ 7 pbcc
+ 8 channelAgility
+ 9 shortSlotTime
+ 10 rsn
+ 11 dsssofdm
+)
+
+typedef WlanIfacePeerFlagsType BITS (
+ 1 authorizedForData
+ 2 qosEnabled
+ 3 erpEnabled
+ 4 powerSaveMode
+ 5 authRefHeld
+ 6 htEnabled
+ 7 htCompat
+ 8 wpsAssoc
+ 9 tsnAssoc
+ 10 ampduRx
+ 11 ampduTx
+ 12 mimoPowerSave
+ 13 sendRts
+ 14 rifs
+ 15 shortGiHT20
+ 16 shortGiHT40
+ 17 amsduRx
+ 18 amsduTx
+)
+
+typedef WlanIfaceChannelFlagsType BITS (
+ 1 turbo
+ 2 cck
+ 3 ofdm
+ 4 spectrum2Ghz
+ 5 spectrum5Ghz
+ 6 passiveScan
+ 7 dynamicCckOfdm
+ 8 gfsk
+ 9 spectrum900Mhz
+ 10 dot11aStaticTurbo
+ 11 halfRate
+ 12 quarterRate
+ 13 ht20
+ 14 ht40u
+ 15 ht40d
+ 16 dfs
+ 17 xmit4ms
+ 18 noAdhoc
+ 19 noHostAp
+ 20 dot11d
+)
+
+typedef WlanIfaceChannelStateType BITS (
+ 1 radar
+ 2 cacDone
+ 3 interferenceDetected
+ 4 radarClear
+)
+
+typedef WlanIfPhyMode ENUM (
+ 1 auto
+ 2 dot11a
+ 3 dot11b
+ 4 dot11g
+ 5 fh
+ 6 turboA
+ 7 turboG
+ 8 sturboA
+ 9 dot11na
+ 10 dot11ng
+ 11 ofdmHalf
+ 12 ofdmQuarter
+)
+
+typedef WlanChannelType ENUM (
+ 1 fhss
+ 2 dot11a
+ 3 dot11b
+ 4 dot11g
+ 5 tenMHz
+ 6 fiveMHz
+ 7 turbo
+ 8 ht
+)
+
+typedef WlanScanFlagsType BITS (
+ 1 noSelection
+ 2 activeScan
+ 3 pickFirst
+ 4 backgroundScan
+ 5 once
+ 6 noBroadcast
+ 7 noAutoSequencing
+ 8 flushCashe
+ 9 chechCashe
+)
+
+typedef WlanMeshNeighborPeerStateType ENUM (
+ 0 idle
+ 1 openTx
+ 2 openRx
+ 3 confirmRx
+ 4 established
+ 5 closing
+)
+
+(1 internet
+ (4 private
+ (1 enterprises
+ (12325 fokus
+ (1 begemot
+ (210 begemotWlan
+ (0 begemotWlanNotifications
+ )
+ (1 begemotWlanInterface
+ (1 wlanInterfaceTable
+ (1 wlanInterfaceEntry : OCTETSTRING op_wlan_iface
+ (1 wlanIfaceIndex INTEGER GET)
+ (2 wlanIfaceName OCTETSTRING GET SET)
+ (3 wlanParentIfName OCTETSTRING GET SET)
+ (4 wlanIfaceOperatingMode WlanIfaceOperatingModeType GET SET)
+ (5 wlanIfaceFlags WlanIfaceFlagsType GET SET)
+ (6 wlanIfaceBssid OCTETSTRING | MacAddress GET SET)
+ (7 wlanIfaceLocalAddress OCTETSTRING | MacAddress GET SET)
+ (8 wlanIfaceStatus RowStatus GET SET)
+ (9 wlanIfaceState ENUM ( 1 up 2 down ) GET SET)
+ ))
+ (2 wlanIfParentTable
+ (1 wlanIfParentEntry : OCTETSTRING op_wlan_if_parent
+ (1 wlanIfParentDriverCapabilities WlanDriverCaps GET)
+ (2 wlanIfParentCryptoCapabilities WlanCryptoCaps GET)
+ (3 wlanIfParentHTCapabilities WlanHTCaps GET)
+ ))
+ (3 wlanIfaceConfigTable
+ (1 wlanIfaceConfigEntry : OCTETSTRING op_wlan_iface_config
+ (1 wlanIfacePacketBurst ENUM ( 1 true 2 false ) GET SET)
+ (2 wlanIfaceCountryCode OCTETSTRING GET SET)
+ (3 wlanIfaceRegDomain WlanRegDomainCode GET SET)
+ (4 wlanIfaceDesiredSsid OCTETSTRING GET SET)
+ (5 wlanIfaceDesiredChannel INTEGER32 GET SET)
+ (6 wlanIfaceDynamicFreqSelection ENUM ( 1 true 2 false ) GET SET)
+ (7 wlanIfaceFastFrames ENUM ( 1 true 2 false ) GET SET)
+ (8 wlanIfaceDturbo ENUM ( 1 true 2 false ) GET SET)
+ (9 wlanIfaceTxPower INTEGER32 GET SET)
+ (10 wlanIfaceFragmentThreshold INTEGER GET SET)
+ (11 wlanIfaceRTSThreshold INTEGER GET SET)
+ (12 wlanIfaceWlanPrivacySubscribe ENUM ( 1 true 2 false ) GET SET)
+ (13 wlanIfaceBgScan ENUM ( 1 true 2 false ) GET SET)
+ (14 wlanIfaceBgScanIdle INTEGER32 GET SET)
+ (15 wlanIfaceBgScanInterval INTEGER32 GET SET)
+ (16 wlanIfaceBeaconMissedThreshold INTEGER GET SET)
+ (17 wlanIfaceDesiredBssid OCTETSTRING | MacAddress GET SET)
+ (18 wlanIfaceRoamingMode ENUM ( 1 device 2 auto 3 manual ) GET SET)
+ (19 wlanIfaceDot11d ENUM ( 1 true 2 false ) GET SET)
+ (20 wlanIfaceDot11h ENUM ( 1 true 2 false ) GET SET)
+ (21 wlanIfaceDynamicWds ENUM ( 1 true 2 false ) GET SET)
+ (22 wlanIfacePowerSave ENUM ( 1 true 2 false ) GET SET)
+ (23 wlanIfaceApBridge ENUM ( 1 true 2 false ) GET SET)
+ (24 wlanIfaceBeaconInterval INTEGER GET SET)
+ (25 wlanIfaceDtimPeriod INTEGER GET SET)
+ (26 wlanIfaceHideSsid ENUM ( 1 true 2 false ) GET SET)
+ (27 wlanIfaceInactivityProccess ENUM ( 1 true 2 false ) GET SET)
+ (28 wlanIfaceDot11gProtMode ENUM ( 1 off 2 cts 3 rtscts ) GET SET)
+ (29 wlanIfaceDot11gPureMode ENUM ( 1 true 2 false ) GET SET)
+ (30 wlanIfaceDot11nPureMode ENUM ( 1 true 2 false ) GET SET)
+ (31 wlanIfaceDot11nAmpdu WlanIfaceDot11nPduType GET SET)
+ (32 wlanIfaceDot11nAmpduDensity INTEGER GET SET)
+ (33 wlanIfaceDot11nAmpduLimit INTEGER GET SET)
+ (34 wlanIfaceDot11nAmsdu WlanIfaceDot11nPduType GET SET)
+ (35 wlanIfaceDot11nAmsduLimit INTEGER GET SET)
+ (36 wlanIfaceDot11nHighThroughput ENUM ( 1 true 2 false ) GET SET)
+ (37 wlanIfaceDot11nHTCompatible ENUM ( 1 true 2 false ) GET SET)
+ (38 wlanIfaceDot11nHTProtMode ENUM ( 1 off 2 rts ) GET SET)
+ (39 wlanIfaceDot11nRIFS ENUM ( 1 true 2 false ) GET SET)
+ (40 wlanIfaceDot11nShortGI ENUM ( 1 true 2 false ) GET SET)
+ (41 wlanIfaceDot11nSMPSMode ENUM ( 1 disabled 2 static 3 dynamic ) GET SET)
+ (42 wlanIfaceTdmaSlot INTEGER GET SET)
+ (43 wlanIfaceTdmaSlotCount INTEGER GET SET)
+ (44 wlanIfaceTdmaSlotLength INTEGER GET SET)
+ (45 wlanIfaceTdmaBeaconInterval INTEGER32 GET SET)
+ ))
+ (4 wlanIfacePeerTable
+ (1 wlanIfacePeerEntry : OCTETSTRING OCTETSTRING | MacAddress op_wlan_if_peer
+ (1 wlanIfacePeerAddress OCTETSTRING | MacAddress GET)
+ (2 wlanIfacePeerAssociationId INTEGER32 GET)
+ (3 wlanIfacePeerVlanTag INTEGER GET SET)
+ (4 wlanIfacePeerFrequency INTEGER32 GET)
+ (5 wlanIfacePeerCurrentTXRate INTEGER32 GET)
+ (6 wlanIfacePeerRxSignalStrength INTEGER32 GET)
+ (7 wlanIfacePeerIdleTimer INTEGER32 GET)
+ (8 wlanIfacePeerTxSequenceNo INTEGER32 GET)
+ (9 wlanIfacePeerRxSequenceNo INTEGER32 GET)
+ (10 wlanIfacePeerTxPower INTEGER32 GET)
+ (11 wlanIfacePeerCapabilities WlanPeerCapabilityFlags GET)
+ (12 wlanIfacePeerFlags WlanIfacePeerFlagsType GET)
+ ))
+ (5 wlanIfaceChannelTable
+ (1 wlanIfaceChannelEntry : OCTETSTRING INTEGER op_wlan_channels
+ (1 wlanIfaceChannelId INTEGER)
+ (2 wlanIfaceChannelIeeeId INTEGER GET)
+ (3 wlanIfaceChannelType WlanChannelType GET)
+ (4 wlanIfaceChannelFlags WlanIfaceChannelFlagsType GET)
+ (5 wlanIfaceChannelFrequency INTEGER32 GET)
+ (6 wlanIfaceChannelMaxRegPower INTEGER32 GET)
+ (7 wlanIfaceChannelMaxTxPower INTEGER32 GET)
+ (8 wlanIfaceChannelMinTxPower INTEGER32 GET)
+ (9 wlanIfaceChannelState WlanIfaceChannelStateType GET)
+ (10 wlanIfaceChannelHTExtension INTEGER32 GET)
+ (11 wlanIfaceChannelMaxAntennaGain INTEGER32 GET)
+ ))
+ (6 wlanIfRoamParamsTable
+ (1 wlanIfRoamParamsEntry : OCTETSTRING WlanIfPhyMode op_wlan_roam_params
+ (1 wlanIfRoamPhyMode WlanIfPhyMode)
+ (2 wlanIfRoamRxSignalStrength INTEGER32 GET)
+ (3 wlanIfRoamTxRateThreshold INTEGER32 GET)
+ ))
+ (7 wlanIfTxParamsTable
+ (1 wlanIfTxParamsEntry : OCTETSTRING WlanIfPhyMode op_wlan_tx_params
+ (1 wlanIfTxPhyMode WlanIfPhyMode)
+ (2 wlanIfTxUnicastRate INTEGER32 GET SET)
+ (3 wlanIfTxMcastRate INTEGER32 GET SET)
+ (4 wlanIfTxMgmtRate INTEGER32 GET SET)
+ (5 wlanIfTxMaxRetryCount INTEGER32 GET SET)
+ ))
+ )
+ (2 begemotWlanScanning
+ (1 wlanScanConfigTable
+ (1 wlanScanConfigEntry : OCTETSTRING op_wlan_scan_config
+ (1 wlanScanFlags WlanScanFlagsType GET SET)
+ (2 wlanScanDuration INTEGER GET SET)
+ (3 wlanScanMinChannelDwellTime INTEGER32 GET SET)
+ (4 wlanScanMaxChannelDwellTime INTEGER32 GET SET)
+ (5 wlanScanConfigStatus ENUM ( 0 unknown 1 notStarted 2 running 3 finished 4 cancel ) GET SET)
+ ))
+ (2 wlanScanResultsTable
+ (1 wlanScanResultsEntry : OCTETSTRING OCTETSTRING OCTETSTRING | MacAddress op_wlan_scan_results
+ (1 wlanScanResultID OCTETSTRING GET)
+ (2 wlanScanResultBssid OCTETSTRING | MacAddress GET)
+ (3 wlanScanResultChannel INTEGER32 GET)
+ (4 wlanScanResultRate INTEGER32 GET)
+ (5 wlanScanResultNoise INTEGER32 GET)
+ (6 wlanScanResultBeaconInterval INTEGER32 GET)
+ (7 wlanScanResultCapabilities WlanPeerCapabilityFlags GET)
+ ))
+ )
+ (3 begemotWlanStatistics
+ (1 wlanIfaceStatisticsTable
+ (1 wlanIfaceStatisticsEntry : OCTETSTRING op_wlan_iface_stats
+ (1 wlanStatsRxBadVersion COUNTER GET)
+ (2 wlanStatsRxTooShort COUNTER GET)
+ (3 wlanStatsRxWrongBssid COUNTER GET)
+ (4 wlanStatsRxDiscardedDups COUNTER GET)
+ (5 wlanStatsRxWrongDir COUNTER GET)
+ (6 wlanStatsRxDiscardMcastEcho COUNTER GET)
+ (7 wlanStatsRxDiscardNoAssoc COUNTER GET)
+ (8 wlanStatsRxWepNoPrivacy COUNTER GET)
+ (9 wlanStatsRxWepUnencrypted COUNTER GET)
+ (10 wlanStatsRxWepFailed COUNTER GET)
+ (11 wlanStatsRxDecapsulationFailed COUNTER GET)
+ (12 wlanStatsRxDiscardMgmt COUNTER GET)
+ (13 wlanStatsRxControl COUNTER GET)
+ (14 wlanStatsRxBeacon COUNTER GET)
+ (15 wlanStatsRxRateSetTooBig COUNTER GET)
+ (16 wlanStatsRxElemMissing COUNTER GET)
+ (17 wlanStatsRxElemTooBig COUNTER GET)
+ (18 wlanStatsRxElemTooSmall COUNTER GET)
+ (19 wlanStatsRxElemUnknown COUNTER GET)
+ (20 wlanStatsRxChannelMismatch COUNTER GET)
+ (21 wlanStatsRxDropped COUNTER GET)
+ (22 wlanStatsRxSsidMismatch COUNTER GET)
+ (23 wlanStatsRxAuthNotSupported COUNTER GET)
+ (24 wlanStatsRxAuthFailed COUNTER GET)
+ (25 wlanStatsRxAuthCM COUNTER GET)
+ (26 wlanStatsRxAssocWrongBssid COUNTER GET)
+ (27 wlanStatsRxAssocNoAuth COUNTER GET)
+ (28 wlanStatsRxAssocCapMismatch COUNTER GET)
+ (29 wlanStatsRxAssocNoRateMatch COUNTER GET)
+ (30 wlanStatsRxBadWpaIE COUNTER GET)
+ (31 wlanStatsRxDeauthenticate COUNTER GET)
+ (32 wlanStatsRxDisassociate COUNTER GET)
+ (33 wlanStatsRxUnknownSubtype COUNTER GET)
+ (34 wlanStatsRxFailedNoBuf COUNTER GET)
+ (35 wlanStatsRxBadAuthRequest COUNTER GET)
+ (36 wlanStatsRxUnAuthorized COUNTER GET)
+ (37 wlanStatsRxBadKeyId COUNTER GET)
+ (38 wlanStatsRxCCMPSeqViolation COUNTER GET)
+ (39 wlanStatsRxCCMPBadFormat COUNTER GET)
+ (40 wlanStatsRxCCMPFailedMIC COUNTER GET)
+ (41 wlanStatsRxTKIPSeqViolation COUNTER GET)
+ (42 wlanStatsRxTKIPBadFormat COUNTER GET)
+ (43 wlanStatsRxTKIPFailedMIC COUNTER GET)
+ (44 wlanStatsRxTKIPFailedICV COUNTER GET)
+ (45 wlanStatsRxDiscardACL COUNTER GET)
+ (46 wlanStatsTxFailedNoBuf COUNTER GET)
+ (47 wlanStatsTxFailedNoNode COUNTER GET)
+ (48 wlanStatsTxUnknownMgmt COUNTER GET)
+ (49 wlanStatsTxBadCipher COUNTER GET)
+ (50 wlanStatsTxNoDefKey COUNTER GET)
+ (51 wlanStatsTxFragmented COUNTER GET)
+ (52 wlanStatsTxFragmentsCreated COUNTER GET)
+ (53 wlanStatsActiveScans COUNTER GET)
+ (54 wlanStatsPassiveScans COUNTER GET)
+ (55 wlanStatsTimeoutInactivity COUNTER GET)
+ (56 wlanStatsCryptoNoMem COUNTER GET)
+ (57 wlanStatsSwCryptoTKIP COUNTER GET)
+ (58 wlanStatsSwCryptoTKIPEnMIC COUNTER GET)
+ (59 wlanStatsSwCryptoTKIPDeMIC COUNTER GET)
+ (60 wlanStatsCryptoTKIPCM COUNTER GET)
+ (61 wlanStatsSwCryptoCCMP COUNTER GET)
+ (62 wlanStatsSwCryptoWEP COUNTER GET)
+ (63 wlanStatsCryptoCipherKeyRejected COUNTER GET)
+ (64 wlanStatsCryptoNoKey COUNTER GET)
+ (65 wlanStatsCryptoDeleteKeyFailed COUNTER GET)
+ (66 wlanStatsCryptoUnknownCipher COUNTER GET)
+ (67 wlanStatsCryptoAttachFailed COUNTER GET)
+ (68 wlanStatsCryptoKeyFailed COUNTER GET)
+ (69 wlanStatsCryptoEnMICFailed COUNTER GET)
+ (70 wlanStatsIBSSCapMismatch COUNTER GET)
+ (71 wlanStatsUnassocStaPSPoll COUNTER GET)
+ (72 wlanStatsBadAidPSPoll COUNTER GET)
+ (73 wlanStatsEmptyPSPoll COUNTER GET)
+ (74 wlanStatsRxFFBadHdr COUNTER GET)
+ (75 wlanStatsRxFFTooShort COUNTER GET)
+ (76 wlanStatsRxFFSplitError COUNTER GET)
+ (77 wlanStatsRxFFDecap COUNTER GET)
+ (78 wlanStatsTxFFEncap COUNTER GET)
+ (79 wlanStatsRxBadBintval COUNTER GET)
+ (80 wlanStatsRxDemicFailed COUNTER GET)
+ (81 wlanStatsRxDefragFailed COUNTER GET)
+ (82 wlanStatsRxMgmt COUNTER GET)
+ (83 wlanStatsRxActionMgmt COUNTER GET)
+ (84 wlanStatsRxAMSDUTooShort COUNTER GET)
+ (85 wlanStatsRxAMSDUSplitError COUNTER GET)
+ (86 wlanStatsRxAMSDUDecap COUNTER GET)
+ (87 wlanStatsTxAMSDUEncap COUNTER GET)
+ (88 wlanStatsAMPDUBadBAR COUNTER GET)
+ (89 wlanStatsAMPDUOowBar COUNTER GET)
+ (90 wlanStatsAMPDUMovedBAR COUNTER GET)
+ (91 wlanStatsAMPDURxBAR COUNTER GET)
+ (92 wlanStatsAMPDURxOor COUNTER GET)
+ (93 wlanStatsAMPDURxCopied COUNTER GET)
+ (94 wlanStatsAMPDURxDropped COUNTER GET)
+ (95 wlanStatsTxDiscardBadState COUNTER GET)
+ (96 wlanStatsTxFailedNoAssoc COUNTER GET)
+ (97 wlanStatsTxClassifyFailed COUNTER GET)
+ (98 wlanStatsDwdsMcastDiscard COUNTER GET)
+ (99 wlanStatsHTAssocRejectNoHT COUNTER GET)
+ (100 wlanStatsHTAssocDowngrade COUNTER GET)
+ (101 wlanStatsHTAssocRateMismatch COUNTER GET)
+ (102 wlanStatsAMPDURxAge COUNTER GET)
+ (103 wlanStatsAMPDUMoved COUNTER GET)
+ (104 wlanStatsADDBADisabledReject COUNTER GET)
+ (105 wlanStatsADDBANoRequest COUNTER GET)
+ (106 wlanStatsADDBABadToken COUNTER GET)
+ (107 wlanStatsADDBABadPolicy COUNTER GET)
+ (108 wlanStatsAMPDUStopped COUNTER GET)
+ (109 wlanStatsAMPDUStopFailed COUNTER GET)
+ (110 wlanStatsAMPDURxReorder COUNTER GET)
+ (111 wlanStatsScansBackground COUNTER GET)
+ (112 wlanLastDeauthReason WlanMgmtReasonCode GET)
+ (113 wlanLastDissasocReason WlanMgmtReasonCode GET)
+ (114 wlanLastAuthFailReason WlanMgmtReasonCode GET)
+ (115 wlanStatsBeaconMissedEvents COUNTER GET)
+ (116 wlanStatsRxDiscardBadStates COUNTER GET)
+ (117 wlanStatsFFFlushed COUNTER GET)
+ (118 wlanStatsTxControlFrames COUNTER GET)
+ (119 wlanStatsAMPDURexmt COUNTER GET)
+ (120 wlanStatsAMPDURexmtFailed COUNTER GET)
+ (121 wlanStatsReset ENUM ( 1 no-op 2 clear ) GET SET)
+ ))
+ )
+ (4 begemotWlanWep
+ (1 wlanWepInterfaceTable
+ (1 wlanWepInterfaceEntry : OCTETSTRING op_wlan_wep_iface
+ (1 wlanWepMode ENUM ( 0 off 1 on 2 mixed ) GET SET)
+ (2 wlanWepDefTxKey INTEGER32 GET SET)
+ ))
+ (2 wlanWepKeyTable
+ (1 wlanWepKeyEntry : OCTETSTRING INTEGER op_wlan_wep_key
+ (1 wlanWepKeyID INTEGER GET SET)
+ (2 wlanWepKeyLength INTEGER32 GET)
+ (3 wlanWepKeySet OCTETSTRING | OctetString GET SET)
+ (4 wlanWepKeyHash OCTETSTRING | OctetString GET)
+ (5 wlanWepKeyStatus RowStatus GET SET)
+ ))
+ )
+ (5 begemotWlanMACAccessControl
+ (1 wlanMACAccessControlTable
+ (1 wlanMACAccessControlEntry : OCTETSTRING op_wlan_mac_access_control
+ (1 wlanMACAccessControlPolicy ENUM ( 0 open 1 allow 2 deny 7 radius ) GET SET)
+ (2 wlanMACAccessControlNacl COUNTER GET)
+ (3 wlanMACAccessControlFlush ENUM ( 0 no-op 1 flush ) GET SET)
+ ))
+ (2 wlanMACAccessControlMACTable
+ (1 wlanMACAccessControlMACEntry : OCTETSTRING OCTETSTRING | MacAddress op_wlan_mac_acl_mac
+ (1 wlanMACAccessControlMAC OCTETSTRING | MacAddress GET SET)
+ (2 wlanMACAccessControlMACStatus RowStatus GET SET)
+ ))
+ )
+ (6 begemotWlanMeshRouting
+ (1 wlanMeshRoutingConfig
+ (1 wlanMeshMaxRetries INTEGER32 op_wlan_mesh_config GET SET)
+ (2 wlanMeshConfirmTimeout INTEGER32 op_wlan_mesh_config GET SET)
+ (3 wlanMeshHoldingTimeout INTEGER32 op_wlan_mesh_config GET SET)
+ (4 wlanMeshRetryTimeout INTEGER32 op_wlan_mesh_config GET SET)
+ )
+ (2 wlanMeshInterface
+ (1 wlanMeshInterfaceTable
+ (1 wlanMeshInterfaceEntry : OCTETSTRING op_wlan_mesh_iface
+ (1 wlanMeshId OCTETSTRING GET SET)
+ (2 wlanMeshTTL INTEGER32 GET SET)
+ (3 wlanMeshPeeringEnabled ENUM ( 1 true 2 false ) GET SET)
+ (4 wlanMeshForwardingEnabled ENUM ( 1 true 2 false ) GET SET)
+ (5 wlanMeshMetric ENUM ( 0 unknown 1 airtime ) GET SET)
+ (6 wlanMeshPath ENUM ( 0 unknown 1 hwmp ) GET SET)
+ (7 wlanMeshRoutesFlush ENUM ( 0 no-op 1 flush ) GET SET)
+ ))
+ (2 wlanMeshNeighborTable
+ (1 wlanMeshNeighborEntry : OCTETSTRING OCTETSTRING | MacAddress op_wlan_mesh_neighbor
+ (1 wlanMeshNeighborAddress OCTETSTRING | MacAddress GET)
+ (2 wlanMeshNeighborFrequency INTEGER32 GET)
+ (3 wlanMeshNeighborLocalId INTEGER32 GET)
+ (4 wlanMeshNeighborPeerId INTEGER32 GET)
+ (5 wlanMeshNeighborPeerState WlanMeshNeighborPeerStateType GET)
+ (6 wlanMeshNeighborCurrentTXRate INTEGER32 GET)
+ (7 wlanMeshNeighborRxSignalStrength INTEGER32 GET)
+ (8 wlanMeshNeighborIdleTimer INTEGER32 GET)
+ (9 wlanMeshNeighborTxSequenceNo INTEGER32 GET)
+ (10 wlanMeshNeighborRxSequenceNo INTEGER32 GET)
+ ))
+ )
+ (3 wlanMeshRoute
+ (1 wlanMeshRouteTable
+ (1 wlanMeshRouteEntry : OCTETSTRING OCTETSTRING | MacAddress op_wlan_mesh_route
+ (1 wlanMeshRouteDestination OCTETSTRING | MacAddress GET SET)
+ (2 wlanMeshRouteNextHop OCTETSTRING | MacAddress GET)
+ (3 wlanMeshRouteHops INTEGER32 GET)
+ (4 wlanMeshRouteMetric UNSIGNED32 GET)
+ (5 wlanMeshRouteLifeTime UNSIGNED32 GET)
+ (6 wlanMeshRouteLastMseq UNSIGNED32 GET)
+ (7 wlanMeshRouteFlags BITS ( 1 valid 2 proxy ) GET)
+ (8 wlanMeshRouteStatus RowStatus GET SET)
+ ))
+ )
+ (4 wlanMeshStatistics
+ (1 wlanMeshStatsTable
+ (1 wlanMeshStatsEntry : OCTETSTRING op_wlan_mesh_stats
+ (1 wlanMeshDroppedBadSta COUNTER GET)
+ (2 wlanMeshDroppedNoLink COUNTER GET)
+ (3 wlanMeshNoFwdTtl COUNTER GET)
+ (4 wlanMeshNoFwdBuf COUNTER GET)
+ (5 wlanMeshNoFwdTooShort COUNTER GET)
+ (6 wlanMeshNoFwdDisabled COUNTER GET)
+ (7 wlanMeshNoFwdPathUnknown COUNTER GET)
+ (8 wlanMeshDroppedBadAE COUNTER GET)
+ (9 wlanMeshRouteAddFailed COUNTER GET)
+ (10 wlanMeshDroppedNoProxy COUNTER GET)
+ (11 wlanMeshDroppedMisaligned COUNTER GET)
+ ))
+ )
+ (5 wlanMeshRouteProtocols
+ (1 wlanMeshProtoHWMP
+ (1 wlanMeshHWMPConfig
+ (1 wlanHWMPRouteInactiveTimeout INTEGER32 op_wlan_hwmp_config GET SET)
+ (2 wlanHWMPRootAnnounceInterval INTEGER32 op_wlan_hwmp_config GET SET)
+ (3 wlanHWMPRootInterval INTEGER32 op_wlan_hwmp_config GET SET)
+ (4 wlanHWMPRootTimeout INTEGER32 op_wlan_hwmp_config GET SET)
+ (5 wlanHWMPPathLifetime INTEGER32 op_wlan_hwmp_config GET SET)
+ (6 wlanHWMPReplyForwardBit INTEGER32 op_wlan_hwmp_config GET SET)
+ (7 wlanHWMPTargetOnlyBit INTEGER32 op_wlan_hwmp_config GET SET)
+ )
+ (2 wlanMeshHWMPInterface
+ (1 wlanHWMPInterfaceTable
+ (1 wlanHWMPInterfaceEntry : OCTETSTRING op_wlan_hwmp_iface
+ (1 wlanHWMPRootMode ENUM ( 1 disabled 2 normal 3 proactive 4 rann ) GET SET)
+ (2 wlanHWMPMaxHops INTEGER32 GET SET)
+ ))
+ )
+ (3 wlanMeshHWMPStatistics
+ (1 wlanMeshHWMPStatsTable
+ (1 wlanMeshHWMPStatsEntry : OCTETSTRING op_wlan_hwmp_stats
+ (1 wlanMeshHWMPWrongSeqNo COUNTER GET)
+ (2 wlanMeshHWMPTxRootPREQ COUNTER GET)
+ (3 wlanMeshHWMPTxRootRANN COUNTER GET)
+ (4 wlanMeshHWMPProxy COUNTER GET)
+ ))
+ )
+ )
+ )
+ ))))))
+)
diff --git a/usr.sbin/bsnmpd/tools/Makefile b/usr.sbin/bsnmpd/tools/Makefile
new file mode 100644
index 0000000..3ffc01e
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+# Author: Shteryana Shopova <syrinx@FreeBSD.org>
+
+SUBDIR= libbsnmptools \
+ bsnmptools
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/bsnmpd/tools/Makefile.inc b/usr.sbin/bsnmpd/tools/Makefile.inc
new file mode 100644
index 0000000..e08fe26
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/Makefile.inc
@@ -0,0 +1,13 @@
+# $FreeBSD$
+# Author: Shteryana Shopova <syrinx@FreeBSD.org>
+
+BINDIR?= /usr/bin
+
+CFLAGS+= -I. -I${.CURDIR}
+
+.if exists(${.OBJDIR}/../libbsnmptools)
+LIBBSNMPTOOLSDIR= ${.OBJDIR}/../libbsnmptools
+.else
+LIBBSNMPTOOLSDIR= ${.CURDIR}/../libbsnmptools
+.endif
+LIBBSNMPTOOLS= ${LIBBSNMPTOOLSDIR}/libbsnmptools.a
diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/Makefile b/usr.sbin/bsnmpd/tools/bsnmptools/Makefile
new file mode 100644
index 0000000..94a1cea
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/bsnmptools/Makefile
@@ -0,0 +1,28 @@
+# $FreeBSD$
+# Author: Shteryana Shopova <syrinx@FreeBSD.org>
+
+.include <bsd.own.mk>
+
+.PATH: ${.CURDIR}
+
+PROG= bsnmpget
+
+DPADD+= ${LIBBSNMP} ${LIBBSNMPTOOLS}
+LDADD+= -lbsnmp -lbsnmptools
+CFLAGS+= -I${.CURDIR}/../libbsnmptools
+LDFLAGS+= -L${LIBBSNMPTOOLSDIR}
+
+.if ${MK_OPENSSL} != "no"
+DPADD+= ${LIBCRYPTO}
+LDADD+= -lcrypto
+.endif
+
+LINKS= ${BINDIR}/bsnmpget ${BINDIR}/bsnmpwalk
+LINKS+= ${BINDIR}/bsnmpget ${BINDIR}/bsnmpset
+
+MAN= bsnmpget.1
+
+MLINKS= bsnmpget.1 bsnmpwalk.1
+MLINKS+= bsnmpget.1 bsnmpset.1
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1 b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1
new file mode 100644
index 0000000..57a85d6
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1
@@ -0,0 +1,426 @@
+.\"
+.\" Copyright (c) 2010 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" Portions of this documentation were written by Shteryana Sotirova Shopova
+.\" under sponsorship from the FreeBSD Foundation.
+.\"
+.\" Copyright (c) 2005-2007 The FreeBSD Project.
+.\" All rights reserved.
+.\"
+.\" Author: Shteryana Shopova <syrinx@FreeBSD.org>
+.\"
+.\" 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 January 10, 2012
+.Dt BSNMPGET 1
+.Os
+.Sh NAME
+.Nm bsnmpget ,
+.Nm bsnmpwalk ,
+.Nm bsnmpset
+.Nd "simple tools for querying SNMP agents"
+.Sh SYNOPSIS
+.Nm
+.Op Fl aDdehnK
+.Op Fl A Ar options
+.Op Fl b Ar buffersize
+.Op Fl C Ar options
+.Op Fl I Ar options
+.Op Fl i Ar filelist
+.Op Fl l Ar filename
+.Op Fl M Ar max-repetitions
+.Op Fl N Ar non-repeaters
+.Op Fl o Ar output
+.Op Fl P Ar options
+.Op Fl p Ar pdu
+.Op Fl r Ar retries
+.Op Fl s Ar [trans::][community@][server][:port]
+.Op Fl t Ar timeout
+.Op Fl U Ar options
+.Op Fl v Ar version
+.Op Ar OID ...
+.Pp
+.Nm bsnmpwalk
+.Op Fl dhnK
+.Op Fl A Ar options
+.Op Fl b Ar buffersize
+.Op Fl C Ar options
+.Op Fl I Ar options
+.Op Fl i Ar filelist
+.Op Fl l Ar filename
+.Op Fl o Ar output
+.Op Fl P Ar options
+.Op Fl r Ar retries
+.Op Fl s Ar [trans::][community@][server][:port]
+.Op Fl t Ar timeout
+.Op Fl U Ar options
+.Op Fl v Ar version
+.Op Ar OID ...
+.Pp
+.Nm bsnmpset
+.Op Fl adehnK
+.Op Fl A Ar options
+.Op Fl b Ar buffersize
+.Op Fl C Ar options
+.Op Fl I Ar options
+.Op Fl i Ar filelist
+.Op Fl l Ar filename
+.Op Fl o Ar output
+.Op Fl P Ar options
+.Op Fl r Ar retries
+.Op Fl s Ar [trans::][community@][server][:port]
+.Op Fl t Ar timeout
+.Op Fl U Ar options
+.Op Fl v Ar version
+.Ar OID Ns = Ar syntax Ns : Ns Ar value
+.Op Ar OID Ns = Ar syntax Ns : Ns Ar value ...
+.Sh DESCRIPTION
+.Nm ,
+.Nm bsnmpwalk
+and
+.Nm bsnmpset
+are simple tools for retrieving management information from and setting
+management information to a Simple Network Management Protocol (SNMP) agent.
+.Pp
+Depending on the options
+.Nm bsnmpget
+constructs either a SMNP GetRequest, GetNextRequest
+or a GetBulkRequest packet, fills in the object identifiers (OIDs) of the
+objects whose values will be retrived, waits for a response and prints it if
+received successfully.
+.Pp
+.Nm Bsnmpwalk
+queries an agent with ether SMNP GetNextRequest or GetBulkRequest packets,
+asking for values of OID instances that are a part of the object subtree
+rooted at the provided OIDs.
+.Pp
+.Nm Bsnmpset
+constructs a SMNP SetRequest packet, fills in the OIDs (object identifiers),
+syntaxes and values of the objects whose values are to be set and waits for a
+response from server.
+.Sh OPTIONS
+The options are as follows (not all apply to all three programs):
+.Bl -tag -width ".It Fl D Ar options"
+.It Fl A Ar options
+Authentication options to use with SNMPv3 PDUs
+.Bl -tag -width \&
+.It Cm proto=[md5|sha]
+The protocol to use when calculating the PDU message digest.
+.It Cm key=authkey
+A binary localized authentication key to use when calculating the PDU message
+digest.
+.El
+.Pp
+By default SNMPv3 PDUs are sent unauthenticated.
+.It Fl a
+Skip any sanity checks when adding OIDs to a Protocol Data Unit (PDU):
+ingore syntax/access type, allow adding of non-leaf objects for GetPdu and
+read-only objects to a SetPDU.
+.It Fl b Ar buffersize
+Tune the size of buffers used to send and receive packets.
+The default size is 10000 bytes which should be enough unless an agent sends
+a really large octetstring.
+The maximum allowed length is 65535 according to the Structure of Management
+Information (SMIv2).
+.It Fl C Ar options
+The context to query with SNMPv3 PDUs.
+.Bl -tag -width \&
+.It Cm context=name
+The context name. Default is "" (empty).
+.It Cm context-engine=engine-id
+The SNMP Engine ID of the context to query with SNMPv3 PDUs, represented as
+binary octet string. By default, this is set to the Engine ID of the SNMP agent.
+.El
+.It Fl D
+Perform SNMP USM Engine Discovery, rather than sending a request for the value
+of a specific object.
+.It Fl d
+Turn on debugging.
+This option will cause the packets sent and received to be dumped to the
+terminal.
+.It Fl e
+Retry on error.
+If an error is returned in the response PDU, resend the request removing the
+variable that caused the error until a valid response is received.
+This is only useful for a GetRequest- and a GetNextRequest-PDU.
+.It Fl h
+Print a short help text with default values for various options.
+.It Fl I Ar options
+Load each MIB description file from the given list to translate symbolic
+object names to their numerical representation and vice versa.
+Use the other options to obtain a non-default behaviour:
+.Bl -tag -width \&
+.It Cm cut=OID
+Specifies the initial OID that was cut by
+.Xr gensnmpdef 1
+when producing the MIB description file.
+The default value is .iso(1).org(3).dod(6) which is what should have been
+used for all the files installed under /usr/share/snmp/defs.
+Use this only if you generated your own files, providing a
+.Fl c
+option to
+.Xr gensnmpdef 1 .
+.It Cm path=filedir
+The directory where files in the list will be searched.
+The default is
+.Pa /usr/share/snmp/defs Ns .
+.It Cm file=filelist
+A comma separated list of files to which the two options above will apply.
+.El
+.Pp
+The file suboption has to come after the other suboptions so that their
+non-default values will be applied to the list of files.
+The order of the other suboptions before each file suboption can be random.
+Suboptions may be separated either by commas or by spaces.
+If using spaces make sure the entire option string is one argument, for
+example using quotes.
+.It Fl i Ar filelist
+List of MIB description files produced by
+.Xr gensnmpdef 1 which
+.Nm bsnmpget ,
+.Nm bsnmpwalk
+or
+.Nm bsnmpset
+will search to translate numerical OIDs to their symbolic object names.
+Multiple files can be provided either giving this option multiple times
+or a comma separated list of file names.
+If a filename begins with a letter the default directory,
+/usr/share/snmp/defs,
+will be searched.
+.It Fl K
+Calculate and display the localized authentication and privacy keys
+corresponding to a plain text password. The password is obtain via the
+environment. Additionally, if one or more OIDs are specified, the calculated
+keys are used when processing the SNMPv3 requests.
+.It Fl l Ar filename
+The path of the posix local (unix domain) socket if local
+transport is used.
+.It Fl M Ar max-repetitions
+The value for the max-repetitions field in a GetBulk PDU.
+Default is 10.
+.It Fl N Ar non-repeaters
+The value for the non-repeaters field in a GetBulk PDU.
+Default is 0.
+.It Fl n
+Only use numerical representations for input and output OIDs and do not
+try to resolve symbolic object names.
+Note that
+.Nm bsnmpget ,
+.Nm bsnmpwalk
+and
+.Nm bsnmpset
+will print numerical OIDs anyway if the corresponding string representation
+is not found in the MIB description files.
+.It Fl o Ar [quiet|short|verbose]
+The format used to print the received response.
+Quiet only prints values, short (default) prints an abbreviated OID
+representation and the value.
+In addition to the short output verbose prints the type before the value.
+.It Fl P Ar options
+Privacy options to use with SNMPv3 PDUs
+.Bl -tag -width \&
+.It Cm proto=[aes|des]
+The protocol to use when encypting/decrypting SNMPv3 PDU data.
+.It Cm key=privkey
+A binary localized privacy key to use when encypting/decrypting SNMPv3 PDU data.
+.El
+.Pp
+By default plain text SNMPv3 PDUs are sent.
+.It Fl p Ar [get|getnext|getbulk]
+The PDU type to send by
+.Nm bsmpget
+and
+.Nm bsnmpwalk .
+Default is get
+for
+.Nm bsmpget
+and getnext for
+.Nm bsnmpwalk .
+Getbulk allows executing the so called SNMP "bulkwalks" allowing the values of
+multiple columns to be retrived in a single PDU by
+.Nm bsnmpwalk .
+.It Fl r Ar retries
+Number of resends of request packets before giving up if the agent does
+not respond after the first try.
+Default is 3.
+.It Fl s Ar [trans::] Ns Ar [community@] Ns Ar [server] Ns Ar [:port]
+Each of the server specification components is optional but at least one
+has to be provided if
+.Ar s
+option is used.
+The server specification is constructed in the following manner:
+.Bl -tag -width \&
+.It Cm trans::
+Transport type may be one of udp, stream or dgram.
+If this option is not provided an udp inet/inet6 socket will be used, which
+is the most common.
+Stream stands for a posix local stream socket and a posix local datagram
+socket will be used if dgram is specified.
+.It Cm community@
+Specify an SNMP community string to be used when sending packets.
+If the option is skipped the default "public" will be used for
+.Nm
+and
+.Nm bsnmpwalk
+and the default "private" community string will be used for
+.Nm bsnmpset .
+.It Cm server
+This might be either the IP address or the hostname where the agent is
+listening.
+The default is
+.Qq localhost .
+.It Cm port
+The destination port to send the requests to.
+This is useful if the SNMP agent listens on a non-default port.
+Default is given by the
+.Qq snmp
+entry in
+.Pa /etc/services ,
+port 161.
+.El
+.It Fl t Ar timeout
+Number of seconds before resending a request packet if the agent does
+not respond.
+The default value is 3 seconds.
+.It Fl U Ar options
+User credentials when sending SNMPv3 PDUs.
+.Bl -tag -width \&
+.It Cm engine=id
+The Engine ID of the SNMP agent represented as a binary octet string.
+.It Cm engine-boots=value
+The value of the snmpEngineBoots of the SNMP agent.
+.It Cm engine-time=value
+The value of the snmpEngineTime of the SNMP agent.
+.Pp
+If any of the above is not specified, SNMP USM Engine Discovery is attempted.
+This is also the default behavior.
+.It Cm name=username
+The USM user name to include in the SNMPv3 PDUs. By default, the user name is
+obtain via the environment
+.El
+.It Fl v Ar version
+The SNMP protocol version to use when sending requests. SNMP versions 1, 2 and
+3 are supported.
+If no version option is provided
+.Nm bsnmpget ,
+.Nm bsnmpwalk
+and
+.Nm bsnmpset
+will use version 2.
+Note that GetBulkRequest-PDUs were introduced in SNMPv2 thus setting the
+version to 1 is incompatiable with sending a GetBulk PDU.
+.It OID
+The object identifier whose value to retrive.
+At least one OID should be provided for
+.Nm bsnmpget
+to be able to send a request.
+.Pp
+For
+.Nm bsnmpwalk
+this is the root object identifier of the subtree whose values are to be
+retrived.
+If no OID is provided
+.Nm bsnmpwalk
+will walk the mib2 subtree rooted
+at .iso(1).org(3).dod(6).internet(1).mgmt(2).mib2(1) .
+.Pp
+Any of the formats used to print a single variable
+is valid as input OID:
+.Bl -tag -width \&
+.It 1.3.6.1.2.1.25.1.1.0
+.It sysDescr
+.It ifPhysAddress.1
+.It ifRcvAddressStatus.2.6.255.255.255.255.255.255
+.It ifRcvAddressType[2,ff:ff:ff:ff:ff:ff]
+.It ifRcvAddressStatus[Integer:1,OctetString:ff:ff:ff:ff:ff:ff]
+(requires
+.Fl o Ar verbose
+option)
+.El
+.Pp
+Square brackets are used to denote an entry's indexes.
+When used in an input OID, the square brackets may have to be
+escaped or the OID has to be quoted to protect it from the shell.
+Note there is no difference between ifName.1 and "ifName[1]".
+.It OID Ns = Ns Ar [syntax Ns :] Ns Ar value
+The object identifier with its syntax type and value that is to be set.
+At least one such string OID=[syntax:]value should be provided to
+.Nm bsnmpset
+to be able to send a request.
+.Bl -tag -width \&
+.It Cm OID
+OID may be input as a string, a string followed by a random number of integers
+(suboids) separated by dots, a sequence of integers separated by dots - that is
+if
+.Ar n
+options is used - and in such case a syntax is required for every value,
+or a string followed by square brackets (used to denote an entry's indexes) and
+corresponding indexes.
+Any of formats used to print a single variable by
+.Nm bsnmpset is
+valid for inpit OID as well:
+.Bl -tag -width \&
+.It 1.3.6.1.2.1.25.1.1.0=TimeTicks:537615486
+.It sysLocation=OctetString:"@ Home" (with Fl o Ar verbose No option)
+.It sysLocation.0="@ Home"
+.It 1.3.6.1.2.1.2.2.1.6.1=OctetString:ffffffffffff
+.It ifPhysAddress.1="00:02:b3:1d:1c:a3"
+.It ifRcvAddressStatus.1.6.255.255.255.255.255.255=1
+.It "ifRcvAddressStatus[Integer:1,OctetString:ff:ff:ff:ff:ff:ff]=Integer:1"
+(with
+.Fl o Ar verbose
+option)
+.El
+.It Cm syntax
+where syntax string is one of:
+Integer, OctetString, OID, IpAddress, Counter32, Gauge, TimeTicks, Counter64.
+.It Cm value
+The value to be set - IP address in form of u.u.u.u - for example
+1.3.1.6.1.2.0=IpAddress:192.168.0.1, strings require inverted-commas if they
+contain any special characters or spaces, all other numeric types don't.
+.El
+.El
+.Sh ENVIRONMENT
+.Nm ,
+.Nm bsnmpwalk
+and
+.Nm bsnmpset
+use the following environment variables:
+.Bl -tag -width SNMPAUTH
+.It Ev SNMPAUTH
+Specifies a default SNMP USM authentication protocol.
+.It Ev SNMPPRIV
+Specifies a default SNMP USM privacy protocol.
+.It Ev SNMPUSER
+Specifies a default SNMP USM user name.
+.It Ev SNMPPASSWD
+Specifies the SNMP USM plain text password to use when calculating localized
+authentication and privacy keys. If this variable exists in the environment,
+SMNPv3 is the default version to use for outgoing requests.
+.El
+.Sh SEE ALSO
+.Xr gensnmpdef 1
+.Sh AUTHORS
+.An Shteryana Shopova Aq syrinx@FreeBSD.org
diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
new file mode 100644
index 0000000..fb0c7e5
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
@@ -0,0 +1,1289 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@FreeBSD.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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.
+ *
+ * Bsnmpget and bsnmpwalk are simple tools for querying SNMP agents,
+ * bsnmpset can be used to set MIB objects in an agent.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+#include <bsnmp/snmpclient.h>
+#include "bsnmptc.h"
+#include "bsnmptools.h"
+
+static const char *program_name = NULL;
+static enum program_e {
+ BSNMPGET,
+ BSNMPWALK,
+ BSNMPSET
+} program;
+
+/* *****************************************************************************
+ * Common bsnmptools functions.
+ */
+static void
+usage(void)
+{
+ fprintf(stderr,
+"Usage:\n"
+"%s %s [-A options] [-b buffersize] [-C options] [-I options]\n"
+"\t[-i filelist] [-l filename]%s [-o output] [-P options]\n"
+"\t%s[-r retries] [-s [trans::][community@][server][:port]]\n"
+"\t[-t timeout] [-U options] [-v version]%s\n",
+ program_name,
+ (program == BSNMPGET) ? "[-aDdehnK]" :
+ (program == BSNMPWALK) ? "[-dhnK]" :
+ (program == BSNMPSET) ? "[-adehnK]" :
+ "",
+ (program == BSNMPGET || program == BSNMPWALK) ?
+ " [-M max-repetitions] [-N non-repeaters]" : "",
+ (program == BSNMPGET || program == BSNMPWALK) ? "[-p pdu] " : "",
+ (program == BSNMPGET) ? " OID [OID ...]" :
+ (program == BSNMPWALK || program == BSNMPSET) ? " [OID ...]" :
+ ""
+ );
+}
+
+static int32_t
+parse_max_repetitions(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ uint32_t v;
+
+ assert(opt_arg != NULL);
+
+ v = strtoul(opt_arg, (void *) NULL, 10);
+
+ if (v > SNMP_MAX_BINDINGS) {
+ warnx("Max repetitions value greater than %d maximum allowed.",
+ SNMP_MAX_BINDINGS);
+ return (-1);
+ }
+
+ SET_MAXREP(snmptoolctx, v);
+ return (2);
+}
+
+static int32_t
+parse_non_repeaters(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ uint32_t v;
+
+ assert(opt_arg != NULL);
+
+ v = strtoul(opt_arg, (void *) NULL, 10);
+
+ if (v > SNMP_MAX_BINDINGS) {
+ warnx("Non repeaters value greater than %d maximum allowed.",
+ SNMP_MAX_BINDINGS);
+ return (-1);
+ }
+
+ SET_NONREP(snmptoolctx, v);
+ return (2);
+}
+
+static int32_t
+parse_pdu_type(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ assert(opt_arg != NULL);
+
+ if (strcasecmp(opt_arg, "getbulk") == 0)
+ SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETBULK);
+ else if (strcasecmp(opt_arg, "getnext") == 0)
+ SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETNEXT);
+ else if (strcasecmp(opt_arg, "get") == 0)
+ SET_PDUTYPE(snmptoolctx, SNMP_PDU_GET);
+ else {
+ warnx("PDU type '%s' not supported.", opt_arg);
+ return (-1);
+ }
+
+ return (2);
+}
+
+static int32_t
+snmptool_parse_options(struct snmp_toolinfo *snmptoolctx, int argc, char **argv)
+{
+ int32_t count, optnum = 0;
+ int ch;
+ const char *opts;
+
+ switch (program) {
+ case BSNMPWALK:
+ opts = "dhnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";
+ break;
+ case BSNMPGET:
+ opts = "aDdehnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";
+ break;
+ case BSNMPSET:
+ opts = "adehnKA:b:C:I:i:l:o:P:r:s:t:U:v:";
+ break;
+ default:
+ return (-1);
+ }
+
+ while ((ch = getopt(argc, argv, opts)) != EOF) {
+ switch (ch) {
+ case 'A':
+ count = parse_authentication(snmptoolctx, optarg);
+ break;
+ case 'a':
+ count = parse_skip_access(snmptoolctx);
+ break;
+ case 'b':
+ count = parse_buflen(optarg);
+ break;
+ case 'D':
+ count = parse_discovery(snmptoolctx);
+ break;
+ case 'd':
+ count = parse_debug();
+ break;
+ case 'e':
+ count = parse_errors(snmptoolctx);
+ break;
+ case 'h':
+ usage();
+ return (-2);
+ case 'C':
+ count = parse_context(snmptoolctx, optarg);
+ break;
+ case 'I':
+ count = parse_include(snmptoolctx, optarg);
+ break;
+ case 'i':
+ count = parse_file(snmptoolctx, optarg);
+ break;
+ case 'K':
+ count = parse_local_key(snmptoolctx);
+ break;
+ case 'l':
+ count = parse_local_path(optarg);
+ break;
+ case 'M':
+ count = parse_max_repetitions(snmptoolctx, optarg);
+ break;
+ case 'N':
+ count = parse_non_repeaters(snmptoolctx, optarg);
+ break;
+ case 'n':
+ count = parse_num_oids(snmptoolctx);
+ break;
+ case 'o':
+ count = parse_output(snmptoolctx, optarg);
+ break;
+ case 'P':
+ count = parse_privacy(snmptoolctx, optarg);
+ break;
+ case 'p':
+ count = parse_pdu_type(snmptoolctx, optarg);
+ break;
+ case 'r':
+ count = parse_retry(optarg);
+ break;
+ case 's':
+ count = parse_server(optarg);
+ break;
+ case 't':
+ count = parse_timeout(optarg);
+ break;
+ case 'U':
+ count = parse_user_security(snmptoolctx, optarg);
+ break;
+ case 'v':
+ count = parse_version(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ return (-1);
+ }
+ if (count < 0)
+ return (-1);
+ optnum += count;
+ }
+
+ return (optnum);
+}
+
+/*
+ * Read user input OID - one of following formats:
+ * 1) 1.2.1.1.2.1.0 - that is if option numeric was given;
+ * 2) string - in such case append .0 to the asn_oid subs;
+ * 3) string.1 - no additional processing required in such case.
+ */
+static char *
+snmptools_parse_stroid(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_object *obj, char *argv)
+{
+ char string[MAXSTR], *str;
+ int32_t i = 0;
+ struct asn_oid in_oid;
+
+ str = argv;
+
+ if (*str == '.')
+ str++;
+
+ while (isalpha(*str) || *str == '_' || (i != 0 && isdigit(*str))) {
+ str++;
+ i++;
+ }
+
+ if (i <= 0 || i >= MAXSTR)
+ return (NULL);
+
+ memset(&in_oid, 0, sizeof(struct asn_oid));
+ if ((str = snmp_parse_suboid((argv + i), &in_oid)) == NULL) {
+ warnx("Invalid OID - %s", argv);
+ return (NULL);
+ }
+
+ strlcpy(string, argv, i + 1);
+ if (snmp_lookup_oidall(snmptoolctx, obj, string) < 0) {
+ warnx("No entry for %s in mapping lists", string);
+ return (NULL);
+ }
+
+ /* If OID given on command line append it. */
+ if (in_oid.len > 0)
+ asn_append_oid(&(obj->val.var), &in_oid);
+ else if (*str == '[') {
+ if ((str = snmp_parse_index(snmptoolctx, str + 1, obj)) == NULL)
+ return (NULL);
+ } else if (obj->val.syntax > 0 && GET_PDUTYPE(snmptoolctx) ==
+ SNMP_PDU_GET) {
+ if (snmp_suboid_append(&(obj->val.var), (asn_subid_t) 0) < 0)
+ return (NULL);
+ }
+
+ return (str);
+}
+
+static int32_t
+snmptools_parse_oid(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_object *obj, char *argv)
+{
+ if (argv == NULL)
+ return (-1);
+
+ if (ISSET_NUMERIC(snmptoolctx)) {
+ if (snmp_parse_numoid(argv, &(obj->val.var)) < 0)
+ return (-1);
+ } else {
+ if (snmptools_parse_stroid(snmptoolctx, obj, argv) == NULL &&
+ snmp_parse_numoid(argv, &(obj->val.var)) < 0)
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int32_t
+snmptool_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)
+{
+ if (obj->error > 0)
+ return (0);
+
+ asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));
+ pdu->nbindings++;
+
+ return (pdu->nbindings);
+}
+
+/* *****************************************************************************
+ * bsnmpget private functions.
+ */
+static int32_t
+snmpget_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
+ struct snmp_object *obj)
+{
+ if (pdu->version == SNMP_V1 && obj->val.syntax ==
+ SNMP_SYNTAX_COUNTER64) {
+ warnx("64-bit counters are not supported in SNMPv1 PDU");
+ return (-1);
+ }
+
+ if (ISSET_NUMERIC(snmptoolctx) || pdu->type == SNMP_PDU_GETNEXT ||
+ pdu->type == SNMP_PDU_GETBULK)
+ return (1);
+
+ if (pdu->type == SNMP_PDU_GET && obj->val.syntax == SNMP_SYNTAX_NULL) {
+ warnx("Only leaf object values can be added to GET PDU");
+ return (-1);
+ }
+
+ return (1);
+}
+
+/*
+ * In case of a getbulk PDU, the error_status and error_index fields are used by
+ * libbsnmp to hold the values of the non-repeaters and max-repetitions fields
+ * that are present only in the getbulk - so before sending the PDU make sure
+ * these have correct values as well.
+ */
+static void
+snmpget_fix_getbulk(struct snmp_pdu *pdu, uint32_t max_rep, uint32_t non_rep)
+{
+ assert(pdu != NULL);
+
+ if (pdu->nbindings < non_rep)
+ pdu->error_status = pdu->nbindings;
+ else
+ pdu->error_status = non_rep;
+
+ if (max_rep > 0)
+ pdu->error_index = max_rep;
+ else
+ pdu->error_index = 1;
+}
+
+static int
+snmptool_get(struct snmp_toolinfo *snmptoolctx)
+{
+ struct snmp_pdu req, resp;
+
+ snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));
+
+ while ((snmp_pdu_add_bindings(snmptoolctx, snmpget_verify_vbind,
+ snmptool_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {
+
+ if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)
+ snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
+ GET_NONREP(snmptoolctx));
+
+ if (snmp_dialog(&req, &resp) == -1) {
+ warnx("Snmp dialog - %s", strerror(errno));
+ break;
+ }
+
+ if (snmp_parse_resp(&resp, &req) >= 0) {
+ snmp_output_resp(snmptoolctx, &resp, NULL);
+ break;
+ }
+
+ snmp_output_err_resp(snmptoolctx, &resp);
+ if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK ||
+ !ISSET_RETRY(snmptoolctx))
+ break;
+
+ /*
+ * Loop through the object list and set object->error to the
+ * varbinding that caused the error.
+ */
+ if (snmp_object_seterror(snmptoolctx,
+ &(resp.bindings[resp.error_index - 1]),
+ resp.error_status) <= 0)
+ break;
+
+ fprintf(stderr, "Retrying...\n");
+ snmp_pdu_free(&resp);
+ snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));
+ }
+
+ snmp_pdu_free(&resp);
+
+ return (0);
+}
+
+
+/* *****************************************************************************
+ * bsnmpwalk private functions.
+ */
+/* The default tree to walk. */
+static const struct asn_oid snmp_mibII_OID = {
+ 6 , { 1, 3, 6, 1, 2, 1 }
+};
+
+static int32_t
+snmpwalk_add_default(struct snmp_toolinfo *snmptoolctx __unused,
+ struct snmp_object *obj, char *string __unused)
+{
+ asn_append_oid(&(obj->val.var), &snmp_mibII_OID);
+ return (1);
+}
+
+/*
+ * Prepare the next GetNext/Get PDU to send.
+ */
+static void
+snmpwalk_nextpdu_create(uint32_t op, struct asn_oid *var, struct snmp_pdu *pdu)
+{
+ snmp_pdu_create(pdu, op);
+ asn_append_oid(&(pdu->bindings[0].var), var);
+ pdu->nbindings = 1;
+}
+
+static int
+snmptool_walk(struct snmp_toolinfo *snmptoolctx)
+{
+ struct snmp_pdu req, resp;
+ struct asn_oid root; /* Keep the initial oid. */
+ int32_t outputs, rc;
+ uint32_t op;
+
+ if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)
+ op = SNMP_PDU_GETBULK;
+ else
+ op = SNMP_PDU_GETNEXT;
+
+ snmp_pdu_create(&req, op);
+
+ while ((rc = snmp_pdu_add_bindings(snmptoolctx, NULL,
+ snmptool_add_vbind, &req, 1)) > 0) {
+
+ /* Remember the root where the walk started from. */
+ memset(&root, 0, sizeof(struct asn_oid));
+ asn_append_oid(&root, &(req.bindings[0].var));
+
+ if (op == SNMP_PDU_GETBULK)
+ snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
+ GET_NONREP(snmptoolctx));
+
+ outputs = 0;
+ while (snmp_dialog(&req, &resp) >= 0) {
+ if ((snmp_parse_resp(&resp, &req)) < 0) {
+ snmp_output_err_resp(snmptoolctx, &resp);
+ snmp_pdu_free(&resp);
+ outputs = -1;
+ break;
+ }
+
+ rc = snmp_output_resp(snmptoolctx, &resp, &root);
+ if (rc < 0) {
+ snmp_pdu_free(&resp);
+ outputs = -1;
+ break;
+ }
+
+ outputs += rc;
+ snmp_pdu_free(&resp);
+
+ if (rc < resp.nbindings)
+ break;
+
+ snmpwalk_nextpdu_create(op,
+ &(resp.bindings[resp.nbindings - 1].var), &req);
+ if (op == SNMP_PDU_GETBULK)
+ snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
+ GET_NONREP(snmptoolctx));
+ }
+
+ /* Just in case our root was a leaf. */
+ if (outputs == 0) {
+ snmpwalk_nextpdu_create(SNMP_PDU_GET, &root, &req);
+ if (snmp_dialog(&req, &resp) == SNMP_CODE_OK) {
+ if (snmp_parse_resp(&resp,&req) < 0)
+ snmp_output_err_resp(snmptoolctx, &resp);
+ else
+ snmp_output_resp(snmptoolctx, &(resp), NULL);
+
+ snmp_pdu_free(&resp);
+ } else
+ warnx("Snmp dialog - %s", strerror(errno));
+ }
+
+ if (snmp_object_remove(snmptoolctx, &root) < 0) {
+ warnx("snmp_object_remove");
+ break;
+ }
+
+ snmp_pdu_create(&req, op);
+ }
+
+ if (rc == 0)
+ return (0);
+ else
+ return (1);
+}
+
+/* *****************************************************************************
+ * bsnmpset private functions.
+ */
+
+static int32_t
+parse_oid_numeric(struct snmp_value *value, char *val)
+{
+ char *endptr;
+ int32_t saved_errno;
+ asn_subid_t suboid;
+
+ do {
+ saved_errno = errno;
+ errno = 0;
+ suboid = strtoul(val, &endptr, 10);
+ if (errno != 0) {
+ warnx("Value %s not supported - %s", val,
+ strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+ errno = saved_errno;
+ if ((asn_subid_t) suboid > ASN_MAXID) {
+ warnx("Suboid %u > ASN_MAXID", suboid);
+ return (-1);
+ }
+ if (snmp_suboid_append(&(value->v.oid), suboid) < 0)
+ return (-1);
+ val = endptr + 1;
+ } while (*endptr == '.');
+
+ if (*endptr != '\0')
+ warnx("OID value %s not supported", val);
+
+ value->syntax = SNMP_SYNTAX_OID;
+ return (0);
+}
+
+/*
+ * Allow OID leaf in both forms:
+ * 1) 1.3.6.1.2... -> in such case call directly the function reading raw OIDs;
+ * 2) begemotSnmpdAgentFreeBSD -> lookup the ASN OID corresponding to that.
+ */
+static int32_t
+parse_oid_string(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_value *value, char *string)
+{
+ struct snmp_object obj;
+
+ if (isdigit(string[0]))
+ return (parse_oid_numeric(value, string));
+
+ memset(&obj, 0, sizeof(struct snmp_object));
+ if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
+ warnx("Unknown OID enum string - %s", string);
+ return (-1);
+ }
+
+ asn_append_oid(&(value->v.oid), &(obj.val.var));
+ return (1);
+}
+
+static int32_t
+parse_ip(struct snmp_value * value, char * val)
+{
+ uint32_t v;
+ int32_t i;
+ char *endptr, *str;
+
+ str = val;
+ for (i = 0; i < 4; i++) {
+ v = strtoul(str, &endptr, 10);
+ if (v > 0xff)
+ return (-1);
+ if (*endptr != '.' && *endptr != '\0' && i != 3)
+ break;
+ str = endptr + 1;
+ value->v.ipaddress[i] = (uint8_t) v;
+ }
+
+ value->syntax = SNMP_SYNTAX_IPADDRESS;
+ return (0);
+}
+
+static int32_t
+parse_int(struct snmp_value *value, char *val)
+{
+ char *endptr;
+ int32_t v, saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtol(val, &endptr, 10);
+
+ if (errno != 0) {
+ warnx("Value %s not supported - %s", val, strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ value->syntax = SNMP_SYNTAX_INTEGER;
+ value->v.integer = v;
+ errno = saved_errno;
+
+ return (0);
+}
+
+static int32_t
+parse_int_string(struct snmp_object *object, char *val)
+{
+ int32_t v;
+
+ if (isdigit(val[0]))
+ return ((parse_int(&(object->val), val)));
+
+ if (object->info == NULL) {
+ warnx("Unknown enumerated integer type - %s", val);
+ return (-1);
+ }
+ if ((v = enum_number_lookup(object->info->snmp_enum, val)) < 0)
+ warnx("Unknown enumerated integer type - %s", val);
+
+ object->val.v.integer = v;
+ return (1);
+}
+
+/*
+ * Here syntax may be one of SNMP_SYNTAX_COUNTER, SNMP_SYNTAX_GAUGE,
+ * SNMP_SYNTAX_TIMETICKS.
+ */
+static int32_t
+parse_uint(struct snmp_value *value, char *val)
+{
+ char *endptr;
+ uint32_t v = 0;
+ int32_t saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoul(val, &endptr, 10);
+
+ if (errno != 0) {
+ warnx("Value %s not supported - %s", val, strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ value->v.uint32 = v;
+ errno = saved_errno;
+
+ return (0);
+}
+
+static int32_t
+parse_ticks(struct snmp_value *value, char *val)
+{
+ if (parse_uint(value, val) < 0)
+ return (-1);
+
+ value->syntax = SNMP_SYNTAX_TIMETICKS;
+ return (0);
+}
+
+static int32_t
+parse_gauge(struct snmp_value *value, char *val)
+{
+ if (parse_uint(value, val) < 0)
+ return (-1);
+
+ value->syntax = SNMP_SYNTAX_GAUGE;
+ return (0);
+}
+
+static int32_t
+parse_counter(struct snmp_value *value, char *val)
+{
+ if (parse_uint(value, val) < 0)
+ return (-1);
+
+ value->syntax = SNMP_SYNTAX_COUNTER;
+ return (0);
+}
+
+static int32_t
+parse_uint64(struct snmp_value *value, char *val)
+{
+ char *endptr;
+ int32_t saved_errno;
+ uint64_t v;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoull(val, &endptr, 10);
+
+ if (errno != 0) {
+ warnx("Value %s not supported - %s", val, strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ value->syntax = SNMP_SYNTAX_COUNTER64;
+ value->v.counter64 = v;
+ errno = saved_errno;
+
+ return (0);
+}
+
+static int32_t
+parse_syntax_val(struct snmp_value *value, enum snmp_syntax syntax, char *val)
+{
+ switch (syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ return (parse_int(value, val));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (parse_ip(value, val));
+ case SNMP_SYNTAX_COUNTER:
+ return (parse_counter(value, val));
+ case SNMP_SYNTAX_GAUGE:
+ return (parse_gauge(value, val));
+ case SNMP_SYNTAX_TIMETICKS:
+ return (parse_ticks(value, val));
+ case SNMP_SYNTAX_COUNTER64:
+ return (parse_uint64(value, val));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_tc2oct(SNMP_STRING, value, val));
+ case SNMP_SYNTAX_OID:
+ return (parse_oid_numeric(value, val));
+ default:
+ /* NOTREACHED */
+ break;
+ }
+
+ return (-1);
+}
+
+/*
+ * Parse a command line argument of type OID=syntax:value and fill in whatever
+ * fields can be derived from the input into snmp_value structure. Reads numeric
+ * OIDs.
+ */
+static int32_t
+parse_pair_numoid_val(char *str, struct snmp_value *snmp_val)
+{
+ int32_t cnt;
+ char *ptr;
+ enum snmp_syntax syntax;
+ char oid_str[ASN_OIDSTRLEN];
+
+ ptr = str;
+ for (cnt = 0; cnt < ASN_OIDSTRLEN; cnt++)
+ if (ptr[cnt] == '=')
+ break;
+
+ if (cnt >= ASN_OIDSTRLEN) {
+ warnx("OID too long - %s", str);
+ return (-1);
+ }
+ strlcpy(oid_str, ptr, (size_t) (cnt + 1));
+
+ ptr = str + cnt + 1;
+ for (cnt = 0; cnt < MAX_CMD_SYNTAX_LEN; cnt++)
+ if(ptr[cnt] == ':')
+ break;
+
+ if (cnt >= MAX_CMD_SYNTAX_LEN) {
+ warnx("Unknown syntax in OID - %s", str);
+ return (-1);
+ }
+
+ if ((syntax = parse_syntax(ptr)) <= SNMP_SYNTAX_NULL) {
+ warnx("Unknown syntax in OID - %s", ptr);
+ return (-1);
+ }
+
+ ptr = ptr + cnt + 1;
+ for (cnt = 0; cnt < MAX_OCTSTRING_LEN; cnt++)
+ if (ptr[cnt] == '\0')
+ break;
+
+ if (ptr[cnt] != '\0') {
+ warnx("Value string too long - %s",ptr);
+ return (-1);
+ }
+
+ /*
+ * Here try parsing the OIDs and syntaxes and then check values - have
+ * to know syntax to check value boundaries.
+ */
+ if (snmp_parse_numoid(oid_str, &(snmp_val->var)) < 0) {
+ warnx("Error parsing OID %s",oid_str);
+ return (-1);
+ }
+
+ if (parse_syntax_val(snmp_val, syntax, ptr) < 0)
+ return (-1);
+
+ return (1);
+}
+
+/* XXX-BZ aruments should be swapped. */
+static int32_t
+parse_syntax_strval(struct snmp_toolinfo *snmptoolctx, char *str,
+ struct snmp_object *object)
+{
+ uint32_t len;
+ enum snmp_syntax syn;
+
+ /*
+ * Syntax string here not required - still may be present.
+ */
+
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
+ for (len = 0 ; *(str + len) != ':'; len++) {
+ if (*(str + len) == '\0') {
+ warnx("Syntax missing in value - %s", str);
+ return (-1);
+ }
+ }
+ if ((syn = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
+ warnx("Unknown syntax in - %s", str);
+ return (-1);
+ }
+ if (syn != object->val.syntax) {
+ if (!ISSET_ERRIGNORE(snmptoolctx)) {
+ warnx("Bad syntax in - %s", str);
+ return (-1);
+ } else
+ object->val.syntax = syn;
+ }
+ len++;
+ } else
+ len = 0;
+
+ switch (object->val.syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ return (parse_int_string(object, str + len));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (parse_ip(&(object->val), str + len));
+ case SNMP_SYNTAX_COUNTER:
+ return (parse_counter(&(object->val), str + len));
+ case SNMP_SYNTAX_GAUGE:
+ return (parse_gauge(&(object->val), str + len));
+ case SNMP_SYNTAX_TIMETICKS:
+ return (parse_ticks(&(object->val), str + len));
+ case SNMP_SYNTAX_COUNTER64:
+ return (parse_uint64(&(object->val), str + len));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_tc2oct(object->info->tc, &(object->val),
+ str + len));
+ case SNMP_SYNTAX_OID:
+ return (parse_oid_string(snmptoolctx, &(object->val),
+ str + len));
+ default:
+ /* NOTREACHED */
+ break;
+ }
+
+ return (-1);
+}
+
+static int32_t
+parse_pair_stroid_val(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_object *obj, char *argv)
+{
+ char *ptr;
+
+ if ((ptr = snmptools_parse_stroid(snmptoolctx, obj, argv)) == NULL)
+ return (-1);
+
+ if (*ptr != '=') {
+ warnx("Value to set expected after OID");
+ return (-1);
+ }
+
+ if (parse_syntax_strval(snmptoolctx, ptr + 1, obj) < 0)
+ return (-1);
+
+ return (1);
+}
+
+
+static int32_t
+snmpset_parse_oid(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_object *obj, char *argv)
+{
+ if (argv == NULL)
+ return (-1);
+
+ if (ISSET_NUMERIC(snmptoolctx)) {
+ if (parse_pair_numoid_val(argv, &(obj->val)) < 0)
+ return (-1);
+ } else {
+ if (parse_pair_stroid_val(snmptoolctx, obj, argv) < 0)
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int32_t
+add_ip_syntax(struct snmp_value *dst, struct snmp_value *src)
+{
+ int8_t i;
+
+ dst->syntax = SNMP_SYNTAX_IPADDRESS;
+ for (i = 0; i < 4; i++)
+ dst->v.ipaddress[i] = src->v.ipaddress[i];
+
+ return (1);
+}
+
+static int32_t
+add_octstring_syntax(struct snmp_value *dst, struct snmp_value *src)
+{
+ if (src->v.octetstring.len > ASN_MAXOCTETSTRING) {
+ warnx("OctetString len too big - %u",src->v.octetstring.len);
+ return (-1);
+ }
+
+ if ((dst->v.octetstring.octets = malloc(src->v.octetstring.len)) ==
+ NULL) {
+ syslog(LOG_ERR, "malloc() failed - %s", strerror(errno));
+ return (-1);
+ }
+
+ memcpy(dst->v.octetstring.octets, src->v.octetstring.octets,
+ src->v.octetstring.len);
+ dst->syntax = SNMP_SYNTAX_OCTETSTRING;
+ dst->v.octetstring.len = src->v.octetstring.len;
+
+ return(0);
+}
+
+static int32_t
+add_oid_syntax(struct snmp_value *dst, struct snmp_value *src)
+{
+ asn_append_oid(&(dst->v.oid), &(src->v.oid));
+ dst->syntax = SNMP_SYNTAX_OID;
+ return (0);
+}
+
+/*
+ * Check syntax - if one of SNMP_SYNTAX_NULL, SNMP_SYNTAX_NOSUCHOBJECT,
+ * SNMP_SYNTAX_NOSUCHINSTANCE, SNMP_SYNTAX_ENDOFMIBVIEW or anything not known -
+ * return error.
+ */
+static int32_t
+snmpset_add_value(struct snmp_value *dst, struct snmp_value *src)
+{
+ if (dst == NULL || src == NULL)
+ return (-1);
+
+ switch (src->syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ dst->v.integer = src->v.integer;
+ dst->syntax = SNMP_SYNTAX_INTEGER;
+ break;
+ case SNMP_SYNTAX_TIMETICKS:
+ dst->v.uint32 = src->v.uint32;
+ dst->syntax = SNMP_SYNTAX_TIMETICKS;
+ break;
+ case SNMP_SYNTAX_GAUGE:
+ dst->v.uint32 = src->v.uint32;
+ dst->syntax = SNMP_SYNTAX_GAUGE;
+ break;
+ case SNMP_SYNTAX_COUNTER:
+ dst->v.uint32 = src->v.uint32;
+ dst->syntax = SNMP_SYNTAX_COUNTER;
+ break;
+ case SNMP_SYNTAX_COUNTER64:
+ dst->v.counter64 = src->v.counter64;
+ dst->syntax = SNMP_SYNTAX_COUNTER64;
+ break;
+ case SNMP_SYNTAX_IPADDRESS:
+ add_ip_syntax(dst, src);
+ break;
+ case SNMP_SYNTAX_OCTETSTRING:
+ add_octstring_syntax(dst, src);
+ break;
+ case SNMP_SYNTAX_OID:
+ add_oid_syntax(dst, src);
+ break;
+ default:
+ warnx("Unknown syntax %d", src->syntax);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int32_t
+snmpset_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
+ struct snmp_object *obj)
+{
+ if (pdu->version == SNMP_V1 && obj->val.syntax ==
+ SNMP_SYNTAX_COUNTER64) {
+ warnx("64-bit counters are not supported in SNMPv1 PDU");
+ return (-1);
+ }
+
+ if (ISSET_NUMERIC(snmptoolctx) || ISSET_ERRIGNORE(snmptoolctx))
+ return (1);
+
+ if (obj->info->access < SNMP_ACCESS_SET) {
+ warnx("Object %s not accessible for set - try 'bsnmpset -a'",
+ obj->info->string);
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int32_t
+snmpset_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)
+{
+ if (pdu->nbindings > SNMP_MAX_BINDINGS) {
+ warnx("Too many OIDs for one PDU");
+ return (-1);
+ }
+
+ if (obj->error > 0)
+ return (0);
+
+ if (snmpset_add_value(&(pdu->bindings[pdu->nbindings]), &(obj->val))
+ < 0)
+ return (-1);
+
+ asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));
+ pdu->nbindings++;
+
+ return (pdu->nbindings);
+}
+
+static int
+snmptool_set(struct snmp_toolinfo *snmptoolctx)
+{
+ struct snmp_pdu req, resp;
+
+ snmp_pdu_create(&req, SNMP_PDU_SET);
+
+ while ((snmp_pdu_add_bindings(snmptoolctx, snmpset_verify_vbind,
+ snmpset_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {
+ if (snmp_dialog(&req, &resp)) {
+ warnx("Snmp dialog - %s", strerror(errno));
+ break;
+ }
+
+ if (snmp_pdu_check(&req, &resp) > 0) {
+ if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
+ snmp_output_resp(snmptoolctx, &resp, NULL);
+ break;
+ }
+
+ snmp_output_err_resp(snmptoolctx, &resp);
+ if (!ISSET_RETRY(snmptoolctx))
+ break;
+
+ if (snmp_object_seterror(snmptoolctx,
+ &(resp.bindings[resp.error_index - 1]),
+ resp.error_status) <= 0)
+ break;
+
+ fprintf(stderr, "Retrying...\n");
+ snmp_pdu_free(&req);
+ snmp_pdu_free(&resp);
+ snmp_pdu_create(&req, SNMP_PDU_SET);
+ }
+
+ snmp_pdu_free(&resp);
+
+ return (0);
+}
+
+/* *****************************************************************************
+ * main
+ */
+/*
+ * According to command line options prepare SNMP Get | GetNext | GetBulk PDU.
+ * Wait for a response and print it.
+ */
+/*
+ * Do a 'snmp walk' - according to command line options request for values
+ * lexicographically subsequent and subrooted at a common node. Send a GetNext
+ * PDU requesting the value for each next variable and print the response. Stop
+ * when a Response PDU is received that contains the value of a variable not
+ * subrooted at the variable the walk started.
+ */
+int
+main(int argc, char ** argv)
+{
+ struct snmp_toolinfo snmptoolctx;
+ int32_t oid_cnt, last_oid, opt_num;
+ int rc = 0;
+
+ /* Make sure program_name is set and valid. */
+ if (*argv == NULL)
+ program_name = "snmptool";
+ else {
+ program_name = strrchr(*argv, '/');
+ if (program_name != NULL)
+ program_name++;
+ else
+ program_name = *argv;
+ }
+
+ if (program_name == NULL) {
+ fprintf(stderr, "Error: No program name?\n");
+ exit (1);
+ } else if (strcmp(program_name, "bsnmpget") == 0)
+ program = BSNMPGET;
+ else if (strcmp(program_name, "bsnmpwalk") == 0)
+ program = BSNMPWALK;
+ else if (strcmp(program_name, "bsnmpset") == 0)
+ program = BSNMPSET;
+ else {
+ fprintf(stderr, "Unknown snmp tool name '%s'.\n", program_name);
+ exit (1);
+ }
+
+ /* Initialize. */
+ if (snmptool_init(&snmptoolctx) < 0)
+ exit (1);
+
+ if ((opt_num = snmptool_parse_options(&snmptoolctx, argc, argv)) < 0) {
+ snmp_tool_freeall(&snmptoolctx);
+ /* On -h (help) exit without error. */
+ if (opt_num == -2)
+ exit(0);
+ else
+ exit(1);
+ }
+
+ oid_cnt = argc - opt_num - 1;
+ if (oid_cnt == 0) {
+ switch (program) {
+ case BSNMPGET:
+ if (!ISSET_EDISCOVER(&snmptoolctx) &&
+ !ISSET_LOCALKEY(&snmptoolctx)) {
+ fprintf(stderr, "No OID given.\n");
+ usage();
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+ break;
+
+ case BSNMPWALK:
+ if (snmp_object_add(&snmptoolctx, snmpwalk_add_default,
+ NULL) < 0) {
+ fprintf(stderr,
+ "Error setting default subtree.\n");
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+ break;
+
+ case BSNMPSET:
+ fprintf(stderr, "No OID given.\n");
+ usage();
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+ }
+
+ if (snmp_import_all(&snmptoolctx) < 0) {
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+
+ /* A simple sanity check - can not send GETBULK when using SNMPv1. */
+ if (program == BSNMPGET && snmp_client.version == SNMP_V1 &&
+ GET_PDUTYPE(&snmptoolctx) == SNMP_PDU_GETBULK) {
+ fprintf(stderr, "Cannot send GETBULK PDU with SNMPv1.\n");
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+
+ for (last_oid = argc - 1; oid_cnt > 0; last_oid--, oid_cnt--) {
+ if ((snmp_object_add(&snmptoolctx, (program == BSNMPSET) ?
+ snmpset_parse_oid : snmptools_parse_oid,
+ argv[last_oid])) < 0) {
+ fprintf(stderr, "Error parsing OID string '%s'.\n",
+ argv[last_oid]);
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+ }
+
+ if (snmp_open(NULL, NULL, NULL, NULL)) {
+ warnx("Failed to open snmp session: %s.", strerror(errno));
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+
+ if (snmp_client.version == SNMP_V3 && snmp_client.engine.engine_len == 0)
+ SET_EDISCOVER(&snmptoolctx);
+
+ if (ISSET_EDISCOVER(&snmptoolctx) &&
+ snmp_discover_engine(snmptoolctx.passwd) < 0) {
+ warnx("Unknown SNMP Engine ID: %s.", strerror(errno));
+ rc = 1;
+ goto cleanup;
+ }
+
+ if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||
+ ISSET_EDISCOVER(&snmptoolctx))
+ snmp_output_engine();
+
+ if (snmp_client.version == SNMP_V3 && ISSET_LOCALKEY(&snmptoolctx) &&
+ !ISSET_EDISCOVER(&snmptoolctx)) {
+ if (snmp_passwd_to_keys(&snmp_client.user,
+ snmptoolctx.passwd) != SNMP_CODE_OK ||
+ snmp_get_local_keys(&snmp_client.user,
+ snmp_client.engine.engine_id,
+ snmp_client.engine.engine_len) != SNMP_CODE_OK) {
+ warnx("Failed to get keys: %s.", strerror(errno));
+ rc = 1;
+ goto cleanup;
+ }
+ }
+
+ if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||
+ ISSET_EDISCOVER(&snmptoolctx))
+ snmp_output_keys();
+
+ if (ISSET_EDISCOVER(&snmptoolctx) && snmptoolctx.objects == 0)
+ goto cleanup;
+
+ switch (program) {
+ case BSNMPGET:
+ rc = snmptool_get(&snmptoolctx);
+ break;
+ case BSNMPWALK:
+ rc = snmptool_walk(&snmptoolctx);
+ break;
+ case BSNMPSET:
+ rc = snmptool_set(&snmptoolctx);
+ break;
+ }
+
+
+cleanup:
+ snmp_tool_freeall(&snmptoolctx);
+ snmp_close();
+
+ exit(rc);
+}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/Makefile b/usr.sbin/bsnmpd/tools/libbsnmptools/Makefile
new file mode 100644
index 0000000..3551464
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/Makefile
@@ -0,0 +1,13 @@
+#
+# $FreeBSD$
+#
+
+.PATH: ${.CURDIR}
+
+LIB= bsnmptools
+#INTERNALLIB=
+SRCS= bsnmpimport.c bsnmpmap.c bsnmptools.c bsnmptc.c
+
+SHLIB_MAJOR= 0
+
+.include <bsd.lib.mk>
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c
new file mode 100644
index 0000000..b92532f
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c
@@ -0,0 +1,971 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@FreeBSD.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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$
+ */
+
+/*
+ * Read file containing table description - reuse magic from gensnmptree.c.
+ * Hopefully one day most of the code here will be part of libbsnmp and
+ * this duplication won't be necessary.
+ *
+ * Syntax is:
+ * ---------
+ * file := top | top file
+ *
+ * top := tree | typedef | include
+ *
+ * tree := head elements ')'
+ *
+ * entry := head ':' index STRING elements ')'
+ *
+ * leaf := head type STRING ACCESS ')'
+ *
+ * column := head type ACCESS ')'
+ *
+ * type := BASETYPE | BASETYPE '|' subtype | enum | bits
+ *
+ * subtype := STRING
+ *
+ * enum := ENUM '(' value ')'
+ *
+ * bits := BITS '(' value ')'
+ *
+ * value := INT STRING | INT STRING value
+ *
+ * head := '(' INT STRING
+ *
+ * elements := EMPTY | elements element
+ *
+ * element := tree | leaf | column
+ *
+ * index := type | index type
+ *
+ * typedef := 'typedef' STRING type
+ *
+ * include := 'include' filespec
+ *
+ * filespec := '"' STRING '"' | '<' STRING '>'
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+#include <bsnmp/snmpagent.h> /* SNMP_INDEXES_MAX */
+#include "bsnmptc.h"
+#include "bsnmptools.h"
+
+enum snmp_tbl_entry {
+ ENTRY_NONE = 0,
+ ENTRY_INDEX,
+ ENTRY_DATA
+};
+
+enum {
+ FL_GET = 0x01,
+ FL_SET = 0x02,
+};
+
+/************************************************************
+ *
+ * Allocate memory and panic just in the case...
+ */
+static void *
+xalloc(size_t size)
+{
+ void *ptr;
+
+ if ((ptr = malloc(size)) == NULL)
+ err(1, "allocing %zu bytes", size);
+
+ return (ptr);
+}
+
+static char *
+savestr(const char *s)
+{
+ if (s == NULL)
+ return (NULL);
+
+ return (strcpy(xalloc(strlen(s) + 1), s));
+}
+
+/************************************************************
+ *
+ * Input stack
+ */
+struct input {
+ FILE *fp;
+ uint32_t lno;
+ char *fname;
+ char *path;
+ LIST_ENTRY(input) link;
+};
+
+LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
+struct input *input = NULL;
+int32_t pbchar = -1;
+
+#define MAX_PATHS 100
+
+static const char *paths[MAX_PATHS + 1] = {
+ "/usr/share/snmp/defs",
+ "/usr/local/share/snmp/defs",
+ NULL
+};
+
+static void
+input_new(FILE *fp, const char *path, const char *fname)
+{
+ struct input *ip;
+
+ ip = xalloc(sizeof(*ip));
+ ip->fp = fp;
+ ip->lno = 1;
+ ip->fname = savestr(fname);
+ ip->path = savestr(path);
+ LIST_INSERT_HEAD(&inputs, ip, link);
+
+ input = ip;
+}
+
+static void
+input_close(void)
+{
+ if (input == NULL)
+ return;
+
+ fclose(input->fp);
+ free(input->fname);
+ free(input->path);
+ LIST_REMOVE(input, link);
+ free(input);
+
+ input = LIST_FIRST(&inputs);
+}
+
+static FILE *
+tryopen(const char *path, const char *fname)
+{
+ char *fn;
+ FILE *fp;
+
+ if (path == NULL)
+ fn = savestr(fname);
+ else {
+ fn = xalloc(strlen(path) + strlen(fname) + 2);
+ sprintf(fn, "%s/%s", path, fname);
+ }
+ fp = fopen(fn, "r");
+ free(fn);
+ return (fp);
+}
+
+static int32_t
+input_fopen(const char *fname)
+{
+ FILE *fp;
+ u_int p;
+
+ if (fname[0] == '/' || fname[0] == '.' || fname[0] == '~') {
+ if ((fp = tryopen(NULL, fname)) != NULL) {
+ input_new(fp, NULL, fname);
+ return (0);
+ }
+
+ } else {
+
+ for (p = 0; paths[p] != NULL; p++)
+ if ((fp = tryopen(paths[p], fname)) != NULL) {
+ input_new(fp, paths[p], fname);
+ return (0);
+ }
+ }
+
+ warnx("cannot open '%s'", fname);
+ return (-1);
+}
+
+static int32_t
+tgetc(void)
+{
+ int c;
+
+ if (pbchar != -1) {
+ c = pbchar;
+ pbchar = -1;
+ return (c);
+ }
+
+ for (;;) {
+ if (input == NULL)
+ return (EOF);
+
+ if ((c = getc(input->fp)) != EOF)
+ return (c);
+
+ input_close();
+ }
+}
+
+static int32_t
+tungetc(int c)
+{
+
+ if (pbchar != -1)
+ return (-1);
+
+ pbchar = c;
+ return (1);
+}
+
+/************************************************************
+ *
+ * Parsing input
+ */
+enum tok {
+ TOK_EOF = 0200, /* end-of-file seen */
+ TOK_NUM, /* number */
+ TOK_STR, /* string */
+ TOK_ACCESS, /* access operator */
+ TOK_TYPE, /* type operator */
+ TOK_ENUM, /* enum token (kind of a type) */
+ TOK_TYPEDEF, /* typedef directive */
+ TOK_DEFTYPE, /* defined type */
+ TOK_INCLUDE, /* include directive */
+ TOK_FILENAME, /* filename ("foo.bar" or <foo.bar>) */
+ TOK_BITS, /* bits token (kind of a type) */
+ TOK_ERR /* unexpected char - exit */
+};
+
+static const struct {
+ const char *str;
+ enum tok tok;
+ uint32_t val;
+} keywords[] = {
+ { "GET", TOK_ACCESS, FL_GET },
+ { "SET", TOK_ACCESS, FL_SET },
+ { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
+ { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
+ { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
+ { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
+ { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
+ { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
+ { "OID", TOK_TYPE, SNMP_SYNTAX_OID },
+ { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
+ { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
+ { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
+ { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
+ { "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER },
+ { "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING },
+ { "typedef", TOK_TYPEDEF, 0 },
+ { "include", TOK_INCLUDE, 0 },
+ { NULL, 0, 0 }
+};
+
+struct {
+ /* Current OID type, regarding table membership. */
+ enum snmp_tbl_entry tbl_type;
+ /* A pointer to a structure in table list to add to its members. */
+ struct snmp_index_entry *table_idx;
+} table_data;
+
+struct asn_oid current_oid;
+char nexttok[MAXSTR];
+u_long val; /* integer values */
+int32_t all_cond; /* all conditions are true */
+int32_t saved_token = -1;
+
+/* Prepare the global data before parsing a new file. */
+static void
+snmp_import_init(struct asn_oid *append)
+{
+ memset(&table_data, 0, sizeof(table_data));
+ memset(&current_oid, 0, sizeof(struct asn_oid));
+ memset(nexttok, 0, MAXSTR);
+
+ if (append != NULL)
+ asn_append_oid(&current_oid, append);
+
+ all_cond = 0;
+ val = 0;
+ saved_token = -1;
+}
+
+static int32_t
+gettoken(struct snmp_toolinfo *snmptoolctx)
+{
+ int c;
+ struct enum_type *t;
+
+ if (saved_token != -1) {
+ c = saved_token;
+ saved_token = -1;
+ return (c);
+ }
+
+ again:
+ /*
+ * Skip any whitespace before the next token.
+ */
+ while ((c = tgetc()) != EOF) {
+ if (c == '\n')
+ input->lno++;
+ if (!isspace(c))
+ break;
+ }
+ if (c == EOF)
+ return (TOK_EOF);
+
+ if (!isascii(c)) {
+ warnx("unexpected character %#2x", (u_int) c);
+ return (TOK_ERR);
+ }
+
+ /*
+ * Skip comments.
+ */
+ if (c == '#') {
+ while ((c = tgetc()) != EOF) {
+ if (c == '\n') {
+ input->lno++;
+ goto again;
+ }
+ }
+ warnx("unexpected EOF in comment");
+ return (TOK_ERR);
+ }
+
+ /*
+ * Single character tokens.
+ */
+ if (strchr("():|", c) != NULL)
+ return (c);
+
+ if (c == '"' || c == '<') {
+ int32_t end = c;
+ size_t n = 0;
+
+ val = 1;
+ if (c == '<') {
+ val = 0;
+ end = '>';
+ }
+
+ while ((c = tgetc()) != EOF) {
+ if (c == end)
+ break;
+ if (n == sizeof(nexttok) - 1) {
+ nexttok[n++] = '\0';
+ warnx("filename too long '%s...'", nexttok);
+ return (TOK_ERR);
+ }
+ nexttok[n++] = c;
+ }
+ nexttok[n++] = '\0';
+ return (TOK_FILENAME);
+ }
+
+ /*
+ * Sort out numbers.
+ */
+ if (isdigit(c)) {
+ size_t n = 0;
+ nexttok[n++] = c;
+ while ((c = tgetc()) != EOF) {
+ if (!isdigit(c)) {
+ if (tungetc(c) < 0)
+ return (TOK_ERR);
+ break;
+ }
+ if (n == sizeof(nexttok) - 1) {
+ nexttok[n++] = '\0';
+ warnx("number too long '%s...'", nexttok);
+ return (TOK_ERR);
+ }
+ nexttok[n++] = c;
+ }
+ nexttok[n++] = '\0';
+ sscanf(nexttok, "%lu", &val);
+ return (TOK_NUM);
+ }
+
+ /*
+ * So that has to be a string.
+ */
+ if (isalpha(c) || c == '_' || c == '-') {
+ size_t n = 0;
+ nexttok[n++] = c;
+ while ((c = tgetc()) != EOF) {
+ if (!isalnum(c) && c != '_' && c != '-') {
+ if (tungetc (c) < 0)
+ return (TOK_ERR);
+ break;
+ }
+ if (n == sizeof(nexttok) - 1) {
+ nexttok[n++] = '\0';
+ warnx("string too long '%s...'", nexttok);
+ return (TOK_ERR);
+ }
+ nexttok[n++] = c;
+ }
+ nexttok[n++] = '\0';
+
+ /*
+ * Keywords.
+ */
+ for (c = 0; keywords[c].str != NULL; c++)
+ if (strcmp(keywords[c].str, nexttok) == 0) {
+ val = keywords[c].val;
+ return (keywords[c].tok);
+ }
+
+ if ((t = snmp_enumtc_lookup(snmptoolctx, nexttok)) != NULL) {
+ val = t->syntax;
+ return (TOK_DEFTYPE);
+ }
+
+ return (TOK_STR);
+ }
+
+ if (isprint(c))
+ warnx("%u: unexpected character '%c'", input->lno, c);
+ else
+ warnx("%u: unexpected character 0x%02x", input->lno, (u_int) c);
+
+ return (TOK_ERR);
+}
+
+/*
+ * Update table information.
+ */
+static struct snmp_index_entry *
+snmp_import_update_table(enum snmp_tbl_entry te, struct snmp_index_entry *tbl)
+{
+ switch (te) {
+ case ENTRY_NONE:
+ if (table_data.tbl_type == ENTRY_NONE)
+ return (NULL);
+ if (table_data.tbl_type == ENTRY_INDEX)
+ table_data.table_idx = NULL;
+ table_data.tbl_type--;
+ return (NULL);
+
+ case ENTRY_INDEX:
+ if (tbl == NULL)
+ warnx("No table_index to add!!!");
+ table_data.table_idx = tbl;
+ table_data.tbl_type = ENTRY_INDEX;
+ return (tbl);
+
+ case ENTRY_DATA:
+ if (table_data.tbl_type == ENTRY_INDEX) {
+ table_data.tbl_type = ENTRY_DATA;
+ return (table_data.table_idx);
+ }
+ return (NULL);
+
+ default:
+ /* NOTREACHED */
+ warnx("Unknown table entry type!!!");
+ break;
+ }
+
+ return (NULL);
+}
+
+static int32_t
+parse_enum(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
+ struct enum_pairs *enums)
+{
+ while ((*tok = gettoken(snmptoolctx)) == TOK_STR) {
+ if (enum_pair_insert(enums, val, nexttok) < 0)
+ return (-1);
+ if ((*tok = gettoken(snmptoolctx)) != TOK_NUM)
+ break;
+ }
+
+ if (*tok != ')') {
+ warnx("')' at end of enums");
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int32_t
+parse_subtype(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
+ enum snmp_tc *tc)
+{
+ if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
+ warnx("subtype expected after '|'");
+ return (-1);
+ }
+
+ *tc = snmp_get_tc(nexttok);
+ *tok = gettoken(snmptoolctx);
+
+ return (1);
+}
+
+static int32_t
+parse_type(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
+ enum snmp_tc *tc, struct enum_pairs **snmp_enum)
+{
+ int32_t syntax, mem;
+
+ syntax = val;
+ *tc = 0;
+
+ if (*tok == TOK_ENUM || *tok == TOK_BITS) {
+ if (*snmp_enum == NULL) {
+ if ((*snmp_enum = enum_pairs_init()) == NULL)
+ return (-1);
+ mem = 1;
+ *tc = SNMP_TC_OWN;
+ } else
+ mem = 0;
+
+ if (gettoken(snmptoolctx) != '(') {
+ warnx("'(' expected after ENUM/BITS");
+ return (-1);
+ }
+
+ if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) {
+ warnx("need value for ENUM//BITS");
+ if (mem == 1) {
+ free(*snmp_enum);
+ *snmp_enum = NULL;
+ }
+ return (-1);
+ }
+
+ if (parse_enum(snmptoolctx, tok, *snmp_enum) < 0) {
+ enum_pairs_free(*snmp_enum);
+ *snmp_enum = NULL;
+ return (-1);
+ }
+
+ *tok = gettoken(snmptoolctx);
+
+ } else if (*tok == TOK_DEFTYPE) {
+ struct enum_type *t;
+
+ *tc = 0;
+ t = snmp_enumtc_lookup(snmptoolctx, nexttok);
+ if (t != NULL)
+ *snmp_enum = t->snmp_enum;
+
+ *tok = gettoken(snmptoolctx);
+
+ } else {
+ if ((*tok = gettoken(snmptoolctx)) == '|') {
+ if (parse_subtype(snmptoolctx, tok, tc) < 0)
+ return (-1);
+ }
+ }
+
+ return (syntax);
+}
+
+static int32_t
+snmp_import_head(struct snmp_toolinfo *snmptoolctx)
+{
+ enum tok tok;
+
+ if ((tok = gettoken(snmptoolctx)) == '(')
+ tok = gettoken(snmptoolctx);
+
+ if (tok != TOK_NUM || val > ASN_MAXID ) {
+ warnx("Suboid expected - line %d", input->lno);
+ return (-1);
+ }
+
+ if (gettoken(snmptoolctx) != TOK_STR) {
+ warnx("Node name expected at line %d", input->lno);
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int32_t
+snmp_import_table(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *obj)
+{
+ int32_t i;
+ enum snmp_tc tc;
+ enum tok tok;
+ struct snmp_index_entry *entry;
+
+ if ((entry = malloc(sizeof(struct snmp_index_entry))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ memset(entry, 0, sizeof(struct snmp_index_entry));
+ STAILQ_INIT(&(entry->index_list));
+
+ for (i = 0, tok = gettoken(snmptoolctx); i < SNMP_INDEXES_MAX; i++) {
+ int32_t syntax;
+ struct enum_pairs *enums = NULL;
+
+ if (tok != TOK_TYPE && tok != TOK_DEFTYPE && tok != TOK_ENUM &&
+ tok != TOK_BITS)
+ break;
+
+ if ((syntax = parse_type(snmptoolctx, &tok, &tc, &enums)) < 0) {
+ enum_pairs_free(enums);
+ snmp_index_listfree(&(entry->index_list));
+ free(entry);
+ return (-1);
+ }
+
+ if (snmp_syntax_insert(&(entry->index_list), enums, syntax,
+ tc) < 0) {
+ snmp_index_listfree(&(entry->index_list));
+ enum_pairs_free(enums);
+ free(entry);
+ return (-1);
+ }
+ }
+
+ if (i == 0 || i > SNMP_INDEXES_MAX) {
+ warnx("Bad number of indexes at line %d", input->lno);
+ snmp_index_listfree(&(entry->index_list));
+ free(entry);
+ return (-1);
+ }
+
+ if (tok != TOK_STR) {
+ warnx("String expected after indexes at line %d", input->lno);
+ snmp_index_listfree(&(entry->index_list));
+ free(entry);
+ return (-1);
+ }
+
+ entry->string = obj->string;
+ entry->strlen = obj->strlen;
+ asn_append_oid(&(entry->var), &(obj->var));
+
+ if ((i = snmp_table_insert(snmptoolctx, entry)) < 0) {
+ snmp_index_listfree(&(entry->index_list));
+ free(entry);
+ return (-1);
+ } else if (i == 0) {
+ /* Same entry already present in lists. */
+ free(entry->string);
+ free(entry);
+ }
+
+ (void) snmp_import_update_table(ENTRY_INDEX, entry);
+
+ return (1);
+}
+
+/*
+ * Read everything after the syntax type that is certainly a leaf OID info.
+ */
+static int32_t
+snmp_import_leaf(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
+ struct snmp_oid2str *oid2str)
+{
+ int32_t i, syntax;
+
+ if ((syntax = parse_type(snmptoolctx, tok, &(oid2str->tc), &(oid2str->snmp_enum)))
+ < 0)
+ return(-1);
+
+ oid2str->syntax = syntax;
+ /*
+ * That is the name of the function, corresponding to the entry.
+ * It is used by bsnmpd, but is not interesting for us.
+ */
+ if (*tok == TOK_STR)
+ *tok = gettoken(snmptoolctx);
+
+ for (i = 0; i < SNMP_ACCESS_GETSET && *tok == TOK_ACCESS; i++) {
+ oid2str->access |= (uint32_t) val;
+ *tok = gettoken(snmptoolctx);
+ }
+
+ if (*tok != ')') {
+ warnx("')' expected at end of line %d", input->lno);
+ return (-1);
+ }
+
+ oid2str->table_idx = snmp_import_update_table(ENTRY_DATA, NULL);
+
+ if ((i = snmp_leaf_insert(snmptoolctx, oid2str)) < 0) {
+ warnx("Error adding leaf %s to list", oid2str->string);
+ return (-1);
+ }
+
+ /*
+ * Same entry is already present in the mapping lists and
+ * the new one was not inserted.
+ */
+ if (i == 0) {
+ free(oid2str->string);
+ free(oid2str);
+ }
+
+ (void) snmp_import_update_table(ENTRY_NONE, NULL);
+
+ return (1);
+}
+
+static int32_t
+snmp_import_object(struct snmp_toolinfo *snmptoolctx)
+{
+ char *string;
+ int i;
+ enum tok tok;
+ struct snmp_oid2str *oid2str;
+
+ if (snmp_import_head(snmptoolctx) < 0)
+ return (-1);
+
+ if ((oid2str = malloc(sizeof(struct snmp_oid2str))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ if ((string = malloc(strlen(nexttok) + 1)) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ free(oid2str);
+ return (-1);
+ }
+
+ memset(oid2str, 0, sizeof(struct snmp_oid2str));
+ strlcpy(string, nexttok, strlen(nexttok) + 1);
+ oid2str->string = string;
+ oid2str->strlen = strlen(nexttok);
+
+ asn_append_oid(&(oid2str->var), &(current_oid));
+ if (snmp_suboid_append(&(oid2str->var), (asn_subid_t) val) < 0)
+ goto error;
+
+ /*
+ * Prepared the entry - now figure out where to insert it.
+ * After the object we have following options:
+ * 1) new line, blank, ) - then it is an enum oid -> snmp_enumlist;
+ * 2) new line , ( - nonleaf oid -> snmp_nodelist;
+ * 2) ':' - table entry - a variable length SYNTAX_TYPE (one or more)
+ * may follow and second string must end line -> snmp_tablelist;
+ * 3) OID , string ) - this is a trap entry or a leaf -> snmp_oidlist;
+ * 4) SYNTAX_TYPE, string (not always), get/set modifier - always last
+ * and )- this is definitely a leaf.
+ */
+
+ switch (tok = gettoken(snmptoolctx)) {
+ case ')':
+ if ((i = snmp_enum_insert(snmptoolctx, oid2str)) < 0)
+ goto error;
+ if (i == 0) {
+ free(oid2str->string);
+ free(oid2str);
+ }
+ return (1);
+
+ case '(':
+ if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
+ goto error;
+
+ /*
+ * Ignore the error for nodes since the .def files currently
+ * contain different strings for 1.3.6.1.2.1 - mibII. Only make
+ * sure the memory is freed and don't complain.
+ */
+ if ((i = snmp_node_insert(snmptoolctx, oid2str)) <= 0) {
+ free(string);
+ free(oid2str);
+ }
+ return (snmp_import_object(snmptoolctx));
+
+ case ':':
+ if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
+ goto error;
+ if (snmp_import_table(snmptoolctx, oid2str) < 0)
+ goto error;
+ /*
+ * A different table entry type was malloced and the data is
+ * contained there.
+ */
+ free(oid2str);
+ return (1);
+
+ case TOK_TYPE:
+ /* FALLTHROUGH */
+ case TOK_DEFTYPE:
+ /* FALLTHROUGH */
+ case TOK_ENUM:
+ /* FALLTHROUGH */
+ case TOK_BITS:
+ if (snmp_import_leaf(snmptoolctx, &tok, oid2str) < 0)
+ goto error;
+ return (1);
+
+ default:
+ warnx("Unexpected token at line %d - %s", input->lno,
+ input->fname);
+ break;
+ }
+
+error:
+ snmp_mapping_entryfree(oid2str);
+
+ return (-1);
+}
+
+static int32_t
+snmp_import_tree(struct snmp_toolinfo *snmptoolctx, enum tok *tok)
+{
+ while (*tok != TOK_EOF) {
+ switch (*tok) {
+ case TOK_ERR:
+ return (-1);
+ case '(':
+ if (snmp_import_object(snmptoolctx) < 0)
+ return (-1);
+ break;
+ case ')':
+ if (snmp_suboid_pop(&current_oid) < 0)
+ return (-1);
+ (void) snmp_import_update_table(ENTRY_NONE, NULL);
+ break;
+ default:
+ /* Anything else here would be illegal. */
+ return (-1);
+ }
+ *tok = gettoken(snmptoolctx);
+ }
+
+ return (0);
+}
+
+static int32_t
+snmp_import_top(struct snmp_toolinfo *snmptoolctx, enum tok *tok)
+{
+ enum snmp_tc tc;
+ struct enum_type *t;
+
+ if (*tok == '(')
+ return (snmp_import_tree(snmptoolctx, tok));
+
+ if (*tok == TOK_TYPEDEF) {
+ if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
+ warnx("type name expected after typedef - %s",
+ input->fname);
+ return (-1);
+ }
+
+ t = snmp_enumtc_init(nexttok);
+
+ *tok = gettoken(snmptoolctx);
+ t->is_enum = (*tok == TOK_ENUM);
+ t->is_bits = (*tok == TOK_BITS);
+ t->syntax = parse_type(snmptoolctx, tok, &tc, &(t->snmp_enum));
+ snmp_enumtc_insert(snmptoolctx, t);
+
+ return (1);
+ }
+
+ if (*tok == TOK_INCLUDE) {
+ int i;
+
+ *tok = gettoken(snmptoolctx);
+ if (*tok != TOK_FILENAME) {
+ warnx("filename expected in include directive - %s",
+ nexttok);
+ return (-1);
+ }
+
+ if (( i = add_filename(snmptoolctx, nexttok, NULL, 1)) == 0) {
+ *tok = gettoken(snmptoolctx);
+ return (1);
+ }
+
+ if (i == -1)
+ return (-1);
+
+ input_fopen(nexttok);
+ *tok = gettoken(snmptoolctx);
+ return (1);
+ }
+
+ warnx("'(' or 'typedef' expected - %s", nexttok);
+ return (-1);
+}
+
+static int32_t
+snmp_import(struct snmp_toolinfo *snmptoolctx)
+{
+ int i;
+ enum tok tok;
+
+ tok = gettoken(snmptoolctx);
+
+ do
+ i = snmp_import_top(snmptoolctx, &tok);
+ while (i > 0);
+
+ return (i);
+}
+
+/*
+ * Read a .def file and import oid<->string mapping.
+ * Mappings are inserted into a global structure containing list for each OID
+ * syntax type.
+ */
+int32_t
+snmp_import_file(struct snmp_toolinfo *snmptoolctx, struct fname *file)
+{
+ int idx;
+
+ snmp_import_init(&(file->cut));
+ input_fopen(file->name);
+ if ((idx = snmp_import(snmptoolctx)) < 0)
+ warnx("Failed to read mappings from file %s", file->name);
+
+ input_close();
+
+ return (idx);
+}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpmap.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpmap.c
new file mode 100644
index 0000000..4f71c58
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpmap.c
@@ -0,0 +1,1018 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@FreeBSD.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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 <sys/param.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+#include "bsnmptc.h"
+#include "bsnmptools.h"
+
+extern int _bsnmptools_debug;
+#define DEBUG if (_bsnmptools_debug) fprintf
+
+/* Allocate memory and initialize list. */
+struct snmp_mappings *
+snmp_mapping_init(void)
+{
+ struct snmp_mappings *m;
+
+ if ((m = malloc(sizeof(struct snmp_mappings))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (NULL);
+ }
+
+ memset(m, 0, sizeof(struct snmp_mappings));
+ return (m);
+}
+
+#define snmp_nodelist mappings->nodelist
+#define snmp_intlist mappings->intlist
+#define snmp_octlist mappings->octlist
+#define snmp_oidlist mappings->oidlist
+#define snmp_iplist mappings->iplist
+#define snmp_ticklist mappings->ticklist
+#define snmp_cntlist mappings->cntlist
+#define snmp_gaugelist mappings->gaugelist
+#define snmp_cnt64list mappings->cnt64list
+#define snmp_enumlist mappings->enumlist
+#define snmp_tablelist mappings->tablelist
+#define snmp_tclist mappings->tclist
+
+void
+enum_pairs_free(struct enum_pairs *headp)
+{
+ struct enum_pair *e;
+
+ if (headp == NULL)
+ return;
+
+ while ((e = STAILQ_FIRST(headp)) != NULL) {
+ STAILQ_REMOVE_HEAD(headp, link);
+
+ if (e->enum_str)
+ free(e->enum_str);
+ free(e);
+ }
+
+ free(headp);
+}
+
+void
+snmp_mapping_entryfree(struct snmp_oid2str *entry)
+{
+ if (entry->string)
+ free(entry->string);
+
+ if (entry->tc == SNMP_TC_OWN)
+ enum_pairs_free(entry->snmp_enum);
+
+ free(entry);
+}
+
+static void
+snmp_mapping_listfree(struct snmp_mapping *headp)
+{
+ struct snmp_oid2str *p;
+
+ while ((p = SLIST_FIRST(headp)) != NULL) {
+ SLIST_REMOVE_HEAD(headp, link);
+
+ if (p->string)
+ free(p->string);
+
+ if (p->tc == SNMP_TC_OWN)
+ enum_pairs_free(p->snmp_enum);
+ free(p);
+ }
+
+ SLIST_INIT(headp);
+}
+
+void
+snmp_index_listfree(struct snmp_idxlist *headp)
+{
+ struct index *i;
+
+ while ((i = STAILQ_FIRST(headp)) != NULL) {
+ STAILQ_REMOVE_HEAD(headp, link);
+ if (i->tc == SNMP_TC_OWN)
+ enum_pairs_free(i->snmp_enum);
+ free(i);
+ }
+
+ STAILQ_INIT(headp);
+}
+
+static void
+snmp_mapping_table_listfree(struct snmp_table_index *headp)
+{
+ struct snmp_index_entry *t;
+
+ while ((t = SLIST_FIRST(headp)) != NULL) {
+ SLIST_REMOVE_HEAD(headp, link);
+
+ if (t->string)
+ free(t->string);
+
+ snmp_index_listfree(&(t->index_list));
+ free(t);
+ }
+}
+
+static void
+snmp_enumtc_listfree(struct snmp_enum_tc *headp)
+{
+ struct enum_type *t;
+
+ while ((t = SLIST_FIRST(headp)) != NULL) {
+ SLIST_REMOVE_HEAD(headp, link);
+
+ if (t->name)
+ free(t->name);
+ enum_pairs_free(t->snmp_enum);
+ free(t);
+ }
+}
+
+int
+snmp_mapping_free(struct snmp_toolinfo *snmptoolctx)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL)
+ return (-1);
+
+ snmp_mapping_listfree(&snmptoolctx->snmp_nodelist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_intlist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_octlist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_oidlist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_iplist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_ticklist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_cntlist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_gaugelist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_cnt64list);
+ snmp_mapping_listfree(&snmptoolctx->snmp_enumlist);
+ snmp_mapping_table_listfree(&snmptoolctx->snmp_tablelist);
+ snmp_enumtc_listfree(&snmptoolctx->snmp_tclist);
+ free(snmptoolctx->mappings);
+
+ return (0);
+}
+
+static void
+snmp_dump_enumpairs(struct enum_pairs *headp)
+{
+ struct enum_pair *entry;
+
+ if (headp == NULL)
+ return;
+
+ fprintf(stderr,"enums: ");
+ STAILQ_FOREACH(entry, headp, link)
+ fprintf(stderr,"%d - %s, ", entry->enum_val,
+ (entry->enum_str == NULL)?"NULL":entry->enum_str);
+
+ fprintf(stderr,"; ");
+}
+
+void
+snmp_dump_oid2str(struct snmp_oid2str *entry)
+{
+ char buf[ASN_OIDSTRLEN];
+
+ if (entry != NULL) {
+ memset(buf, 0, sizeof(buf));
+ asn_oid2str_r(&(entry->var), buf);
+ DEBUG(stderr, "%s - %s - %d - %d - %d", buf, entry->string,
+ entry->syntax, entry->access, entry->strlen);
+ snmp_dump_enumpairs(entry->snmp_enum);
+ DEBUG(stderr,"%s \n", (entry->table_idx == NULL)?"No table":
+ entry->table_idx->string);
+ }
+}
+
+static void
+snmp_dump_indexlist(struct snmp_idxlist *headp)
+{
+ struct index *entry;
+
+ if (headp == NULL)
+ return;
+
+ STAILQ_FOREACH(entry, headp, link) {
+ fprintf(stderr,"%d, ", entry->syntax);
+ snmp_dump_enumpairs(entry->snmp_enum);
+ }
+
+ fprintf(stderr,"\n");
+}
+
+/* Initialize the enum pairs list of a oid2str entry. */
+struct enum_pairs *
+enum_pairs_init(void)
+{
+ struct enum_pairs *snmp_enum;
+
+ if ((snmp_enum = malloc(sizeof(struct enum_pairs))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (NULL);
+ }
+
+ STAILQ_INIT(snmp_enum);
+ return (snmp_enum);
+}
+
+/*
+ * Given a number and string, allocate memory for a (int, string) pair and add
+ * it to the given oid2str mapping entry's enum pairs list.
+ */
+int32_t
+enum_pair_insert(struct enum_pairs *headp, int32_t enum_val, char *enum_str)
+{
+ struct enum_pair *e_new;
+
+ if ((e_new = malloc(sizeof(struct enum_pair))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ memset(e_new, 0, sizeof(struct enum_pair));
+
+ if ((e_new->enum_str = malloc(strlen(enum_str) + 1)) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ free(e_new);
+ return (-1);
+ }
+
+ e_new->enum_val = enum_val;
+ strlcpy(e_new->enum_str, enum_str, strlen(enum_str) + 1);
+ STAILQ_INSERT_TAIL(headp, e_new, link);
+
+ return (1);
+
+}
+
+/*
+ * Insert an entry in a list - entries are lexicographicaly order by asn_oid.
+ * Returns 1 on success, -1 if list is not initialized, 0 if a matching oid already
+ * exists. Error cheking is left to calling function.
+ */
+static int
+snmp_mapping_insert(struct snmp_mapping *headp, struct snmp_oid2str *entry)
+{
+ int32_t rc;
+ struct snmp_oid2str *temp, *prev;
+
+ if (entry == NULL)
+ return(-1);
+
+ if ((prev = SLIST_FIRST(headp)) == NULL ||
+ asn_compare_oid(&(entry->var), &(prev->var)) < 0) {
+ SLIST_INSERT_HEAD(headp, entry, link);
+ return (1);
+ } else
+ rc = -1; /* Make the compiler happy. */
+
+ SLIST_FOREACH(temp, headp, link) {
+ if ((rc = asn_compare_oid(&(entry->var), &(temp->var))) <= 0)
+ break;
+ prev = temp;
+ rc = -1;
+ }
+
+ switch (rc) {
+ case 0:
+ /* Ops, matching OIDs - hope the rest info also matches. */
+ if (strncmp(temp->string, entry->string, entry->strlen)) {
+ syslog(LOG_INFO, "Matching OIDs with different string "
+ "mappings: old - %s, new - %s", temp->string,
+ entry->string);
+ return (-1);
+ }
+ /*
+ * Ok, we have that already.
+ * As long as the strings match - don't complain.
+ */
+ return (0);
+
+ case 1:
+ SLIST_INSERT_AFTER(temp, entry, link);
+ break;
+
+ case -1:
+ SLIST_INSERT_AFTER(prev, entry, link);
+ break;
+
+ default:
+ /* NOTREACHED */
+ return (-1);
+ }
+
+ return (1);
+}
+
+int32_t
+snmp_node_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_nodelist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_int_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_intlist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_oct_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_octlist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_oid_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_oidlist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_ip_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_iplist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_tick_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_ticklist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_cnt_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_cntlist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_gauge_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_gaugelist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_cnt64_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_cnt64list,entry));
+
+ return (-1);
+}
+
+int32_t
+snmp_enum_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_enumlist,entry));
+
+ return (-1);
+}
+
+int32_t
+snmp_leaf_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ switch (entry->syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ return (snmp_int_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_oct_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_OID:
+ return (snmp_oid_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (snmp_ip_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_COUNTER:
+ return (snmp_cnt_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_GAUGE:
+ return (snmp_gauge_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_TIMETICKS:
+ return (snmp_tick_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_COUNTER64:
+ return (snmp_cnt64_insert(snmptoolctx, entry));
+ default:
+ break;
+ }
+
+ return (-1);
+}
+
+static int32_t
+snmp_index_insert(struct snmp_idxlist *headp, struct index *idx)
+{
+ if (headp == NULL || idx == NULL)
+ return (-1);
+
+ STAILQ_INSERT_TAIL(headp, idx, link);
+ return (1);
+}
+
+int32_t
+snmp_syntax_insert(struct snmp_idxlist *headp, struct enum_pairs *enums,
+ enum snmp_syntax syntax, enum snmp_tc tc)
+{
+ struct index *idx;
+
+ if ((idx = malloc(sizeof(struct index))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ memset(idx, 0, sizeof(struct index));
+
+ if (snmp_index_insert(headp, idx) < 0) {
+ free(idx);
+ return (-1);
+ }
+
+ idx->syntax = syntax;
+ idx->snmp_enum = enums;
+ idx->tc = tc;
+
+ return (1);
+}
+
+int32_t
+snmp_table_insert(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_index_entry *entry)
+{
+ int32_t rc;
+ struct snmp_index_entry *temp, *prev;
+
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL ||
+ entry == NULL)
+ return(-1);
+
+ if ((prev = SLIST_FIRST(&snmptoolctx->snmp_tablelist)) == NULL ||
+ asn_compare_oid(&(entry->var), &(prev->var)) < 0) {
+ SLIST_INSERT_HEAD(&snmptoolctx->snmp_tablelist, entry, link);
+ return (1);
+ } else
+ rc = -1; /* Make the compiler happy. */
+
+ SLIST_FOREACH(temp, &snmptoolctx->snmp_tablelist, link) {
+ if ((rc = asn_compare_oid(&(entry->var), &(temp->var))) <= 0)
+ break;
+ prev = temp;
+ rc = -1;
+ }
+
+ switch (rc) {
+ case 0:
+ /* Ops, matching OIDs - hope the rest info also matches. */
+ if (strncmp(temp->string, entry->string, entry->strlen)) {
+ syslog(LOG_INFO, "Matching OIDs with different string "
+ "mapping - old - %s, new - %s", temp->string,
+ entry->string);
+ return (-1);
+ }
+ return(0);
+
+ case 1:
+ SLIST_INSERT_AFTER(temp, entry, link);
+ break;
+
+ case -1:
+ SLIST_INSERT_AFTER(prev, entry, link);
+ break;
+
+ default:
+ /* NOTREACHED */
+ return (-1);
+ }
+
+ return (1);
+}
+
+struct enum_type *
+snmp_enumtc_init(char *name)
+{
+ struct enum_type *enum_tc;
+
+ if ((enum_tc = malloc(sizeof(struct enum_type))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (NULL);
+ }
+
+ memset(enum_tc, 0, sizeof(struct enum_type));
+ if ((enum_tc->name = malloc(strlen(name) + 1)) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ free(enum_tc);
+ return (NULL);
+ }
+ strlcpy(enum_tc->name, name, strlen(name) + 1);
+
+ return (enum_tc);
+}
+
+void
+snmp_enumtc_free(struct enum_type *tc)
+{
+ if (tc->name)
+ free(tc->name);
+ if (tc->snmp_enum)
+ enum_pairs_free(tc->snmp_enum);
+ free(tc);
+}
+
+void
+snmp_enumtc_insert(struct snmp_toolinfo *snmptoolctx, struct enum_type *entry)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL)
+ return; /* XXX no error handling? */
+
+ SLIST_INSERT_HEAD(&snmptoolctx->snmp_tclist, entry, link);
+}
+
+struct enum_type *
+snmp_enumtc_lookup(struct snmp_toolinfo *snmptoolctx, char *name)
+{
+ struct enum_type *temp;
+
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL)
+ return (NULL);
+
+ SLIST_FOREACH(temp, &snmptoolctx->snmp_tclist, link) {
+ if (strcmp(temp->name, name) == 0)
+ return (temp);
+ }
+ return (NULL);
+}
+
+static void
+snmp_mapping_dumplist(struct snmp_mapping *headp)
+{
+ char buf[ASN_OIDSTRLEN];
+ struct snmp_oid2str *entry;
+
+ if (headp == NULL)
+ return;
+
+ SLIST_FOREACH(entry,headp,link) {
+ memset(buf, 0, sizeof(buf));
+ asn_oid2str_r(&(entry->var), buf);
+ fprintf(stderr, "%s - %s - %d - %d - %d", buf, entry->string,
+ entry->syntax, entry->access ,entry->strlen);
+ fprintf(stderr," - %s \n", (entry->table_idx == NULL)?
+ "No table":entry->table_idx->string);
+ }
+}
+
+static void
+snmp_mapping_dumptable(struct snmp_table_index *headp)
+{
+ char buf[ASN_OIDSTRLEN];
+ struct snmp_index_entry *entry;
+
+ if (headp == NULL)
+ return;
+
+ SLIST_FOREACH(entry, headp, link) {
+ memset(buf, 0, sizeof(buf));
+ asn_oid2str_r(&(entry->var), buf);
+ fprintf(stderr,"%s - %s - %d - ", buf, entry->string,
+ entry->strlen);
+ snmp_dump_indexlist(&(entry->index_list));
+ }
+}
+
+void
+snmp_mapping_dump(struct snmp_toolinfo *snmptoolctx /* int bits */)
+{
+ if (!_bsnmptools_debug)
+ return;
+
+ if (snmptoolctx == NULL) {
+ fprintf(stderr,"No snmptool context!\n");
+ return;
+ }
+
+ if (snmptoolctx->mappings == NULL) {
+ fprintf(stderr,"No mappings!\n");
+ return;
+ }
+
+ fprintf(stderr,"snmp_nodelist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_nodelist);
+
+ fprintf(stderr,"snmp_intlist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_intlist);
+
+ fprintf(stderr,"snmp_octlist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_octlist);
+
+ fprintf(stderr,"snmp_oidlist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_oidlist);
+
+ fprintf(stderr,"snmp_iplist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_iplist);
+
+ fprintf(stderr,"snmp_ticklist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_ticklist);
+
+ fprintf(stderr,"snmp_cntlist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_cntlist);
+
+ fprintf(stderr,"snmp_gaugelist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_gaugelist);
+
+ fprintf(stderr,"snmp_cnt64list:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_cnt64list);
+
+ fprintf(stderr,"snmp_enumlist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_enumlist);
+
+ fprintf(stderr,"snmp_tablelist:\n");
+ snmp_mapping_dumptable(&snmptoolctx->snmp_tablelist);
+}
+
+char *
+enum_string_lookup(struct enum_pairs *headp, int32_t enum_val)
+{
+ struct enum_pair *temp;
+
+ if (headp == NULL)
+ return (NULL);
+
+ STAILQ_FOREACH(temp, headp, link) {
+ if (temp->enum_val == enum_val)
+ return (temp->enum_str);
+ }
+
+ return (NULL);
+}
+
+int32_t
+enum_number_lookup(struct enum_pairs *headp, char *e_str)
+{
+ struct enum_pair *tmp;
+
+ if (headp == NULL)
+ return (-1);
+
+ STAILQ_FOREACH(tmp, headp, link)
+ if (strncmp(tmp->enum_str, e_str, strlen(tmp->enum_str)) == 0)
+ return (tmp->enum_val);
+
+ return (-1);
+}
+
+static int32_t
+snmp_lookuplist_string(struct snmp_mapping *headp, struct snmp_object *s)
+{
+ struct snmp_oid2str *temp;
+
+ if (headp == NULL)
+ return (-1);
+
+ SLIST_FOREACH(temp, headp, link)
+ if (asn_compare_oid(&(temp->var), &(s->val.var)) == 0)
+ break;
+
+ if ((s->info = temp) == NULL)
+ return (-1);
+
+ return (1);
+}
+
+/* provided an asn_oid find the corresponding string for it */
+static int32_t
+snmp_lookup_leaf(struct snmp_mapping *headp, struct snmp_object *s)
+{
+ struct snmp_oid2str *temp;
+
+ if (headp == NULL)
+ return (-1);
+
+ SLIST_FOREACH(temp,headp,link) {
+ if ((asn_compare_oid(&(temp->var), &(s->val.var)) == 0) ||
+ (asn_is_suboid(&(temp->var), &(s->val.var)))) {
+ s->info = temp;
+ return (1);
+ }
+ }
+
+ return (-1);
+}
+
+int32_t
+snmp_lookup_leafstring(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL || s == NULL)
+ return (-1);
+
+ switch (s->val.syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ return (snmp_lookup_leaf(&snmptoolctx->snmp_intlist, s));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_lookup_leaf(&snmptoolctx->snmp_octlist, s));
+ case SNMP_SYNTAX_OID:
+ return (snmp_lookup_leaf(&snmptoolctx->snmp_oidlist, s));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (snmp_lookup_leaf(&snmptoolctx->snmp_iplist, s));
+ case SNMP_SYNTAX_COUNTER:
+ return (snmp_lookup_leaf(&snmptoolctx->snmp_cntlist, s));
+ case SNMP_SYNTAX_GAUGE:
+ return (snmp_lookup_leaf(
+ &snmptoolctx->snmp_gaugelist, s));
+ case SNMP_SYNTAX_TIMETICKS:
+ return (snmp_lookup_leaf(
+ &snmptoolctx->snmp_ticklist, s));
+ case SNMP_SYNTAX_COUNTER64:
+ return (snmp_lookup_leaf(
+ &snmptoolctx->snmp_cnt64list, s));
+ case SNMP_SYNTAX_NOSUCHOBJECT:
+ /* FALLTHROUGH */
+ case SNMP_SYNTAX_NOSUCHINSTANCE:
+ /* FALLTHROUGH */
+ case SNMP_SYNTAX_ENDOFMIBVIEW:
+ return (snmp_lookup_allstring(snmptoolctx, s));
+ default:
+ warnx("Unknown syntax - %d", s->val.syntax);
+ break;
+ }
+
+ return (-1);
+}
+
+int32_t
+snmp_lookup_enumstring(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL || s == NULL)
+ return (-1);
+
+ return (snmp_lookuplist_string(&snmptoolctx->snmp_enumlist, s));
+}
+
+int32_t
+snmp_lookup_oidstring(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL || s == NULL)
+ return (-1);
+
+ return (snmp_lookuplist_string(&snmptoolctx->snmp_oidlist, s));
+}
+
+int32_t
+snmp_lookup_nodestring(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL || s == NULL)
+ return (-1);
+
+ return (snmp_lookuplist_string(&snmptoolctx->snmp_nodelist, s));
+}
+
+int32_t
+snmp_lookup_allstring(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL)
+ return (-1);
+
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_intlist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_octlist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_oidlist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_iplist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_cntlist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_gaugelist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_ticklist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_cnt64list, s) > 0)
+ return (1);
+ if (snmp_lookuplist_string(&snmptoolctx->snmp_enumlist, s) > 0)
+ return (1);
+ if (snmp_lookuplist_string(&snmptoolctx->snmp_nodelist, s) > 0)
+ return (1);
+
+ return (-1);
+}
+
+int32_t
+snmp_lookup_nonleaf_string(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_object *s)
+{
+ if (snmptoolctx == NULL)
+ return (-1);
+
+ if (snmp_lookuplist_string(&snmptoolctx->snmp_nodelist, s) > 0)
+ return (1);
+ if (snmp_lookuplist_string(&snmptoolctx->snmp_enumlist, s) > 0)
+ return (1);
+
+ return (-1);
+}
+
+static int32_t
+snmp_lookup_oidlist(struct snmp_mapping *hp, struct snmp_object *s, char *oid)
+{
+ struct snmp_oid2str *temp;
+
+ if (hp == NULL)
+ return (-1);
+
+ SLIST_FOREACH(temp, hp, link) {
+ if (temp->strlen != strlen(oid))
+ continue;
+
+ if (strncmp(temp->string, oid, temp->strlen))
+ continue;
+
+ s->val.syntax = temp->syntax;
+ s->info = temp;
+ asn_append_oid(&(s->val.var), &(temp->var));
+ return (1);
+ }
+
+ return (-1);
+}
+
+static int32_t
+snmp_lookup_tablelist(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_table_index *headp, struct snmp_object *s, char *oid)
+{
+ struct snmp_index_entry *temp;
+
+ if (snmptoolctx == NULL || headp == NULL)
+ return (-1);
+
+ SLIST_FOREACH(temp, headp, link) {
+ if (temp->strlen != strlen(oid))
+ continue;
+
+ if (strncmp(temp->string, oid, temp->strlen))
+ continue;
+
+ /*
+ * Another hack here - if we were given a table name
+ * return the corresponding pointer to it's entry.
+ * That should not change the reponce we'll get.
+ */
+ s->val.syntax = SNMP_SYNTAX_NULL;
+ asn_append_oid(&(s->val.var), &(temp->var));
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_nodelist, s) > 0)
+ return (1);
+ else
+ return (-1);
+ }
+
+ return (-1);
+}
+
+int32_t
+snmp_lookup_oidall(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s,
+ char *oid)
+{
+ if (snmptoolctx == NULL || s == NULL || oid == NULL)
+ return (-1);
+
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_intlist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_octlist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_oidlist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_iplist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_ticklist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_cntlist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_gaugelist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_cnt64list, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_nodelist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_tablelist(snmptoolctx, &snmptoolctx->snmp_tablelist,
+ s, oid) > 0)
+ return (1);
+
+ return (-1);
+}
+
+int32_t
+snmp_lookup_enumoid(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s,
+ char *oid)
+{
+ if (snmptoolctx == NULL || s == NULL)
+ return (-1);
+
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_enumlist, s, oid));
+}
+
+int32_t
+snmp_lookup_oid(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s,
+ char *oid)
+{
+ if (snmptoolctx == NULL || s == NULL)
+ return (-1);
+
+ switch (s->val.syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_intlist,
+ s, oid));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_octlist,
+ s, oid));
+ case SNMP_SYNTAX_OID:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_oidlist,
+ s, oid));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_iplist,
+ s, oid));
+ case SNMP_SYNTAX_COUNTER:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_cntlist,
+ s, oid));
+ case SNMP_SYNTAX_GAUGE:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_gaugelist,
+ s, oid));
+ case SNMP_SYNTAX_TIMETICKS:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_ticklist,
+ s, oid));
+ case SNMP_SYNTAX_COUNTER64:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_cnt64list,
+ s, oid));
+ case SNMP_SYNTAX_NULL:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_nodelist,
+ s, oid));
+ default:
+ warnx("Unknown syntax - %d", s->val.syntax);
+ break;
+ }
+
+ return (-1);
+}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c
new file mode 100644
index 0000000..dc22c69
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c
@@ -0,0 +1,1287 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@FreeBSD.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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.
+ *
+ * Textual conventions for OctetStrings
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+#include "bsnmptc.h"
+#include "bsnmptools.h"
+
+/* OctetString, DisplayString */
+static char *snmp_oct2str(uint32_t, char *, char *);
+static char *snmp_str2asn_oid(char *, struct asn_oid *);
+static int parse_octetstring(struct snmp_value *, char *);
+
+/* DateAndTime */
+static char *snmp_octstr2date(uint32_t, char *, char *);
+static char *snmp_date2asn_oid(char * , struct asn_oid *);
+static int parse_dateandtime(struct snmp_value *, char *);
+
+/* PhysAddress */
+static char *snmp_oct2physAddr(uint32_t, char *, char *);
+static char *snmp_addr2asn_oid(char *, struct asn_oid *);
+static int parse_physaddress(struct snmp_value *, char *);
+
+/* NTPTimeStamp */
+static char *snmp_oct2ntp_ts(uint32_t, char *, char *);
+static char *snmp_ntp_ts2asn_oid(char *, struct asn_oid *);
+static int parse_ntp_ts(struct snmp_value *, char *);
+
+/* BridgeId */
+static char *snmp_oct2bridgeid(uint32_t, char *, char *);
+static char *snmp_bridgeid2oct(char *, struct asn_oid *);
+static int parse_bridge_id(struct snmp_value *, char *);
+
+/* BridgePortId */
+static char *snmp_oct2bport_id(uint32_t, char *, char *);
+static char *snmp_bport_id2oct(char *, struct asn_oid *);
+static int parse_bport_id(struct snmp_value *, char *);
+
+/* InetAddress */
+static char *snmp_oct2inetaddr(uint32_t len, char *octets, char *buf);
+static char *snmp_inetaddr2oct(char *str, struct asn_oid *oid);
+static int32_t parse_inetaddr(struct snmp_value *value, char *string);
+
+static char *snmp_oct2bits(uint32_t len, char *octets, char *buf);
+static char *snmp_bits2oct(char *str, struct asn_oid *oid);
+static int32_t parse_bits(struct snmp_value *value, char *string);
+
+struct snmp_text_conv {
+ enum snmp_tc tc;
+ const char *tc_str;
+ int32_t len;
+ snmp_oct2tc_f oct2tc;
+ snmp_tc2oid_f tc2oid;
+ snmp_tc2oct_f tc2oct;
+} text_convs[] = {
+ { SNMP_STRING, "OctetString", SNMP_VAR_STRSZ,
+ snmp_oct2str, snmp_str2asn_oid, parse_octetstring },
+
+ { SNMP_DISPLAYSTRING, "DisplayString" , SNMP_VAR_STRSZ,
+ snmp_oct2str, snmp_str2asn_oid, parse_octetstring },
+
+ { SNMP_DATEANDTIME, "DateAndTime", SNMP_DATETIME_STRSZ,
+ snmp_octstr2date, snmp_date2asn_oid, parse_dateandtime },
+
+ { SNMP_PHYSADDR, "PhysAddress", SNMP_PHYSADDR_STRSZ,
+ snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
+
+ { SNMP_ATMESI, "AtmESI", SNMP_PHYSADDR_STRSZ,
+ snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
+
+ { SNMP_NTP_TIMESTAMP, "NTPTimeStamp", SNMP_NTP_TS_STRSZ,
+ snmp_oct2ntp_ts, snmp_ntp_ts2asn_oid, parse_ntp_ts },
+
+ { SNMP_MACADDRESS, "MacAddress", SNMP_PHYSADDR_STRSZ,
+ snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
+
+ { SNMP_BRIDGE_ID, "BridgeId", SNMP_BRIDGEID_STRSZ,
+ snmp_oct2bridgeid, snmp_bridgeid2oct, parse_bridge_id },
+
+ { SNMP_BPORT_ID, "BridgePortId", SNMP_BPORT_STRSZ,
+ snmp_oct2bport_id, snmp_bport_id2oct, parse_bport_id },
+
+ { SNMP_INETADDRESS, "InetAddress", SNMP_INADDRS_STRSZ,
+ snmp_oct2inetaddr, snmp_inetaddr2oct, parse_inetaddr },
+
+ { SNMP_TC_OWN, "BITS", SNMP_VAR_STRSZ,
+ snmp_oct2bits, snmp_bits2oct, parse_bits },
+
+ { SNMP_UNKNOWN, "Unknown", SNMP_VAR_STRSZ, snmp_oct2str,
+ snmp_str2asn_oid, parse_octetstring } /* keep last */
+};
+
+/* Common API */
+enum snmp_tc
+snmp_get_tc(char *str)
+{
+ int i;
+ for (i = 0; i < SNMP_UNKNOWN; i++) {
+ if (!strncmp(text_convs[i].tc_str, str,
+ strlen(text_convs[i].tc_str)))
+ return (text_convs[i].tc);
+ }
+
+ return (SNMP_STRING);
+}
+
+char *
+snmp_oct2tc(enum snmp_tc tc, uint32_t len, char *octets)
+{
+ uint32_t tc_len;
+ char * buf;
+
+ if (tc < 0 || tc > SNMP_UNKNOWN)
+ tc = SNMP_UNKNOWN;
+
+ if (text_convs[tc].len > 0)
+ tc_len = text_convs[tc].len;
+ else
+ tc_len = 2 * len + 3;
+
+ if ((buf = malloc(tc_len)) == NULL ) {
+ syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
+ return (NULL);
+ }
+
+ memset(buf, 0, tc_len);
+ if (text_convs[tc].oct2tc(len, octets, buf) == NULL) {
+ free(buf);
+ return (NULL);
+ }
+
+ return (buf);
+}
+
+char *
+snmp_tc2oid(enum snmp_tc tc, char *str, struct asn_oid *oid)
+{
+ if (tc < 0 || tc > SNMP_UNKNOWN)
+ tc = SNMP_UNKNOWN;
+
+ return (text_convs[tc].tc2oid(str, oid));
+}
+
+int32_t
+snmp_tc2oct(enum snmp_tc tc, struct snmp_value *value, char *string)
+{
+ if (tc < 0 || tc > SNMP_UNKNOWN)
+ tc = SNMP_UNKNOWN;
+
+ return (text_convs[tc].tc2oct(value, string));
+}
+
+/*****************************************************
+* Basic OctetString type.
+*/
+static char *
+snmp_oct2str(uint32_t len, char *octets, char *buf)
+{
+ uint8_t binary = 0;
+ uint32_t i;
+ char *ptr;
+
+ if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
+ return (NULL);
+
+ for (ptr = buf, i = 0; i < len; i++)
+ if (!isprint(octets[i])) {
+ binary = 1;
+ buf += sprintf(buf, "0x");
+ break;
+ }
+
+ for (ptr = buf, i = 0; i < len; i++)
+ if (!binary)
+ ptr += sprintf(ptr, "%c", octets[i]);
+ else
+ ptr += sprintf(ptr, "%2.2x", (u_char)octets[i]);
+
+ return (buf);
+}
+
+static char *
+snmp_str2asn_oid(char *str, struct asn_oid *oid)
+{
+ uint32_t i, len = 0;
+
+ /*
+ * OctetStrings are allowed max length of ASN_MAXOCTETSTRING,
+ * but trying to index an entry with such a long OctetString
+ * will fail anyway.
+ */
+ for (len = 0; len < ASN_MAXOIDLEN; len++) {
+ if (strchr(",]", *(str + len)) != NULL)
+ break;
+ }
+
+ if (len >= ASN_MAXOIDLEN)
+ return (NULL);
+
+ if (snmp_suboid_append(oid, (asn_subid_t) len) < 0)
+ return (NULL);
+
+ for (i = 0; i < len; i++)
+ if (snmp_suboid_append(oid, (asn_subid_t) *(str + i)) < 0)
+ return (NULL);
+
+ return (str + len);
+}
+
+static int32_t
+parse_octetstring(struct snmp_value *value, char *val)
+{
+ size_t len;
+
+ if ((len = strlen(val)) >= MAX_OCTSTRING_LEN) {
+ warnx("Octetstring too long - %d is max allowed",
+ MAX_OCTSTRING_LEN - 1);
+ return (-1);
+ }
+
+ value->v.octetstring.len = len;
+
+ if((value->v.octetstring.octets = malloc(len)) == NULL) {
+ syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ memcpy(value->v.octetstring.octets, val, len);
+ value->syntax = SNMP_SYNTAX_OCTETSTRING;
+
+ return (0);
+}
+
+/*************************************************************
+ * DateAndTime
+ *************************************************************
+ * rfc 2579 specification:
+ * DateAndTime ::= TEXTUAL-CONVENTION
+ * DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
+ * STATUS current
+ * DESCRIPTION
+ * "A date-time specification.
+ *
+ * field octets contents range
+ * ----- ------ -------- -----
+ * 1 1-2 year* 0..65536
+ * 2 3 month 1..12
+ * 3 4 day 1..31
+ * 4 5 hour 0..23
+ * 5 6 minutes 0..59
+ * 6 7 seconds 0..60
+ * (use 60 for leap-second)
+ * 7 8 deci-seconds 0..9
+ * 8 9 direction from UTC '+' / '-'
+ * 9 10 hours from UTC* 0..13
+ * 10 11 minutes from UTC 0..59
+ *
+ * * Notes:
+ * - the value of year is in network-byte order
+ * - daylight saving time in New Zealand is +13
+ *
+ * For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+ * displayed as:
+ *
+ * 1992-5-26,13:30:15.0,-4:0
+ */
+static char *
+snmp_octstr2date(uint32_t len, char *octets, char *buf)
+{
+ int year;
+ char *ptr;
+
+ if (len != SNMP_DATETIME_OCTETS || octets == NULL || buf == NULL)
+ return (NULL);
+
+ buf[0]= '\0';
+ year = (octets[0] << 8);
+ year += (octets[1]);
+
+ ptr = buf;
+ ptr += sprintf(ptr, "%4.4d-%.2d-%.2d, ", year, octets[2],octets[3]);
+ ptr += sprintf(ptr, "%2.2d:%2.2d:%2.2d.%.2d, ", octets[4],octets[5],
+ octets[6],octets[7]);
+ ptr += sprintf(ptr, "%c%.2d:%.2d", octets[8],octets[9],octets[10]);
+
+ return (buf);
+}
+
+static char *
+snmp_date2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr, *ptr;
+ uint32_t v;
+ int32_t saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0)
+ return (NULL);
+
+ /* Read 'YYYY-' and write it in two subs. */
+ ptr = str;
+ saved_errno = errno;
+ errno = 0;
+ v = strtoul(ptr, &endptr, 10);
+ if (v > 0xffff)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != '-')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0)
+ return (NULL);
+ if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
+ return (NULL);
+
+ /* 'MM-' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != '-')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'DD,' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != '-')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'HH:' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != ':')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'MM:' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != ':')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'SS.' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != '.')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'M(mseconds),' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != ',')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'UTC' - optional */
+ ptr = endptr + 1;
+ if (*ptr == 'U' && *(ptr + 1) == 'T' && *(ptr + 1) == 'C')
+ ptr += 3;
+
+ /* '+/-' */
+ if (*ptr == '-' || *ptr == '+') {
+ if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0)
+ return (NULL);
+ } else
+ goto error1;
+
+ /* 'HH:' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != ':')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'MM' - last one - ignore endptr here. */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+
+ error:
+ errno = saved_errno;
+ error1:
+ warnx("Date value %s not supported", str);
+ return (NULL);
+}
+
+/* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */
+static int32_t
+parse_dateandtime(struct snmp_value *sv, char *val)
+{
+ char *endptr;
+ uint32_t v;
+ uint8_t date[SNMP_DATETIME_OCTETS];
+
+ /* 'YYYY-' */
+ v = strtoul(val, &endptr, 10);
+ if (v > 0xffff || *endptr != '-')
+ goto error;
+ date[0] = ((v & 0xff00) >> 8);
+ date[1] = (v & 0xff);
+ val = endptr + 1;
+
+ /* 'MM-' */
+ v = strtoul(val, &endptr, 10);
+ if (v == 0 || v > 12 || *endptr != '-')
+ goto error;
+ date[2] = v;
+ val = endptr + 1;
+
+ /* 'DD,' */
+ v = strtoul(val, &endptr, 10);
+ if (v == 0 || v > 31 || *endptr != ',')
+ goto error;
+ date[3] = v;
+ val = endptr + 1;
+
+ /* 'HH:' */
+ v = strtoul(val, &endptr, 10);
+ if (v > 23 || *endptr != ':')
+ goto error;
+ date[4] = v;
+ val = endptr + 1;
+
+ /* 'MM:' */
+ v = strtoul(val, &endptr, 10);
+ if (v > 59 || *endptr != ':')
+ goto error;
+ date[5] = v;
+ val = endptr + 1;
+
+ /* 'SS.' */
+ v = strtoul(val, &endptr, 10);
+ if (v > 60 || *endptr != '.')
+ goto error;
+ date[6] = v;
+ val = endptr + 1;
+
+ /* '(deci-)s,' */
+ v = strtoul(val, &endptr, 10);
+ if (v > 9 || *endptr != ',')
+ goto error;
+ date[7] = v;
+ val = endptr + 1;
+
+ /* offset - '+/-' */
+ if (*val != '-' && *val != '+')
+ goto error;
+ date[8] = (uint8_t) *val;
+ val = endptr + 1;
+
+ /* 'HH:' - offset from UTC */
+ v = strtoul(val, &endptr, 10);
+ if (v > 13 || *endptr != ':')
+ goto error;
+ date[9] = v;
+ val = endptr + 1;
+
+ /* 'MM'\0'' offset from UTC */
+ v = strtoul(val, &endptr, 10);
+ if (v > 59 || *endptr != '\0')
+ goto error;
+ date[10] = v;
+
+ if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) {
+ warnx("malloc() failed - %s", strerror(errno));
+ return (-1);
+ }
+
+ sv->v.octetstring.len = SNMP_DATETIME_OCTETS;
+ memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS);
+ sv->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+
+ error:
+ warnx("Date value %s not supported", val);
+ return (-1);
+}
+
+/**************************************************************
+ * PhysAddress
+ */
+static char *
+snmp_oct2physAddr(uint32_t len, char *octets, char *buf)
+{
+ char *ptr;
+ uint32_t i;
+
+ if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL)
+ return (NULL);
+
+ buf[0]= '\0';
+
+ ptr = buf;
+ ptr += sprintf(ptr, "%2.2x", octets[0]);
+ for (i = 1; i < 6; i++)
+ ptr += sprintf(ptr, ":%2.2x", octets[i]);
+
+ return (buf);
+}
+
+static char *
+snmp_addr2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr, *ptr;
+ uint32_t v, i;
+ int saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0)
+ return (NULL);
+
+ ptr = str;
+ for (i = 0; i < 5; i++) {
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 16);
+ errno = saved_errno;
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", str);
+ return (NULL);
+ }
+ if (*endptr != ':') {
+ warnx("Failed adding oid - %s",str);
+ return (NULL);
+ }
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+ ptr = endptr + 1;
+ }
+
+ /* The last one - don't check the ending char here. */
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 16);
+ errno = saved_errno;
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", str);
+ return (NULL);
+ }
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+static int32_t
+parse_physaddress(struct snmp_value *sv, char *val)
+{
+ char *endptr;
+ int32_t i;
+ uint32_t v;
+ uint8_t phys_addr[SNMP_PHYSADDR_OCTETS];
+
+ for (i = 0; i < 5; i++) {
+ v = strtoul(val, &endptr, 16);
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", val);
+ return (-1);
+ }
+ if(*endptr != ':') {
+ warnx("Failed reading octet - %s", val);
+ return (-1);
+ }
+ phys_addr[i] = v;
+ val = endptr + 1;
+ }
+
+ /* The last one - don't check the ending char here. */
+ v = strtoul(val, &endptr, 16);
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", val);
+ return (-1);
+ }
+ phys_addr[5] = v;
+
+ if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) {
+ syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS;
+ memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS);
+ sv->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+}
+
+/**************************************************************
+ * NTPTimeStamp
+ **************************************************************
+ * NTP MIB, Revision 0.2, 7/25/97:
+ * NTPTimeStamp ::= TEXTUAL-CONVENTION
+ * DISPLAY-HINT "4x.4x"
+ * STATUS current
+ * DESCRIPTION
+ * ""
+ * SYNTAX OCTET STRING (SIZE(8))
+ */
+static char *
+snmp_oct2ntp_ts(uint32_t len, char *octets, char *buf)
+{
+ char *ptr;
+ uint32_t i;
+
+ if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL)
+ return (NULL);
+
+ buf[0]= '\0';
+
+ ptr = buf;
+ i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3];
+ ptr += sprintf(ptr, "%4.4d", i);
+ i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7];
+ ptr += sprintf(ptr, ".%4.4d", i);
+
+ return (buf);
+}
+
+static char *
+snmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr, *ptr;
+ uint32_t v, i, d;
+ struct asn_oid suboid;
+ int saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0)
+ return (NULL);
+
+ ptr = str;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0 || (v / 1000) > 9) {
+ warnx("Integer value %s not supported", str);
+ errno = saved_errno;
+ return (NULL);
+ } else
+ errno = saved_errno;
+
+ if (*endptr != '.') {
+ warnx("Failed adding oid - %s",str);
+ return (NULL);
+ }
+
+ memset(&suboid, 0, sizeof(struct asn_oid));
+ suboid.len = SNMP_NTP_TS_OCTETS;
+
+ for (i = 0, d = 1000; i < 4; i++) {
+ suboid.subs[i] = v / d;
+ v = v % d;
+ d = d / 10;
+ }
+
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0 || (v / 1000) > 9) {
+ warnx("Integer value %s not supported", str);
+ errno = saved_errno;
+ return (NULL);
+ } else
+ errno = saved_errno;
+
+ for (i = 0, d = 1000; i < 4; i++) {
+ suboid.subs[i + 4] = v / d;
+ v = v % d;
+ d = d / 10;
+ }
+
+ asn_append_oid(oid, &suboid);
+ return (endptr);
+}
+
+static int32_t
+parse_ntp_ts(struct snmp_value *sv, char *val)
+{
+ char *endptr;
+ int32_t i, d, saved_errno;
+ uint32_t v;
+ uint8_t ntp_ts[SNMP_NTP_TS_OCTETS];
+
+ saved_errno = errno;
+ v = strtoul(val, &endptr, 10);
+ if (errno != 0 || (v / 1000) > 9) {
+ saved_errno = errno;
+ warnx("Integer value %s not supported", val);
+ return (-1);
+ } else
+ saved_errno = errno;
+
+ if (*endptr != '.') {
+ warnx("Failed reading octet - %s", val);
+ return (-1);
+ }
+
+ for (i = 0, d = 1000; i < 4; i++) {
+ ntp_ts[i] = v / d;
+ v = v % d;
+ d = d / 10;
+ }
+ val = endptr + 1;
+
+ saved_errno = errno;
+ v = strtoul(val, &endptr, 10);
+ if (errno != 0 || (v / 1000) > 9) {
+ saved_errno = errno;
+ warnx("Integer value %s not supported", val);
+ return (-1);
+ } else
+ saved_errno = errno;
+
+ for (i = 0, d = 1000; i < 4; i++) {
+ ntp_ts[i + 4] = v / d;
+ v = v % d;
+ d = d / 10;
+ }
+
+ if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) {
+ syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ sv->v.octetstring.len = SNMP_NTP_TS_OCTETS;
+ memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS);
+ sv->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+}
+
+/**************************************************************
+ * BridgeId
+ **************************************************************
+ * BRIDGE-MIB, REVISION "200509190000Z"
+ * 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))
+ */
+static char *
+snmp_oct2bridgeid(uint32_t len, char *octets, char *buf)
+{
+ char *ptr;
+ uint32_t i, priority;
+
+ if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL)
+ return (NULL);
+
+ buf[0]= '\0';
+ ptr = buf;
+
+ priority = octets[0] << 8;
+ priority += octets[1];
+ if (priority > SNMP_MAX_BRIDGE_PRIORITY) {
+ warnx("Invalid bridge priority %d", priority);
+ return (NULL);
+ } else
+ ptr += sprintf(ptr, "%d.", octets[0]);
+
+ ptr += sprintf(ptr, "%2.2x", octets[2]);
+
+ for (i = 1; i < 6; i++)
+ ptr += sprintf(ptr, ":%2.2x", octets[i + 2]);
+
+ return (buf);
+}
+
+static char *
+snmp_bridgeid2oct(char *str, struct asn_oid *oid)
+{
+ char *endptr, *ptr;
+ uint32_t v, i;
+ int32_t saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0)
+ return (NULL);
+
+ ptr = str;
+ /* Read the priority. */
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ errno = 0;
+
+ if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
+ errno = saved_errno;
+ warnx("Bad bridge priority value %d", v);
+ return (NULL);
+ }
+
+ if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0)
+ return (NULL);
+
+ if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
+ return (NULL);
+
+ ptr = endptr + 1;
+ for (i = 0; i < 5; i++) {
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 16);
+ errno = saved_errno;
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", str);
+ return (NULL);
+ }
+ if (*endptr != ':') {
+ warnx("Failed adding oid - %s",str);
+ return (NULL);
+ }
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+ ptr = endptr + 1;
+ }
+
+ /* The last one - don't check the ending char here. */
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 16);
+ errno = saved_errno;
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", str);
+ return (NULL);
+ }
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+static int32_t
+parse_bridge_id(struct snmp_value *sv, char *string)
+{
+ char *ptr, *endptr;
+ int32_t i, saved_errno;
+ uint32_t v;
+ uint8_t bridge_id[SNMP_BRIDGEID_OCTETS];
+
+ ptr = string;
+ /* Read the priority. */
+ saved_errno = errno;
+ errno = 0;
+ v = strtoul(string, &endptr, 10);
+ errno = saved_errno;
+
+ if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
+ errno = saved_errno;
+ warnx("Bad bridge priority value %d", v);
+ return (-1);
+ }
+
+ bridge_id[0] = (v & 0xff00);
+ bridge_id[1] = (v & 0xff);
+
+ string = endptr + 1;
+
+ for (i = 0; i < 5; i++) {
+ v = strtoul(string, &endptr, 16);
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", string);
+ return (-1);
+ }
+ if(*endptr != ':') {
+ warnx("Failed reading octet - %s", string);
+ return (-1);
+ }
+ bridge_id[i + 2] = v;
+ string = endptr + 1;
+ }
+
+ /* The last one - don't check the ending char here. */
+ v = strtoul(string, &endptr, 16);
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", string);
+ return (-1);
+ }
+ bridge_id[7] = v;
+
+ if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) {
+ syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS;
+ memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS);
+ sv->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+}
+
+/**************************************************************
+ * BridgePortId
+ **************************************************************
+ * BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z"
+ * 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))
+ */
+static char *
+snmp_oct2bport_id(uint32_t len, char *octets, char *buf)
+{
+ char *ptr;
+
+ if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL)
+ return (NULL);
+
+ buf[0]= '\0';
+ ptr = buf;
+
+ ptr += sprintf(ptr, "%d.", octets[0]);
+ ptr += sprintf(ptr, "%d", octets[1]);
+
+ return (buf);
+}
+
+static char *
+snmp_bport_id2oct(char *str, struct asn_oid *oid)
+{
+ char *endptr, *ptr;
+ uint32_t v;
+ int saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0)
+ return (NULL);
+
+ ptr = str;
+ /* Read the priority. */
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ errno = 0;
+
+ if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
+ errno = saved_errno;
+ warnx("Bad bridge port priority value %d", v);
+ return (NULL);
+ }
+
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 16);
+ errno = saved_errno;
+
+ if (v > 0xff) {
+ warnx("Bad port number - %d", v);
+ return (NULL);
+ }
+
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+static int32_t
+parse_bport_id(struct snmp_value *value, char *string)
+{
+ char *ptr, *endptr;
+ int saved_errno;
+ uint32_t v;
+ uint8_t bport_id[SNMP_BPORT_OCTETS];
+
+ ptr = string;
+ /* Read the priority. */
+ saved_errno = errno;
+ errno = 0;
+ v = strtoul(string, &endptr, 10);
+ errno = saved_errno;
+
+ if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
+ errno = saved_errno;
+ warnx("Bad bridge port priority value %d", v);
+ return (-1);
+ }
+
+ bport_id[0] = v;
+
+ string = endptr + 1;
+ v = strtoul(string, &endptr, 16);
+ if (v > 0xff) {
+ warnx("Bad port number - %d", v);
+ return (-1);
+ }
+
+ bport_id[1] = v;
+
+ if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) {
+ syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ value->v.octetstring.len = SNMP_BPORT_OCTETS;
+ memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS);
+ value->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+}
+/**************************************************************
+ * InetAddress
+ **************************************************************
+ * INET-ADDRESS-MIB, REVISION "200502040000Z"
+ * InetAddress ::= TEXTUAL-CONVENTION
+ * STATUS current
+ * DESCRIPTION
+ * "Denotes a generic Internet address.
+ *
+ * An InetAddress value is always interpreted within the context
+ * of an InetAddressType value. Every usage of the InetAddress
+ * textual convention is required to specify the InetAddressType
+ * object that provides the context. It is suggested that the
+ * InetAddressType object be logically registered before the
+ * object(s) that use the InetAddress textual convention, if
+ * they appear in the same logical row.
+ *
+ * The value of an InetAddress object must always be
+ * consistent with the value of the associated InetAddressType
+ * object. Attempts to set an InetAddress object to a value
+ * inconsistent with the associated InetAddressType
+ * must fail with an inconsistentValue error.
+ *
+ * When this textual convention is used as the syntax of an
+ * index object, there may be issues with the limit of 128
+ * sub-identifiers specified in SMIv2, STD 58. In this case,
+ * the object definition MUST include a 'SIZE' clause to
+ * limit the number of potential instance sub-identifiers;
+ * otherwise the applicable constraints MUST be stated in
+ * the appropriate conceptual row DESCRIPTION clauses, or
+ * in the surrounding documentation if there is no single
+ * DESCRIPTION clause that is appropriate."
+ * SYNTAX OCTET STRING (SIZE (0..255))
+ **************************************************************
+ * TODO: FIXME!!! syrinx: Since we do not support checking the
+ * consistency of a varbinding based on the value of a previous
+ * one, try to guess the type of address based on the
+ * OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently
+ * not supported.
+ */
+static char *
+snmp_oct2inetaddr(uint32_t len, char *octets, char *buf)
+{
+ int af;
+ void *ip;
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+
+ if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
+ return (NULL);
+
+ switch (len) {
+ /* XXX: FIXME - IPv4*/
+ case 4:
+ memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr));
+ af = AF_INET;
+ ip = &ipv4;
+ break;
+
+ /* XXX: FIXME - IPv4*/
+ case 16:
+ memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr));
+ af = AF_INET6;
+ ip = &ipv6;
+ break;
+
+ default:
+ return (NULL);
+ }
+
+ if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) {
+ warnx("inet_ntop failed - %s", strerror(errno));
+ return (NULL);
+ }
+
+ return (buf);
+}
+
+static char *
+snmp_inetaddr2oct(char *str, struct asn_oid *oid)
+{
+ return (NULL);
+}
+
+static int32_t
+parse_inetaddr(struct snmp_value *value, char *string)
+{
+ return (-1);
+}
+
+/**************************************************************
+ * SNMP BITS type - XXX: FIXME
+ **************************************************************/
+static char *
+snmp_oct2bits(uint32_t len, char *octets, char *buf)
+{
+ int i, bits;
+ uint64_t value;
+
+ if (len > sizeof(value) || octets == NULL || buf == NULL)
+ return (NULL);
+
+ for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8)
+ value += octets[i] << bits;
+
+ buf[0]= '\0';
+ sprintf(buf, "0x%llx.",(long long unsigned) value);
+
+ return (buf);
+}
+
+static char *
+snmp_bits2oct(char *str, struct asn_oid *oid)
+{
+ char *endptr;
+ int i, size, bits, saved_errno;
+ uint64_t v, mask = 0xFF00000000000000;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoull(str, &endptr, 16);
+ if (errno != 0) {
+ warnx("Bad BITS value %s - %s", str, strerror(errno));
+ errno = saved_errno;
+ return (NULL);
+ }
+
+ bits = 8;
+ /* Determine length - up to 8 octets supported so far. */
+ for (size = sizeof(v); size > 0; size--) {
+ if ((v & mask) != 0)
+ break;
+ mask = mask >> bits;
+ }
+
+ if (size == 0)
+ size = 1;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) size) < 0)
+ return (NULL);
+
+ for (i = 0, bits = 0; i < size; i++, bits += 8)
+ if (snmp_suboid_append(oid,
+ (asn_subid_t)((v & mask) >> bits)) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+static int32_t
+parse_bits(struct snmp_value *value, char *string)
+{
+ char *endptr;
+ int i, size, bits, saved_errno;
+ uint64_t v, mask = 0xFF00000000000000;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoull(string, &endptr, 16);
+
+ if (errno != 0) {
+ warnx("Bad BITS value %s - %s", string, strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ bits = 8;
+ /* Determine length - up to 8 octets supported so far. */
+ for (size = sizeof(v); size > 0; size--) {
+ if ((v & mask) != 0)
+ break;
+ mask = mask >> bits;
+ }
+
+ if (size == 0)
+ size = 1;
+
+ if ((value->v.octetstring.octets = malloc(size)) == NULL) {
+ syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ value->v.octetstring.len = size;
+ for (i = 0, bits = 0; i < size; i++, bits += 8)
+ value->v.octetstring.octets[i] = (v & mask) >> bits;
+ value->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.h b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.h
new file mode 100644
index 0000000..fd06676
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.h
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@FreeBSD.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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.
+ *
+ * Textual conventions for snmp
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BSNMP_TEXT_CONV_H_
+#define _BSNMP_TEXT_CONV_H_
+
+/* Variable display length string. */
+#define SNMP_VAR_STRSZ -1
+
+/*
+ * 11 bytes - octets that represent DateAndTime Textual convention
+ * and the size of string used to diplay that.
+ */
+#define SNMP_DATETIME_OCTETS 11
+#define SNMP_DATETIME_STRSZ 32
+
+/*
+ * 6 bytes - octets that represent PhysAddress Textual convention
+ * and the size of string used to diplay that.
+ */
+#define SNMP_PHYSADDR_OCTETS 6
+#define SNMP_PHYSADDR_STRSZ 19
+
+/* NTPTimeStamp. */
+#define SNMP_NTP_TS_OCTETS 8
+#define SNMP_NTP_TS_STRSZ 10
+
+/* BridgeId. */
+#define SNMP_BRIDGEID_OCTETS 8
+#define SNMP_BRIDGEID_STRSZ 25
+#define SNMP_MAX_BRIDGE_PRIORITY 65535
+
+/* BridgePortId. */
+#define SNMP_BPORT_OCTETS 2
+#define SNMP_BPORT_STRSZ 7
+#define SNMP_MAX_BPORT_PRIORITY 255
+
+/* InetAddress. */
+#define SNMP_INADDRS_STRSZ INET6_ADDRSTRLEN
+
+enum snmp_tc {
+ SNMP_STRING = 0,
+ SNMP_DISPLAYSTRING = 1,
+ SNMP_DATEANDTIME = 2,
+ SNMP_PHYSADDR = 3,
+ SNMP_ATMESI = 4,
+ SNMP_NTP_TIMESTAMP = 5,
+ SNMP_MACADDRESS = 6,
+ SNMP_BRIDGE_ID = 7,
+ SNMP_BPORT_ID = 8,
+ SNMP_INETADDRESS = 9,
+ SNMP_TC_OWN = 10,
+ SNMP_UNKNOWN, /* keep last */
+};
+
+typedef char * (*snmp_oct2tc_f) (uint32_t len, char *octs, char *buf);
+typedef char * (*snmp_tc2oid_f) (char *str, struct asn_oid *oid);
+typedef int32_t (*snmp_tc2oct_f) (struct snmp_value *value, char *string);
+
+enum snmp_tc snmp_get_tc(char *str);
+char *snmp_oct2tc(enum snmp_tc tc, uint32_t len, char *octets);
+char *snmp_tc2oid(enum snmp_tc tc, char *str, struct asn_oid *oid);
+int32_t snmp_tc2oct(enum snmp_tc tc, struct snmp_value *value, char *string);
+
+#endif /* _BSNMP_TEXT_CONV_H_ */
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
new file mode 100755
index 0000000..52aa1a9
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
@@ -0,0 +1,2132 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@FreeBSD.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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.
+ *
+ * Helper functions for snmp client tools
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+#include <bsnmp/snmpclient.h>
+#include "bsnmptc.h"
+#include "bsnmptools.h"
+
+/* Internal varibale to turn on library debugging for testing and to
+ * find bugs. It is not exported via the header file.
+ * XXX should we cover it by some #ifdef BSNMPTOOLS_DEBUG? */
+int _bsnmptools_debug = 0;
+
+/* Default files to import mapping from if none explicitly provided. */
+#define bsnmpd_defs "/usr/share/snmp/defs/tree.def"
+#define mibII_defs "/usr/share/snmp/defs/mibII_tree.def"
+
+/*
+ * The .iso.org.dod oid that has to be prepended to every OID when requesting
+ * a value.
+ */
+const struct asn_oid IsoOrgDod_OID = {
+ 3, { 1, 3, 6 }
+};
+
+
+#define SNMP_ERR_UNKNOWN 0
+
+/*
+ * An array of error strings corresponding to error definitions from libbsnmp.
+ */
+static const struct {
+ const char *str;
+ int32_t error;
+} error_strings[] = {
+ { "Unknown", SNMP_ERR_UNKNOWN },
+ { "Too big ", SNMP_ERR_TOOBIG },
+ { "No such Name", SNMP_ERR_NOSUCHNAME },
+ { "Bad Value", SNMP_ERR_BADVALUE },
+ { "Readonly", SNMP_ERR_READONLY },
+ { "General error", SNMP_ERR_GENERR },
+ { "No access", SNMP_ERR_NO_ACCESS },
+ { "Wrong type", SNMP_ERR_WRONG_TYPE },
+ { "Wrong length", SNMP_ERR_WRONG_LENGTH },
+ { "Wrong encoding", SNMP_ERR_WRONG_ENCODING },
+ { "Wrong value", SNMP_ERR_WRONG_VALUE },
+ { "No creation", SNMP_ERR_NO_CREATION },
+ { "Inconsistent value", SNMP_ERR_INCONS_VALUE },
+ { "Resource unavailable", SNMP_ERR_RES_UNAVAIL },
+ { "Commit failed", SNMP_ERR_COMMIT_FAILED },
+ { "Undo failed", SNMP_ERR_UNDO_FAILED },
+ { "Authorization error", SNMP_ERR_AUTH_ERR },
+ { "Not writable", SNMP_ERR_NOT_WRITEABLE },
+ { "Inconsistent name", SNMP_ERR_INCONS_NAME },
+ { NULL, 0 }
+};
+
+/* This one and any following are exceptions. */
+#define SNMP_SYNTAX_UNKNOWN SNMP_SYNTAX_NOSUCHOBJECT
+
+static const struct {
+ const char *str;
+ enum snmp_syntax stx;
+} syntax_strings[] = {
+ { "Null", SNMP_SYNTAX_NULL },
+ { "Integer", SNMP_SYNTAX_INTEGER },
+ { "OctetString", SNMP_SYNTAX_OCTETSTRING },
+ { "OID", SNMP_SYNTAX_OID },
+ { "IpAddress", SNMP_SYNTAX_IPADDRESS },
+ { "Counter32", SNMP_SYNTAX_COUNTER },
+ { "Gauge", SNMP_SYNTAX_GAUGE },
+ { "TimeTicks", SNMP_SYNTAX_TIMETICKS },
+ { "Counter64", SNMP_SYNTAX_COUNTER64 },
+ { "Unknown", SNMP_SYNTAX_UNKNOWN },
+};
+
+int
+snmptool_init(struct snmp_toolinfo *snmptoolctx)
+{
+ char *str;
+ size_t slen;
+
+ memset(snmptoolctx, 0, sizeof(struct snmp_toolinfo));
+ snmptoolctx->objects = 0;
+ snmptoolctx->mappings = NULL;
+ snmptoolctx->flags = SNMP_PDU_GET; /* XXX */
+ SLIST_INIT(&snmptoolctx->filelist);
+ snmp_client_init(&snmp_client);
+ SET_MAXREP(snmptoolctx, SNMP_MAX_REPETITIONS);
+
+ if (add_filename(snmptoolctx, bsnmpd_defs, &IsoOrgDod_OID, 0) < 0)
+ warnx("Error adding file %s to list", bsnmpd_defs);
+
+ if (add_filename(snmptoolctx, mibII_defs, &IsoOrgDod_OID, 0) < 0)
+ warnx("Error adding file %s to list", mibII_defs);
+
+ /* Read the environment */
+ if ((str = getenv("SNMPAUTH")) != NULL) {
+ slen = strlen(str);
+ if (slen == strlen("md5") && strcasecmp(str, "md5") == 0)
+ snmp_client.user.auth_proto = SNMP_AUTH_HMAC_MD5;
+ else if (slen == strlen("sha")&& strcasecmp(str, "sha") == 0)
+ snmp_client.user.auth_proto = SNMP_AUTH_HMAC_SHA;
+ else if (slen != 0)
+ warnx("Bad authentication type - %s in SNMPAUTH", str);
+ }
+
+ if ((str = getenv("SNMPPRIV")) != NULL) {
+ slen = strlen(str);
+ if (slen == strlen("des") && strcasecmp(str, "des") == 0)
+ snmp_client.user.priv_proto = SNMP_PRIV_DES;
+ else if (slen == strlen("aes")&& strcasecmp(str, "aes") == 0)
+ snmp_client.user.priv_proto = SNMP_PRIV_AES;
+ else if (slen != 0)
+ warnx("Bad privacy type - %s in SNMPPRIV", str);
+ }
+
+ if ((str = getenv("SNMPUSER")) != NULL) {
+ if ((slen = strlen(str)) > sizeof(snmp_client.user.sec_name)) {
+ warnx("Username too long - %s in SNMPUSER", str);
+ return (-1);
+ }
+ if (slen > 0) {
+ strlcpy(snmp_client.user.sec_name, str,
+ sizeof(snmp_client.user.sec_name));
+ snmp_client.version = SNMP_V3;
+ }
+ }
+
+ if ((str = getenv("SNMPPASSWD")) != NULL) {
+ if ((slen = strlen(str)) > MAXSTR)
+ slen = MAXSTR - 1;
+ if ((snmptoolctx->passwd = malloc(slen + 1)) == NULL) {
+ warnx("malloc() failed - %s", strerror(errno));
+ return (-1);
+ }
+ if (slen > 0)
+ strlcpy(snmptoolctx->passwd, str, slen + 1);
+ }
+
+ return (0);
+}
+
+#define OBJECT_IDX_LIST(o) o->info->table_idx->index_list
+
+/*
+ * Walk through the file list and import string<->oid mappings from each file.
+ */
+int32_t
+snmp_import_all(struct snmp_toolinfo *snmptoolctx)
+{
+ int32_t fc;
+ struct fname *tmp;
+
+ if (snmptoolctx == NULL)
+ return (-1);
+
+ if (ISSET_NUMERIC(snmptoolctx))
+ return (0);
+
+ if ((snmptoolctx->mappings = snmp_mapping_init()) == NULL)
+ return (-1);
+
+ fc = 0;
+ if (SLIST_EMPTY(&snmptoolctx->filelist)) {
+ warnx("No files to read OID <-> string conversions from");
+ return (-1);
+ } else {
+ SLIST_FOREACH(tmp, &snmptoolctx->filelist, link) {
+ if (tmp->done)
+ continue;
+ if (snmp_import_file(snmptoolctx, tmp) < 0) {
+ fc = -1;
+ break;
+ }
+ fc++;
+ }
+ }
+
+ snmp_mapping_dump(snmptoolctx);
+ return (fc);
+}
+
+/*
+ * Add a filename to the file list - the initial idea of keeping a list with all
+ * files to read OIDs from was that an application might want to have loaded in
+ * memory the OIDs from a single file only and when done with them read the OIDs
+ * from another file. This is not used yet but might be a good idea at some
+ * point. Size argument is number of bytes in string including trailing '\0',
+ * not string length.
+ */
+int32_t
+add_filename(struct snmp_toolinfo *snmptoolctx, const char *filename,
+ const struct asn_oid *cut, int32_t done)
+{
+ char *fstring;
+ struct fname *entry;
+
+ if (snmptoolctx == NULL)
+ return (-1);
+
+ /* Make sure file was not in list. */
+ SLIST_FOREACH(entry, &snmptoolctx->filelist, link) {
+ if (strncmp(entry->name, filename, strlen(entry->name)) == 0)
+ return (0);
+ }
+
+ if ((fstring = malloc(strlen(filename) + 1)) == NULL) {
+ warnx("malloc() failed - %s", strerror(errno));
+ return (-1);
+ }
+
+ if ((entry = malloc(sizeof(struct fname))) == NULL) {
+ warnx("malloc() failed - %s", strerror(errno));
+ free(fstring);
+ return (-1);
+ }
+
+ memset(entry, 0, sizeof(struct fname));
+
+ if (cut != NULL)
+ asn_append_oid(&(entry->cut), cut);
+ strlcpy(fstring, filename, strlen(filename) + 1);
+ entry->name = fstring;
+ entry->done = done;
+ SLIST_INSERT_HEAD(&snmptoolctx->filelist, entry, link);
+
+ return (1);
+}
+
+void
+free_filelist(struct snmp_toolinfo *snmptoolctx)
+{
+ struct fname *f;
+
+ if (snmptoolctx == NULL)
+ return; /* XXX error handling */
+
+ while ((f = SLIST_FIRST(&snmptoolctx->filelist)) != NULL) {
+ SLIST_REMOVE_HEAD(&snmptoolctx->filelist, link);
+ if (f->name)
+ free(f->name);
+ free(f);
+ }
+}
+
+static char
+isvalid_fchar(char c, int pos)
+{
+ if (isalpha(c)|| c == '/'|| c == '_' || c == '.' || c == '~' ||
+ (pos != 0 && isdigit(c))){
+ return (c);
+ }
+
+ if (c == '\0')
+ return (0);
+
+ if (!isascii(c) || !isprint(c))
+ warnx("Unexpected character %#2x", (u_int) c);
+ else
+ warnx("Illegal character '%c'", c);
+
+ return (-1);
+}
+
+/*
+ * Re-implement getsubopt from scratch, because the second argument is broken
+ * and will not compile with WARNS=5.
+ * Copied from src/contrib/bsnmp/snmpd/main.c.
+ */
+static int
+getsubopt1(char **arg, const char *const *options, char **valp, char **optp)
+{
+ static const char *const delim = ",\t ";
+ u_int i;
+ char *ptr;
+
+ *optp = NULL;
+
+ /* Skip leading junk. */
+ for (ptr = *arg; *ptr != '\0'; ptr++)
+ if (strchr(delim, *ptr) == NULL)
+ break;
+ if (*ptr == '\0') {
+ *arg = ptr;
+ return (-1);
+ }
+ *optp = ptr;
+
+ /* Find the end of the option. */
+ while (*++ptr != '\0')
+ if (strchr(delim, *ptr) != NULL || *ptr == '=')
+ break;
+
+ if (*ptr != '\0') {
+ if (*ptr == '=') {
+ *ptr++ = '\0';
+ *valp = ptr;
+ while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
+ ptr++;
+ if (*ptr != '\0')
+ *ptr++ = '\0';
+ } else
+ *ptr++ = '\0';
+ }
+
+ *arg = ptr;
+
+ for (i = 0; *options != NULL; options++, i++)
+ if (strcmp(*optp, *options) == 0)
+ return (i);
+ return (-1);
+}
+
+static int32_t
+parse_path(char *value)
+{
+ int32_t i, len;
+
+ if (value == NULL)
+ return (-1);
+
+ for (len = 0; len < MAXPATHLEN; len++) {
+ i = isvalid_fchar(*(value + len), len) ;
+
+ if (i == 0)
+ break;
+ else if (i < 0)
+ return (-1);
+ }
+
+ if (len >= MAXPATHLEN || value[len] != '\0') {
+ warnx("Bad pathname - '%s'", value);
+ return (-1);
+ }
+
+ return (len);
+}
+
+static int32_t
+parse_flist(struct snmp_toolinfo *snmptoolctx, char *value, char *path,
+ const struct asn_oid *cut)
+{
+ int32_t namelen;
+ char filename[MAXPATHLEN + 1];
+
+ if (value == NULL)
+ return (-1);
+
+ do {
+ memset(filename, 0, MAXPATHLEN + 1);
+
+ if (isalpha(*value) && (path == NULL || path[0] == '\0')) {
+ strlcpy(filename, SNMP_DEFS_DIR, MAXPATHLEN + 1);
+ namelen = strlen(SNMP_DEFS_DIR);
+ } else if (path != NULL){
+ strlcpy(filename, path, MAXPATHLEN + 1);
+ namelen = strlen(path);
+ } else
+ namelen = 0;
+
+ for ( ; namelen < MAXPATHLEN; value++) {
+ if (isvalid_fchar(*value, namelen) > 0) {
+ filename[namelen++] = *value;
+ continue;
+ }
+
+ if (*value == ',' )
+ value++;
+ else if (*value == '\0')
+ ;
+ else {
+ if (!isascii(*value) || !isprint(*value))
+ warnx("Unexpected character %#2x in"
+ " filename", (u_int) *value);
+ else
+ warnx("Illegal character '%c' in"
+ " filename", *value);
+ return (-1);
+ }
+
+ filename[namelen]='\0';
+ break;
+ }
+
+ if ((namelen == MAXPATHLEN) && (filename[MAXPATHLEN] != '\0')) {
+ warnx("Filename %s too long", filename);
+ return (-1);
+ }
+
+ if (add_filename(snmptoolctx, filename, cut, 0) < 0) {
+ warnx("Error adding file %s to list", filename);
+ return (-1);
+ }
+ } while (*value != '\0');
+
+ return(1);
+}
+
+static int32_t
+parse_ascii(char *ascii, uint8_t *binstr, size_t binlen)
+{
+ int32_t alen, count, saved_errno, i;
+ uint32_t val;
+ char dptr[3];
+
+ /* Filter 0x at the beginning */
+ if ((alen = strlen(ascii)) > 2 && ascii[0] == '0' && ascii[1] == 'x')
+ i = 2;
+ else
+ i = 0;
+
+ saved_errno = errno;
+ errno = 0;
+ for (count = 0; i < alen; i += 2) {
+ /* XXX: consider strlen(ascii) % 2 != 0 */
+ dptr[0] = ascii[i];
+ dptr[1] = ascii[i + 1];
+ dptr[2] = '\0';
+ if ((val = strtoul(dptr, NULL, 16)) > 0xFF || errno != 0) {
+ errno = saved_errno;
+ return (-1);
+ }
+ binstr[count] = (uint8_t) val;
+ if (++count >= binlen) {
+ warnx("Key %s too long - truncating to %zu octets",
+ ascii, binlen);
+ break;
+ }
+ }
+
+ return (count);
+}
+
+/*
+ * Functions to parse common input options for client tools and fill in the
+ * snmp_client structure.
+ */
+int32_t
+parse_authentication(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ int32_t count, subopt;
+ char *val, *option;
+ const char *const subopts[] = {
+ "proto",
+ "key",
+ NULL
+ };
+
+ assert(opt_arg != NULL);
+ count = 1;
+ while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
+ switch (subopt) {
+ case 0:
+ if (val == NULL) {
+ warnx("Suboption 'proto' requires an argument");
+ return (-1);
+ }
+ if (strlen(val) != 3) {
+ warnx("Unknown auth protocol - %s", val);
+ return (-1);
+ }
+ if (strncasecmp("md5", val, strlen("md5")) == 0)
+ snmp_client.user.auth_proto =
+ SNMP_AUTH_HMAC_MD5;
+ else if (strncasecmp("sha", val, strlen("sha")) == 0)
+ snmp_client.user.auth_proto =
+ SNMP_AUTH_HMAC_SHA;
+ else {
+ warnx("Unknown auth protocol - %s", val);
+ return (-1);
+ }
+ break;
+ case 1:
+ if (val == NULL) {
+ warnx("Suboption 'key' requires an argument");
+ return (-1);
+ }
+ if (parse_ascii(val, snmp_client.user.auth_key,
+ SNMP_AUTH_KEY_SIZ) < 0) {
+ warnx("Bad authentication key- %s", val);
+ return (-1);
+ }
+ break;
+ default:
+ warnx("Unknown suboption - '%s'", suboptarg);
+ return (-1);
+ }
+ count += 1;
+ }
+ return (2/* count */);
+}
+
+int32_t
+parse_privacy(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ int32_t count, subopt;
+ char *val, *option;
+ const char *const subopts[] = {
+ "proto",
+ "key",
+ NULL
+ };
+
+ assert(opt_arg != NULL);
+ count = 1;
+ while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
+ switch (subopt) {
+ case 0:
+ if (val == NULL) {
+ warnx("Suboption 'proto' requires an argument");
+ return (-1);
+ }
+ if (strlen(val) != 3) {
+ warnx("Unknown privacy protocol - %s", val);
+ return (-1);
+ }
+ if (strncasecmp("aes", val, strlen("aes")) == 0)
+ snmp_client.user.priv_proto = SNMP_PRIV_AES;
+ else if (strncasecmp("des", val, strlen("des")) == 0)
+ snmp_client.user.priv_proto = SNMP_PRIV_DES;
+ else {
+ warnx("Unknown privacy protocol - %s", val);
+ return (-1);
+ }
+ break;
+ case 1:
+ if (val == NULL) {
+ warnx("Suboption 'key' requires an argument");
+ return (-1);
+ }
+ if (parse_ascii(val, snmp_client.user.priv_key,
+ SNMP_PRIV_KEY_SIZ) < 0) {
+ warnx("Bad privacy key- %s", val);
+ return (-1);
+ }
+ break;
+ default:
+ warnx("Unknown suboption - '%s'", suboptarg);
+ return (-1);
+ }
+ count += 1;
+ }
+ return (2/* count */);
+}
+
+int32_t
+parse_context(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ int32_t count, subopt;
+ char *val, *option;
+ const char *const subopts[] = {
+ "context",
+ "context-engine",
+ NULL
+ };
+
+ assert(opt_arg != NULL);
+ count = 1;
+ while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
+ switch (subopt) {
+ case 0:
+ if (val == NULL) {
+ warnx("Suboption 'context' - no argument");
+ return (-1);
+ }
+ strlcpy(snmp_client.cname, val, SNMP_CONTEXT_NAME_SIZ);
+ break;
+ case 1:
+ if (val == NULL) {
+ warnx("Suboption 'context-engine' - no argument");
+ return (-1);
+ }
+ if ((snmp_client.clen = parse_ascii(val,
+ snmp_client.cengine, SNMP_ENGINE_ID_SIZ)) < 0) {
+ warnx("Bad EngineID - %s", val);
+ return (-1);
+ }
+ break;
+ default:
+ warnx("Unknown suboption - '%s'", suboptarg);
+ return (-1);
+ }
+ count += 1;
+ }
+ return (2/* count */);
+}
+
+int32_t
+parse_user_security(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ int32_t count, subopt, saved_errno;
+ char *val, *option;
+ const char *const subopts[] = {
+ "engine",
+ "engine-boots",
+ "engine-time",
+ "name",
+ NULL
+ };
+
+ assert(opt_arg != NULL);
+ count = 1;
+ while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
+ switch (subopt) {
+ case 0:
+ if (val == NULL) {
+ warnx("Suboption 'engine' - no argument");
+ return (-1);
+ }
+ snmp_client.engine.engine_len = parse_ascii(val,
+ snmp_client.engine.engine_id, SNMP_ENGINE_ID_SIZ);
+ if (snmp_client.engine.engine_len < 0) {
+ warnx("Bad EngineID - %s", val);
+ return (-1);
+ }
+ break;
+ case 1:
+ if (val == NULL) {
+ warnx("Suboption 'engine-boots' - no argument");
+ return (-1);
+ }
+ saved_errno = errno;
+ errno = 0;
+ snmp_client.engine.engine_boots = strtoul(val, NULL, 10);
+ if (errno != 0) {
+ warnx("Bad 'engine-boots' value %s - %s", val,
+ strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+ errno = saved_errno;
+ break;
+ case 2:
+ if (val == NULL) {
+ warnx("Suboption 'engine-time' - no argument");
+ return (-1);
+ }
+ saved_errno = errno;
+ errno = 0;
+ snmp_client.engine.engine_time = strtoul(val, NULL, 10);
+ if (errno != 0) {
+ warnx("Bad 'engine-time' value %s - %s", val,
+ strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+ errno = saved_errno;
+ break;
+ case 3:
+ strlcpy(snmp_client.user.sec_name, val,
+ SNMP_ADM_STR32_SIZ);
+ break;
+ default:
+ warnx("Unknown suboption - '%s'", suboptarg);
+ return (-1);
+ }
+ count += 1;
+ }
+ return (2/* count */);
+}
+
+int32_t
+parse_file(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ assert(opt_arg != NULL);
+
+ if (parse_flist(snmptoolctx, opt_arg, NULL, &IsoOrgDod_OID) < 0)
+ return (-1);
+
+ return (2);
+}
+
+int32_t
+parse_include(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ char path[MAXPATHLEN + 1];
+ int32_t cut_dflt, len, subopt;
+ struct asn_oid cut;
+ char *val, *option;
+ const char *const subopts[] = {
+ "cut",
+ "path",
+ "file",
+ NULL
+ };
+
+#define INC_CUT 0
+#define INC_PATH 1
+#define INC_LIST 2
+
+ assert(opt_arg != NULL);
+
+ /* if (opt == 'i')
+ free_filelist(snmptoolctx, ); */
+ /*
+ * This function should be called only after getopt(3) - otherwise if
+ * no previous validation of opt_arg strlen() may not return what is
+ * expected.
+ */
+
+ path[0] = '\0';
+ memset(&cut, 0, sizeof(struct asn_oid));
+ cut_dflt = -1;
+
+ while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
+ switch (subopt) {
+ case INC_CUT:
+ if (val == NULL) {
+ warnx("Suboption 'cut' requires an argument");
+ return (-1);
+ } else {
+ if (snmp_parse_numoid(val, &cut) < 0)
+ return (-1);
+ }
+ cut_dflt = 1;
+ break;
+
+ case INC_PATH:
+ if ((len = parse_path(val)) < 0)
+ return (-1);
+ strlcpy(path, val, len + 1);
+ break;
+
+ case INC_LIST:
+ if (val == NULL)
+ return (-1);
+ if (cut_dflt == -1)
+ len = parse_flist(snmptoolctx, val, path, &IsoOrgDod_OID);
+ else
+ len = parse_flist(snmptoolctx, val, path, &cut);
+ if (len < 0)
+ return (-1);
+ break;
+
+ default:
+ warnx("Unknown suboption - '%s'", suboptarg);
+ return (-1);
+ }
+ }
+
+ /* XXX: Fix me - returning two is wrong here */
+ return (2);
+}
+
+int32_t
+parse_server(char *opt_arg)
+{
+ assert(opt_arg != NULL);
+
+ if (snmp_parse_server(&snmp_client, opt_arg) < 0)
+ return (-1);
+
+ if (snmp_client.trans > SNMP_TRANS_UDP && snmp_client.chost == NULL) {
+ if ((snmp_client.chost = malloc(strlen(SNMP_DEFAULT_LOCAL + 1)))
+ == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+ strcpy(snmp_client.chost, SNMP_DEFAULT_LOCAL);
+ }
+
+ return (2);
+}
+
+int32_t
+parse_timeout(char *opt_arg)
+{
+ int32_t v, saved_errno;
+
+ assert(opt_arg != NULL);
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtol(opt_arg, NULL, 10);
+ if (errno != 0) {
+ warnx( "Error parsing timeout value - %s", strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ snmp_client.timeout.tv_sec = v;
+ errno = saved_errno;
+ return (2);
+}
+
+int32_t
+parse_retry(char *opt_arg)
+{
+ uint32_t v;
+ int32_t saved_errno;
+
+ assert(opt_arg != NULL);
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoul(opt_arg, NULL, 10);
+ if (errno != 0) {
+ warnx("Error parsing retries count - %s", strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ snmp_client.retries = v;
+ errno = saved_errno;
+ return (2);
+}
+
+int32_t
+parse_version(char *opt_arg)
+{
+ uint32_t v;
+ int32_t saved_errno;
+
+ assert(opt_arg != NULL);
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoul(opt_arg, NULL, 10);
+ if (errno != 0) {
+ warnx("Error parsing version - %s", strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ switch (v) {
+ case 1:
+ snmp_client.version = SNMP_V1;
+ break;
+ case 2:
+ snmp_client.version = SNMP_V2c;
+ break;
+ case 3:
+ snmp_client.version = SNMP_V3;
+ break;
+ default:
+ warnx("Unsupported SNMP version - %u", v);
+ errno = saved_errno;
+ return (-1);
+ }
+
+ errno = saved_errno;
+ return (2);
+}
+
+int32_t
+parse_local_path(char *opt_arg)
+{
+ assert(opt_arg != NULL);
+
+ if (sizeof(opt_arg) > sizeof(SNMP_LOCAL_PATH)) {
+ warnx("Filename too long - %s", opt_arg);
+ return (-1);
+ }
+
+ strlcpy(snmp_client.local_path, opt_arg, sizeof(SNMP_LOCAL_PATH));
+ return (2);
+}
+
+int32_t
+parse_buflen(char *opt_arg)
+{
+ uint32_t size;
+ int32_t saved_errno;
+
+ assert(opt_arg != NULL);
+
+ saved_errno = errno;
+ errno = 0;
+
+ size = strtoul(opt_arg, NULL, 10);
+ if (errno != 0) {
+ warnx("Error parsing buffer size - %s", strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ if (size > MAX_BUFF_SIZE) {
+ warnx("Buffer size too big - %d max allowed", MAX_BUFF_SIZE);
+ errno = saved_errno;
+ return (-1);
+ }
+
+ snmp_client.txbuflen = snmp_client.rxbuflen = size;
+ errno = saved_errno;
+ return (2);
+}
+
+int32_t
+parse_debug(void)
+{
+ snmp_client.dump_pdus = 1;
+ return (1);
+}
+
+int32_t
+parse_discovery(struct snmp_toolinfo *snmptoolctx)
+{
+ SET_EDISCOVER(snmptoolctx);
+ snmp_client.version = SNMP_V3;
+ return (1);
+}
+
+int32_t
+parse_local_key(struct snmp_toolinfo *snmptoolctx)
+{
+ SET_LOCALKEY(snmptoolctx);
+ snmp_client.version = SNMP_V3;
+ return (1);
+}
+
+int32_t
+parse_num_oids(struct snmp_toolinfo *snmptoolctx)
+{
+ SET_NUMERIC(snmptoolctx);
+ return (1);
+}
+
+int32_t
+parse_output(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ assert(opt_arg != NULL);
+
+ if (strlen(opt_arg) > strlen("verbose")) {
+ warnx( "Invalid output option - %s",opt_arg);
+ return (-1);
+ }
+
+ if (strncasecmp(opt_arg, "short", strlen(opt_arg)) == 0)
+ SET_OUTPUT(snmptoolctx, OUTPUT_SHORT);
+ else if (strncasecmp(opt_arg, "verbose", strlen(opt_arg)) == 0)
+ SET_OUTPUT(snmptoolctx, OUTPUT_VERBOSE);
+ else if (strncasecmp(opt_arg,"tabular", strlen(opt_arg)) == 0)
+ SET_OUTPUT(snmptoolctx, OUTPUT_TABULAR);
+ else if (strncasecmp(opt_arg, "quiet", strlen(opt_arg)) == 0)
+ SET_OUTPUT(snmptoolctx, OUTPUT_QUIET);
+ else {
+ warnx( "Invalid output option - %s", opt_arg);
+ return (-1);
+ }
+
+ return (2);
+}
+
+int32_t
+parse_errors(struct snmp_toolinfo *snmptoolctx)
+{
+ SET_RETRY(snmptoolctx);
+ return (1);
+}
+
+int32_t
+parse_skip_access(struct snmp_toolinfo *snmptoolctx)
+{
+ SET_ERRIGNORE(snmptoolctx);
+ return (1);
+}
+
+char *
+snmp_parse_suboid(char *str, struct asn_oid *oid)
+{
+ char *endptr;
+ asn_subid_t suboid;
+
+ if (*str == '.')
+ str++;
+
+ if (*str < '0' || *str > '9')
+ return (str);
+
+ do {
+ suboid = strtoul(str, &endptr, 10);
+ if ((asn_subid_t) suboid > ASN_MAXID) {
+ warnx("Suboid %u > ASN_MAXID", suboid);
+ return (NULL);
+ }
+ if (snmp_suboid_append(oid, suboid) < 0)
+ return (NULL);
+ str = endptr + 1;
+ } while (*endptr == '.');
+
+ return (endptr);
+}
+
+static char *
+snmp_int2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr;
+ int32_t v, saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtol(str, &endptr, 10);
+ if (errno != 0) {
+ warnx("Integer value %s not supported - %s", str,
+ strerror(errno));
+ errno = saved_errno;
+ return (NULL);
+ }
+ errno = saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+/* It is a bit weird to have a table indexed by OID but still... */
+static char *
+snmp_oid2asn_oid(struct snmp_toolinfo *snmptoolctx, char *str,
+ struct asn_oid *oid)
+{
+ int32_t i;
+ char string[MAXSTR], *endptr;
+ struct snmp_object obj;
+
+ for (i = 0; i < MAXSTR; i++)
+ if (isalpha (*(str + i)) == 0)
+ break;
+
+ endptr = str + i;
+ memset(&obj, 0, sizeof(struct snmp_object));
+ if (i == 0) {
+ if ((endptr = snmp_parse_suboid(str, &(obj.val.var))) == NULL)
+ return (NULL);
+ if (snmp_suboid_append(oid, (asn_subid_t) obj.val.var.len) < 0)
+ return (NULL);
+ } else {
+ strlcpy(string, str, i + 1);
+ string[i] = '\0';
+ if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
+ warnx("Unknown string - %s",string);
+ return (NULL);
+ }
+ free(string);
+ }
+
+ asn_append_oid(oid, &(obj.val.var));
+ return (endptr);
+}
+
+static char *
+snmp_ip2asn_oid(char *str, struct asn_oid *oid)
+{
+ uint32_t v;
+ int32_t i;
+ char *endptr, *ptr;
+
+ ptr = str;
+ for (i = 0; i < 4; i++) {
+ v = strtoul(ptr, &endptr, 10);
+ if (v > 0xff)
+ return (NULL);
+ if (*endptr != '.' && strchr("],\0", *endptr) == NULL && i != 3)
+ return (NULL);
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+ ptr = endptr + 1;
+ }
+
+ return (endptr);
+}
+
+/* 32-bit counter, gauge, timeticks. */
+static char *
+snmp_uint2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr;
+ uint32_t v;
+ int32_t saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoul(str, &endptr, 10);
+ if (errno != 0) {
+ warnx("Integer value %s not supported - %s\n", str,
+ strerror(errno));
+ errno = saved_errno;
+ return (NULL);
+ }
+ errno = saved_errno;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+static char *
+snmp_cnt64_2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr;
+ uint64_t v;
+ int32_t saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoull(str, &endptr, 10);
+
+ if (errno != 0) {
+ warnx("Integer value %s not supported - %s", str,
+ strerror(errno));
+ errno = saved_errno;
+ return (NULL);
+ }
+ errno = saved_errno;
+ if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xffffffff)) < 0)
+ return (NULL);
+
+ if (snmp_suboid_append(oid, (asn_subid_t) (v >> 32)) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+enum snmp_syntax
+parse_syntax(char *str)
+{
+ int32_t i;
+
+ for (i = 0; i < SNMP_SYNTAX_UNKNOWN; i++) {
+ if (strncmp(syntax_strings[i].str, str,
+ strlen(syntax_strings[i].str)) == 0)
+ return (syntax_strings[i].stx);
+ }
+
+ return (SNMP_SYNTAX_NULL);
+}
+
+static char *
+snmp_parse_subindex(struct snmp_toolinfo *snmptoolctx, char *str,
+ struct index *idx, struct snmp_object *object)
+{
+ char *ptr;
+ int32_t i;
+ enum snmp_syntax stx;
+ char syntax[MAX_CMD_SYNTAX_LEN];
+
+ ptr = str;
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
+ for (i = 0; i < MAX_CMD_SYNTAX_LEN ; i++) {
+ if (*(ptr + i) == ':')
+ break;
+ }
+
+ if (i >= MAX_CMD_SYNTAX_LEN) {
+ warnx("Unknown syntax in OID - %s", str);
+ return (NULL);
+ }
+ /* Expect a syntax string here. */
+ if ((stx = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
+ warnx("Invalid syntax - %s",syntax);
+ return (NULL);
+ }
+
+ if (stx != idx->syntax && !ISSET_ERRIGNORE(snmptoolctx)) {
+ warnx("Syntax mismatch - %d expected, %d given",
+ idx->syntax, stx);
+ return (NULL);
+ }
+ /*
+ * That is where the suboid started + the syntax length + one
+ * character for ':'.
+ */
+ ptr = str + i + 1;
+ } else
+ stx = idx->syntax;
+
+ switch (stx) {
+ case SNMP_SYNTAX_INTEGER:
+ return (snmp_int2asn_oid(ptr, &(object->val.var)));
+ case SNMP_SYNTAX_OID:
+ return (snmp_oid2asn_oid(snmptoolctx, ptr,
+ &(object->val.var)));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (snmp_ip2asn_oid(ptr, &(object->val.var)));
+ case SNMP_SYNTAX_COUNTER:
+ /* FALLTHROUGH */
+ case SNMP_SYNTAX_GAUGE:
+ /* FALLTHROUGH */
+ case SNMP_SYNTAX_TIMETICKS:
+ return (snmp_uint2asn_oid(ptr, &(object->val.var)));
+ case SNMP_SYNTAX_COUNTER64:
+ return (snmp_cnt64_2asn_oid(ptr, &(object->val.var)));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_tc2oid(idx->tc, ptr, &(object->val.var)));
+ default:
+ /* NOTREACHED */
+ break;
+ }
+
+ return (NULL);
+}
+
+char *
+snmp_parse_index(struct snmp_toolinfo *snmptoolctx, char *str,
+ struct snmp_object *object)
+{
+ char *ptr;
+ struct index *temp;
+
+ if (object->info->table_idx == NULL)
+ return (NULL);
+
+ ptr = NULL;
+ STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(object)), link) {
+ if ((ptr = snmp_parse_subindex(snmptoolctx, str, temp, object))
+ == NULL)
+ return (NULL);
+
+ if (*ptr != ',' && *ptr != ']')
+ return (NULL);
+ str = ptr + 1;
+ }
+
+ if (ptr == NULL || *ptr != ']') {
+ warnx("Mismatching index - %s", str);
+ return (NULL);
+ }
+
+ return (ptr + 1);
+}
+
+/*
+ * Fill in the struct asn_oid member of snmp_value with suboids from input.
+ * If an error occurs - print message on stderr and return (-1).
+ * If all is ok - return the length of the oid.
+ */
+int32_t
+snmp_parse_numoid(char *argv, struct asn_oid *var)
+{
+ char *endptr, *str;
+ asn_subid_t suboid;
+
+ str = argv;
+
+ if (*str == '.')
+ str++;
+
+ do {
+ if (var->len == ASN_MAXOIDLEN) {
+ warnx("Oid too long - %u", var->len);
+ return (-1);
+ }
+
+ suboid = strtoul(str, &endptr, 10);
+ if (suboid > ASN_MAXID) {
+ warnx("Oid too long - %u", var->len);
+ return (-1);
+ }
+
+ var->subs[var->len++] = suboid;
+ str = endptr + 1;
+ } while ( *endptr == '.');
+
+ if (*endptr != '\0') {
+ warnx("Invalid oid string - %s", argv);
+ return (-1);
+ }
+
+ return (var->len);
+}
+
+/* Append a length 1 suboid to an asn_oid structure. */
+int32_t
+snmp_suboid_append(struct asn_oid *var, asn_subid_t suboid)
+{
+ if (var == NULL)
+ return (-1);
+
+ if (var->len >= ASN_MAXOIDLEN) {
+ warnx("Oid too long - %u", var->len);
+ return (-1);
+ }
+
+ var->subs[var->len++] = suboid;
+
+ return (1);
+}
+
+/* Pop the last suboid from an asn_oid structure. */
+int32_t
+snmp_suboid_pop(struct asn_oid *var)
+{
+ asn_subid_t suboid;
+
+ if (var == NULL)
+ return (-1);
+
+ if (var->len < 1)
+ return (-1);
+
+ suboid = var->subs[--(var->len)];
+ var->subs[var->len] = 0;
+
+ return (suboid);
+}
+
+/*
+ * Parse the command-line provided string into an OID - alocate memory for a new
+ * snmp object, fill in its fields and insert it in the object list. A
+ * (snmp_verify_inoid_f) function must be provided to validate the input string.
+ */
+int32_t
+snmp_object_add(struct snmp_toolinfo *snmptoolctx, snmp_verify_inoid_f func,
+ char *string)
+{
+ struct snmp_object *obj;
+
+ if (snmptoolctx == NULL)
+ return (-1);
+
+ /* XXX-BZ does that chack make sense? */
+ if (snmptoolctx->objects >= SNMP_MAX_BINDINGS) {
+ warnx("Too many bindings in PDU - %u", snmptoolctx->objects + 1);
+ return (-1);
+ }
+
+ if ((obj = malloc(sizeof(struct snmp_object))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ memset(obj, 0, sizeof(struct snmp_object));
+ if (func(snmptoolctx, obj, string) < 0) {
+ warnx("Invalid OID - %s", string);
+ free(obj);
+ return (-1);
+ }
+
+ snmptoolctx->objects++;
+ SLIST_INSERT_HEAD(&snmptoolctx->snmp_objectlist, obj, link);
+
+ return (1);
+}
+
+/* Given an OID, find it in the object list and remove it. */
+int32_t
+snmp_object_remove(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
+{
+ struct snmp_object *temp;
+
+ if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist)) {
+ warnx("Object list already empty");
+ return (-1);
+ }
+
+
+ SLIST_FOREACH(temp, &snmptoolctx->snmp_objectlist, link)
+ if (asn_compare_oid(&(temp->val.var), oid) == 0)
+ break;
+
+ if (temp == NULL) {
+ warnx("No such object in list");
+ return (-1);
+ }
+
+ SLIST_REMOVE(&snmptoolctx->snmp_objectlist, temp, snmp_object, link);
+ if (temp->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
+ temp->val.v.octetstring.octets != NULL)
+ free(temp->val.v.octetstring.octets);
+ free(temp);
+
+ return (1);
+}
+
+static void
+snmp_object_freeall(struct snmp_toolinfo *snmptoolctx)
+{
+ struct snmp_object *o;
+
+ while ((o = SLIST_FIRST(&snmptoolctx->snmp_objectlist)) != NULL) {
+ SLIST_REMOVE_HEAD(&snmptoolctx->snmp_objectlist, link);
+
+ if (o->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
+ o->val.v.octetstring.octets != NULL)
+ free(o->val.v.octetstring.octets);
+ free(o);
+ }
+}
+
+/* Do all possible memory release before exit. */
+void
+snmp_tool_freeall(struct snmp_toolinfo *snmptoolctx)
+{
+ if (snmp_client.chost != NULL) {
+ free(snmp_client.chost);
+ snmp_client.chost = NULL;
+ }
+
+ if (snmp_client.cport != NULL) {
+ free(snmp_client.cport);
+ snmp_client.cport = NULL;
+ }
+
+ snmp_mapping_free(snmptoolctx);
+ free_filelist(snmptoolctx);
+ snmp_object_freeall(snmptoolctx);
+
+ if (snmptoolctx->passwd != NULL) {
+ free(snmptoolctx->passwd);
+ snmptoolctx->passwd = NULL;
+ }
+}
+
+/*
+ * Fill all variables from the object list into a PDU. (snmp_verify_vbind_f)
+ * function should check whether the variable is consistent in this PDU
+ * (e.g do not add non-leaf OIDs to a GET PDU, or OIDs with read access only to
+ * a SET PDU) - might be NULL though. (snmp_add_vbind_f) function is the
+ * function actually adds the variable to the PDU and must not be NULL.
+ */
+int32_t
+snmp_pdu_add_bindings(struct snmp_toolinfo *snmptoolctx,
+ snmp_verify_vbind_f vfunc, snmp_add_vbind_f afunc,
+ struct snmp_pdu *pdu, int32_t maxcount)
+{
+ int32_t nbindings, abind;
+ struct snmp_object *obj;
+
+ if (pdu == NULL || afunc == NULL)
+ return (-1);
+
+ /* Return 0 in case of no more work todo. */
+ if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist))
+ return (0);
+
+ if (maxcount < 0 || maxcount > SNMP_MAX_BINDINGS) {
+ warnx("maxcount out of range: <0 || >SNMP_MAX_BINDINGS");
+ return (-1);
+ }
+
+ nbindings = 0;
+ SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link) {
+ if ((vfunc != NULL) && (vfunc(snmptoolctx, pdu, obj) < 0)) {
+ nbindings = -1;
+ break;
+ }
+ if ((abind = afunc(pdu, obj)) < 0) {
+ nbindings = -1;
+ break;
+ }
+
+ if (abind > 0) {
+ /* Do not put more varbindings than requested. */
+ if (++nbindings >= maxcount)
+ break;
+ }
+ }
+
+ return (nbindings);
+}
+
+/*
+ * Locate an object in the object list and set a corresponding error status.
+ */
+int32_t
+snmp_object_seterror(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_value *err_value, int32_t error_status)
+{
+ struct snmp_object *obj;
+
+ if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist) || err_value == NULL)
+ return (-1);
+
+ SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link)
+ if (asn_compare_oid(&(err_value->var), &(obj->val.var)) == 0) {
+ obj->error = error_status;
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Check a PDU received in response to a SNMP_PDU_GET/SNMP_PDU_GETBULK request
+ * but don't compare syntaxes - when sending a request PDU they must be null.
+ * This is a (almost) complete copy of snmp_pdu_check() - with matching syntaxes
+ * checks and some other checks skipped.
+ */
+int32_t
+snmp_parse_get_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
+{
+ uint32_t i;
+
+ for (i = 0; i < req->nbindings; i++) {
+ if (asn_compare_oid(&req->bindings[i].var,
+ &resp->bindings[i].var) != 0) {
+ warnx("Bad OID in response");
+ return (-1);
+ }
+
+ if (snmp_client.version != SNMP_V1 && (resp->bindings[i].syntax
+ == SNMP_SYNTAX_NOSUCHOBJECT || resp->bindings[i].syntax ==
+ SNMP_SYNTAX_NOSUCHINSTANCE))
+ return (0);
+ }
+
+ return (1);
+}
+
+int32_t
+snmp_parse_getbulk_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
+{
+ int32_t N, R, M, r;
+
+ if (req->error_status > (int32_t) resp->nbindings) {
+ warnx("Bad number of bindings in response");
+ return (-1);
+ }
+
+ for (N = 0; N < req->error_status; N++) {
+ if (asn_is_suboid(&req->bindings[N].var,
+ &resp->bindings[N].var) == 0)
+ return (0);
+ if (resp->bindings[N].syntax == SNMP_SYNTAX_ENDOFMIBVIEW)
+ return (0);
+ }
+
+ for (R = N , r = N; R < (int32_t) req->nbindings; R++) {
+ for (M = 0; M < req->error_index && (r + M) <
+ (int32_t) resp->nbindings; M++) {
+ if (asn_is_suboid(&req->bindings[R].var,
+ &resp->bindings[r + M].var) == 0)
+ return (0);
+
+ if (resp->bindings[r + M].syntax ==
+ SNMP_SYNTAX_ENDOFMIBVIEW) {
+ M++;
+ break;
+ }
+ }
+ r += M;
+ }
+
+ return (0);
+}
+
+int32_t
+snmp_parse_getnext_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
+{
+ uint32_t i;
+
+ for (i = 0; i < req->nbindings; i++) {
+ if (asn_is_suboid(&req->bindings[i].var, &resp->bindings[i].var)
+ == 0)
+ return (0);
+
+ if (resp->version != SNMP_V1 && resp->bindings[i].syntax ==
+ SNMP_SYNTAX_ENDOFMIBVIEW)
+ return (0);
+ }
+
+ return (1);
+}
+
+/*
+ * Should be called to check a response to get/getnext/getbulk.
+ */
+int32_t
+snmp_parse_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
+{
+ if (resp == NULL || req == NULL)
+ return (-2);
+
+ if (resp->version != req->version) {
+ warnx("Response has wrong version");
+ return (-1);
+ }
+
+ if (resp->error_status == SNMP_ERR_NOSUCHNAME) {
+ warnx("Error - No Such Name");
+ return (0);
+ }
+
+ if (resp->error_status != SNMP_ERR_NOERROR) {
+ warnx("Error %d in response", resp->error_status);
+ return (-1);
+ }
+
+ if (resp->nbindings != req->nbindings && req->type != SNMP_PDU_GETBULK){
+ warnx("Bad number of bindings in response");
+ return (-1);
+ }
+
+ switch (req->type) {
+ case SNMP_PDU_GET:
+ return (snmp_parse_get_resp(resp,req));
+ case SNMP_PDU_GETBULK:
+ return (snmp_parse_getbulk_resp(resp,req));
+ case SNMP_PDU_GETNEXT:
+ return (snmp_parse_getnext_resp(resp,req));
+ default:
+ /* NOTREACHED */
+ break;
+ }
+
+ return (-2);
+}
+
+static void
+snmp_output_octetstring(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
+ uint32_t len, uint8_t *octets)
+{
+ char *buf;
+
+ if (len == 0 || octets == NULL)
+ return;
+
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_OCTETSTRING].str);
+
+ if ((buf = snmp_oct2tc(tc, len, (char *) octets)) != NULL) {
+ fprintf(stdout, "%s", buf);
+ free(buf);
+ }
+}
+
+static void
+snmp_output_octetindex(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
+ struct asn_oid *oid)
+{
+ uint32_t i;
+ uint8_t *s;
+
+ if ((s = malloc(oid->subs[0] + 1)) == NULL)
+ syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
+ else {
+ for (i = 0; i < oid->subs[0]; i++)
+ s[i] = (u_char) (oid->subs[i + 1]);
+
+ snmp_output_octetstring(snmptoolctx, tc, oid->subs[0], s);
+ free(s);
+ }
+}
+
+/*
+ * Check and output syntax type and value.
+ */
+static void
+snmp_output_oid_value(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
+{
+ char oid_string[ASN_OIDSTRLEN];
+ struct snmp_object obj;
+
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_OID].str);
+
+ if(!ISSET_NUMERIC(snmptoolctx)) {
+ memset(&obj, 0, sizeof(struct snmp_object));
+ asn_append_oid(&(obj.val.var), oid);
+
+ if (snmp_lookup_enumstring(snmptoolctx, &obj) > 0)
+ fprintf(stdout, "%s" , obj.info->string);
+ else if (snmp_lookup_oidstring(snmptoolctx, &obj) > 0)
+ fprintf(stdout, "%s" , obj.info->string);
+ else if (snmp_lookup_nodestring(snmptoolctx, &obj) > 0)
+ fprintf(stdout, "%s" , obj.info->string);
+ else {
+ (void) asn_oid2str_r(oid, oid_string);
+ fprintf(stdout, "%s", oid_string);
+ }
+ } else {
+ (void) asn_oid2str_r(oid, oid_string);
+ fprintf(stdout, "%s", oid_string);
+ }
+}
+
+static void
+snmp_output_int(struct snmp_toolinfo *snmptoolctx, struct enum_pairs *enums,
+ int32_t int_val)
+{
+ char *string;
+
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_INTEGER].str);
+
+ if (enums != NULL && (string = enum_string_lookup(enums, int_val))
+ != NULL)
+ fprintf(stdout, "%s", string);
+ else
+ fprintf(stdout, "%d", int_val);
+}
+
+static void
+snmp_output_ipaddress(struct snmp_toolinfo *snmptoolctx, uint8_t *ip)
+{
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_IPADDRESS].str);
+
+ fprintf(stdout, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
+}
+
+static void
+snmp_output_counter(struct snmp_toolinfo *snmptoolctx, uint32_t counter)
+{
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_COUNTER].str);
+
+ fprintf(stdout, "%u", counter);
+}
+
+static void
+snmp_output_gauge(struct snmp_toolinfo *snmptoolctx, uint32_t gauge)
+{
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_GAUGE].str);
+
+ fprintf(stdout, "%u", gauge);
+}
+
+static void
+snmp_output_ticks(struct snmp_toolinfo *snmptoolctx, uint32_t ticks)
+{
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_TIMETICKS].str);
+
+ fprintf(stdout, "%u", ticks);
+}
+
+static void
+snmp_output_counter64(struct snmp_toolinfo *snmptoolctx, uint64_t counter64)
+{
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_COUNTER64].str);
+
+ fprintf(stdout,"%ju", counter64);
+}
+
+int32_t
+snmp_output_numval(struct snmp_toolinfo *snmptoolctx, struct snmp_value *val,
+ struct snmp_oid2str *entry)
+{
+ if (val == NULL)
+ return (-1);
+
+ if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
+ fprintf(stdout, " = ");
+
+ switch (val->syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ if (entry != NULL)
+ snmp_output_int(snmptoolctx, entry->snmp_enum,
+ val->v.integer);
+ else
+ snmp_output_int(snmptoolctx, NULL, val->v.integer);
+ break;
+
+ case SNMP_SYNTAX_OCTETSTRING:
+ if (entry != NULL)
+ snmp_output_octetstring(snmptoolctx, entry->tc,
+ val->v.octetstring.len, val->v.octetstring.octets);
+ else
+ snmp_output_octetstring(snmptoolctx, SNMP_STRING,
+ val->v.octetstring.len, val->v.octetstring.octets);
+ break;
+
+ case SNMP_SYNTAX_OID:
+ snmp_output_oid_value(snmptoolctx, &(val->v.oid));
+ break;
+
+ case SNMP_SYNTAX_IPADDRESS:
+ snmp_output_ipaddress(snmptoolctx, val->v.ipaddress);
+ break;
+
+ case SNMP_SYNTAX_COUNTER:
+ snmp_output_counter(snmptoolctx, val->v.uint32);
+ break;
+
+ case SNMP_SYNTAX_GAUGE:
+ snmp_output_gauge(snmptoolctx, val->v.uint32);
+ break;
+
+ case SNMP_SYNTAX_TIMETICKS:
+ snmp_output_ticks(snmptoolctx, val->v.uint32);
+ break;
+
+ case SNMP_SYNTAX_COUNTER64:
+ snmp_output_counter64(snmptoolctx, val->v.counter64);
+ break;
+
+ case SNMP_SYNTAX_NOSUCHOBJECT:
+ fprintf(stdout, "No Such Object\n");
+ return (val->syntax);
+
+ case SNMP_SYNTAX_NOSUCHINSTANCE:
+ fprintf(stdout, "No Such Instance\n");
+ return (val->syntax);
+
+ case SNMP_SYNTAX_ENDOFMIBVIEW:
+ fprintf(stdout, "End of Mib View\n");
+ return (val->syntax);
+
+ case SNMP_SYNTAX_NULL:
+ /* NOTREACHED */
+ fprintf(stdout, "agent returned NULL Syntax\n");
+ return (val->syntax);
+
+ default:
+ /* NOTREACHED - If here - then all went completely wrong. */
+ fprintf(stdout, "agent returned unknown syntax\n");
+ return (-1);
+ }
+
+ fprintf(stdout, "\n");
+
+ return (0);
+}
+
+static int32_t
+snmp_fill_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *obj,
+ struct snmp_value *val)
+{
+ int32_t rc;
+ asn_subid_t suboid;
+
+ if (obj == NULL || val == NULL)
+ return (-1);
+
+ if ((suboid = snmp_suboid_pop(&(val->var))) > ASN_MAXID)
+ return (-1);
+
+ memset(obj, 0, sizeof(struct snmp_object));
+ asn_append_oid(&(obj->val.var), &(val->var));
+ obj->val.syntax = val->syntax;
+
+ if (obj->val.syntax > 0)
+ rc = snmp_lookup_leafstring(snmptoolctx, obj);
+ else
+ rc = snmp_lookup_nonleaf_string(snmptoolctx, obj);
+
+ (void) snmp_suboid_append(&(val->var), suboid);
+ (void) snmp_suboid_append(&(obj->val.var), suboid);
+
+ return (rc);
+}
+
+static int32_t
+snmp_output_index(struct snmp_toolinfo *snmptoolctx, struct index *stx,
+ struct asn_oid *oid)
+{
+ uint8_t ip[4];
+ uint32_t bytes = 1;
+ uint64_t cnt64;
+ struct asn_oid temp, out;
+
+ if (oid->len < bytes)
+ return (-1);
+
+ memset(&temp, 0, sizeof(struct asn_oid));
+ asn_append_oid(&temp, oid);
+
+ switch (stx->syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ snmp_output_int(snmptoolctx, stx->snmp_enum, temp.subs[0]);
+ break;
+
+ case SNMP_SYNTAX_OCTETSTRING:
+ if ((temp.subs[0] > temp.len -1 ) || (temp.subs[0] >
+ ASN_MAXOCTETSTRING))
+ return (-1);
+ snmp_output_octetindex(snmptoolctx, stx->tc, &temp);
+ bytes += temp.subs[0];
+ break;
+
+ case SNMP_SYNTAX_OID:
+ if ((temp.subs[0] > temp.len -1) || (temp.subs[0] >
+ ASN_MAXOIDLEN))
+ return (-1);
+
+ bytes += temp.subs[0];
+ memset(&out, 0, sizeof(struct asn_oid));
+ asn_slice_oid(&out, &temp, 1, bytes);
+ snmp_output_oid_value(snmptoolctx, &out);
+ break;
+
+ case SNMP_SYNTAX_IPADDRESS:
+ if (temp.len < 4)
+ return (-1);
+ for (bytes = 0; bytes < 4; bytes++)
+ ip[bytes] = temp.subs[bytes];
+
+ snmp_output_ipaddress(snmptoolctx, ip);
+ bytes = 4;
+ break;
+
+ case SNMP_SYNTAX_COUNTER:
+ snmp_output_counter(snmptoolctx, temp.subs[0]);
+ break;
+
+ case SNMP_SYNTAX_GAUGE:
+ snmp_output_gauge(snmptoolctx, temp.subs[0]);
+ break;
+
+ case SNMP_SYNTAX_TIMETICKS:
+ snmp_output_ticks(snmptoolctx, temp.subs[0]);
+ break;
+
+ case SNMP_SYNTAX_COUNTER64:
+ if (oid->len < 2)
+ return (-1);
+ bytes = 2;
+ memcpy(&cnt64, temp.subs, bytes);
+ snmp_output_counter64(snmptoolctx, cnt64);
+ break;
+
+ default:
+ return (-1);
+ }
+
+ return (bytes);
+}
+
+static int32_t
+snmp_output_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *o)
+{
+ int32_t i, first, len;
+ struct asn_oid oid;
+ struct index *temp;
+
+ if (ISSET_NUMERIC(snmptoolctx))
+ return (-1);
+
+ if (o->info->table_idx == NULL) {
+ fprintf(stdout,"%s.%d", o->info->string,
+ o->val.var.subs[o->val.var.len - 1]);
+ return (1);
+ }
+
+ fprintf(stdout,"%s[", o->info->string);
+ memset(&oid, 0, sizeof(struct asn_oid));
+
+ len = 1;
+ asn_slice_oid(&oid, &(o->val.var), (o->info->table_idx->var.len + len),
+ o->val.var.len);
+
+ first = 1;
+ STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(o)), link) {
+ if(first)
+ first = 0;
+ else
+ fprintf(stdout, ", ");
+ if ((i = snmp_output_index(snmptoolctx, temp, &oid)) < 0)
+ break;
+ len += i;
+ memset(&oid, 0, sizeof(struct asn_oid));
+ asn_slice_oid(&oid, &(o->val.var),
+ (o->info->table_idx->var.len + len), o->val.var.len + 1);
+ }
+
+ fprintf(stdout,"]");
+ return (1);
+}
+
+void
+snmp_output_err_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu)
+{
+ char buf[ASN_OIDSTRLEN];
+ struct snmp_object object;
+
+ if (pdu == NULL || (pdu->error_index > (int32_t) pdu->nbindings)) {
+ fprintf(stdout,"Invalid error index in PDU\n");
+ return;
+ }
+
+ fprintf(stdout, "Agent %s:%s returned error \n", snmp_client.chost,
+ snmp_client.cport);
+
+ if (!ISSET_NUMERIC(snmptoolctx) && (snmp_fill_object(snmptoolctx, &object,
+ &(pdu->bindings[pdu->error_index - 1])) > 0))
+ snmp_output_object(snmptoolctx, &object);
+ else {
+ asn_oid2str_r(&(pdu->bindings[pdu->error_index - 1].var), buf);
+ fprintf(stdout,"%s", buf);
+ }
+
+ fprintf(stdout," caused error - ");
+ if ((pdu->error_status > 0) && (pdu->error_status <=
+ SNMP_ERR_INCONS_NAME))
+ fprintf(stdout, "%s\n", error_strings[pdu->error_status].str);
+ else
+ fprintf(stdout,"%s\n", error_strings[SNMP_ERR_UNKNOWN].str);
+}
+
+int32_t
+snmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
+ struct asn_oid *root)
+{
+ int32_t error;
+ char p[ASN_OIDSTRLEN];
+ uint32_t i;
+ struct snmp_object object;
+
+ i = error = 0;
+ while (i < pdu->nbindings) {
+ if (root != NULL && !(asn_is_suboid(root,
+ &(pdu->bindings[i].var))))
+ break;
+
+ if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) {
+ if (!ISSET_NUMERIC(snmptoolctx) &&
+ (snmp_fill_object(snmptoolctx, &object,
+ &(pdu->bindings[i])) > 0))
+ snmp_output_object(snmptoolctx, &object);
+ else {
+ asn_oid2str_r(&(pdu->bindings[i].var), p);
+ fprintf(stdout, "%s", p);
+ }
+ }
+ error |= snmp_output_numval(snmptoolctx, &(pdu->bindings[i]), object.info);
+ i++;
+ }
+
+ if (error)
+ return (-1);
+
+ return (i);
+}
+
+void
+snmp_output_engine(void)
+{
+ uint32_t i;
+ char *cptr, engine[2 * SNMP_ENGINE_ID_SIZ + 2];
+
+ cptr = engine;
+ for (i = 0; i < snmp_client.engine.engine_len; i++)
+ cptr += sprintf(cptr, "%.2x", snmp_client.engine.engine_id[i]);
+ *cptr++ = '\0';
+
+ fprintf(stdout, "Engine ID 0x%s\n", engine);
+ fprintf(stdout, "Boots : %u\t\tTime : %d\n",
+ snmp_client.engine.engine_boots,
+ snmp_client.engine.engine_time);
+}
+
+void
+snmp_output_keys(void)
+{
+ uint32_t i, keylen = 0;
+ char *cptr, extkey[2 * SNMP_AUTH_KEY_SIZ + 2];
+
+ fprintf(stdout, "Localized keys for %s\n", snmp_client.user.sec_name);
+ if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_MD5) {
+ fprintf(stdout, "MD5 : 0x");
+ keylen = SNMP_AUTH_HMACMD5_KEY_SIZ;
+ } else if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_SHA) {
+ fprintf(stdout, "SHA : 0x");
+ keylen = SNMP_AUTH_HMACSHA_KEY_SIZ;
+ }
+ if (snmp_client.user.auth_proto != SNMP_AUTH_NOAUTH) {
+ cptr = extkey;
+ for (i = 0; i < keylen; i++)
+ cptr += sprintf(cptr, "%.2x",
+ snmp_client.user.auth_key[i]);
+ *cptr++ = '\0';
+ fprintf(stdout, "%s\n", extkey);
+ }
+
+ if (snmp_client.user.priv_proto == SNMP_PRIV_DES) {
+ fprintf(stdout, "DES : 0x");
+ keylen = SNMP_PRIV_DES_KEY_SIZ;
+ } else if (snmp_client.user.priv_proto == SNMP_PRIV_AES) {
+ fprintf(stdout, "AES : 0x");
+ keylen = SNMP_PRIV_AES_KEY_SIZ;
+ }
+ if (snmp_client.user.priv_proto != SNMP_PRIV_NOPRIV) {
+ cptr = extkey;
+ for (i = 0; i < keylen; i++)
+ cptr += sprintf(cptr, "%.2x",
+ snmp_client.user.priv_key[i]);
+ *cptr++ = '\0';
+ fprintf(stdout, "%s\n", extkey);
+ }
+}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h
new file mode 100644
index 0000000..c14fe52
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h
@@ -0,0 +1,333 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@FreeBSD.org>
+ *
+ * Redistribution of this software and documentation 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 or documentation 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.
+ *
+ * Helper functions common for all tools.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BSNMP_TOOLS_H_
+#define _BSNMP_TOOLS_H_
+
+/* From asn1.h + 1 byte for trailing zero. */
+#define MAX_OCTSTRING_LEN ASN_MAXOCTETSTRING + 1
+#define MAX_CMD_SYNTAX_LEN 12
+
+/* Arbitrary upper limit on node names and function names - gensnmptree.c. */
+#define MAXSTR 1000
+
+/* Should be enough to fetch the biggest allowed octet string. */
+#define MAX_BUFF_SIZE (ASN_MAXOCTETSTRING + 50)
+
+#define SNMP_DEFS_DIR "/usr/share/snmp/defs/"
+#define SNMP_DEFAULT_LOCAL "/var/run/snmpd.sock"
+
+#define SNMP_MAX_REPETITIONS 10
+
+enum snmp_access {
+ SNMP_ACCESS_NONE = 0,
+ SNMP_ACCESS_GET,
+ SNMP_ACCESS_SET,
+ SNMP_ACCESS_GETSET,
+};
+
+/* A structure for integer-string enumerations. */
+struct enum_pair {
+ int32_t enum_val;
+ char *enum_str;
+ STAILQ_ENTRY(enum_pair) link;
+};
+
+STAILQ_HEAD(enum_pairs, enum_pair);
+
+struct enum_type {
+ char *name;
+ uint32_t syntax;
+ int32_t is_enum;
+ int32_t is_bits;
+ struct enum_pairs *snmp_enum;
+ SLIST_ENTRY(enum_type) link;
+};
+
+SLIST_HEAD(snmp_enum_tc, enum_type);
+
+struct index {
+ enum snmp_tc tc;
+ enum snmp_syntax syntax;
+ struct enum_pairs *snmp_enum;
+ STAILQ_ENTRY(index) link;
+};
+
+STAILQ_HEAD(snmp_idxlist, index);
+
+struct snmp_index_entry {
+ char *string;
+ uint32_t strlen;
+ struct asn_oid var;
+ struct snmp_idxlist index_list;
+ SLIST_ENTRY(snmp_index_entry) link;
+};
+
+/* Information needed for oid to string conversion. */
+struct snmp_oid2str {
+ char *string;
+ uint32_t strlen;
+ enum snmp_tc tc;
+ enum snmp_syntax syntax;
+ enum snmp_access access;
+ struct asn_oid var;
+ /* A pointer to a entry from the table list - OK if NULL. */
+ struct snmp_index_entry *table_idx;
+ /*
+ * A singly-linked tail queue of all (int, string) pairs -
+ * for INTEGER syntax only.
+ */
+ struct enum_pairs *snmp_enum;
+ SLIST_ENTRY(snmp_oid2str) link;
+};
+
+/* A structure to hold each oid input by user. */
+struct snmp_object {
+ /* Flag - if set, the variable caused error in a previous request. */
+ int32_t error;
+ /*
+ * A pointer in the mapping lists - not used if OIDs are input as
+ * numericals.
+ */
+ struct snmp_oid2str *info;
+ /* A snmp value to hold the actual oid, syntax and value. */
+ struct snmp_value val;
+ SLIST_ENTRY(snmp_object) link;
+};
+
+struct fname {
+ char *name;
+ int32_t done;
+ struct asn_oid cut;
+ SLIST_ENTRY(fname) link;
+};
+
+SLIST_HEAD(snmp_mapping, snmp_oid2str);
+SLIST_HEAD(fname_list, fname);
+SLIST_HEAD(snmp_table_index, snmp_index_entry);
+
+/*
+ * Keep a list for every syntax type.
+ */
+struct snmp_mappings {
+ /* The list containing all non-leaf nodes. */
+ struct snmp_mapping nodelist;
+ /* INTEGER/INTEGER32 types. */
+ struct snmp_mapping intlist;
+ /* OCTETSTRING types. */
+ struct snmp_mapping octlist;
+ /* OID types. */
+ struct snmp_mapping oidlist;
+ /* IPADDRESS types. */
+ struct snmp_mapping iplist;
+ /* TIMETICKS types. */
+ struct snmp_mapping ticklist;
+ /* COUNTER types. */
+ struct snmp_mapping cntlist;
+ /* GAUGE types. */
+ struct snmp_mapping gaugelist;
+ /* COUNTER64 types. */
+ struct snmp_mapping cnt64list;
+ /* ENUM values for oid types. */
+ struct snmp_mapping enumlist;
+ /* Description of all table entry types. */
+ struct snmp_table_index tablelist;
+ /* Defined enumerated textual conventions. */
+ struct snmp_enum_tc tclist;
+};
+
+struct snmp_toolinfo {
+ uint32_t flags;
+ /* Number of initially input OIDs. */
+ int32_t objects;
+ /* List of all input OIDs. */
+ SLIST_HEAD(snmp_objectlist, snmp_object) snmp_objectlist;
+ /* All known OID to string mapping data. */
+ struct snmp_mappings *mappings;
+ /* A list of .defs filenames to search oid<->string mapping. */
+ struct fname_list filelist;
+ /* SNMPv3 USM user credentials */
+ char *passwd;
+};
+
+/* XXX we might want to get away with this and will need to touch
+ * XXX the MACROS then too */
+extern struct snmp_toolinfo snmptool;
+
+/* Definitions for some flags' bits. */
+#define OUTPUT_BITS 0x00000003 /* bits 0-1 for output type */
+#define NUMERIC_BIT 0x00000004 /* bit 2 for numeric oids */
+#define RETRY_BIT 0x00000008 /* bit 3 for retry on error response */
+#define ERRIGNORE_BIT 0x00000010 /* bit 4 for skip sanity checking */
+#define ERRIGNORE_BIT 0x00000010 /* bit 4 for skip sanity checking */
+#define EDISCOVER_BIT 0x00000020 /* bit 5 for SNMP Engine Discovery */
+#define LOCALKEY_BIT 0x00000040 /* bit 6 for using localized key */
+ /* 0x00000080 */ /* bit 7 reserved */
+#define PDUTYPE_BITS 0x00000f00 /* bits 8-11 for pdu type */
+ /* 0x0000f000 */ /* bit 12-15 reserved */
+#define MAXREP_BITS 0x00ff0000 /* bits 16-23 for max-repetit. value */
+#define NONREP_BITS 0xff000000 /* bits 24-31 for non-repeaters value */
+
+#define OUTPUT_SHORT 0x0
+#define OUTPUT_VERBOSE 0x1
+#define OUTPUT_TABULAR 0x2
+#define OUTPUT_QUIET 0x3
+
+/* Macros for playing with flags' bits. */
+#define SET_OUTPUT(ctx, type) ((ctx)->flags |= ((type) & OUTPUT_BITS))
+#define GET_OUTPUT(ctx) ((ctx)->flags & OUTPUT_BITS)
+
+#define SET_NUMERIC(ctx) ((ctx)->flags |= NUMERIC_BIT)
+#define ISSET_NUMERIC(ctx) ((ctx)->flags & NUMERIC_BIT)
+
+#define SET_RETRY(ctx) ((ctx)->flags |= RETRY_BIT)
+#define ISSET_RETRY(ctx) ((ctx)->flags & RETRY_BIT)
+
+#define SET_ERRIGNORE(ctx) ((ctx)->flags |= ERRIGNORE_BIT)
+#define ISSET_ERRIGNORE(ctx) ((ctx)->flags & ERRIGNORE_BIT)
+
+#define SET_EDISCOVER(ctx) ((ctx)->flags |= EDISCOVER_BIT)
+#define ISSET_EDISCOVER(ctx) ((ctx)->flags & EDISCOVER_BIT)
+
+#define SET_LOCALKEY(ctx) ((ctx)->flags |= LOCALKEY_BIT)
+#define ISSET_LOCALKEY(ctx) ((ctx)->flags & LOCALKEY_BIT)
+
+#define SET_PDUTYPE(ctx, type) (((ctx)->flags |= (((type) & 0xf) << 8)))
+#define GET_PDUTYPE(ctx) (((ctx)->flags & PDUTYPE_BITS) >> 8)
+
+#define SET_MAXREP(ctx, i) (((ctx)->flags |= (((i) & 0xff) << 16)))
+#define GET_MAXREP(ctx) (((ctx)->flags & MAXREP_BITS) >> 16)
+
+#define SET_NONREP(ctx, i) (((ctx)->flags |= (((i) & 0xff) << 24)))
+#define GET_NONREP(ctx) (((ctx)->flags & NONREP_BITS) >> 24)
+
+
+extern const struct asn_oid IsoOrgDod_OID;
+
+int snmptool_init(struct snmp_toolinfo *);
+int32_t snmp_import_file(struct snmp_toolinfo *, struct fname *);
+int32_t snmp_import_all(struct snmp_toolinfo *);
+int32_t add_filename(struct snmp_toolinfo *, const char *,
+ const struct asn_oid *, int32_t);
+void free_filelist(struct snmp_toolinfo *);
+void snmp_tool_freeall(struct snmp_toolinfo *);
+void snmp_import_dump(int);
+
+/* bsnmpmap.c */
+struct snmp_mappings *snmp_mapping_init(void);
+int32_t snmp_mapping_free(struct snmp_toolinfo *);
+void snmp_index_listfree(struct snmp_idxlist *);
+void snmp_dump_oid2str(struct snmp_oid2str *);
+int32_t snmp_node_insert(struct snmp_toolinfo *, struct snmp_oid2str *);
+int32_t snmp_leaf_insert(struct snmp_toolinfo *, struct snmp_oid2str *);
+int32_t snmp_enum_insert(struct snmp_toolinfo *, struct snmp_oid2str *);
+struct enum_pairs *enum_pairs_init(void);
+void enum_pairs_free(struct enum_pairs *);
+void snmp_mapping_entryfree(struct snmp_oid2str *);
+int32_t enum_pair_insert(struct enum_pairs *, int32_t, char *);
+char *enum_string_lookup(struct enum_pairs *, int32_t);
+int32_t enum_number_lookup(struct enum_pairs *, char *);
+int32_t snmp_syntax_insert(struct snmp_idxlist *, struct enum_pairs *,
+ enum snmp_syntax, enum snmp_tc);
+int32_t snmp_table_insert(struct snmp_toolinfo *, struct snmp_index_entry *);
+
+struct enum_type *snmp_enumtc_init(char *);
+void snmp_enumtc_free(struct enum_type *);
+void snmp_enumtc_insert(struct snmp_toolinfo *, struct enum_type *);
+struct enum_type *snmp_enumtc_lookup(struct snmp_toolinfo *, char *);
+
+void snmp_mapping_dump(struct snmp_toolinfo *);
+int32_t snmp_lookup_leafstring(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_enumstring(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_oidstring(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_nonleaf_string(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_allstring(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_nodestring(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_oidall(struct snmp_toolinfo *, struct snmp_object *, char *);
+int32_t snmp_lookup_enumoid(struct snmp_toolinfo *, struct snmp_object *, char *);
+int32_t snmp_lookup_oid(struct snmp_toolinfo *, struct snmp_object *, char *);
+
+/* Functions parsing common options for all tools. */
+int32_t parse_server(char *);
+int32_t parse_timeout(char *);
+int32_t parse_retry(char *);
+int32_t parse_version(char *);
+int32_t parse_local_path(char *);
+int32_t parse_buflen(char *);
+int32_t parse_debug(void);
+int32_t parse_discovery(struct snmp_toolinfo *);
+int32_t parse_local_key(struct snmp_toolinfo *);
+int32_t parse_num_oids(struct snmp_toolinfo *);
+int32_t parse_file(struct snmp_toolinfo *, char *);
+int32_t parse_include(struct snmp_toolinfo *, char *);
+int32_t parse_output(struct snmp_toolinfo *, char *);
+int32_t parse_errors(struct snmp_toolinfo *);
+int32_t parse_skip_access(struct snmp_toolinfo *);
+int32_t parse_authentication(struct snmp_toolinfo *, char *);
+int32_t parse_privacy(struct snmp_toolinfo *, char *);
+int32_t parse_context(struct snmp_toolinfo *, char *);
+int32_t parse_user_security(struct snmp_toolinfo *, char *);
+
+typedef int32_t (*snmp_verify_inoid_f) (struct snmp_toolinfo *,
+ struct snmp_object *, char *);
+int32_t snmp_object_add(struct snmp_toolinfo *, snmp_verify_inoid_f, char *);
+int32_t snmp_object_remove(struct snmp_toolinfo *, struct asn_oid *oid);
+int32_t snmp_object_seterror(struct snmp_toolinfo *, struct snmp_value *,
+ int32_t);
+
+enum snmp_syntax parse_syntax(char *);
+char *snmp_parse_suboid(char *, struct asn_oid *);
+char *snmp_parse_index(struct snmp_toolinfo *, char *, struct snmp_object *);
+int32_t snmp_parse_numoid(char *, struct asn_oid *);
+int32_t snmp_suboid_append(struct asn_oid *, asn_subid_t);
+int32_t snmp_suboid_pop(struct asn_oid *);
+
+typedef int32_t (*snmp_verify_vbind_f) (struct snmp_toolinfo *,
+ struct snmp_pdu *, struct snmp_object *);
+typedef int32_t (*snmp_add_vbind_f) (struct snmp_pdu *, struct snmp_object *);
+int32_t snmp_pdu_add_bindings(struct snmp_toolinfo *, snmp_verify_vbind_f,
+ snmp_add_vbind_f, struct snmp_pdu *, int32_t);
+
+int32_t snmp_parse_get_resp(struct snmp_pdu *, struct snmp_pdu *);
+int32_t snmp_parse_getbulk_resp(struct snmp_pdu *, struct snmp_pdu *);
+int32_t snmp_parse_getnext_resp(struct snmp_pdu *, struct snmp_pdu *);
+int32_t snmp_parse_resp(struct snmp_pdu *, struct snmp_pdu *);
+int32_t snmp_output_numval(struct snmp_toolinfo *, struct snmp_value *,
+ struct snmp_oid2str *);
+void snmp_output_val(struct snmp_value *);
+int32_t snmp_output_resp(struct snmp_toolinfo *, struct snmp_pdu *, struct asn_oid *);
+void snmp_output_err_resp(struct snmp_toolinfo *, struct snmp_pdu *);
+void snmp_output_engine(void);
+void snmp_output_keys(void);
+
+#endif /* _BSNMP_TOOLS_H_ */
OpenPOWER on IntegriCloud