summaryrefslogtreecommitdiffstats
path: root/lib/libbsnmp
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2003-11-10 09:17:34 +0000
committerharti <harti@FreeBSD.org>2003-11-10 09:17:34 +0000
commit7b57d9c6313625d49db14627e36df6a025f80e1b (patch)
treea08fe72c1c59801d1df8d9afd531f364b1035c43 /lib/libbsnmp
parentaddfc2e6e8f2dfc8ae85f60699b1203bf15264eb (diff)
downloadFreeBSD-src-7b57d9c6313625d49db14627e36df6a025f80e1b.zip
FreeBSD-src-7b57d9c6313625d49db14627e36df6a025f80e1b.tar.gz
Add build infrastructure for libbsnmp and the modules. Add the
netgraph module for the SNMP daemon.
Diffstat (limited to 'lib/libbsnmp')
-rw-r--r--lib/libbsnmp/Makefile5
-rw-r--r--lib/libbsnmp/Makefile.inc8
-rw-r--r--lib/libbsnmp/libbsnmp/Makefile17
-rw-r--r--lib/libbsnmp/modules/Makefile11
-rw-r--r--lib/libbsnmp/modules/Makefile.inc16
-rw-r--r--lib/libbsnmp/modules/snmp_mibII/Makefile19
-rw-r--r--lib/libbsnmp/modules/snmp_mibII/genfiles20
-rw-r--r--lib/libbsnmp/modules/snmp_mibII/mibII_oid.h35
-rw-r--r--lib/libbsnmp/modules/snmp_mibII/mibII_tree.c154
-rw-r--r--lib/libbsnmp/modules/snmp_mibII/mibII_tree.h163
-rw-r--r--lib/libbsnmp/modules/snmp_netgraph/BEGEMOT-NETGRAPH.txt398
-rw-r--r--lib/libbsnmp/modules/snmp_netgraph/Makefile15
-rw-r--r--lib/libbsnmp/modules/snmp_netgraph/genfiles17
-rw-r--r--lib/libbsnmp/modules/snmp_netgraph/netgraph_oid.h5
-rw-r--r--lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.c30
-rw-r--r--lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.def78
-rw-r--r--lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.h27
-rw-r--r--lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.3416
-rw-r--r--lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.c1691
-rw-r--r--lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.h91
20 files changed, 3216 insertions, 0 deletions
diff --git a/lib/libbsnmp/Makefile b/lib/libbsnmp/Makefile
new file mode 100644
index 0000000..c639fa8
--- /dev/null
+++ b/lib/libbsnmp/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR+= libbsnmp modules
+
+.include <bsd.subdir.mk>
diff --git a/lib/libbsnmp/Makefile.inc b/lib/libbsnmp/Makefile.inc
new file mode 100644
index 0000000..5304ebd
--- /dev/null
+++ b/lib/libbsnmp/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+SHLIB_MAJOR= 1
+SHLIB_MINOR= 4
+
+WARNS?= 6
+
+INCSDIR= ${INCLUDEDIR}/bsnmp
diff --git a/lib/libbsnmp/libbsnmp/Makefile b/lib/libbsnmp/libbsnmp/Makefile
new file mode 100644
index 0000000..6591567
--- /dev/null
+++ b/lib/libbsnmp/libbsnmp/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+
+CONTRIB= ${.CURDIR}/../../../contrib/bsnmp/lib
+.PATH: ${CONTRIB}
+
+LIB = bsnmp
+
+WARNS= 6
+CFLAGS= -I${CONTRIB}
+
+SRCS= asn1.c snmp.c snmpagent.c snmpclient.c
+INCS= asn1.h snmp.h snmpagent.h snmpclient.h
+MAN= asn1.3 bsnmplib.3 bsnmpclient.3 bsnmpagent.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libbsnmp/modules/Makefile b/lib/libbsnmp/modules/Makefile
new file mode 100644
index 0000000..ad5df5f
--- /dev/null
+++ b/lib/libbsnmp/modules/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../contrib/bsnmp/snmpd
+
+SUBDIR= snmp_mibII \
+ snmp_netgraph
+
+INCS= snmpmod.h
+INCSDIR= ${INCLUDEDIR}/bsnmp
+
+.include <bsd.prog.mk>
diff --git a/lib/libbsnmp/modules/Makefile.inc b/lib/libbsnmp/modules/Makefile.inc
new file mode 100644
index 0000000..c9d6718
--- /dev/null
+++ b/lib/libbsnmp/modules/Makefile.inc
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NOINSTALLLIB= yes
+NOPROFILE= yes
+
+LIB= snmp_${MOD}
+SHLIB_NAME= snmp_${MOD}.so.${SHLIB_MAJOR}
+
+SRCS:= ${MOD}_oid.h ${MOD}_tree.c ${MOD}_tree.h ${SRCS}
+
+MIBSDIR= ${SHAREDIR}/bsnmp/mibs
+DEFSDIR= ${SHAREDIR}/bsnmp/defs
+
+FILESGROUPS += DEFS MIBS
+
+.include "../Makefile.inc"
diff --git a/lib/libbsnmp/modules/snmp_mibII/Makefile b/lib/libbsnmp/modules/snmp_mibII/Makefile
new file mode 100644
index 0000000..7fa524a
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_mibII/Makefile
@@ -0,0 +1,19 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+
+CONTRIB=${.CURDIR}/../../../../contrib/bsnmp/snmp_mibII
+.PATH: ${CONTRIB}
+
+MOD= mibII
+SRCS= mibII.c mibII_ifmib.c mibII_ip.c mibII_interfaces.c \
+ mibII_ipaddr.c mibII_ifstack.c mibII_rcvaddr.c \
+ mibII_nettomedia.c mibII_tcp.c mibII_udp.c mibII_route.c
+MAN= snmp_mibII.3
+
+DEFS= ${MOD}_tree.def
+INCS= snmp_${MOD}.h
+
+CFLAGS+= -I${INCLUDEDIR}/bsnmp -I${.CURDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/libbsnmp/modules/snmp_mibII/genfiles b/lib/libbsnmp/modules/snmp_mibII/genfiles
new file mode 100644
index 0000000..b797670
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_mibII/genfiles
@@ -0,0 +1,20 @@
+#!/bin/sh
+# $FreeBSD$
+
+CONTRIB="../../../../contrib/bsnmp/snmp_mibII"
+
+XSYM="ipAddrTable ifTable ifRcvAddressEntry ifMIB ipMIB tcpMIB udpMIB \
+ ipForward ifIndex linkDown linkUp"
+
+gensnmptree <${CONTRIB}/mibII_tree.def -e ${XSYM} >mibII_oid.h
+gensnmptree <${CONTRIB}/mibII_tree.def -l -p mibII_
+
+for i in mibII_tree.h mibII_tree.c mibII_oid.h ; do
+ ex $i <<'EOF'
+0a
+/* $FreeBSD$ */
+/* generated file, don't edit - use ./genfiles */
+.
+wq
+EOF
+done
diff --git a/lib/libbsnmp/modules/snmp_mibII/mibII_oid.h b/lib/libbsnmp/modules/snmp_mibII/mibII_oid.h
new file mode 100644
index 0000000..301f900
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_mibII/mibII_oid.h
@@ -0,0 +1,35 @@
+/* $FreeBSD$ */
+/* generated file, don't edit - use ./genfiles */
+#define OID_ipAddrTable 20
+#define OIDLEN_ipAddrTable 8
+#define OIDX_ipAddrTable { 8, { 1, 3, 6, 1, 2, 1, 4, 20, } }
+#define OID_ifTable 2
+#define OIDLEN_ifTable 8
+#define OIDX_ifTable { 8, { 1, 3, 6, 1, 2, 1, 2, 2, } }
+#define OID_ifRcvAddressEntry 1
+#define OIDLEN_ifRcvAddressEntry 10
+#define OIDX_ifRcvAddressEntry { 10, { 1, 3, 6, 1, 2, 1, 31, 1, 4, 1, } }
+#define OID_ifMIB 31
+#define OIDLEN_ifMIB 7
+#define OIDX_ifMIB { 7, { 1, 3, 6, 1, 2, 1, 31, } }
+#define OID_ipMIB 48
+#define OIDLEN_ipMIB 7
+#define OIDX_ipMIB { 7, { 1, 3, 6, 1, 2, 1, 48, } }
+#define OID_tcpMIB 49
+#define OIDLEN_tcpMIB 7
+#define OIDX_tcpMIB { 7, { 1, 3, 6, 1, 2, 1, 49, } }
+#define OID_udpMIB 50
+#define OIDLEN_udpMIB 7
+#define OIDX_udpMIB { 7, { 1, 3, 6, 1, 2, 1, 50, } }
+#define OID_ipForward 24
+#define OIDLEN_ipForward 8
+#define OIDX_ipForward { 8, { 1, 3, 6, 1, 2, 1, 4, 24, } }
+#define OID_ifIndex 1
+#define OIDLEN_ifIndex 10
+#define OIDX_ifIndex { 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 1, } }
+#define OID_linkDown 3
+#define OIDLEN_linkDown 10
+#define OIDX_linkDown { 10, { 1, 3, 6, 1, 6, 3, 1, 1, 5, 3, } }
+#define OID_linkUp 4
+#define OIDLEN_linkUp 10
+#define OIDX_linkUp { 10, { 1, 3, 6, 1, 6, 3, 1, 1, 5, 4, } }
diff --git a/lib/libbsnmp/modules/snmp_mibII/mibII_tree.c b/lib/libbsnmp/modules/snmp_mibII/mibII_tree.c
new file mode 100644
index 0000000..3d8ecc8
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_mibII/mibII_tree.c
@@ -0,0 +1,154 @@
+/* $FreeBSD$ */
+/* generated file, don't edit - use ./genfiles */
+#include <sys/types.h>
+#include <stdio.h>
+#include "asn1.h"
+#include "snmp.h"
+#include "snmpagent.h"
+#include "mibII_tree.h"
+
+const struct snmp_node mibII_ctree[] = {
+ {{ 8, { 1, 3, 6, 1, 2, 1, 2, 1, }}, "ifNumber", SNMP_NODE_LEAF, SNMP_SYNTAX_INTEGER, op_interfaces, 0, 0, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 1, }}, "ifIndex", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 2, }}, "ifDescr", SNMP_NODE_COLUMN, SNMP_SYNTAX_OCTETSTRING, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3, }}, "ifType", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 4, }}, "ifMtu", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 5, }}, "ifSpeed", SNMP_NODE_COLUMN, SNMP_SYNTAX_GAUGE, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6, }}, "ifPhysAddress", SNMP_NODE_COLUMN, SNMP_SYNTAX_OCTETSTRING, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 7, }}, "ifAdminStatus", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ifentry, 0|SNMP_NODE_CANSET, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 8, }}, "ifOperStatus", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 9, }}, "ifLastChange", SNMP_NODE_COLUMN, SNMP_SYNTAX_TIMETICKS, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 10, }}, "ifInOctets", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 11, }}, "ifInUcastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 12, }}, "ifInNUcastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 13, }}, "ifInDiscards", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 14, }}, "ifInErrors", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 15, }}, "ifInUnknownProtos", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 16, }}, "ifOutOctets", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 17, }}, "ifOutUcastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 18, }}, "ifOutNUcastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 19, }}, "ifOutDiscards", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 20, }}, "ifOutErrors", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 21, }}, "ifOutQLen", SNMP_NODE_COLUMN, SNMP_SYNTAX_GAUGE, op_ifentry, 0, 0x11, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 2, 2, 1, 22, }}, "ifSpecific", SNMP_NODE_COLUMN, SNMP_SYNTAX_OID, op_ifentry, 0, 0x11, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 1, }}, "ipForwarding", SNMP_NODE_LEAF, SNMP_SYNTAX_INTEGER, op_ip, 0|SNMP_NODE_CANSET, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 2, }}, "ipDefaultTTL", SNMP_NODE_LEAF, SNMP_SYNTAX_INTEGER, op_ip, 0|SNMP_NODE_CANSET, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 3, }}, "ipInReceives", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 4, }}, "ipInHdrErrors", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 5, }}, "ipInAddrErrors", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 6, }}, "ipForwDatagrams", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 7, }}, "ipInUnknownProtos", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 8, }}, "ipInDiscards", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 9, }}, "ipInDelivers", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 10, }}, "ipOutRequests", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 11, }}, "ipOutDiscards", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 12, }}, "ipOutNoRoutes", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 13, }}, "ipReasmTimeout", SNMP_NODE_LEAF, SNMP_SYNTAX_INTEGER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 14, }}, "ipReasmReqds", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 15, }}, "ipReasmOKs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 16, }}, "ipReasmFails", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 17, }}, "ipFragOKs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 18, }}, "ipFragFails", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 4, 19, }}, "ipFragCreates", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ipstat, 0, 0, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 4, 20, 1, 1, }}, "ipAdEntAddr", SNMP_NODE_COLUMN, SNMP_SYNTAX_IPADDRESS, op_ipaddr, 0, 0x41, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 4, 20, 1, 2, }}, "ipAdEntIfIndex", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ipaddr, 0|SNMP_NODE_CANSET, 0x41, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 4, 20, 1, 3, }}, "ipAdEntNetMask", SNMP_NODE_COLUMN, SNMP_SYNTAX_IPADDRESS, op_ipaddr, 0|SNMP_NODE_CANSET, 0x41, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 4, 20, 1, 4, }}, "ipAdEntBcastAddr", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ipaddr, 0|SNMP_NODE_CANSET, 0x41, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 4, 20, 1, 5, }}, "ipAdEntReasmMaxSize", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ipaddr, 0, 0x41, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 4, 22, 1, 1, }}, "ipNetToMediaIfIndex", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_nettomedia, 0, 0x412, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 4, 22, 1, 2, }}, "ipNetToMediaPhysAddress", SNMP_NODE_COLUMN, SNMP_SYNTAX_OCTETSTRING, op_nettomedia, 0, 0x412, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 4, 22, 1, 3, }}, "ipNetToMediaNetAddress", SNMP_NODE_COLUMN, SNMP_SYNTAX_IPADDRESS, op_nettomedia, 0, 0x412, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 4, 22, 1, 4, }}, "ipNetToMediaType", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_nettomedia, 0, 0x412, NULL },
+ {{ 9, { 1, 3, 6, 1, 2, 1, 4, 24, 3, }}, "ipCidrRouteNumber", SNMP_NODE_LEAF, SNMP_SYNTAX_GAUGE, op_route, 0, 0, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 1, }}, "ipCidrRouteDest", SNMP_NODE_COLUMN, SNMP_SYNTAX_IPADDRESS, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 2, }}, "ipCidrRouteMask", SNMP_NODE_COLUMN, SNMP_SYNTAX_IPADDRESS, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 3, }}, "ipCidrRouteTos", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 4, }}, "ipCidrRouteNextHop", SNMP_NODE_COLUMN, SNMP_SYNTAX_IPADDRESS, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 5, }}, "ipCidrRouteIfIndex", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 6, }}, "ipCidrRouteType", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 7, }}, "ipCidrRouteProto", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 8, }}, "ipCidrRouteAge", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 9, }}, "ipCidrRouteInfo", SNMP_NODE_COLUMN, SNMP_SYNTAX_OID, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 10, }}, "ipCidrRouteNextHopAS", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 11, }}, "ipCidrRouteMetric1", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 12, }}, "ipCidrRouteMetric2", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 13, }}, "ipCidrRouteMetric3", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 14, }}, "ipCidrRouteMetric4", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 15, }}, "ipCidrRouteMetric5", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 4, 24, 4, 1, 16, }}, "ipCidrRouteStatus", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_route_table, 0, 0x41444, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 1, }}, "icmpInMsgs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 2, }}, "icmpInErrors", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 3, }}, "icmpInDestUnreachs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 4, }}, "icmpInTimeExcds", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 5, }}, "icmpInParmProbs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 6, }}, "icmpInSrcQuenchs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 7, }}, "icmpInRedirects", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 8, }}, "icmpInEchos", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 9, }}, "icmpInEchoReps", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 10, }}, "icmpInTimestamps", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 11, }}, "icmpInTimestampReps", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 12, }}, "icmpInAddrMasks", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 13, }}, "icmpInAddrMaskReps", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 14, }}, "icmpOutMsgs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 15, }}, "icmpOutErrors", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 16, }}, "icmpOutDestUnreachs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 17, }}, "icmpOutTimeExcds", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 18, }}, "icmpOutParmProbs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 19, }}, "icmpOutSrcQuenchs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 20, }}, "icmpOutRedirects", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 21, }}, "icmpOutEchos", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 22, }}, "icmpOutEchoReps", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 23, }}, "icmpOutTimestamps", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 24, }}, "icmpOutTimestampReps", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 25, }}, "icmpOutAddrMasks", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 5, 26, }}, "icmpOutAddrMaskReps", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_icmpstat, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 1, }}, "tcpRtoAlgorithm", SNMP_NODE_LEAF, SNMP_SYNTAX_INTEGER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 2, }}, "tcpRtoMin", SNMP_NODE_LEAF, SNMP_SYNTAX_INTEGER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 3, }}, "tcpRtoMax", SNMP_NODE_LEAF, SNMP_SYNTAX_INTEGER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 4, }}, "tcpMaxConn", SNMP_NODE_LEAF, SNMP_SYNTAX_INTEGER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 5, }}, "tcpActiveOpens", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 6, }}, "tcpPassiveOpens", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 7, }}, "tcpAttemptFails", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 8, }}, "tcpEstabResets", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 9, }}, "tcpCurrEstab", SNMP_NODE_LEAF, SNMP_SYNTAX_GAUGE, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 10, }}, "tcpInSegs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 11, }}, "tcpOutSegs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 12, }}, "tcpRetransSegs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_tcp, 0, 0, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 6, 13, 1, 1, }}, "tcpConnState", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_tcpconn, 0, 0x14144, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 6, 13, 1, 2, }}, "tcpConnLocalAddress", SNMP_NODE_COLUMN, SNMP_SYNTAX_IPADDRESS, op_tcpconn, 0, 0x14144, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 6, 13, 1, 3, }}, "tcpConnLocalPort", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_tcpconn, 0, 0x14144, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 6, 13, 1, 4, }}, "tcpConnRemAddress", SNMP_NODE_COLUMN, SNMP_SYNTAX_IPADDRESS, op_tcpconn, 0, 0x14144, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 6, 13, 1, 5, }}, "tcpConnRemPort", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_tcpconn, 0, 0x14144, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 6, 14, }}, "tcpInErrs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_tcp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 7, 1, }}, "udpInDatagrams", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_udp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 7, 2, }}, "udpNoPorts", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_udp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 7, 3, }}, "udpInErrors", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_udp, 0, 0, NULL },
+ {{ 8, { 1, 3, 6, 1, 2, 1, 7, 4, }}, "udpOutDatagrams", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_udp, 0, 0, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 7, 5, 1, 1, }}, "udpLocalAddress", SNMP_NODE_COLUMN, SNMP_SYNTAX_IPADDRESS, op_udptable, 0, 0x142, NULL },
+ {{ 10, { 1, 3, 6, 1, 2, 1, 7, 5, 1, 2, }}, "udpLocalPort", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_udptable, 0, 0x142, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 1, }}, "ifName", SNMP_NODE_COLUMN, SNMP_SYNTAX_OCTETSTRING, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 2, }}, "ifInMulticastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 3, }}, "ifInBroadcastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 4, }}, "ifOutMulticastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 5, }}, "ifOutBroadcastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 6, }}, "ifHCInOctets", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER64, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 7, }}, "ifHCInUcastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER64, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 8, }}, "ifHCInMulticastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER64, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 9, }}, "ifHCInBroadcastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER64, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 10, }}, "ifHCOutOctets", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER64, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 11, }}, "ifHCOutUcastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER64, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 12, }}, "ifHCOutMulticastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER64, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 13, }}, "ifHCOutBroadcastPkts", SNMP_NODE_COLUMN, SNMP_SYNTAX_COUNTER64, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 14, }}, "ifLinkUpDownTrapEnable", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ifxtable, 0|SNMP_NODE_CANSET, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 15, }}, "ifHighSpeed", SNMP_NODE_COLUMN, SNMP_SYNTAX_GAUGE, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 16, }}, "ifPromiscuousMode", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ifxtable, 0|SNMP_NODE_CANSET, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 17, }}, "ifConnectorPresent", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 18, }}, "ifAlias", SNMP_NODE_COLUMN, SNMP_SYNTAX_OCTETSTRING, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 19, }}, "ifCounterDiscontinuityTime", SNMP_NODE_COLUMN, SNMP_SYNTAX_TIMETICKS, op_ifxtable, 0, 0x11, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 2, 1, 3, }}, "ifStackStatus", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ifstack, 0, 0x112, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 4, 1, 2, }}, "ifRcvAddressStatus", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_rcvaddr, 0, 0x212, NULL },
+ {{ 11, { 1, 3, 6, 1, 2, 1, 31, 1, 4, 1, 3, }}, "ifRcvAddressType", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_rcvaddr, 0, 0x212, NULL },
+ {{ 9, { 1, 3, 6, 1, 2, 1, 31, 1, 5, }}, "ifTableLastChange", SNMP_NODE_LEAF, SNMP_SYNTAX_TIMETICKS, op_ifmib, 0, 0, NULL },
+ {{ 9, { 1, 3, 6, 1, 2, 1, 31, 1, 6, }}, "ifStackLastChange", SNMP_NODE_LEAF, SNMP_SYNTAX_TIMETICKS, op_ifmib, 0, 0, NULL },
+};
+
diff --git a/lib/libbsnmp/modules/snmp_mibII/mibII_tree.h b/lib/libbsnmp/modules/snmp_mibII/mibII_tree.h
new file mode 100644
index 0000000..e19ac3c
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_mibII/mibII_tree.h
@@ -0,0 +1,163 @@
+/* $FreeBSD$ */
+/* generated file, don't edit - use ./genfiles */
+int op_interfaces(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ifNumber 1
+int op_ifentry(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ifIndex 1
+# define LEAF_ifDescr 2
+# define LEAF_ifType 3
+# define LEAF_ifMtu 4
+# define LEAF_ifSpeed 5
+# define LEAF_ifPhysAddress 6
+# define LEAF_ifAdminStatus 7
+# define LEAF_ifOperStatus 8
+# define LEAF_ifLastChange 9
+# define LEAF_ifInOctets 10
+# define LEAF_ifInUcastPkts 11
+# define LEAF_ifInNUcastPkts 12
+# define LEAF_ifInDiscards 13
+# define LEAF_ifInErrors 14
+# define LEAF_ifInUnknownProtos 15
+# define LEAF_ifOutOctets 16
+# define LEAF_ifOutUcastPkts 17
+# define LEAF_ifOutNUcastPkts 18
+# define LEAF_ifOutDiscards 19
+# define LEAF_ifOutErrors 20
+# define LEAF_ifOutQLen 21
+# define LEAF_ifSpecific 22
+int op_ip(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ipForwarding 1
+# define LEAF_ipDefaultTTL 2
+int op_ipstat(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ipInReceives 3
+# define LEAF_ipInHdrErrors 4
+# define LEAF_ipInAddrErrors 5
+# define LEAF_ipForwDatagrams 6
+# define LEAF_ipInUnknownProtos 7
+# define LEAF_ipInDiscards 8
+# define LEAF_ipInDelivers 9
+# define LEAF_ipOutRequests 10
+# define LEAF_ipOutDiscards 11
+# define LEAF_ipOutNoRoutes 12
+# define LEAF_ipReasmTimeout 13
+# define LEAF_ipReasmReqds 14
+# define LEAF_ipReasmOKs 15
+# define LEAF_ipReasmFails 16
+# define LEAF_ipFragOKs 17
+# define LEAF_ipFragFails 18
+# define LEAF_ipFragCreates 19
+int op_ipaddr(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ipAdEntAddr 1
+# define LEAF_ipAdEntIfIndex 2
+# define LEAF_ipAdEntNetMask 3
+# define LEAF_ipAdEntBcastAddr 4
+# define LEAF_ipAdEntReasmMaxSize 5
+int op_nettomedia(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ipNetToMediaIfIndex 1
+# define LEAF_ipNetToMediaPhysAddress 2
+# define LEAF_ipNetToMediaNetAddress 3
+# define LEAF_ipNetToMediaType 4
+int op_route(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ipCidrRouteNumber 3
+int op_route_table(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ipCidrRouteDest 1
+# define LEAF_ipCidrRouteMask 2
+# define LEAF_ipCidrRouteTos 3
+# define LEAF_ipCidrRouteNextHop 4
+# define LEAF_ipCidrRouteIfIndex 5
+# define LEAF_ipCidrRouteType 6
+# define LEAF_ipCidrRouteProto 7
+# define LEAF_ipCidrRouteAge 8
+# define LEAF_ipCidrRouteInfo 9
+# define LEAF_ipCidrRouteNextHopAS 10
+# define LEAF_ipCidrRouteMetric1 11
+# define LEAF_ipCidrRouteMetric2 12
+# define LEAF_ipCidrRouteMetric3 13
+# define LEAF_ipCidrRouteMetric4 14
+# define LEAF_ipCidrRouteMetric5 15
+# define LEAF_ipCidrRouteStatus 16
+int op_icmpstat(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_icmpInMsgs 1
+# define LEAF_icmpInErrors 2
+# define LEAF_icmpInDestUnreachs 3
+# define LEAF_icmpInTimeExcds 4
+# define LEAF_icmpInParmProbs 5
+# define LEAF_icmpInSrcQuenchs 6
+# define LEAF_icmpInRedirects 7
+# define LEAF_icmpInEchos 8
+# define LEAF_icmpInEchoReps 9
+# define LEAF_icmpInTimestamps 10
+# define LEAF_icmpInTimestampReps 11
+# define LEAF_icmpInAddrMasks 12
+# define LEAF_icmpInAddrMaskReps 13
+# define LEAF_icmpOutMsgs 14
+# define LEAF_icmpOutErrors 15
+# define LEAF_icmpOutDestUnreachs 16
+# define LEAF_icmpOutTimeExcds 17
+# define LEAF_icmpOutParmProbs 18
+# define LEAF_icmpOutSrcQuenchs 19
+# define LEAF_icmpOutRedirects 20
+# define LEAF_icmpOutEchos 21
+# define LEAF_icmpOutEchoReps 22
+# define LEAF_icmpOutTimestamps 23
+# define LEAF_icmpOutTimestampReps 24
+# define LEAF_icmpOutAddrMasks 25
+# define LEAF_icmpOutAddrMaskReps 26
+int op_tcp(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_tcpRtoAlgorithm 1
+# define LEAF_tcpRtoMin 2
+# define LEAF_tcpRtoMax 3
+# define LEAF_tcpMaxConn 4
+# define LEAF_tcpActiveOpens 5
+# define LEAF_tcpPassiveOpens 6
+# define LEAF_tcpAttemptFails 7
+# define LEAF_tcpEstabResets 8
+# define LEAF_tcpCurrEstab 9
+# define LEAF_tcpInSegs 10
+# define LEAF_tcpOutSegs 11
+# define LEAF_tcpRetransSegs 12
+int op_tcpconn(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_tcpConnState 1
+# define LEAF_tcpConnLocalAddress 2
+# define LEAF_tcpConnLocalPort 3
+# define LEAF_tcpConnRemAddress 4
+# define LEAF_tcpConnRemPort 5
+# define LEAF_tcpInErrs 14
+int op_udp(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_udpInDatagrams 1
+# define LEAF_udpNoPorts 2
+# define LEAF_udpInErrors 3
+# define LEAF_udpOutDatagrams 4
+int op_udptable(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_udpLocalAddress 1
+# define LEAF_udpLocalPort 2
+int op_ifxtable(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ifName 1
+# define LEAF_ifInMulticastPkts 2
+# define LEAF_ifInBroadcastPkts 3
+# define LEAF_ifOutMulticastPkts 4
+# define LEAF_ifOutBroadcastPkts 5
+# define LEAF_ifHCInOctets 6
+# define LEAF_ifHCInUcastPkts 7
+# define LEAF_ifHCInMulticastPkts 8
+# define LEAF_ifHCInBroadcastPkts 9
+# define LEAF_ifHCOutOctets 10
+# define LEAF_ifHCOutUcastPkts 11
+# define LEAF_ifHCOutMulticastPkts 12
+# define LEAF_ifHCOutBroadcastPkts 13
+# define LEAF_ifLinkUpDownTrapEnable 14
+# define LEAF_ifHighSpeed 15
+# define LEAF_ifPromiscuousMode 16
+# define LEAF_ifConnectorPresent 17
+# define LEAF_ifAlias 18
+# define LEAF_ifCounterDiscontinuityTime 19
+int op_ifstack(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ifStackStatus 3
+int op_rcvaddr(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ifRcvAddressStatus 2
+# define LEAF_ifRcvAddressType 3
+int op_ifmib(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_ifTableLastChange 5
+# define LEAF_ifStackLastChange 6
+#define mibII_CTREE_SIZE 142
+extern const struct snmp_node mibII_ctree[];
diff --git a/lib/libbsnmp/modules/snmp_netgraph/BEGEMOT-NETGRAPH.txt b/lib/libbsnmp/modules/snmp_netgraph/BEGEMOT-NETGRAPH.txt
new file mode 100644
index 0000000..d49216a
--- /dev/null
+++ b/lib/libbsnmp/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 "200201310000Z"
+ 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 "15a"
+ STATUS current
+ DESCRIPTION
+ "Name of a netgraph type."
+ SYNTAX OCTET STRING (SIZE(1..15))
+
+NgNodeName ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "15a"
+ STATUS current
+ DESCRIPTION
+ "Name of a netgraph node."
+ SYNTAX OCTET STRING (SIZE(1..15))
+
+NgNodeNameOrEmpty ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "15a"
+ STATUS current
+ DESCRIPTION
+ "Name of a netgraph node."
+ SYNTAX OCTET STRING (SIZE(0..15))
+
+NgHookName ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "15a"
+ STATUS current
+ DESCRIPTION
+ "Name of a netgraph hook."
+ SYNTAX OCTET STRING (SIZE(1..15))
+
+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/lib/libbsnmp/modules/snmp_netgraph/Makefile b/lib/libbsnmp/modules/snmp_netgraph/Makefile
new file mode 100644
index 0000000..6ccdf5f
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_netgraph/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+
+MOD= netgraph
+SRCS= snmp_netgraph.c
+MAN= snmp_netgraph.3
+
+MIBS= BEGEMOT-NETGRAPH.txt
+DEFS= ${MOD}_tree.def
+INCS= snmp_${MOD}.h
+
+CFLAGS+= -I${INCLUDEDIR}/bsnmp -I${.CURDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/libbsnmp/modules/snmp_netgraph/genfiles b/lib/libbsnmp/modules/snmp_netgraph/genfiles
new file mode 100644
index 0000000..b92a392
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_netgraph/genfiles
@@ -0,0 +1,17 @@
+#!/bin/sh
+# $FreeBSD$
+
+XSYM="begemotNg"
+
+gensnmptree <netgraph_tree.def -e ${XSYM} >netgraph_oid.h
+gensnmptree <netgraph_tree.def -l -p netgraph_
+
+for i in netgraph_tree.h netgraph_tree.c netgraph_oid.h ; do
+ ex $i <<'EOF'
+0a
+/* $FreeBSD$ */
+/* generated file, don't edit - use ./genfiles */
+.
+wq
+EOF
+done
diff --git a/lib/libbsnmp/modules/snmp_netgraph/netgraph_oid.h b/lib/libbsnmp/modules/snmp_netgraph/netgraph_oid.h
new file mode 100644
index 0000000..5be1a16
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_netgraph/netgraph_oid.h
@@ -0,0 +1,5 @@
+/* $FreeBSD$ */
+/* generated file, don't edit - use ./genfiles */
+#define OID_begemotNg 2
+#define OIDLEN_begemotNg 9
+#define OIDX_begemotNg { 9, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, } }
diff --git a/lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.c b/lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.c
new file mode 100644
index 0000000..4b249f0
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.c
@@ -0,0 +1,30 @@
+/* $FreeBSD$ */
+/* generated file, don't edit - use ./genfiles */
+#include <sys/types.h>
+#include <stdio.h>
+#include "asn1.h"
+#include "snmp.h"
+#include "snmpagent.h"
+#include "netgraph_tree.h"
+
+const struct snmp_node netgraph_ctree[] = {
+ {{ 12, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 1, 1, }}, "begemotNgControlNodeName", SNMP_NODE_LEAF, SNMP_SYNTAX_OCTETSTRING, op_ng_config, 0|SNMP_NODE_CANSET, 0, NULL },
+ {{ 12, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 1, 2, }}, "begemotNgResBufSiz", SNMP_NODE_LEAF, SNMP_SYNTAX_INTEGER, op_ng_config, 0|SNMP_NODE_CANSET, 0, NULL },
+ {{ 12, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 1, 3, }}, "begemotNgTimeout", SNMP_NODE_LEAF, SNMP_SYNTAX_INTEGER, op_ng_config, 0|SNMP_NODE_CANSET, 0, NULL },
+ {{ 12, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 1, 4, }}, "begemotNgDebugLevel", SNMP_NODE_LEAF, SNMP_SYNTAX_GAUGE, op_ng_config, 0|SNMP_NODE_CANSET, 0, NULL },
+ {{ 12, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 2, 1, }}, "begemotNgNoMems", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ng_stats, 0, 0, NULL },
+ {{ 12, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 2, 2, }}, "begemotNgMsgReadErrs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ng_stats, 0, 0, NULL },
+ {{ 12, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 2, 3, }}, "begemotNgTooLargeMsgs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ng_stats, 0, 0, NULL },
+ {{ 12, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 2, 4, }}, "begemotNgDataReadErrs", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ng_stats, 0, 0, NULL },
+ {{ 12, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 2, 5, }}, "begemotNgTooLargeDatas", SNMP_NODE_LEAF, SNMP_SYNTAX_COUNTER, op_ng_stats, 0, 0, NULL },
+ {{ 13, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 3, 1, 2, }}, "begemotNgTypeStatus", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ng_type, 0|SNMP_NODE_CANSET, 0x21, NULL },
+ {{ 13, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 4, 1, 2, }}, "begemotNgNodeStatus", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ng_node, 0, 0x11, NULL },
+ {{ 13, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 4, 1, 3, }}, "begemotNgNodeName", SNMP_NODE_COLUMN, SNMP_SYNTAX_OCTETSTRING, op_ng_node, 0, 0x11, NULL },
+ {{ 13, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 4, 1, 4, }}, "begemotNgNodeType", SNMP_NODE_COLUMN, SNMP_SYNTAX_OCTETSTRING, op_ng_node, 0, 0x11, NULL },
+ {{ 13, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 4, 1, 5, }}, "begemotNgNodeHooks", SNMP_NODE_COLUMN, SNMP_SYNTAX_GAUGE, op_ng_node, 0, 0x11, NULL },
+ {{ 13, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 5, 1, 3, }}, "begemotNgHookStatus", SNMP_NODE_COLUMN, SNMP_SYNTAX_INTEGER, op_ng_hook, 0, 0x262, NULL },
+ {{ 13, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 5, 1, 4, }}, "begemotNgHookPeerNodeId", SNMP_NODE_COLUMN, SNMP_SYNTAX_GAUGE, op_ng_hook, 0, 0x262, NULL },
+ {{ 13, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 5, 1, 5, }}, "begemotNgHookPeerHook", SNMP_NODE_COLUMN, SNMP_SYNTAX_OCTETSTRING, op_ng_hook, 0, 0x262, NULL },
+ {{ 13, { 1, 3, 6, 1, 4, 1, 12325, 1, 2, 1, 5, 1, 6, }}, "begemotNgHookPeerType", SNMP_NODE_COLUMN, SNMP_SYNTAX_OCTETSTRING, op_ng_hook, 0, 0x262, NULL },
+};
+
diff --git a/lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.def b/lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.def
new file mode 100644
index 0000000..eff59ff
--- /dev/null
+++ b/lib/libbsnmp/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/lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.h b/lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.h
new file mode 100644
index 0000000..5b6d3f6
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_netgraph/netgraph_tree.h
@@ -0,0 +1,27 @@
+/* $FreeBSD$ */
+/* generated file, don't edit - use ./genfiles */
+int op_ng_config(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_begemotNgControlNodeName 1
+# define LEAF_begemotNgResBufSiz 2
+# define LEAF_begemotNgTimeout 3
+# define LEAF_begemotNgDebugLevel 4
+int op_ng_stats(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_begemotNgNoMems 1
+# define LEAF_begemotNgMsgReadErrs 2
+# define LEAF_begemotNgTooLargeMsgs 3
+# define LEAF_begemotNgDataReadErrs 4
+# define LEAF_begemotNgTooLargeDatas 5
+int op_ng_type(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_begemotNgTypeStatus 2
+int op_ng_node(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_begemotNgNodeStatus 2
+# define LEAF_begemotNgNodeName 3
+# define LEAF_begemotNgNodeType 4
+# define LEAF_begemotNgNodeHooks 5
+int op_ng_hook(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op);
+# define LEAF_begemotNgHookStatus 3
+# define LEAF_begemotNgHookPeerNodeId 4
+# define LEAF_begemotNgHookPeerHook 5
+# define LEAF_begemotNgHookPeerType 6
+#define netgraph_CTREE_SIZE 18
+extern const struct snmp_node netgraph_ctree[];
diff --git a/lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.3 b/lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.3
new file mode 100644
index 0000000..fdd55fa
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.3
@@ -0,0 +1,416 @@
+.\"
+.\" 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 October 7, 2003
+.Dt snmp_netgraph 3
+.Os
+.Sh NAME
+.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" "u_int32_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 performa,
+.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 reponse 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 asynchronuosly 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 registerred
+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
+.Fn
+.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 occures 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 occures 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
+.Pp
+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_NODELEN
++ 1 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_TYPELEN
++ 1 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_HOOKLEN
++ 1 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 occurres 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
+who's 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.
+.Sh SEE ALSO
+.Xr snmpmod 3 ,
+.Xr gensnmptree 1
+.Sh AUTHORS
+.An Hartmut Brandt Aq harti@freebsd.org
diff --git a/lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.c b/lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.c
new file mode 100644
index 0000000..4a70834
--- /dev/null
+++ b/lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.c
@@ -0,0 +1,1691 @@
+/*
+ * 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 "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_PATHLEN + 1];
+};
+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_HOOKLEN + 1];
+ 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_TYPELEN + 1];
+ struct asn_oid index;
+ TAILQ_ENTRY(ngtype) link;
+};
+TAILQ_HEAD(ngtype_list, ngtype);
+
+static struct ngtype_list ngtype_list;
+static u_int32_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_PATHLEN + 1];
+
+ 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_PATHLEN + 1];
+
+ 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_PATHLEN + 1];
+
+ 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_PATHLEN + 1];
+ 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_PATHLEN + 1];
+
+ 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_PATHLEN + 1];
+
+ 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_HOOKLEN + 1];
+ 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_NODELEN + 1)) == NULL)
+ return (ENOMEM);
+ snprintf(snmp_nodename, NG_NODELEN + 1, "%s", argv[0]);
+ }
+
+ /* 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_PATHLEN + 1, "%s:", node);
+ snprintf(conn.ourhook, NG_HOOKLEN + 1, ourhook);
+ snprintf(conn.peerhook, NG_HOOKLEN + 1, peerhook);
+ 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_PATHLEN + 1, "[%x]:", id);
+ snprintf(conn.ourhook, NG_HOOKLEN + 1, ourhook);
+ snprintf(conn.peerhook, NG_HOOKLEN + 1, peerhook);
+ 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_PATHLEN + 1];
+
+ snprintf(path, NG_PATHLEN + 1, "[%x]:", id);
+
+ snprintf(conn.path, NG_PATHLEN + 1, "[%x]:", peer);
+ snprintf(conn.ourhook, NG_HOOKLEN + 1, ourhook);
+ snprintf(conn.peerhook, NG_HOOKLEN + 1, peerhook);
+ 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_PATHLEN + 1];
+ ng_ID_t tee;
+
+ if ((tee = ng_mkpeer_id(id, NULL, "tee", ourhook, "left")) == 0)
+ return (-1);
+
+ snprintf(path, NG_PATHLEN + 1, "[%x]:", tee);
+
+ snprintf(conn.path, NG_PATHLEN + 1, "[%x]:", peer);
+ snprintf(conn.ourhook, NG_HOOKLEN + 1, "right");
+ snprintf(conn.peerhook, NG_HOOKLEN + 1, peerhook);
+ 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_PATHLEN + 1];
+ struct ngm_mkpeer mkpeer;
+ struct ngm_name name;
+
+ strcpy(mkpeer.type, type);
+ strcpy(mkpeer.ourhook, hook);
+ strcpy(mkpeer.peerhook, peerhook);
+
+ 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)) == NULL)
+ 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_PATHLEN + 1];
+
+ sprintf(path, "[%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;
+
+ snprintf(rmhook.ourhook, NG_HOOKLEN + 1, "%s", ourhook);
+ 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_PATHLEN + 1];
+
+ snprintf(rmhook.ourhook, NG_HOOKLEN + 1, "%s", hook);
+ sprintf(path, "[%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_TYPELEN) {
+ 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/lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.h b/lib/libbsnmp/modules/snmp_netgraph/snmp_netgraph.h
new file mode 100644
index 0000000..21e553c
--- /dev/null
+++ b/lib/libbsnmp/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
OpenPOWER on IntegriCloud