From 5ef49162ea9763ca9878c22e3736766d8f1db014 Mon Sep 17 00:00:00 2001
From: Kozlov Dmitry <dima@server>
Date: Fri, 19 Aug 2011 14:04:55 +0400
Subject: snmp support

---
 README                                             |  29 +-
 accel-pppd/accel-ppp.conf                          |   4 +
 accel-pppd/cli/std_cmd.c                           |   5 +-
 accel-pppd/ctrl/l2tp/l2tp.c                        |   7 +
 accel-pppd/ctrl/pppoe/pppoe.c                      |   8 +
 accel-pppd/ctrl/pptp/pptp.c                        |   7 +
 accel-pppd/extra/CMakeLists.txt                    |   4 +
 accel-pppd/extra/net-snmp/ACCEL-PPP-MIB.txt        | 326 +++++++
 accel-pppd/extra/net-snmp/CMakeLists.txt           |  23 +
 accel-pppd/extra/net-snmp/agent.c                  | 150 ++++
 accel-pppd/extra/net-snmp/sessionTable.c           | 201 +++++
 accel-pppd/extra/net-snmp/sessionTable.h           | 195 +++++
 .../extra/net-snmp/sessionTable_data_access.c      | 304 +++++++
 .../extra/net-snmp/sessionTable_data_access.h      |  76 ++
 accel-pppd/extra/net-snmp/sessionTable_data_get.c  | 696 +++++++++++++++
 accel-pppd/extra/net-snmp/sessionTable_data_get.h  |  66 ++
 accel-pppd/extra/net-snmp/sessionTable_data_set.c  |  24 +
 accel-pppd/extra/net-snmp/sessionTable_data_set.h  |  27 +
 accel-pppd/extra/net-snmp/sessionTable_enums.h     |  85 ++
 accel-pppd/extra/net-snmp/sessionTable_interface.c | 946 +++++++++++++++++++++
 accel-pppd/extra/net-snmp/sessionTable_interface.h |  84 ++
 accel-pppd/extra/net-snmp/sessionTable_oids.h      |  46 +
 accel-pppd/extra/net-snmp/shutdown.c               |  88 ++
 accel-pppd/extra/net-snmp/shutdown.h               |  12 +
 accel-pppd/extra/net-snmp/statCore.c               | 147 ++++
 accel-pppd/extra/net-snmp/statCore.h               |  14 +
 accel-pppd/extra/net-snmp/statL2TP.c               |  94 ++
 accel-pppd/extra/net-snmp/statL2TP.h               |  11 +
 accel-pppd/extra/net-snmp/statPPP.c                |  93 ++
 accel-pppd/extra/net-snmp/statPPP.h                |  11 +
 accel-pppd/extra/net-snmp/statPPPOE.c              |  93 ++
 accel-pppd/extra/net-snmp/statPPPOE.h              |  11 +
 accel-pppd/extra/net-snmp/statPPTP.c               |  92 ++
 accel-pppd/extra/net-snmp/statPPTP.h               |  11 +
 accel-pppd/extra/net-snmp/terminate.c              | 379 +++++++++
 accel-pppd/extra/net-snmp/terminate.h              |  15 +
 accel-pppd/log.c                                   |   9 +
 accel-pppd/log.h                                   |   8 -
 accel-pppd/ppp/ppp.c                               |   4 +-
 accel-pppd/ppp/ppp.h                               |   4 +
 accel-pppd/radius/serv.c                           |  23 +-
 accel-pppd/radius/stat_accm.c                      |  11 +-
 accel-pppd/triton/triton.c                         |  10 +-
 43 files changed, 4426 insertions(+), 27 deletions(-)
 create mode 100644 accel-pppd/extra/net-snmp/ACCEL-PPP-MIB.txt
 create mode 100644 accel-pppd/extra/net-snmp/CMakeLists.txt
 create mode 100644 accel-pppd/extra/net-snmp/agent.c
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable.c
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable.h
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable_data_access.c
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable_data_access.h
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable_data_get.c
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable_data_get.h
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable_data_set.c
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable_data_set.h
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable_enums.h
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable_interface.c
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable_interface.h
 create mode 100644 accel-pppd/extra/net-snmp/sessionTable_oids.h
 create mode 100644 accel-pppd/extra/net-snmp/shutdown.c
 create mode 100644 accel-pppd/extra/net-snmp/shutdown.h
 create mode 100644 accel-pppd/extra/net-snmp/statCore.c
 create mode 100644 accel-pppd/extra/net-snmp/statCore.h
 create mode 100644 accel-pppd/extra/net-snmp/statL2TP.c
 create mode 100644 accel-pppd/extra/net-snmp/statL2TP.h
 create mode 100644 accel-pppd/extra/net-snmp/statPPP.c
 create mode 100644 accel-pppd/extra/net-snmp/statPPP.h
 create mode 100644 accel-pppd/extra/net-snmp/statPPPOE.c
 create mode 100644 accel-pppd/extra/net-snmp/statPPPOE.h
 create mode 100644 accel-pppd/extra/net-snmp/statPPTP.c
 create mode 100644 accel-pppd/extra/net-snmp/statPPTP.h
 create mode 100644 accel-pppd/extra/net-snmp/terminate.c
 create mode 100644 accel-pppd/extra/net-snmp/terminate.h

diff --git a/README b/README
index b75c40fd..e8aace76 100644
--- a/README
+++ b/README
@@ -23,6 +23,7 @@ Features
 13. Supported pppd compatible ip-up/ip-down scripts
 14. Builtin tbf shaper manager
 15. Command line interface via telnet
+16. SNMP support (master or subagent via AgentX)
 
 
 Requirment
@@ -33,6 +34,7 @@ Requirment
 5. libnl-2.0 or probably later (required for builtin shaper)
 6. libcrypto-0.9.8 or probably later (openssl-0.9.8)
 7. libpcre
+8. net-snmp-5.x 
 
 
 Compilation and instalation
@@ -42,7 +44,7 @@ or specify other location via KDIR.
 1. cd /path/to/accel-ppp-1.3.5
 2. mkdir build
 3. cd build
-4. cmake [-DBUILD_DRIVER=FALSE] [-DKDIR=/usr/src/linux] [-DCMAKE_INSTALL_PREFIX=/usr/local] [-DCMAKE_BUILD_TYPE=Release] [-DLOG_PGSQL=FALSE] [-DSHAPER=FALSE] [-DRADIUS=TRUE] ..
+4. cmake [-DBUILD_DRIVER=FALSE] [-DKDIR=/usr/src/linux] [-DCMAKE_INSTALL_PREFIX=/usr/local] [-DCMAKE_BUILD_TYPE=Release] [-DLOG_PGSQL=FALSE] [-DSHAPER=FALSE] [-DRADIUS=TRUE] [-DNETSNMP=FALSE] ..
    Please note that the double dot record in the end of the command is essential. You'll probably get error or misconfigured sources if you miss it.
    BUILD_DRIVER, KDIR, CMAKE_INSTALL_PREFIX, CMAKE_BUILD_TYPE, LOG_PGSQL, SHAPER, RADIUS  are optional,
    But while pptp is not present in mainline kernel you probably need BUILD_DRIVER.
@@ -124,6 +126,31 @@ The optional fifth column in chap-secrets file is used to pass rate information
 Its format is same as for radius attributes, except you cann't utilize time ranges functionality.
 
 
+SNMP
+----
+SNMP is implemented using net-snmp libraries. By default accel-ppp starts in subagent mode,
+so make sure that net-snmp configured with subagent control turned on (read net-snmp's README.agentx for more details).
+Also you can start accel-ppp as master agent using following configuration:
+[snmp]
+master=1
+
+Usage:
+Place accel-pppd/extra/net-snmp/ACCEL-PPP-MIB.txt to your mibs directory.
+Also you can find used numerical oids in this file.
+1. Requesting statistics:
+snmpwalk -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::accelPPPStat
+2. Requesting sessions:
+snmptable -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::sessionsTable
+3. Terminate session by session identifier (Acct-Session-ID):
+snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termBySID.0 = 0000000000000001
+4. Terminate session by interface name:
+snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByIfName = ppp2
+5. Terminaten session by IP address (Framed-IP-Address):
+snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByIP = 192.168.10.10
+6. Terminate session by username:
+snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByUsername = user1
+
+
 Warning !!!
 -----------
 1. The pptp driver conflicts with ip_gre driver (in kernel), so make sure that ip_gre is not built-in or loaded at run time
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf
index 1dc6bd2a..31932420 100644
--- a/accel-pppd/accel-ppp.conf
+++ b/accel-pppd/accel-ppp.conf
@@ -129,3 +129,7 @@ gw-ip-address=192.168.100.1
 telnet=127.0.0.1:2000
 tcp=127.0.0.1:2001
 #password=123
+
+[snmp]
+master=0
+agent-name=accel-ppp
diff --git a/accel-pppd/cli/std_cmd.c b/accel-pppd/cli/std_cmd.c
index e24b3fa0..1c8e149f 100644
--- a/accel-pppd/cli/std_cmd.c
+++ b/accel-pppd/cli/std_cmd.c
@@ -16,6 +16,7 @@
 
 static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client)
 {
+	struct timespec ts;
 	time_t dt;
 	int day,hour;
 	char statm_fname[128];
@@ -33,8 +34,8 @@ static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt,
 		fclose(f);
 	}
 
-	time(&dt);
-	dt -= triton_stat.start_time;
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	dt = ts.tv_sec - triton_stat.start_time;
 	day = dt / (60 * 60 * 24);
 	dt %= 60 * 60 * 24;
 	hour = dt / (60 * 60);
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c
index 0f36a98a..c9ed08e6 100644
--- a/accel-pppd/ctrl/l2tp/l2tp.c
+++ b/accel-pppd/ctrl/l2tp/l2tp.c
@@ -301,6 +301,7 @@ static int l2tp_tunnel_alloc(struct l2tp_serv_t *serv, struct l2tp_packet_t *pac
 	conn->hello_timer.expire = l2tp_send_HELLO;
 	conn->hello_timer.period = conf_hello_interval * 1000;
 	conn->ctrl.ctx = &conn->ctx;
+	conn->ctrl.type = CTRL_TYPE_L2TP;
 	conn->ctrl.name = "l2tp";
 	conn->ctrl.started = l2tp_ppp_started;
 	conn->ctrl.finished = l2tp_ppp_finished;
@@ -1091,6 +1092,12 @@ static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt,
 	return CLI_CMD_OK;
 }
 
+void __export l2tp_get_stat(unsigned int **starting, unsigned int **active)
+{
+	*starting = &stat_starting;
+	*active = &stat_active;
+}
+
 static void load_config(void)
 {
 	char *opt;
diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c
index fb288657..031766b0 100644
--- a/accel-pppd/ctrl/pppoe/pppoe.c
+++ b/accel-pppd/ctrl/pppoe/pppoe.c
@@ -74,6 +74,7 @@ int conf_tr101 = 1;
 static mempool_t conn_pool;
 static mempool_t pado_pool;
 
+unsigned int stat_starting;
 unsigned int stat_active;
 unsigned int stat_delayed_pado;
 unsigned long stat_PADI_recv;
@@ -247,6 +248,7 @@ static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const ui
 	conn->ctrl.started = ppp_started;
 	conn->ctrl.finished = ppp_finished;
 	conn->ctrl.max_mtu = MAX_PPPOE_MTU;
+	conn->ctrl.type = CTRL_TYPE_PPPOE;
 	conn->ctrl.name = "pppoe";
 
 	conn->ctrl.calling_station_id = _malloc(IFNAMSIZ + 19);
@@ -1217,6 +1219,12 @@ void pppoe_server_stop(const char *ifname)
 	pthread_rwlock_unlock(&serv_lock);
 }
 
+void __export pppoe_get_stat(unsigned int **starting, unsigned int **active)
+{
+	*starting = &stat_starting;
+	*active = &stat_active;
+}
+
 static int init_secret(struct pppoe_serv_t *serv)
 {
 	int fd;
diff --git a/accel-pppd/ctrl/pptp/pptp.c b/accel-pppd/ctrl/pptp/pptp.c
index cad7b23f..715a77b0 100644
--- a/accel-pppd/ctrl/pptp/pptp.c
+++ b/accel-pppd/ctrl/pptp/pptp.c
@@ -656,6 +656,7 @@ static int pptp_connect(struct triton_md_handler_t *h)
 		conn->ctrl.started = ppp_started;
 		conn->ctrl.finished = ppp_finished;
 		conn->ctrl.max_mtu = PPTP_MAX_MTU;
+		conn->ctrl.type = CTRL_TYPE_PPTP;
 		conn->ctrl.name = "pptp";
 		
 		conn->ctrl.calling_station_id = _malloc(17);
@@ -703,6 +704,12 @@ static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt,
 	return CLI_CMD_OK;
 }
 
+void __export pptp_get_stat(unsigned int **starting, unsigned int **active)
+{
+	*starting = &stat_starting;
+	*active = &stat_active;
+}
+
 static void load_config(void)
 {
 	char *opt;
diff --git a/accel-pppd/extra/CMakeLists.txt b/accel-pppd/extra/CMakeLists.txt
index 03d857ab..21449061 100644
--- a/accel-pppd/extra/CMakeLists.txt
+++ b/accel-pppd/extra/CMakeLists.txt
@@ -17,3 +17,7 @@ IF (SHAPER)
 	INSTALL(TARGETS shaper_tbf LIBRARY DESTINATION lib/accel-ppp)
 ENDIF (SHAPER)
 
+
+IF (NETSNMP)
+	ADD_SUBDIRECTORY(net-snmp)
+ENDIF (NETSNMP)
diff --git a/accel-pppd/extra/net-snmp/ACCEL-PPP-MIB.txt b/accel-pppd/extra/net-snmp/ACCEL-PPP-MIB.txt
new file mode 100644
index 00000000..5af38e80
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/ACCEL-PPP-MIB.txt
@@ -0,0 +1,326 @@
+ACCEL-PPP-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+    MODULE-IDENTITY, OBJECT-TYPE, Gauge32
+    NOTIFICATION-TYPE                       FROM SNMPv2-SMI
+    netSnmp                                 FROM NET-SNMP-MIB
+    InetAddressIPv4                         FROM INET-ADDRESS-MIB
+    IANAtunnelType                          FROM IANAifType-MIB
+;
+
+accelPPP MODULE-IDENTITY
+    LAST-UPDATED "201108180000Z"
+    ORGANIZATION "accel-ppp.sourceforge.net"
+    CONTACT-INFO    
+          "email:    xeb@mail.ru"
+    DESCRIPTION
+	"MIB objects for accel-ppp"
+    REVISION     "201108180000Z"
+    DESCRIPTION
+	"First draft"
+    ::= { netSnmp 100 }
+
+--
+-- top level structure
+--
+accelPPPStat      OBJECT IDENTIFIER ::= { accelPPP 1 }
+accelPPPSessions  OBJECT IDENTIFIER ::= { accelPPP 2 }
+accelPPPAdmin     OBJECT IDENTIFIER ::= { accelPPP 3 }
+--accelPPPNotifications OBJECT IDENTIFIER ::= { accelPPP 4 }
+
+statCore          OBJECT IDENTIFIER ::= { accelPPPStat 1 }
+statPPP           OBJECT IDENTIFIER ::= { accelPPPStat 2 }
+statPPTP          OBJECT IDENTIFIER ::= { accelPPPStat 3 }
+statL2TP          OBJECT IDENTIFIER ::= { accelPPPStat 4 }
+statPPPOE         OBJECT IDENTIFIER ::= { accelPPPStat 5 }
+--statRadius        OBJECT IDENTIFIER ::= { accelPPPStat 6 }
+
+
+statCoreUpTime OBJECT-TYPE
+    SYNTAX      Gauge32
+		UNITS       "seconds"
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"accel-ppp uptime"
+    ::= { statCore 1 }
+
+statCoreCPU OBJECT-TYPE
+    SYNTAX      INTEGER (0..100)
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"cpu utilization"
+    ::= { statCore 2 }
+
+statCoreMemRss OBJECT-TYPE
+    SYNTAX      INTEGER
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"memory rss size"
+    ::= { statCore 3 }
+
+
+--
+-- PPP stats
+--
+
+statPPPStarting OBJECT-TYPE
+    SYNTAX      INTEGER
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"count of sessions which are
+			in starting phase"
+    ::= { statPPP 1 }
+
+statPPPActive OBJECT-TYPE
+    SYNTAX      INTEGER
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"count of active sessions"
+    ::= { statPPP 2 }
+
+statPPPFinishing OBJECT-TYPE
+    SYNTAX      INTEGER
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"count of active which are
+			in finishing phase"
+    ::= { statPPP 3 }
+
+--
+-- PPTP stats
+--
+
+statPPTPStarting OBJECT-TYPE
+    SYNTAX      INTEGER
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"count of connections which are
+			in starting phase"
+    ::= { statPPTP 1 }
+
+statPPTPActive OBJECT-TYPE
+    SYNTAX      INTEGER
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"count of active connections"
+    ::= { statPPTP 2 }
+
+--
+-- L2TP stats
+--
+
+statL2TPStarting OBJECT-TYPE
+    SYNTAX      INTEGER
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"count of connections which are
+			in starting phase"
+    ::= { statL2TP 1 }
+
+statL2TPActive OBJECT-TYPE
+    SYNTAX      INTEGER
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"count of active connections"
+    ::= { statL2TP 2 }
+
+--
+-- PPPOE stats
+--
+
+statPPPOEStarting OBJECT-TYPE
+    SYNTAX      INTEGER
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"count of connections which are
+			in starting phase"
+    ::= { statPPPOE 1 }
+
+statPPPOEActive OBJECT-TYPE
+    SYNTAX      INTEGER
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"count of active connections"
+    ::= { statPPPOE 2 }
+
+
+--
+-- PPP session table
+--
+
+sessionTable OBJECT-TYPE
+    SYNTAX      SEQUENCE OF sessionEntry
+    MAX-ACCESS  not-accessible
+    STATUS      current
+    DESCRIPTION
+			"this table contains information about
+			connected sessions"
+    ::= { accelPPPSessions 1 }
+
+sessionEntry OBJECT-TYPE
+    SYNTAX      sessionEntry
+    MAX-ACCESS  not-accessible
+    STATUS      current
+    DESCRIPTION
+			"A row describing a given session"
+    INDEX   { sesSID }
+    ::= { sessionTable 1 }
+
+sessionEntry ::= SEQUENCE {
+	sesSID          OCTET STRING,
+	sesIfName       OCTET STRING,
+	sesUsername     OCTET STRING,
+	sesIP           InetAddress,
+	sesType         IANAtunnelType,
+	sesState        INTEGER,
+	sesUptime       TimeTicks,
+	sesCallingSID   OCTET STRING,
+	sesCalledSID    OCTET STRING
+}
+
+sesSID OBJECT-TYPE
+    SYNTAX      OCTET STRING (SIZE(16))
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"Acct-Session-ID"
+    ::= { sessionEntry 1 }
+
+sesIfName OBJECT-TYPE
+    SYNTAX      OCTET STRING
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"name of ppp interface"
+    ::= { sessionEntry 2 }
+
+sesUsername OBJECT-TYPE
+    SYNTAX      OCTET STRING
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"session user name"
+    ::= { sessionEntry 3 }
+
+sesIP OBJECT-TYPE
+    SYNTAX      InetAddressIPv4
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"assigned IP address"
+    ::= { sessionEntry 4 }
+
+sesType OBJECT-TYPE
+    SYNTAX      INTEGER {
+									pptp(1),
+									l2tp(2),
+									pppoe(3)
+		            }
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"name of ppp interface"
+    ::= { sessionEntry 5 }
+
+sesState OBJECT-TYPE
+    SYNTAX      INTEGER {
+			            starting(1),
+									active(2),
+									finishing(3)
+		            }
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"state of session"
+    ::= { sessionEntry 6 }
+
+sesUptime OBJECT-TYPE
+    SYNTAX      Gauge32
+		UNITS       "seconds"
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"uptime of session"
+    ::= { sessionEntry 7 }
+
+sesCallingSID OBJECT-TYPE
+    SYNTAX      OCTET STRING
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"Calling-Station-ID"
+    ::= { sessionEntry 8 }
+
+sesCalledSID OBJECT-TYPE
+    SYNTAX      OCTET STRING
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+			"Called-Station-ID"
+    ::= { sessionEntry 9 }
+
+--
+-- Administration
+--
+
+terminate        OBJECT IDENTIFIER ::= { accelPPPAdmin 1 }
+
+termBySID OBJECT-TYPE
+    SYNTAX      OCTET STRING
+    MAX-ACCESS  write-only
+    STATUS      current
+    DESCRIPTION
+			"Terminate session softly identified by Acct-Session-ID"
+    ::= { terminate 1 }
+
+termByIfName OBJECT-TYPE
+    SYNTAX      OCTET STRING
+    MAX-ACCESS  write-only
+    STATUS      current
+    DESCRIPTION
+			"Terminate session softly identified by interface name"
+    ::= { terminate 2 }
+
+termByIP OBJECT-TYPE
+    SYNTAX      OCTET STRING
+    MAX-ACCESS  write-only
+    STATUS      current
+    DESCRIPTION
+			"Terminate session softly identified by Framed-IP-Address"
+    ::= { terminate 3 }
+
+termByUsername OBJECT-TYPE
+    SYNTAX      OCTET STRING
+    MAX-ACCESS  write-only
+    STATUS      current
+    DESCRIPTION
+			"Terminate session softly identified by username"
+    ::= { terminate 4 }
+
+
+shutdown OBJECT-TYPE
+    SYNTAX      INTEGER {
+                  normal(0),
+									soft(1),
+									hard(2),
+									cancel(3)
+		            }
+    MAX-ACCESS  write-only
+    STATUS      current
+    DESCRIPTION
+			"shutdown accel-ppp"
+    ::= { accelPPPAdmin 2 }
+
+END
diff --git a/accel-pppd/extra/net-snmp/CMakeLists.txt b/accel-pppd/extra/net-snmp/CMakeLists.txt
new file mode 100644
index 00000000..4dadb2ce
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/CMakeLists.txt
@@ -0,0 +1,23 @@
+SET(sources
+	agent.c
+	sessionTable.c
+	sessionTable_data_access.c
+	sessionTable_data_get.c
+	sessionTable_data_set.c
+	sessionTable_interface.c
+	statCore.c
+	statL2TP.c
+	statPPP.c
+	statPPPOE.c
+	statPPTP.c
+	terminate.c
+	shutdown.c
+)
+
+ADD_LIBRARY(net-snmp SHARED ${sources})
+TARGET_LINK_LIBRARIES(net-snmp netsnmpagent netsnmphelpers netsnmpmibs
+netsnmp)
+
+INSTALL(TARGETS net-snmp
+	LIBRARY DESTINATION lib/accel-ppp
+)
diff --git a/accel-pppd/extra/net-snmp/agent.c b/accel-pppd/extra/net-snmp/agent.c
new file mode 100644
index 00000000..dd38b446
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/agent.c
@@ -0,0 +1,150 @@
+#include <pthread.h>
+#include <signal.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include "log.h"
+#include "triton.h"
+
+#include "statCore.h"
+#include "statPPP.h"
+#include "statPPTP.h"
+#include "statL2TP.h"
+#include "statPPPOE.h"
+#include "terminate.h"
+#include "shutdown.h"
+#include "sessionTable.h"
+
+static const char *conf_agent_name = "accel-ppp";
+static int conf_master = 0;
+/*static const char *conf_oid_prefix = "1.3.6.1.4.1.8072.100";
+
+static oid* oid_prefix;
+static size_t oid_prefix_size;*/
+
+static pthread_t snmp_thr;
+static int snmp_term = 0;
+
+/*int accel_ppp_alloc_oid(oid tail, size_t size, oid **oid)
+{
+	*oid = malloc(sizeof(oid) * (oid_prefix_size + size));
+
+	memcpy(*oid, oid_prefix, oid_prefix_size);
+	memcpy((*oid) + oid_prefix_size, tail, size);
+
+	return oid_prefix_size + size;
+}*/
+
+static int agent_log(int major, int minor, void *serv_arg, void *cl_arg)
+{
+	struct snmp_log_message *m = serv_arg;
+	
+	switch (m->priority) {
+		case LOG_EMERG:
+			log_emerg("net-snmp: %s", m->msg);
+			break;
+		case LOG_ALERT:
+		case LOG_CRIT:
+		case LOG_ERR:
+			log_error("net-snmp: %s", m->msg);
+			break;
+		case LOG_WARNING:
+			log_warn("net-snmp: %s", m->msg);
+			break;
+		case LOG_NOTICE:
+			log_info1("net-snmp: %s", m->msg);
+			break;
+		case LOG_INFO:
+			log_info2("net-snmp: %s", m->msg);
+			break;
+		case LOG_DEBUG:
+			log_debug("net-snmp: %s", m->msg);
+			break;
+		default:
+			log_msg("net-snmp: %s", m->msg);
+	}
+	return 0;
+}
+
+static void *snmp_thread(void *a)
+{
+	sigset_t set;
+
+	sigfillset(&set);
+	sigdelset(&set, SIGKILL);
+	sigdelset(&set, SIGSTOP);
+	pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+	snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, agent_log, NULL);
+  snmp_disable_log();
+	snmp_enable_calllog();
+	//snmp_set_do_debugging(1);
+	//netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);
+	
+	if (!conf_master)
+		netsnmp_enable_subagent();
+
+	init_agent(conf_agent_name);
+
+	init_statCore();
+	init_statPPP();
+	init_statPPTP();
+	init_statL2TP();
+	init_statPPPOE();
+	init_terminate();
+	init_shutdown();
+	init_sessionTable();
+
+	init_snmp(conf_agent_name);
+
+	if (conf_master)
+		init_master_agent();
+	
+	while (!snmp_term) {
+    agent_check_and_process(1);
+	}
+	
+	snmp_shutdown(conf_agent_name);
+
+  SOCK_CLEANUP;
+
+	return NULL;
+}
+
+static void snmp_ctx_close(struct triton_context_t *ctx)
+{
+	snmp_term = 1;
+	snmp_shutdown(conf_agent_name);
+	triton_context_unregister(ctx);
+}
+
+static struct triton_context_t ctx = {
+	.close = snmp_ctx_close,
+};
+
+static void init(void)
+{
+	const char *opt;
+
+	opt = conf_get_opt("snmp", "master");
+	if (opt)
+		conf_master = atoi(opt);
+
+	opt = conf_get_opt("snmp", "agent-name");
+	if (opt)
+		conf_agent_name = opt;
+	
+	/*opt = conf_get_opt("snmp", "oid-prefix")
+	if (opt)
+		conf_oid_prefix = opt;*/
+	
+	pthread_create(&snmp_thr, NULL, snmp_thread, NULL);
+	triton_context_register(&ctx, NULL);
+	triton_context_wakeup(&ctx);
+	triton_collect_cpu_usage();
+}
+
+DEFINE_INIT(100, init);
+
diff --git a/accel-pppd/extra/net-snmp/sessionTable.c b/accel-pppd/extra/net-snmp/sessionTable.c
new file mode 100644
index 00000000..dc7d62bd
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable.c
@@ -0,0 +1,201 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *       version : 14170 $ of $ 
+ *
+ * $Id:$
+ */
+/** \page MFD helper for sessionTable
+ *
+ * \section intro Introduction
+ * Introductory text.
+ *
+ */
+/* standard Net-SNMP includes */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+/* include our parent header */
+#include "sessionTable.h"
+
+#include <net-snmp/agent/mib_modules.h>
+
+#include "sessionTable_interface.h"
+
+oid sessionTable_oid[] = { SESSIONTABLE_OID };
+int sessionTable_oid_size = OID_LENGTH(sessionTable_oid);
+
+    sessionTable_registration  sessionTable_user_context;
+
+void initialize_table_sessionTable(void);
+void shutdown_table_sessionTable(void);
+
+
+/**
+ * Initializes the sessionTable module
+ */
+void
+init_sessionTable(void)
+{
+    DEBUGMSGTL(("verbose:sessionTable:init_sessionTable","called\n"));
+
+    /*
+     * TODO:300:o: Perform sessionTable one-time module initialization.
+     */
+     
+    /*
+     * here we initialize all the tables we're planning on supporting
+     */
+    if (should_init("sessionTable"))
+        initialize_table_sessionTable();
+
+} /* init_sessionTable */
+
+/**
+ * Shut-down the sessionTable module (agent is exiting)
+ */
+void
+shutdown_sessionTable(void)
+{
+    if (should_init("sessionTable"))
+        shutdown_table_sessionTable();
+
+}
+
+/**
+ * Initialize the table sessionTable 
+ *    (Define its contents and how it's structured)
+ */
+void
+initialize_table_sessionTable(void)
+{
+    sessionTable_registration * user_context;
+    u_long flags;
+
+    DEBUGMSGTL(("verbose:sessionTable:initialize_table_sessionTable","called\n"));
+
+    /*
+     * TODO:301:o: Perform sessionTable one-time table initialization.
+     */
+
+    /*
+     * TODO:302:o: |->Initialize sessionTable user context
+     * if you'd like to pass in a pointer to some data for this
+     * table, allocate or set it up here.
+     */
+    /*
+     * a netsnmp_data_list is a simple way to store void pointers. A simple
+     * string token is used to add, find or remove pointers.
+     */
+    user_context = netsnmp_create_data_list("sessionTable", NULL, NULL);
+    
+    /*
+     * No support for any flags yet, but in the future you would
+     * set any flags here.
+     */
+    flags = 0;
+    
+    /*
+     * call interface initialization code
+     */
+    _sessionTable_initialize_interface(user_context, flags);
+} /* initialize_table_sessionTable */
+
+/**
+ * Shutdown the table sessionTable 
+ */
+void
+shutdown_table_sessionTable(void)
+{
+    /*
+     * call interface shutdown code
+     */
+    _sessionTable_shutdown_interface(&sessionTable_user_context);
+}
+
+/**
+ * extra context initialization (eg default values)
+ *
+ * @param rowreq_ctx    : row request context
+ * @param user_init_ctx : void pointer for user (parameter to rowreq_ctx_allocate)
+ *
+ * @retval MFD_SUCCESS  : no errors
+ * @retval MFD_ERROR    : error (context allocate will fail)
+ */
+int
+sessionTable_rowreq_ctx_init(sessionTable_rowreq_ctx *rowreq_ctx,
+                           void *user_init_ctx)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_rowreq_ctx_init","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+    
+    /*
+     * TODO:210:o: |-> Perform extra sessionTable rowreq initialization. (eg DEFVALS)
+     */
+
+    return MFD_SUCCESS;
+} /* sessionTable_rowreq_ctx_init */
+
+/**
+ * extra context cleanup
+ *
+ */
+void sessionTable_rowreq_ctx_cleanup(sessionTable_rowreq_ctx *rowreq_ctx)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_rowreq_ctx_cleanup","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+    
+    /*
+     * TODO:211:o: |-> Perform extra sessionTable rowreq cleanup.
+     */
+} /* sessionTable_rowreq_ctx_cleanup */
+
+/**
+ * pre-request callback
+ *
+ *
+ * @retval MFD_SUCCESS              : success.
+ * @retval MFD_ERROR                : other error
+ */
+int
+sessionTable_pre_request(sessionTable_registration * user_context)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_pre_request","called\n"));
+
+    /*
+     * TODO:510:o: Perform sessionTable pre-request actions.
+     */
+
+    return MFD_SUCCESS;
+} /* sessionTable_pre_request */
+
+/**
+ * post-request callback
+ *
+ * Note:
+ *   New rows have been inserted into the container, and
+ *   deleted rows have been removed from the container and
+ *   released.
+ *
+ * @param user_context
+ * @param rc : MFD_SUCCESS if all requests succeeded
+ *
+ * @retval MFD_SUCCESS : success.
+ * @retval MFD_ERROR   : other error (ignored)
+ */
+int
+sessionTable_post_request(sessionTable_registration * user_context, int rc)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_post_request","called\n"));
+
+    /*
+     * TODO:511:o: Perform sessionTable post-request actions.
+     */
+
+    return MFD_SUCCESS;
+} /* sessionTable_post_request */
+
+
+/** @{ */
diff --git a/accel-pppd/extra/net-snmp/sessionTable.h b/accel-pppd/extra/net-snmp/sessionTable.h
new file mode 100644
index 00000000..f5619d98
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable.h
@@ -0,0 +1,195 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *       version : 14170 $ of $
+ *
+ * $Id:$
+ */
+#ifndef SESSIONTABLE_H
+#define SESSIONTABLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** @addtogroup misc misc: Miscellaneous routines
+ *
+ * @{
+ */
+#include <net-snmp/library/asn1.h>
+
+#include "ppp.h"
+
+/* other required module components */
+    /* *INDENT-OFF*  */
+config_add_mib(ACCEL-PPP-MIB)
+config_require(ACCEL-PPP-MIB/sessionTable/sessionTable_interface)
+config_require(ACCEL-PPP-MIB/sessionTable/sessionTable_data_access)
+config_require(ACCEL-PPP-MIB/sessionTable/sessionTable_data_get)
+config_require(ACCEL-PPP-MIB/sessionTable/sessionTable_data_set)
+    /* *INDENT-ON*  */
+
+/* OID and column number definitions for sessionTable */
+#include "sessionTable_oids.h"
+
+/* enum definions */
+#include "sessionTable_enums.h"
+
+/* *********************************************************************
+ * function declarations
+ */
+void init_sessionTable(void);
+void shutdown_sessionTable(void);
+
+/* *********************************************************************
+ * Table declarations
+ */
+/**********************************************************************
+ **********************************************************************
+ ***
+ *** Table sessionTable
+ ***
+ **********************************************************************
+ **********************************************************************/
+/*
+ * ACCEL-PPP-MIB::sessionTable is subid 1 of accelPPPSessions.
+ * Its status is Current.
+ * OID: .1.3.6.1.4.1.8072.100.2.1, length: 10
+*/
+/* *********************************************************************
+ * When you register your mib, you get to provide a generic
+ * pointer that will be passed back to you for most of the
+ * functions calls.
+ *
+ * TODO:100:r: Review all context structures
+ */
+    /*
+     * TODO:101:o: |-> Review sessionTable registration context.
+     */
+typedef netsnmp_data_list sessionTable_registration;
+
+/**********************************************************************/
+/*
+ * TODO:110:r: |-> Review sessionTable data context structure.
+ * This structure is used to represent the data for sessionTable.
+ */
+struct sessionTable_data_s
+{
+	char ifname[PPP_IFNAME_LEN];
+	char *username;
+	in_addr_t peer_addr;
+	int type;
+	int state;
+	unsigned long uptime;
+	char *calling_sid;
+	char *called_sid;
+};
+typedef struct sessionTable_data_s sessionTable_data;
+
+
+/*
+ * TODO:120:r: |-> Review sessionTable mib index.
+ * This structure is used to represent the index for sessionTable.
+ */
+typedef struct sessionTable_mib_index_s {
+
+        /*
+         * sesSID(1)/OCTETSTR/ASN_OCTET_STR/char(char)//L/A/w/e/R/d/h
+         */
+   char   sesSID[PPP_SESSIONID_LEN];
+   size_t      sesSID_len;
+
+
+} sessionTable_mib_index;
+
+    /*
+     * TODO:121:r: |   |-> Review sessionTable max index length.
+     * If you KNOW that your indexes will never exceed a certain
+     * length, update this macro to that length.
+     *
+     * BE VERY CAREFUL TO TAKE INTO ACCOUNT THE MAXIMUM
+     * POSSIBLE LENGHT FOR EVERY VARIABLE LENGTH INDEX!
+     * Guessing 128 - col/entry(2)  - oid len(10)
+*/
+#define MAX_sessionTable_IDX_LEN     PPP_SESSIONID_LEN + 1
+
+
+/* *********************************************************************
+ * TODO:130:o: |-> Review sessionTable Row request (rowreq) context.
+ * When your functions are called, you will be passed a
+ * sessionTable_rowreq_ctx pointer.
+ */
+typedef struct sessionTable_rowreq_ctx_s {
+
+    /** this must be first for container compare to work */
+    netsnmp_index        oid_idx;
+    oid                  oid_tmp[MAX_sessionTable_IDX_LEN];
+    
+    sessionTable_mib_index        tbl_idx;
+    
+    sessionTable_data            * data;
+
+    /*
+     * flags per row. Currently, the first (lower) 8 bits are reserved
+     * for the user. See mfd.h for other flags.
+     */
+    u_int                       rowreq_flags;
+
+    /*
+     * TODO:131:o: |   |-> Add useful data to sessionTable rowreq context.
+     */
+    
+    /*
+     * storage for future expansion
+     */
+    netsnmp_data_list             *sessionTable_data_list;
+
+} sessionTable_rowreq_ctx;
+
+typedef struct sessionTable_ref_rowreq_ctx_s {
+    sessionTable_rowreq_ctx *rowreq_ctx;
+} sessionTable_ref_rowreq_ctx;
+
+/* *********************************************************************
+ * function prototypes
+ */
+    int sessionTable_pre_request(sessionTable_registration * user_context);
+    int sessionTable_post_request(sessionTable_registration * user_context,
+        int rc);
+
+    int sessionTable_rowreq_ctx_init(sessionTable_rowreq_ctx *rowreq_ctx,
+                                   void *user_init_ctx);
+    void sessionTable_rowreq_ctx_cleanup(sessionTable_rowreq_ctx *rowreq_ctx);
+
+    sessionTable_data * sessionTable_allocate_data(void);
+    void sessionTable_release_data(sessionTable_data *data);
+
+
+    sessionTable_rowreq_ctx *
+                  sessionTable_row_find_by_mib_index(sessionTable_mib_index *mib_idx);
+
+extern oid sessionTable_oid[];
+extern int sessionTable_oid_size;
+
+
+#include "sessionTable_interface.h"
+#include "sessionTable_data_access.h"
+#include "sessionTable_data_get.h"
+#include "sessionTable_data_set.h"
+
+/*
+ * DUMMY markers, ignore
+ *
+ * TODO:099:x: *************************************************************
+ * TODO:199:x: *************************************************************
+ * TODO:299:x: *************************************************************
+ * TODO:399:x: *************************************************************
+ * TODO:499:x: *************************************************************
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SESSIONTABLE_H */
+/** @} */
diff --git a/accel-pppd/extra/net-snmp/sessionTable_data_access.c b/accel-pppd/extra/net-snmp/sessionTable_data_access.c
new file mode 100644
index 00000000..847197af
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable_data_access.c
@@ -0,0 +1,304 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *       version : 14170 $ of $ 
+ *
+ * $Id:$
+ */
+/* standard Net-SNMP includes */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+/* include our parent header */
+#include "sessionTable.h"
+
+
+#include "sessionTable_data_access.h"
+
+#include "ppp.h"
+
+/** @ingroup interface
+ * @addtogroup data_access data_access: Routines to access data
+ *
+ * These routines are used to locate the data used to satisfy
+ * requests.
+ * 
+ * @{
+ */
+/**********************************************************************
+ **********************************************************************
+ ***
+ *** Table sessionTable
+ ***
+ **********************************************************************
+ **********************************************************************/
+/*
+ * ACCEL-PPP-MIB::sessionTable is subid 1 of accelPPPSessions.
+ * Its status is Current.
+ * OID: .1.3.6.1.4.1.8072.100.2.1, length: 10
+*/
+
+/**
+ * initialization for sessionTable data access
+ *
+ * This function is called during startup to allow you to
+ * allocate any resources you need for the data table.
+ *
+ * @param sessionTable_reg
+ *        Pointer to sessionTable_registration
+ *
+ * @retval MFD_SUCCESS : success.
+ * @retval MFD_ERROR   : unrecoverable error.
+ */
+int
+sessionTable_init_data(sessionTable_registration * sessionTable_reg)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_init_data","called\n"));
+
+    /*
+     * TODO:303:o: Initialize sessionTable data->
+     */
+    /*
+    ***************************************************
+    ***             START EXAMPLE CODE              ***
+    ***---------------------------------------------***/
+    /*
+     * if you are the sole writer for the file, you could
+     * open it here. However, as stated earlier, we are assuming
+     * the worst case, which in this case means that the file is
+     * written to by someone else, and might not even exist when
+     * we start up. So we can't do anything here.
+     */
+    /*
+    ***---------------------------------------------***
+    ***              END  EXAMPLE CODE              ***
+    ***************************************************/
+
+    return MFD_SUCCESS;
+} /* sessionTable_init_data */
+
+/**
+ * container overview
+ *
+ */
+
+/**
+ * container initialization
+ *
+ * @param container_ptr_ptr A pointer to a container pointer. If you
+ *        create a custom container, use this parameter to return it
+ *        to the MFD helper. If set to NULL, the MFD helper will
+ *        allocate a container for you.
+ *
+ *  This function is called at startup to allow you to customize certain
+ *  aspects of the access method. For the most part, it is for advanced
+ *  users. The default code should suffice for most cases. If no custom
+ *  container is allocated, the MFD code will create one for your.
+ *
+ * @remark
+ *  This would also be a good place to do any initialization needed
+ *  for you data source. For example, opening a connection to another
+ *  process that will supply the data, opening a database, etc.
+ */
+void
+sessionTable_container_init(netsnmp_container **container_ptr_ptr,
+                             netsnmp_cache *cache)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_container_init","called\n"));
+    
+    if (NULL == container_ptr_ptr) {
+        snmp_log(LOG_ERR,"bad container param to sessionTable_container_init\n");
+        return;
+    }
+
+    /*
+     * For advanced users, you can use a custom container. If you
+     * do not create one, one will be created for you.
+     */
+    *container_ptr_ptr = NULL;
+
+    if (NULL == cache) {
+        snmp_log(LOG_ERR,"bad cache param to sessionTable_container_init\n");
+        return;
+    }
+
+    /*
+     * TODO:345:A: Set up sessionTable cache properties.
+     *
+     * Also for advanced users, you can set parameters for the
+     * cache. Do not change the magic pointer, as it is used
+     * by the MFD helper. To completely disable caching, set
+     * cache->enabled to 0.
+     */
+    cache->timeout = -1; /* seconds */
+} /* sessionTable_container_init */
+
+/**
+ * container shutdown
+ *
+ * @param container_ptr A pointer to the container.
+ *
+ *  This function is called at shutdown to allow you to customize certain
+ *  aspects of the access method. For the most part, it is for advanced
+ *  users. The default code should suffice for most cases.
+ *
+ *  This function is called before sessionTable_container_free().
+ *
+ * @remark
+ *  This would also be a good place to do any cleanup needed
+ *  for you data source. For example, closing a connection to another
+ *  process that supplied the data, closing a database, etc.
+ */
+void
+sessionTable_container_shutdown(netsnmp_container *container_ptr)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_container_shutdown","called\n"));
+    
+    if (NULL == container_ptr) {
+        snmp_log(LOG_ERR,"bad params to sessionTable_container_shutdown\n");
+        return;
+    }
+
+} /* sessionTable_container_shutdown */
+
+/**
+ * load initial data
+ *
+ * TODO:350:M: Implement sessionTable data load
+ *
+ * @param container container to which items should be inserted
+ *
+ * @retval MFD_SUCCESS              : success.
+ * @retval MFD_RESOURCE_UNAVAILABLE : Can't access data source
+ * @retval MFD_ERROR                : other error.
+ *
+ *  This function is called to load the index(es) (and data, optionally)
+ *  for the every row in the data set.
+ *
+ * @remark
+ *  While loading the data, the only important thing is the indexes.
+ *  If access to your data is cheap/fast (e.g. you have a pointer to a
+ *  structure in memory), it would make sense to update the data here.
+ *  If, however, the accessing the data invovles more work (e.g. parsing
+ *  some other existing data, or peforming calculations to derive the data),
+ *  then you can limit yourself to setting the indexes and saving any
+ *  information you will need later. Then use the saved information in
+ *  sessionTable_row_prep() for populating data->
+ *
+ * @note
+ *  If you need consistency between rows (like you want statistics
+ *  for each row to be from the same time frame), you should set all
+ *  data here.
+ *
+ */
+int
+sessionTable_container_load(netsnmp_container *container)
+{
+    sessionTable_rowreq_ctx *rowreq_ctx;
+    size_t                 count = 0;
+		struct ppp_t *ppp;
+		time_t t;
+		
+		time(&t);
+
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_container_load","called\n"));
+
+		pthread_rwlock_rdlock(&ppp_lock);
+		list_for_each_entry(ppp, &ppp_list, entry) {
+        rowreq_ctx = sessionTable_allocate_rowreq_ctx(NULL, NULL);
+        if (NULL == rowreq_ctx) {
+						pthread_rwlock_unlock(&ppp_lock);
+            snmp_log(LOG_ERR, "memory allocation failed\n");
+            return MFD_RESOURCE_UNAVAILABLE;
+        }
+        if(MFD_SUCCESS != sessionTable_indexes_set(rowreq_ctx
+                               , ppp->sessionid, PPP_SESSIONID_LEN
+               )) {
+            snmp_log(LOG_ERR,"error setting index while loading "
+                     "sessionTable data->\n");
+            sessionTable_release_rowreq_ctx(rowreq_ctx);
+            continue;
+        }
+				
+				strcpy(rowreq_ctx->data->ifname, ppp->ifname);
+
+				if (ppp->username)
+					rowreq_ctx->data->username = strdup(ppp->username);
+				else
+					ppp->username = strdup("");
+
+				rowreq_ctx->data->peer_addr = ppp->peer_ipaddr;
+				rowreq_ctx->data->type = ppp->ctrl->type;
+				rowreq_ctx->data->state = ppp->state;
+				rowreq_ctx->data->uptime = (ppp->stop_time ? ppp->stop_time : t) - ppp->start_time;
+				rowreq_ctx->data->calling_sid = strdup(ppp->ctrl->calling_station_id);
+				rowreq_ctx->data->called_sid = strdup(ppp->ctrl->called_station_id);
+
+        CONTAINER_INSERT(container, rowreq_ctx);
+        ++count;
+    }
+		pthread_rwlock_unlock(&ppp_lock);
+
+    DEBUGMSGT(("verbose:sessionTable:sessionTable_container_load",
+               "inserted %d records\n", count));
+
+    return MFD_SUCCESS;
+} /* sessionTable_container_load */
+
+/**
+ * container clean up
+ *
+ * @param container container with all current items
+ *
+ *  This optional callback is called prior to all
+ *  item's being removed from the container. If you
+ *  need to do any processing before that, do it here.
+ *
+ * @note
+ *  The MFD helper will take care of releasing all the row contexts.
+ *  If you did not pass a data context pointer when allocating
+ *  the rowreq context, the one that was allocated will be deleted.
+ *  If you did pass one in, it will not be deleted and that memory
+ *  is your responsibility.
+ *
+ */
+void
+sessionTable_container_free(netsnmp_container *container)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_container_free","called\n"));
+
+    /*
+     * TODO:380:M: Free sessionTable container data->
+     */
+} /* sessionTable_container_free */
+
+/**
+ * prepare row for processing.
+ *
+ *  When the agent has located the row for a request, this function is
+ *  called to prepare the row for processing. If you fully populated
+ *  the data context during the index setup phase, you may not need to
+ *  do anything.
+ *
+ * @param rowreq_ctx pointer to a context.
+ *
+ * @retval MFD_SUCCESS     : success.
+ * @retval MFD_ERROR       : other error.
+ */
+int
+sessionTable_row_prep( sessionTable_rowreq_ctx *rowreq_ctx)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_row_prep","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+
+    /*
+     * TODO:390:o: Prepare row for request.
+     * If populating row data was delayed, this is the place to
+     * fill in the row for this request.
+     */
+
+    return MFD_SUCCESS;
+} /* sessionTable_row_prep */
+
+/** @} */
diff --git a/accel-pppd/extra/net-snmp/sessionTable_data_access.h b/accel-pppd/extra/net-snmp/sessionTable_data_access.h
new file mode 100644
index 00000000..1c420cee
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable_data_access.h
@@ -0,0 +1,76 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *       version : 14170 $ of $
+ *
+ * $Id:$
+ */
+#ifndef SESSIONTABLE_DATA_ACCESS_H
+#define SESSIONTABLE_DATA_ACCESS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* *********************************************************************
+ * function declarations
+ */
+
+/* *********************************************************************
+ * Table declarations
+ */
+/**********************************************************************
+ **********************************************************************
+ ***
+ *** Table sessionTable
+ ***
+ **********************************************************************
+ **********************************************************************/
+/*
+ * ACCEL-PPP-MIB::sessionTable is subid 1 of accelPPPSessions.
+ * Its status is Current.
+ * OID: .1.3.6.1.4.1.8072.100.2.1, length: 10
+*/
+
+
+    int sessionTable_init_data(sessionTable_registration * sessionTable_reg);
+
+
+    /*
+     * TODO:180:o: Review sessionTable cache timeout.
+     * The number of seconds before the cache times out
+     */
+#define SESSIONTABLE_CACHE_TIMEOUT   60
+
+void sessionTable_container_init(netsnmp_container **container_ptr_ptr,
+                             netsnmp_cache *cache);
+void sessionTable_container_shutdown(netsnmp_container *container_ptr);
+
+int sessionTable_container_load(netsnmp_container *container);
+void sessionTable_container_free(netsnmp_container *container);
+
+int sessionTable_cache_load(netsnmp_container *container);
+void sessionTable_cache_free(netsnmp_container *container);
+
+    /*
+    ***************************************************
+    ***             START EXAMPLE CODE              ***
+    ***---------------------------------------------***/
+/* *********************************************************************
+ * Since we have no idea how you really access your data, we'll go with
+ * a worst case example: a flat text file.
+ */
+#define MAX_LINE_SIZE 256
+    /*
+    ***---------------------------------------------***
+    ***              END  EXAMPLE CODE              ***
+    ***************************************************/
+    int sessionTable_row_prep( sessionTable_rowreq_ctx *rowreq_ctx);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SESSIONTABLE_DATA_ACCESS_H */
diff --git a/accel-pppd/extra/net-snmp/sessionTable_data_get.c b/accel-pppd/extra/net-snmp/sessionTable_data_get.c
new file mode 100644
index 00000000..1dcea1e8
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable_data_get.c
@@ -0,0 +1,696 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *       version : 12088 $ of $ 
+ *
+ * $Id:$
+ */
+/* standard Net-SNMP includes */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+/* include our parent header */
+#include "sessionTable.h"
+
+
+/** @defgroup data_get data_get: Routines to get data
+ *
+ * TODO:230:M: Implement sessionTable get routines.
+ * TODO:240:M: Implement sessionTable mapping routines (if any).
+ *
+ * These routine are used to get the value for individual objects. The
+ * row context is passed, along with a pointer to the memory where the
+ * value should be copied.
+ *
+ * @{
+ */
+/**********************************************************************
+ **********************************************************************
+ ***
+ *** Table sessionTable
+ ***
+ **********************************************************************
+ **********************************************************************/
+/*
+ * ACCEL-PPP-MIB::sessionTable is subid 1 of accelPPPSessions.
+ * Its status is Current.
+ * OID: .1.3.6.1.4.1.8072.100.2.1, length: 10
+*/
+
+/* ---------------------------------------------------------------------
+ * TODO:200:r: Implement sessionTable data context functions.
+ */
+/*
+ * sessionTable_allocate_data
+ *
+ * Purpose: create new sessionTable_data->
+ */
+sessionTable_data *
+sessionTable_allocate_data(void)
+{
+    sessionTable_data *rtn = SNMP_MALLOC_TYPEDEF(sessionTable_data);
+
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_allocate_data","called\n"));
+
+    if(NULL == rtn) {
+        snmp_log(LOG_ERR, "unable to malloc memory for new "
+                 "sessionTable_data->\n");
+    }
+
+		memset(rtn, 0, sizeof(*rtn));
+
+    return rtn;
+} /* sessionTable_allocate_data */
+
+/*
+ * sessionTable_release_data
+ *
+ * Purpose: release sessionTable data->
+ */
+void
+sessionTable_release_data(sessionTable_data *data)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_release_data","called\n"));
+
+		if (data->username)
+			free(data->username);
+
+		if (data->calling_sid)
+			free(data->calling_sid);
+
+		if (data->called_sid)
+			free(data->called_sid);
+
+    free(data);
+} /* sessionTable_release_data */
+
+
+
+/**
+ * set mib index(es)
+ *
+ * @param tbl_idx mib index structure
+ * @param sesSID_ptr
+ * @param sesSID_ptr_len
+ *
+ * @retval MFD_SUCCESS     : success.
+ * @retval MFD_ERROR       : other error.
+ *
+ * @remark
+ *  This convenience function is useful for setting all the MIB index
+ *  components with a single function call. It is assume that the C values
+ *  have already been mapped from their native/rawformat to the MIB format.
+ */
+int
+sessionTable_indexes_set_tbl_idx(sessionTable_mib_index *tbl_idx, char *sesSID_val_ptr,  size_t sesSID_val_ptr_len)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_indexes_set_tbl_idx","called\n"));
+
+    /* sesSID(1)/OCTETSTR/ASN_OCTET_STR/char(char)//L/A/w/e/R/d/h */
+    tbl_idx->sesSID_len = sizeof(tbl_idx->sesSID)/sizeof(tbl_idx->sesSID[0]); /* max length */
+    /** WARNING: this code might not work for struct sessionTable_data_s */
+    /*
+     * make sure there is enough space for sesSID data
+     */
+    if ((NULL == tbl_idx->sesSID) ||
+        (tbl_idx->sesSID_len <
+         (sesSID_val_ptr_len))) {
+        snmp_log(LOG_ERR,"not enough space for value\n");
+        return MFD_ERROR;
+    }
+    tbl_idx->sesSID_len = sesSID_val_ptr_len;
+    memcpy( tbl_idx->sesSID, sesSID_val_ptr, sesSID_val_ptr_len* sizeof(sesSID_val_ptr[0]) );
+    
+
+    return MFD_SUCCESS;
+} /* sessionTable_indexes_set_tbl_idx */
+
+/**
+ * @internal
+ * set row context indexes
+ *
+ * @param reqreq_ctx the row context that needs updated indexes
+ *
+ * @retval MFD_SUCCESS     : success.
+ * @retval MFD_ERROR       : other error.
+ *
+ * @remark
+ *  This function sets the mib indexs, then updates the oid indexs
+ *  from the mib index.
+ */
+int
+sessionTable_indexes_set(sessionTable_rowreq_ctx *rowreq_ctx, char *sesSID_val_ptr,  size_t sesSID_val_ptr_len)
+{
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_indexes_set","called\n"));
+
+    if(MFD_SUCCESS != sessionTable_indexes_set_tbl_idx(&rowreq_ctx->tbl_idx
+                                   , sesSID_val_ptr, sesSID_val_ptr_len
+           ))
+        return MFD_ERROR;
+
+    /*
+     * convert mib index to oid index
+     */
+    rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx->oid_tmp) / sizeof(oid);
+    if(0 != sessionTable_index_to_oid(&rowreq_ctx->oid_idx,
+                                    &rowreq_ctx->tbl_idx)) {
+        return MFD_ERROR;
+    }
+
+    return MFD_SUCCESS;
+} /* sessionTable_indexes_set */
+
+
+/*---------------------------------------------------------------------
+ * ACCEL-PPP-MIB::sessionEntry.sesIfName
+ * sesIfName is subid 2 of sessionEntry.
+ * Its status is Current, and its access level is ReadOnly.
+ * OID: .1.3.6.1.4.1.8072.100.2.1.1.2
+ * Description:
+name of ppp interface
+ *
+ * Attributes:
+ *   accessible 1     isscalar 0     enums  0      hasdefval 0
+ *   readable   1     iscolumn 1     ranges 0      hashint   0
+ *   settable   0
+ *
+ *
+ * Its syntax is OCTETSTR (based on perltype OCTETSTR)
+ * The net-snmp type is ASN_OCTET_STR. The C type decl is char (char)
+ * This data type requires a length.
+ */
+/**
+ * Extract the current value of the sesIfName data->
+ *
+ * Set a value using the data context for the row.
+ *
+ * @param rowreq_ctx
+ *        Pointer to the row request context.
+ * @param sesIfName_val_ptr_ptr
+ *        Pointer to storage for a char variable
+ * @param sesIfName_val_ptr_len_ptr
+ *        Pointer to a size_t. On entry, it will contain the size (in bytes)
+ *        pointed to by sesIfName.
+ *        On exit, this value should contain the data size (in bytes).
+ *
+ * @retval MFD_SUCCESS         : success
+ * @retval MFD_SKIP            : skip this node (no value for now)
+ * @retval MFD_ERROR           : Any other error
+*
+ * @note If you need more than (*sesIfName_val_ptr_len_ptr) bytes of memory,
+ *       allocate it using malloc() and update sesIfName_val_ptr_ptr.
+ *       <b>DO NOT</b> free the previous pointer.
+ *       The MFD helper will release the memory you allocate.
+ *
+ * @remark If you call this function yourself, you are responsible
+ *         for checking if the pointer changed, and freeing any
+ *         previously allocated memory. (Not necessary if you pass
+ *         in a pointer to static memory, obviously.)
+ */
+int
+sesIfName_get( sessionTable_rowreq_ctx *rowreq_ctx, char **sesIfName_val_ptr_ptr, size_t *sesIfName_val_ptr_len_ptr )
+{
+   int len;
+   /** we should have a non-NULL pointer and enough storage */
+   netsnmp_assert( (NULL != sesIfName_val_ptr_ptr) && (NULL != *sesIfName_val_ptr_ptr));
+   netsnmp_assert( NULL != sesIfName_val_ptr_len_ptr );
+
+
+    DEBUGMSGTL(("verbose:sessionTable:sesIfName_get","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+
+		len = strlen(rowreq_ctx->data->ifname);
+
+    if ((NULL == (* sesIfName_val_ptr_ptr )) ||
+        ((* sesIfName_val_ptr_len_ptr ) < len)) {
+        /*
+         * allocate space for sesIfName data
+         */
+        (* sesIfName_val_ptr_ptr ) = malloc(len);
+        if(NULL == (* sesIfName_val_ptr_ptr )) {
+            snmp_log(LOG_ERR,"could not allocate memory\n");
+            return MFD_ERROR;
+        }
+    }
+    (* sesIfName_val_ptr_len_ptr ) = len;
+    memcpy( (* sesIfName_val_ptr_ptr ), rowreq_ctx->data->ifname, len);
+
+    return MFD_SUCCESS;
+} /* sesIfName_get */
+
+/*---------------------------------------------------------------------
+ * ACCEL-PPP-MIB::sessionEntry.sesUsername
+ * sesUsername is subid 3 of sessionEntry.
+ * Its status is Current, and its access level is ReadOnly.
+ * OID: .1.3.6.1.4.1.8072.100.2.1.1.3
+ * Description:
+session user name
+ *
+ * Attributes:
+ *   accessible 1     isscalar 0     enums  0      hasdefval 0
+ *   readable   1     iscolumn 1     ranges 0      hashint   0
+ *   settable   0
+ *
+ *
+ * Its syntax is OCTETSTR (based on perltype OCTETSTR)
+ * The net-snmp type is ASN_OCTET_STR. The C type decl is char (char)
+ * This data type requires a length.
+ */
+/**
+ * Extract the current value of the sesUsername data->
+ *
+ * Set a value using the data context for the row.
+ *
+ * @param rowreq_ctx
+ *        Pointer to the row request context.
+ * @param sesUsername_val_ptr_ptr
+ *        Pointer to storage for a char variable
+ * @param sesUsername_val_ptr_len_ptr
+ *        Pointer to a size_t. On entry, it will contain the size (in bytes)
+ *        pointed to by sesUsername.
+ *        On exit, this value should contain the data size (in bytes).
+ *
+ * @retval MFD_SUCCESS         : success
+ * @retval MFD_SKIP            : skip this node (no value for now)
+ * @retval MFD_ERROR           : Any other error
+*
+ * @note If you need more than (*sesUsername_val_ptr_len_ptr) bytes of memory,
+ *       allocate it using malloc() and update sesUsername_val_ptr_ptr.
+ *       <b>DO NOT</b> free the previous pointer.
+ *       The MFD helper will release the memory you allocate.
+ *
+ * @remark If you call this function yourself, you are responsible
+ *         for checking if the pointer changed, and freeing any
+ *         previously allocated memory. (Not necessary if you pass
+ *         in a pointer to static memory, obviously.)
+ */
+int
+sesUsername_get( sessionTable_rowreq_ctx *rowreq_ctx, char **sesUsername_val_ptr_ptr, size_t *sesUsername_val_ptr_len_ptr )
+{
+   int len;
+   /** we should have a non-NULL pointer and enough storage */
+   netsnmp_assert( (NULL != sesUsername_val_ptr_ptr) && (NULL != *sesUsername_val_ptr_ptr));
+   netsnmp_assert( NULL != sesUsername_val_ptr_len_ptr );
+
+
+    DEBUGMSGTL(("verbose:sessionTable:sesUsername_get","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+
+		len = strlen(rowreq_ctx->data->username);
+
+    if ((NULL == (* sesUsername_val_ptr_ptr )) ||
+        ((* sesUsername_val_ptr_len_ptr ) < len)) {
+        /*
+         * allocate space for sesIfName data
+         */
+        (* sesUsername_val_ptr_ptr ) = malloc(len);
+        if(NULL == (* sesUsername_val_ptr_ptr )) {
+            snmp_log(LOG_ERR,"could not allocate memory\n");
+            return MFD_ERROR;
+        }
+    }
+    (* sesUsername_val_ptr_len_ptr ) = len;
+    memcpy( (* sesUsername_val_ptr_ptr ), rowreq_ctx->data->username, len);
+    
+		return MFD_SUCCESS;
+} /* sesUsername_get */
+
+/*---------------------------------------------------------------------
+ * ACCEL-PPP-MIB::sessionEntry.sesIP
+ * sesIP is subid 4 of sessionEntry.
+ * Its status is Current, and its access level is ReadOnly.
+ * OID: .1.3.6.1.4.1.8072.100.2.1.1.4
+ * Description:
+assigned IP address
+ *
+ * Attributes:
+ *   accessible 1     isscalar 0     enums  0      hasdefval 0
+ *   readable   1     iscolumn 1     ranges 0      hashint   0
+ *   settable   0
+ *
+ *
+ * Its syntax is OCTETSTR (based on perltype OCTETSTR)
+ * The net-snmp type is ASN_OCTET_STR. The C type decl is char (char)
+ * This data type requires a length.
+ */
+/**
+ * Extract the current value of the sesIP data->
+ *
+ * Set a value using the data context for the row.
+ *
+ * @param rowreq_ctx
+ *        Pointer to the row request context.
+ * @param sesIP_val_ptr_ptr
+ *        Pointer to storage for a char variable
+ * @param sesIP_val_ptr_len_ptr
+ *        Pointer to a size_t. On entry, it will contain the size (in bytes)
+ *        pointed to by sesIP.
+ *        On exit, this value should contain the data size (in bytes).
+ *
+ * @retval MFD_SUCCESS         : success
+ * @retval MFD_SKIP            : skip this node (no value for now)
+ * @retval MFD_ERROR           : Any other error
+*
+ * @note If you need more than (*sesIP_val_ptr_len_ptr) bytes of memory,
+ *       allocate it using malloc() and update sesIP_val_ptr_ptr.
+ *       <b>DO NOT</b> free the previous pointer.
+ *       The MFD helper will release the memory you allocate.
+ *
+ * @remark If you call this function yourself, you are responsible
+ *         for checking if the pointer changed, and freeing any
+ *         previously allocated memory. (Not necessary if you pass
+ *         in a pointer to static memory, obviously.)
+ */
+int
+sesIP_get( sessionTable_rowreq_ctx *rowreq_ctx, char **sesIP_val_ptr_ptr, size_t *sesIP_val_ptr_len_ptr )
+{
+   int len = 4;
+   /** we should have a non-NULL pointer and enough storage */
+   netsnmp_assert( (NULL != sesIP_val_ptr_ptr) && (NULL != *sesIP_val_ptr_ptr));
+   netsnmp_assert( NULL != sesIP_val_ptr_len_ptr );
+
+
+    DEBUGMSGTL(("verbose:sessionTable:sesIP_get","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+
+    if ((NULL == (* sesIP_val_ptr_ptr )) ||
+        ((* sesIP_val_ptr_len_ptr ) < len)) {
+        /*
+         * allocate space for sesIfName data
+         */
+        (* sesIP_val_ptr_ptr ) = malloc(len);
+        if(NULL == (* sesIP_val_ptr_ptr )) {
+            snmp_log(LOG_ERR,"could not allocate memory\n");
+            return MFD_ERROR;
+        }
+    }
+    (* sesIP_val_ptr_len_ptr ) = len;
+    memcpy( (* sesIP_val_ptr_ptr ), &rowreq_ctx->data->peer_addr, len);
+
+    return MFD_SUCCESS;
+} /* sesIP_get */
+
+/*---------------------------------------------------------------------
+ * ACCEL-PPP-MIB::sessionEntry.sesType
+ * sesType is subid 5 of sessionEntry.
+ * Its status is Current, and its access level is ReadOnly.
+ * OID: .1.3.6.1.4.1.8072.100.2.1.1.5
+ * Description:
+name of ppp interface
+ *
+ * Attributes:
+ *   accessible 1     isscalar 0     enums  1      hasdefval 0
+ *   readable   1     iscolumn 1     ranges 0      hashint   0
+ *   settable   0
+ *
+ * Enum range: 10/16. Values:  other(1), direct(2), gre(3), minimal(4), l2tp(5), pptp(6), l2f(7), udp(8), atmp(9), msdp(10), sixToFour(11), sixOverFour(12), isatap(13), teredo(14)
+ *
+ * Its syntax is IANAtunnelType (based on perltype INTEGER)
+ * The net-snmp type is ASN_INTEGER. The C type decl is long (u_long)
+ */
+/**
+ * Extract the current value of the sesType data->
+ *
+ * Set a value using the data context for the row.
+ *
+ * @param rowreq_ctx
+ *        Pointer to the row request context.
+ * @param sesType_val_ptr
+ *        Pointer to storage for a long variable
+ *
+ * @retval MFD_SUCCESS         : success
+ * @retval MFD_SKIP            : skip this node (no value for now)
+ * @retval MFD_ERROR           : Any other error
+ */
+int
+sesType_get( sessionTable_rowreq_ctx *rowreq_ctx, u_long * sesType_val_ptr )
+{
+   /** we should have a non-NULL pointer */
+   netsnmp_assert( NULL != sesType_val_ptr );
+
+
+    DEBUGMSGTL(("verbose:sessionTable:sesType_get","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+
+    (* sesType_val_ptr ) = rowreq_ctx->data->type;
+
+    return MFD_SUCCESS;
+} /* sesType_get */
+
+/*---------------------------------------------------------------------
+ * ACCEL-PPP-MIB::sessionEntry.sesState
+ * sesState is subid 6 of sessionEntry.
+ * Its status is Current, and its access level is ReadOnly.
+ * OID: .1.3.6.1.4.1.8072.100.2.1.1.6
+ * Description:
+state of session
+ *
+ * Attributes:
+ *   accessible 1     isscalar 0     enums  1      hasdefval 0
+ *   readable   1     iscolumn 1     ranges 0      hashint   0
+ *   settable   0
+ *
+ * Enum range: 3/8. Values:  starting(1), active(2), finishing(3)
+ *
+ * Its syntax is INTEGER (based on perltype INTEGER)
+ * The net-snmp type is ASN_INTEGER. The C type decl is long (u_long)
+ */
+/**
+ * Extract the current value of the sesState data->
+ *
+ * Set a value using the data context for the row.
+ *
+ * @param rowreq_ctx
+ *        Pointer to the row request context.
+ * @param sesState_val_ptr
+ *        Pointer to storage for a long variable
+ *
+ * @retval MFD_SUCCESS         : success
+ * @retval MFD_SKIP            : skip this node (no value for now)
+ * @retval MFD_ERROR           : Any other error
+ */
+int
+sesState_get( sessionTable_rowreq_ctx *rowreq_ctx, u_long * sesState_val_ptr )
+{
+   /** we should have a non-NULL pointer */
+   netsnmp_assert( NULL != sesState_val_ptr );
+
+
+    DEBUGMSGTL(("verbose:sessionTable:sesState_get","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+    
+		(* sesState_val_ptr ) = rowreq_ctx->data->state;
+
+    return MFD_SUCCESS;
+} /* sesState_get */
+
+/*---------------------------------------------------------------------
+ * ACCEL-PPP-MIB::sessionEntry.sesUptime
+ * sesUptime is subid 7 of sessionEntry.
+ * Its status is Current, and its access level is ReadOnly.
+ * OID: .1.3.6.1.4.1.8072.100.2.1.1.7
+ * Description:
+uptime of session
+ *
+ * Attributes:
+ *   accessible 1     isscalar 0     enums  0      hasdefval 0
+ *   readable   1     iscolumn 1     ranges 0      hashint   0
+ *   settable   0
+ *
+ *
+ * Its syntax is TICKS (based on perltype TICKS)
+ * The net-snmp type is ASN_TIMETICKS. The C type decl is u_long (u_long)
+ */
+/**
+ * Extract the current value of the sesUptime data->
+ *
+ * Set a value using the data context for the row.
+ *
+ * @param rowreq_ctx
+ *        Pointer to the row request context.
+ * @param sesUptime_val_ptr
+ *        Pointer to storage for a u_long variable
+ *
+ * @retval MFD_SUCCESS         : success
+ * @retval MFD_SKIP            : skip this node (no value for now)
+ * @retval MFD_ERROR           : Any other error
+ */
+int
+sesUptime_get( sessionTable_rowreq_ctx *rowreq_ctx, u_long * sesUptime_val_ptr )
+{
+   /** we should have a non-NULL pointer */
+   netsnmp_assert( NULL != sesUptime_val_ptr );
+
+
+    DEBUGMSGTL(("verbose:sessionTable:sesUptime_get","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+
+    (* sesUptime_val_ptr ) = rowreq_ctx->data->uptime;
+
+    return MFD_SUCCESS;
+} /* sesUptime_get */
+
+/*---------------------------------------------------------------------
+ * ACCEL-PPP-MIB::sessionEntry.sesCallingSID
+ * sesCallingSID is subid 8 of sessionEntry.
+ * Its status is Current, and its access level is ReadOnly.
+ * OID: .1.3.6.1.4.1.8072.100.2.1.1.8
+ * Description:
+Calling-Station-ID
+ *
+ * Attributes:
+ *   accessible 1     isscalar 0     enums  0      hasdefval 0
+ *   readable   1     iscolumn 1     ranges 0      hashint   0
+ *   settable   0
+ *
+ *
+ * Its syntax is OCTETSTR (based on perltype OCTETSTR)
+ * The net-snmp type is ASN_OCTET_STR. The C type decl is char (char)
+ * This data type requires a length.
+ */
+/**
+ * Extract the current value of the sesCallingSID data->
+ *
+ * Set a value using the data context for the row.
+ *
+ * @param rowreq_ctx
+ *        Pointer to the row request context.
+ * @param sesCallingSID_val_ptr_ptr
+ *        Pointer to storage for a char variable
+ * @param sesCallingSID_val_ptr_len_ptr
+ *        Pointer to a size_t. On entry, it will contain the size (in bytes)
+ *        pointed to by sesCallingSID.
+ *        On exit, this value should contain the data size (in bytes).
+ *
+ * @retval MFD_SUCCESS         : success
+ * @retval MFD_SKIP            : skip this node (no value for now)
+ * @retval MFD_ERROR           : Any other error
+*
+ * @note If you need more than (*sesCallingSID_val_ptr_len_ptr) bytes of memory,
+ *       allocate it using malloc() and update sesCallingSID_val_ptr_ptr.
+ *       <b>DO NOT</b> free the previous pointer.
+ *       The MFD helper will release the memory you allocate.
+ *
+ * @remark If you call this function yourself, you are responsible
+ *         for checking if the pointer changed, and freeing any
+ *         previously allocated memory. (Not necessary if you pass
+ *         in a pointer to static memory, obviously.)
+ */
+int
+sesCallingSID_get( sessionTable_rowreq_ctx *rowreq_ctx, char **sesCallingSID_val_ptr_ptr, size_t *sesCallingSID_val_ptr_len_ptr )
+{
+   int len;
+   /** we should have a non-NULL pointer and enough storage */
+   netsnmp_assert( (NULL != sesCallingSID_val_ptr_ptr) && (NULL != *sesCallingSID_val_ptr_ptr));
+   netsnmp_assert( NULL != sesCallingSID_val_ptr_len_ptr );
+
+
+    DEBUGMSGTL(("verbose:sessionTable:sesCallingSID_get","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+
+		len = strlen(rowreq_ctx->data->calling_sid);
+
+    if ((NULL == (* sesCallingSID_val_ptr_ptr )) ||
+        ((* sesCallingSID_val_ptr_len_ptr ) < len)) {
+        /*
+         * allocate space for sesCallingSID data
+         */
+        (* sesCallingSID_val_ptr_ptr ) = malloc(len);
+        if(NULL == (* sesCallingSID_val_ptr_ptr )) {
+            snmp_log(LOG_ERR,"could not allocate memory\n");
+            return MFD_ERROR;
+        }
+    }
+    (* sesCallingSID_val_ptr_len_ptr ) = len;
+    memcpy( (* sesCallingSID_val_ptr_ptr ), rowreq_ctx->data->calling_sid, len);
+
+    return MFD_SUCCESS;
+} /* sesCallingSID_get */
+
+/*---------------------------------------------------------------------
+ * ACCEL-PPP-MIB::sessionEntry.sesCalledSID
+ * sesCalledSID is subid 9 of sessionEntry.
+ * Its status is Current, and its access level is ReadOnly.
+ * OID: .1.3.6.1.4.1.8072.100.2.1.1.9
+ * Description:
+Called-Station-ID
+ *
+ * Attributes:
+ *   accessible 1     isscalar 0     enums  0      hasdefval 0
+ *   readable   1     iscolumn 1     ranges 0      hashint   0
+ *   settable   0
+ *
+ *
+ * Its syntax is OCTETSTR (based on perltype OCTETSTR)
+ * The net-snmp type is ASN_OCTET_STR. The C type decl is char (char)
+ * This data type requires a length.
+ */
+/**
+ * Extract the current value of the sesCalledSID data->
+ *
+ * Set a value using the data context for the row.
+ *
+ * @param rowreq_ctx
+ *        Pointer to the row request context.
+ * @param sesCalledSID_val_ptr_ptr
+ *        Pointer to storage for a char variable
+ * @param sesCalledSID_val_ptr_len_ptr
+ *        Pointer to a size_t. On entry, it will contain the size (in bytes)
+ *        pointed to by sesCalledSID.
+ *        On exit, this value should contain the data size (in bytes).
+ *
+ * @retval MFD_SUCCESS         : success
+ * @retval MFD_SKIP            : skip this node (no value for now)
+ * @retval MFD_ERROR           : Any other error
+*
+ * @note If you need more than (*sesCalledSID_val_ptr_len_ptr) bytes of memory,
+ *       allocate it using malloc() and update sesCalledSID_val_ptr_ptr.
+ *       <b>DO NOT</b> free the previous pointer.
+ *       The MFD helper will release the memory you allocate.
+ *
+ * @remark If you call this function yourself, you are responsible
+ *         for checking if the pointer changed, and freeing any
+ *         previously allocated memory. (Not necessary if you pass
+ *         in a pointer to static memory, obviously.)
+ */
+int
+sesCalledSID_get( sessionTable_rowreq_ctx *rowreq_ctx, char **sesCalledSID_val_ptr_ptr, size_t *sesCalledSID_val_ptr_len_ptr )
+{
+	 int len;
+
+   /** we should have a non-NULL pointer and enough storage */
+   netsnmp_assert( (NULL != sesCalledSID_val_ptr_ptr) && (NULL != *sesCalledSID_val_ptr_ptr));
+   netsnmp_assert( NULL != sesCalledSID_val_ptr_len_ptr );
+
+
+    DEBUGMSGTL(("verbose:sessionTable:sesCalledSID_get","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+
+		len = strlen(rowreq_ctx->data->called_sid);
+
+    if ((NULL == (* sesCalledSID_val_ptr_ptr )) ||
+        ((* sesCalledSID_val_ptr_len_ptr ) < len)) {
+        /*
+         * allocate space for sesCalledSID data
+         */
+        (* sesCalledSID_val_ptr_ptr ) = malloc(len);
+        if(NULL == (* sesCalledSID_val_ptr_ptr )) {
+            snmp_log(LOG_ERR,"could not allocate memory\n");
+            return MFD_ERROR;
+        }
+    }
+    (* sesCalledSID_val_ptr_len_ptr ) = len;
+    memcpy( (* sesCalledSID_val_ptr_ptr ), rowreq_ctx->data->called_sid, len);
+
+    return MFD_SUCCESS;
+} /* sesCalledSID_get */
+
+/** @} */
diff --git a/accel-pppd/extra/net-snmp/sessionTable_data_get.h b/accel-pppd/extra/net-snmp/sessionTable_data_get.h
new file mode 100644
index 00000000..e5a3ae62
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable_data_get.h
@@ -0,0 +1,66 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *       version : 12088 $ of $
+ *
+ * $Id:$
+ *
+ * @file sessionTable_data_get.h
+ *
+ * @addtogroup get
+ *
+ * Prototypes for get functions
+ *
+ * @{
+ */
+#ifndef SESSIONTABLE_DATA_GET_H
+#define SESSIONTABLE_DATA_GET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* *********************************************************************
+ * GET function declarations
+ */
+
+/* *********************************************************************
+ * GET Table declarations
+ */
+/**********************************************************************
+ **********************************************************************
+ ***
+ *** Table sessionTable
+ ***
+ **********************************************************************
+ **********************************************************************/
+/*
+ * ACCEL-PPP-MIB::sessionTable is subid 1 of accelPPPSessions.
+ * Its status is Current.
+ * OID: .1.3.6.1.4.1.8072.100.2.1, length: 10
+*/
+    /*
+     * indexes
+     */
+
+    int sesIfName_get( sessionTable_rowreq_ctx *rowreq_ctx, char **sesIfName_val_ptr_ptr, size_t *sesIfName_val_ptr_len_ptr );
+    int sesUsername_get( sessionTable_rowreq_ctx *rowreq_ctx, char **sesUsername_val_ptr_ptr, size_t *sesUsername_val_ptr_len_ptr );
+    int sesIP_get( sessionTable_rowreq_ctx *rowreq_ctx, char **sesIP_val_ptr_ptr, size_t *sesIP_val_ptr_len_ptr );
+    int sesType_get( sessionTable_rowreq_ctx *rowreq_ctx, u_long * sesType_val_ptr );
+    int sesState_get( sessionTable_rowreq_ctx *rowreq_ctx, u_long * sesState_val_ptr );
+    int sesUptime_get( sessionTable_rowreq_ctx *rowreq_ctx, u_long * sesUptime_val_ptr );
+    int sesCallingSID_get( sessionTable_rowreq_ctx *rowreq_ctx, char **sesCallingSID_val_ptr_ptr, size_t *sesCallingSID_val_ptr_len_ptr );
+    int sesCalledSID_get( sessionTable_rowreq_ctx *rowreq_ctx, char **sesCalledSID_val_ptr_ptr, size_t *sesCalledSID_val_ptr_len_ptr );
+
+
+int sessionTable_indexes_set_tbl_idx(sessionTable_mib_index *tbl_idx, char *sesSID_val_ptr,  size_t sesSID_val_ptr_len);
+int sessionTable_indexes_set(sessionTable_rowreq_ctx *rowreq_ctx, char *sesSID_val_ptr,  size_t sesSID_val_ptr_len);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SESSIONTABLE_DATA_GET_H */
+/** @} */
diff --git a/accel-pppd/extra/net-snmp/sessionTable_data_set.c b/accel-pppd/extra/net-snmp/sessionTable_data_set.c
new file mode 100644
index 00000000..ebfeeeaa
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable_data_set.c
@@ -0,0 +1,24 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *       version : 12077 $ of $
+ *
+ * $Id:$
+ *
+ */
+/* standard Net-SNMP includes */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+/* include our parent header */
+#include "sessionTable.h"
+
+
+/** @defgroup data_set data_set: Routines to set data
+ *
+ * These routines are used to set the value for individual objects. The
+ * row context is passed, along with the new value.
+ * 
+ * @{
+ */
+/** @} */
diff --git a/accel-pppd/extra/net-snmp/sessionTable_data_set.h b/accel-pppd/extra/net-snmp/sessionTable_data_set.h
new file mode 100644
index 00000000..70534baa
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable_data_set.h
@@ -0,0 +1,27 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *       version : 12077 $ of $ 
+ *
+ * $Id:$
+ */
+#ifndef SESSIONTABLE_DATA_SET_H
+#define SESSIONTABLE_DATA_SET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* *********************************************************************
+ * SET function declarations
+ */
+
+/* *********************************************************************
+ * SET Table declarations
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SESSIONTABLE_DATA_SET_H */
diff --git a/accel-pppd/extra/net-snmp/sessionTable_enums.h b/accel-pppd/extra/net-snmp/sessionTable_enums.h
new file mode 100644
index 00000000..c7ce8450
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable_enums.h
@@ -0,0 +1,85 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *  : generic-table-enums.m2c 12526 2005-07-15 22:41:16Z rstory $
+ *
+ * $Id:$
+ */
+#ifndef SESSIONTABLE_ENUMS_H
+#define SESSIONTABLE_ENUMS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /*
+ * NOTES on enums
+ * ==============
+ *
+ * Value Mapping
+ * -------------
+ * If the values for your data type don't exactly match the
+ * possible values defined by the mib, you should map them
+ * below. For example, a boolean flag (1/0) is usually represented
+ * as a TruthValue in a MIB, which maps to the values (1/2).
+ *
+ */
+/*************************************************************************
+ *************************************************************************
+ *
+ * enum definitions for table sessionTable
+ *
+ *************************************************************************
+ *************************************************************************/
+
+/*************************************************************
+ * constants for enums for the MIB node
+ * sesType (IANAtunnelType / ASN_INTEGER)
+ *
+ * since a Textual Convention may be referenced more than once in a
+ * MIB, protect againt redefinitions of the enum values.
+ */
+#ifndef IANATUNNELTYPE_ENUMS
+#define IANATUNNELTYPE_ENUMS
+
+#define IANATUNNELTYPE_OTHER  1 
+#define IANATUNNELTYPE_DIRECT  2 
+#define IANATUNNELTYPE_GRE  3 
+#define IANATUNNELTYPE_MINIMAL  4 
+#define IANATUNNELTYPE_L2TP  5 
+#define IANATUNNELTYPE_PPTP  6 
+#define IANATUNNELTYPE_L2F  7 
+#define IANATUNNELTYPE_UDP  8 
+#define IANATUNNELTYPE_ATMP  9 
+#define IANATUNNELTYPE_MSDP  10 
+#define IANATUNNELTYPE_SIXTOFOUR  11 
+#define IANATUNNELTYPE_SIXOVERFOUR  12 
+#define IANATUNNELTYPE_ISATAP  13 
+#define IANATUNNELTYPE_TEREDO  14 
+
+#endif /* IANATUNNELTYPE_ENUMS */
+
+
+/*************************************************************
+ * constants for enums for the MIB node
+ * sesState (INTEGER / ASN_INTEGER)
+ *
+ * since a Textual Convention may be referenced more than once in a
+ * MIB, protect againt redefinitions of the enum values.
+ */
+#ifndef SESSTATE_ENUMS
+#define SESSTATE_ENUMS
+
+#define SESSTATE_STARTING  1 
+#define SESSTATE_ACTIVE  2 
+#define SESSTATE_FINISHING  3 
+
+#endif /* SESSTATE_ENUMS */
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SESSIONTABLE_ENUMS_H */
diff --git a/accel-pppd/extra/net-snmp/sessionTable_interface.c b/accel-pppd/extra/net-snmp/sessionTable_interface.c
new file mode 100644
index 00000000..cf60f910
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable_interface.c
@@ -0,0 +1,946 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *       version : 15899 $ of $ 
+ *
+ * $Id:$
+ */
+/*
+ * *********************************************************************
+ * *********************************************************************
+ * *********************************************************************
+ * ***                                                               ***
+ * ***  NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE  ***
+ * ***                                                               ***
+ * ***                                                               ***
+ * ***       THIS FILE DOES NOT CONTAIN ANY USER EDITABLE CODE.      ***
+ * ***                                                               ***
+ * ***                                                               ***
+ * ***       THE GENERATED CODE IS INTERNAL IMPLEMENTATION, AND      ***
+ * ***                                                               ***
+ * ***                                                               ***
+ * ***    IS SUBJECT TO CHANGE WITHOUT WARNING IN FUTURE RELEASES.   ***
+ * ***                                                               ***
+ * ***                                                               ***
+ * *********************************************************************
+ * *********************************************************************
+ * *********************************************************************
+ */
+
+/* standard Net-SNMP includes */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+/* include our parent header */
+#include "sessionTable.h"
+
+
+#include <net-snmp/agent/table_container.h>
+#include <net-snmp/library/container.h>
+
+#include "sessionTable_interface.h"
+
+#include <ctype.h>
+
+/**********************************************************************
+ **********************************************************************
+ ***
+ *** Table sessionTable
+ ***
+ **********************************************************************
+ **********************************************************************/
+/*
+ * ACCEL-PPP-MIB::sessionTable is subid 1 of accelPPPSessions.
+ * Its status is Current.
+ * OID: .1.3.6.1.4.1.8072.100.2.1, length: 10
+*/
+typedef struct sessionTable_interface_ctx_s {
+
+   netsnmp_container              *container;
+   netsnmp_cache                  *cache;
+
+   sessionTable_registration *      user_ctx;
+   
+   netsnmp_table_registration_info  tbl_info;
+
+   netsnmp_baby_steps_access_methods access_multiplexer;
+
+} sessionTable_interface_ctx;
+
+static sessionTable_interface_ctx sessionTable_if_ctx;
+
+static void _sessionTable_container_init(
+    sessionTable_interface_ctx *if_ctx);
+static void _sessionTable_container_shutdown(
+    sessionTable_interface_ctx *if_ctx);
+
+
+netsnmp_container *
+sessionTable_container_get( void )
+{
+    return sessionTable_if_ctx.container;
+}
+
+sessionTable_registration *
+sessionTable_registration_get( void )
+{
+    return sessionTable_if_ctx.user_ctx;
+}
+
+sessionTable_registration *
+sessionTable_registration_set( sessionTable_registration * newreg )
+{
+    sessionTable_registration * old = sessionTable_if_ctx.user_ctx;
+    sessionTable_if_ctx.user_ctx = newreg;
+    return old;
+}
+
+int
+sessionTable_container_size( void )
+{
+    return CONTAINER_SIZE(sessionTable_if_ctx.container);
+}
+
+/*
+ * mfd multiplexer modes
+ */
+static Netsnmp_Node_Handler _mfd_sessionTable_pre_request;
+static Netsnmp_Node_Handler _mfd_sessionTable_post_request;
+static Netsnmp_Node_Handler _mfd_sessionTable_object_lookup;
+static Netsnmp_Node_Handler _mfd_sessionTable_get_values;
+/**
+ * @internal
+ * Initialize the table sessionTable 
+ *    (Define its contents and how it's structured)
+ */
+void
+_sessionTable_initialize_interface(sessionTable_registration * reg_ptr,  u_long flags)
+{
+    netsnmp_baby_steps_access_methods *access_multiplexer =
+        &sessionTable_if_ctx.access_multiplexer;
+    netsnmp_table_registration_info *tbl_info = &sessionTable_if_ctx.tbl_info;
+    netsnmp_handler_registration *reginfo;
+    netsnmp_mib_handler *handler;
+    int    mfd_modes = 0;
+
+    DEBUGMSGTL(("internal:sessionTable:_sessionTable_initialize_interface","called\n"));
+
+
+    /*************************************************
+     *
+     * save interface context for sessionTable
+     */
+    /*
+     * Setting up the table's definition
+     */
+    netsnmp_table_helper_add_indexes(tbl_info,
+                                  ASN_OCTET_STR, /** index: sesSID */
+                             0);
+
+    /*  Define the minimum and maximum accessible columns.  This
+        optimizes retrival. */
+    tbl_info->min_column = SESSIONTABLE_MIN_COL;
+    tbl_info->max_column = SESSIONTABLE_MAX_COL;
+
+    /*
+     * save users context
+     */
+    sessionTable_if_ctx.user_ctx = reg_ptr;
+
+    /*
+     * call data access initialization code
+     */
+    sessionTable_init_data(reg_ptr);
+
+    /*
+     * set up the container
+     */
+    _sessionTable_container_init(&sessionTable_if_ctx);
+    if (NULL == sessionTable_if_ctx.container) {
+        snmp_log(LOG_ERR,"could not initialize container for sessionTable\n");
+        return;
+    }
+    
+    /*
+     * access_multiplexer: REQUIRED wrapper for get request handling
+     */
+    access_multiplexer->object_lookup = _mfd_sessionTable_object_lookup;
+    access_multiplexer->get_values = _mfd_sessionTable_get_values;
+
+    /*
+     * no wrappers yet
+     */
+    access_multiplexer->pre_request = _mfd_sessionTable_pre_request;
+    access_multiplexer->post_request = _mfd_sessionTable_post_request;
+
+
+    /*************************************************
+     *
+     * Create a registration, save our reg data, register table.
+     */
+    DEBUGMSGTL(("sessionTable:init_sessionTable",
+                "Registering sessionTable as a mibs-for-dummies table.\n"));		 
+    handler = netsnmp_baby_steps_access_multiplexer_get(access_multiplexer);
+    reginfo = netsnmp_handler_registration_create("sessionTable", handler,
+                                                  sessionTable_oid,
+                                                  sessionTable_oid_size,
+                                                  HANDLER_CAN_BABY_STEP |
+                                                  HANDLER_CAN_RONLY
+                                                  );
+    if(NULL == reginfo) {
+        snmp_log(LOG_ERR,"error registering table sessionTable\n");
+        return;
+    }
+    reginfo->my_reg_void = &sessionTable_if_ctx;
+
+    /*************************************************
+     *
+     * set up baby steps handler, create it and inject it
+     */
+    if( access_multiplexer->object_lookup )
+        mfd_modes |= BABY_STEP_OBJECT_LOOKUP;
+    if( access_multiplexer->set_values )
+        mfd_modes |= BABY_STEP_SET_VALUES;
+    if( access_multiplexer->irreversible_commit )
+        mfd_modes |= BABY_STEP_IRREVERSIBLE_COMMIT;
+    if( access_multiplexer->object_syntax_checks )
+        mfd_modes |= BABY_STEP_CHECK_OBJECT;
+
+    if( access_multiplexer->pre_request )
+        mfd_modes |= BABY_STEP_PRE_REQUEST;
+    if( access_multiplexer->post_request )
+        mfd_modes |= BABY_STEP_POST_REQUEST;
+    
+    if( access_multiplexer->undo_setup )
+        mfd_modes |= BABY_STEP_UNDO_SETUP;
+    if( access_multiplexer->undo_cleanup )
+        mfd_modes |= BABY_STEP_UNDO_CLEANUP;
+    if( access_multiplexer->undo_sets )
+        mfd_modes |= BABY_STEP_UNDO_SETS;
+    
+    if( access_multiplexer->row_creation )
+        mfd_modes |= BABY_STEP_ROW_CREATE;
+    if( access_multiplexer->consistency_checks )
+        mfd_modes |= BABY_STEP_CHECK_CONSISTENCY;
+    if( access_multiplexer->commit )
+        mfd_modes |= BABY_STEP_COMMIT;
+    if( access_multiplexer->undo_commit )
+        mfd_modes |= BABY_STEP_UNDO_COMMIT;
+    
+    handler = netsnmp_baby_steps_handler_get(mfd_modes);
+    netsnmp_inject_handler(reginfo, handler);
+
+    /*************************************************
+     *
+     * inject row_merge helper with prefix rootoid_len + 2 (entry.col)
+     */
+    handler = netsnmp_get_row_merge_handler(reginfo->rootoid_len + 2);
+    netsnmp_inject_handler(reginfo, handler);
+
+    /*************************************************
+     *
+     * inject container_table helper
+     */
+    handler =
+        netsnmp_container_table_handler_get(tbl_info,
+                                            sessionTable_if_ctx.container,
+                                            TABLE_CONTAINER_KEY_NETSNMP_INDEX);
+    netsnmp_inject_handler( reginfo, handler );
+
+    /*************************************************
+     *
+     * inject cache helper
+     */
+    if(NULL != sessionTable_if_ctx.cache) {
+        handler = netsnmp_cache_handler_get(sessionTable_if_ctx.cache);
+        netsnmp_inject_handler( reginfo, handler );
+    }
+
+    /*
+     * register table
+     */
+    netsnmp_register_table(reginfo, tbl_info);
+
+} /* _sessionTable_initialize_interface */
+
+/**
+ * @internal
+ * Shutdown the table sessionTable
+ */
+void
+_sessionTable_shutdown_interface(sessionTable_registration * reg_ptr)
+{
+    /*
+     * shutdown the container
+     */
+    _sessionTable_container_shutdown(&sessionTable_if_ctx);
+}
+
+void
+sessionTable_valid_columns_set(netsnmp_column_info *vc)
+{
+    sessionTable_if_ctx.tbl_info.valid_columns = vc;
+} /* sessionTable_valid_columns_set */
+
+/**
+ * @internal
+ * convert the index component stored in the context to an oid
+ */
+int
+sessionTable_index_to_oid(netsnmp_index *oid_idx,
+                         sessionTable_mib_index *mib_idx)
+{
+    int err = SNMP_ERR_NOERROR;
+    
+    /*
+     * temp storage for parsing indexes
+     */
+    /*
+     * sesSID(1)/OCTETSTR/ASN_OCTET_STR/char(char)//L/A/w/e/R/d/h
+     */
+    netsnmp_variable_list var_sesSID;
+
+    /*
+     * set up varbinds
+     */
+    memset( &var_sesSID, 0x00, sizeof(var_sesSID) );
+    var_sesSID.type = ASN_OCTET_STR;
+
+    /*
+     * chain temp index varbinds together
+     */
+    var_sesSID.next_variable =  NULL;
+
+
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_index_to_oid","called\n"));
+
+        /* sesSID(1)/OCTETSTR/ASN_OCTET_STR/char(char)//L/A/w/e/R/d/h */
+    snmp_set_var_value(&var_sesSID, (u_char*)&mib_idx->sesSID,
+                       mib_idx->sesSID_len * sizeof(mib_idx->sesSID[0]));
+
+
+    err = build_oid_noalloc(oid_idx->oids, oid_idx->len, &oid_idx->len,
+                           NULL, 0, &var_sesSID);
+    if(err)
+        snmp_log(LOG_ERR,"error %d converting index to oid\n", err);
+
+    /*
+     * parsing may have allocated memory. free it.
+     */
+    snmp_reset_var_buffers( &var_sesSID );
+
+    return err;
+} /* sessionTable_index_to_oid */
+
+/**
+ * extract sessionTable indexes from a netsnmp_index
+ *
+ * @retval SNMP_ERR_NOERROR  : no error
+ * @retval SNMP_ERR_GENERR   : error
+ */
+int
+sessionTable_index_from_oid(netsnmp_index *oid_idx,
+                         sessionTable_mib_index *mib_idx)
+{
+    int err = SNMP_ERR_NOERROR;
+    
+    /*
+     * temp storage for parsing indexes
+     */
+    /*
+     * sesSID(1)/OCTETSTR/ASN_OCTET_STR/char(char)//L/A/w/e/R/d/h
+     */
+    netsnmp_variable_list var_sesSID;
+
+    /*
+     * set up varbinds
+     */
+    memset( &var_sesSID, 0x00, sizeof(var_sesSID) );
+    var_sesSID.type = ASN_OCTET_STR;
+
+    /*
+     * chain temp index varbinds together
+     */
+    var_sesSID.next_variable =  NULL;
+
+
+    DEBUGMSGTL(("verbose:sessionTable:sessionTable_index_from_oid","called\n"));
+
+    /*
+     * parse the oid into the individual index components
+     */
+    err = parse_oid_indexes( oid_idx->oids, oid_idx->len,
+                             &var_sesSID );
+    if (err == SNMP_ERR_NOERROR) {
+        /*
+         * copy out values
+         */
+    /*
+     * NOTE: val_len is in bytes, sesSID_len might not be
+     */
+         if(var_sesSID.val_len > sizeof(mib_idx->sesSID))
+             err = SNMP_ERR_GENERR;
+         else {
+             memcpy(mib_idx->sesSID, var_sesSID.val.string, var_sesSID.val_len);
+             mib_idx->sesSID_len = var_sesSID.val_len / sizeof(mib_idx->sesSID[0]);
+         }
+
+
+    }
+
+    /*
+     * parsing may have allocated memory. free it.
+     */
+    snmp_reset_var_buffers( &var_sesSID );
+
+    return err;
+} /* sessionTable_index_from_oid */
+
+
+/* *********************************************************************
+ * @internal
+ * allocate resources for a sessionTable_rowreq_ctx
+ */
+sessionTable_rowreq_ctx *
+sessionTable_allocate_rowreq_ctx(sessionTable_data *data, void *user_init_ctx)
+{
+    sessionTable_rowreq_ctx *rowreq_ctx =
+                  SNMP_MALLOC_TYPEDEF(sessionTable_rowreq_ctx);
+
+    DEBUGMSGTL(("internal:sessionTable:sessionTable_allocate_rowreq_ctx","called\n"));
+
+    if(NULL == rowreq_ctx) {
+        snmp_log(LOG_ERR,"Couldn't allocate memory for a "
+                 "sessionTable_rowreq_ctx.\n");
+        return NULL;
+    }
+    else {
+        if(NULL != data) {
+            /*
+             * track if we got data from user
+             */
+            rowreq_ctx->rowreq_flags |= MFD_ROW_DATA_FROM_USER;
+            rowreq_ctx->data = data;
+        }
+        else if (NULL == (rowreq_ctx->data = sessionTable_allocate_data())) {
+            SNMP_FREE(rowreq_ctx);
+            return NULL;
+        }
+    }
+
+    /*
+     * undo context will be allocated when needed (in *_undo_setup)
+     */
+
+    rowreq_ctx->oid_idx.oids = rowreq_ctx->oid_tmp;
+
+    rowreq_ctx->sessionTable_data_list = NULL;
+
+    /*
+     * if we allocated data, call init routine
+     */
+    if (!(rowreq_ctx->rowreq_flags & MFD_ROW_DATA_FROM_USER)) {
+        if(SNMPERR_SUCCESS !=
+            sessionTable_rowreq_ctx_init(rowreq_ctx, user_init_ctx)) {
+           sessionTable_release_rowreq_ctx(rowreq_ctx);
+           rowreq_ctx = NULL;
+        }
+    }
+
+    return rowreq_ctx;
+} /* sessionTable_allocate_rowreq_ctx */
+
+/*
+ * @internal
+ * release resources for a sessionTable_rowreq_ctx
+ */
+void
+sessionTable_release_rowreq_ctx(sessionTable_rowreq_ctx *rowreq_ctx)
+{
+    DEBUGMSGTL(("internal:sessionTable:sessionTable_release_rowreq_ctx","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+    
+    sessionTable_rowreq_ctx_cleanup(rowreq_ctx);
+
+    /*
+     * for non-transient data, don't free data we got from the user
+     */
+    if ((rowreq_ctx->data) &&
+        !(rowreq_ctx->rowreq_flags & MFD_ROW_DATA_FROM_USER))
+        sessionTable_release_data(rowreq_ctx->data);
+ 
+    /*
+     * free index oid pointer
+     */
+    if(rowreq_ctx->oid_idx.oids != rowreq_ctx->oid_tmp)
+        free(rowreq_ctx->oid_idx.oids);
+
+    SNMP_FREE(rowreq_ctx);
+} /* sessionTable_release_rowreq_ctx */
+
+/**
+ * @internal
+ * wrapper
+ */
+static int
+_mfd_sessionTable_pre_request(netsnmp_mib_handler *handler,
+                            netsnmp_handler_registration *reginfo,
+                            netsnmp_agent_request_info *agtreq_info,
+                            netsnmp_request_info *requests)
+{
+    int rc;
+
+    DEBUGMSGTL(("internal:sessionTable:_mfd_sessionTable_pre_request",
+                "called\n"));
+    
+    if (1 != netsnmp_row_merge_status_first(reginfo, agtreq_info)) {
+        DEBUGMSGTL(("internal:sessionTable",
+                    "skipping additional pre_request\n"));
+        return SNMP_ERR_NOERROR;
+    }
+        
+    rc = sessionTable_pre_request(sessionTable_if_ctx.user_ctx);
+    if (MFD_SUCCESS != rc) {
+        /*
+         * nothing we can do about it but log it
+         */
+        DEBUGMSGTL(("sessionTable","error %d from "
+                    "sessionTable_pre_request\n", rc));
+        netsnmp_request_set_error_all(requests, SNMP_VALIDATE_ERR(rc));
+    }
+    
+    return SNMP_ERR_NOERROR;
+} /* _mfd_sessionTable_pre_request */
+
+/**
+ * @internal
+ * wrapper
+ */
+static int
+_mfd_sessionTable_post_request(netsnmp_mib_handler *handler,
+                             netsnmp_handler_registration *reginfo,
+                             netsnmp_agent_request_info *agtreq_info,
+                             netsnmp_request_info *requests)
+{
+    sessionTable_rowreq_ctx *rowreq_ctx =
+                  netsnmp_container_table_row_extract(requests);
+    int rc, packet_rc;
+
+    DEBUGMSGTL(("internal:sessionTable:_mfd_sessionTable_post_request",
+                "called\n"));
+
+    /*
+     * release row context, if deleted
+     */
+    if (rowreq_ctx && (rowreq_ctx->rowreq_flags & MFD_ROW_DELETED))
+        sessionTable_release_rowreq_ctx(rowreq_ctx);
+
+    /*
+     * wait for last call before calling user
+     */
+    if (1 != netsnmp_row_merge_status_last(reginfo, agtreq_info)) {
+        DEBUGMSGTL(("internal:sessionTable",
+                    "waiting for last post_request\n"));
+        return SNMP_ERR_NOERROR;
+    }
+    
+    packet_rc = netsnmp_check_all_requests_error(agtreq_info->asp, 0);
+    rc = sessionTable_post_request(sessionTable_if_ctx.user_ctx,packet_rc);
+    if (MFD_SUCCESS != rc) {
+        /*
+         * nothing we can do about it but log it
+         */
+        DEBUGMSGTL(("sessionTable","error %d from "
+                    "sessionTable_post_request\n", rc));
+    }
+    
+    return SNMP_ERR_NOERROR;
+} /* _mfd_sessionTable_post_request */
+
+/**
+ * @internal
+ * wrapper
+ */
+static int
+_mfd_sessionTable_object_lookup(netsnmp_mib_handler *handler,
+                         netsnmp_handler_registration *reginfo,
+                         netsnmp_agent_request_info *agtreq_info,
+                         netsnmp_request_info *requests)
+{
+    int                    rc = SNMP_ERR_NOERROR;
+    sessionTable_rowreq_ctx *rowreq_ctx =
+                  netsnmp_container_table_row_extract(requests);
+    
+    DEBUGMSGTL(("internal:sessionTable:_mfd_sessionTable_object_lookup","called\n"));
+
+    /*
+     * get our context from mfd
+     * sessionTable_interface_ctx *if_ctx =
+     *             (sessionTable_interface_ctx *)reginfo->my_reg_void;
+     */
+
+    if(NULL == rowreq_ctx) {
+        rc = SNMP_ERR_NOCREATION;
+    }
+
+    if (MFD_SUCCESS != rc)
+        netsnmp_request_set_error_all(requests, rc);
+    else
+        sessionTable_row_prep(rowreq_ctx);
+
+    return SNMP_VALIDATE_ERR(rc);
+} /* _mfd_sessionTable_object_lookup */
+
+/***********************************************************************
+ *
+ * GET processing
+ *
+ ***********************************************************************/
+/*
+ * @internal
+ * Retrieve the value for a particular column
+ */
+NETSNMP_STATIC_INLINE int
+_sessionTable_get_column( sessionTable_rowreq_ctx *rowreq_ctx,
+                       netsnmp_variable_list *var, int column )
+{
+    int rc = SNMPERR_SUCCESS;
+    
+    DEBUGMSGTL(("internal:sessionTable:_mfd_sessionTable_get_column",
+                "called for %d\n", column));
+
+
+    netsnmp_assert(NULL != rowreq_ctx);
+
+    switch(column) {
+
+    /* (INDEX) sesSID(1)/OCTETSTR/ASN_OCTET_STR/char(char)//L/A/w/e/R/d/h */
+    case COLUMN_SESSID:
+    var->type = ASN_OCTET_STR;
+    /*
+     * NOTE: val_len is in bytes, sesSID_len might not be (e.g. oids)
+     */
+        if (var->val_len < (rowreq_ctx->tbl_idx.sesSID_len *
+                            sizeof(rowreq_ctx->tbl_idx.sesSID[0]))) {
+           var->val.string = malloc(rowreq_ctx->tbl_idx.sesSID_len *
+                                    sizeof(rowreq_ctx->tbl_idx.sesSID[0]));
+        }
+        var->val_len = rowreq_ctx->tbl_idx.sesSID_len * sizeof(rowreq_ctx->tbl_idx.sesSID[0]);
+        memcpy( var->val.string, rowreq_ctx->tbl_idx.sesSID, var->val_len );
+        break;
+
+    /* sesIfName(2)/OCTETSTR/ASN_OCTET_STR/char(char)//L/A/w/e/r/d/h */
+    case COLUMN_SESIFNAME:
+    var->type = ASN_OCTET_STR;
+rc = sesIfName_get(rowreq_ctx, (char **)&var->val.string, &var->val_len );
+        break;
+
+    /* sesUsername(3)/OCTETSTR/ASN_OCTET_STR/char(char)//L/A/w/e/r/d/h */
+    case COLUMN_SESUSERNAME:
+    var->type = ASN_OCTET_STR;
+rc = sesUsername_get(rowreq_ctx, (char **)&var->val.string, &var->val_len );
+        break;
+
+    /* sesIP(4)/InetAddressIPv4/ASN_OCTET_STR/char(char)//L/A/w/e/R/d/H */
+    case COLUMN_SESIP:
+    var->type = ASN_OCTET_STR;
+rc = sesIP_get(rowreq_ctx, (char **)&var->val.string, &var->val_len );
+        break;
+
+    /* sesType(5)/INTEGER/ASN_INTEGER/long(u_long)//l/A/w/E/r/d/h */
+    case COLUMN_SESTYPE:
+    var->val_len = sizeof(u_long);
+    var->type = ASN_INTEGER;
+rc = sesType_get(rowreq_ctx, (u_long *)var->val.string );
+        break;
+
+    /* sesState(6)/INTEGER/ASN_INTEGER/long(u_long)//l/A/w/E/r/d/h */
+    case COLUMN_SESSTATE:
+    var->val_len = sizeof(u_long);
+    var->type = ASN_INTEGER;
+rc = sesState_get(rowreq_ctx, (u_long *)var->val.string );
+        break;
+
+    /* sesUptime(7)/GAUGE/ASN_GAUGE/u_long(u_long)//l/A/w/e/r/d/h */
+    case COLUMN_SESUPTIME:
+    var->val_len = sizeof(u_long);
+    var->type = ASN_GAUGE;
+rc = sesUptime_get(rowreq_ctx, (u_long *)var->val.string );
+        break;
+
+    /* sesCallingSID(8)/OCTETSTR/ASN_OCTET_STR/char(char)//L/A/w/e/r/d/h */
+    case COLUMN_SESCALLINGSID:
+    var->type = ASN_OCTET_STR;
+rc = sesCallingSID_get(rowreq_ctx, (char **)&var->val.string, &var->val_len );
+        break;
+
+    /* sesCalledSID(9)/OCTETSTR/ASN_OCTET_STR/char(char)//L/A/w/e/r/d/h */
+    case COLUMN_SESCALLEDSID:
+    var->type = ASN_OCTET_STR;
+rc = sesCalledSID_get(rowreq_ctx, (char **)&var->val.string, &var->val_len );
+        break;
+
+     default:
+        if (SESSIONTABLE_MIN_COL <= column && column <= SESSIONTABLE_MAX_COL) {
+            DEBUGMSGTL(("internal:sessionTable:_mfd_sessionTable_get_column",
+                "assume column %d is reserved\n", column));
+            rc = MFD_SKIP;
+        } else {
+            snmp_log(LOG_ERR,
+                "unknown column %d in _sessionTable_get_column\n", column);
+        }
+        break;
+    }
+
+    return rc;
+} /* _sessionTable_get_column */
+
+int
+_mfd_sessionTable_get_values(netsnmp_mib_handler *handler,
+                         netsnmp_handler_registration *reginfo,
+                         netsnmp_agent_request_info *agtreq_info,
+                         netsnmp_request_info *requests)
+{
+    sessionTable_rowreq_ctx *rowreq_ctx =
+                  netsnmp_container_table_row_extract(requests);
+    netsnmp_table_request_info * tri;
+    u_char                     * old_string;
+    void                      (*dataFreeHook)(void *);
+    int                        rc;
+
+    DEBUGMSGTL(("internal:sessionTable:_mfd_sessionTable_get_values","called\n"));
+
+    netsnmp_assert(NULL != rowreq_ctx);
+    
+    for(;requests; requests = requests->next) {
+        /*
+         * save old pointer, so we can free it if replaced
+         */
+        old_string = requests->requestvb->val.string;
+        dataFreeHook = requests->requestvb->dataFreeHook;
+        if(NULL == requests->requestvb->val.string) {
+            requests->requestvb->val.string = requests->requestvb->buf;
+            requests->requestvb->val_len = sizeof(requests->requestvb->buf);
+        }
+        else if(requests->requestvb->buf == requests->requestvb->val.string) {
+            if(requests->requestvb->val_len != sizeof(requests->requestvb->buf))
+                requests->requestvb->val_len = sizeof(requests->requestvb->buf);
+        }
+
+        /*
+         * get column data
+         */
+        tri = netsnmp_extract_table_info(requests);
+        if(NULL == tri)
+            continue;
+        
+        rc = _sessionTable_get_column(rowreq_ctx, requests->requestvb, tri->colnum);
+        if(rc) {
+            if(MFD_SKIP == rc) {
+                requests->requestvb->type = SNMP_NOSUCHINSTANCE;
+                rc = SNMP_ERR_NOERROR;
+            }
+        }
+        else if (NULL == requests->requestvb->val.string) {
+            snmp_log(LOG_ERR,"NULL varbind data pointer!\n");
+            rc = SNMP_ERR_GENERR;
+        }
+        if(rc)
+            netsnmp_request_set_error(requests, SNMP_VALIDATE_ERR(rc));
+
+        /*
+         * if the buffer wasn't used previously for the old data (i.e. it
+         * was allcoated memory)  and the get routine replaced the pointer,
+         * we need to free the previous pointer.
+         */
+        if(old_string && (old_string != requests->requestvb->buf) &&
+           (requests->requestvb->val.string != old_string)) {
+            if(dataFreeHook)
+                (*dataFreeHook)(old_string);
+            else
+                free(old_string);
+        }
+    } /* for results */
+
+    return SNMP_ERR_NOERROR;
+} /* _mfd_sessionTable_get_values */
+
+
+/***********************************************************************
+ *
+ * SET processing
+ *
+ ***********************************************************************/
+
+/*
+ * SET PROCESSING NOT APPLICABLE (per MIB or user setting)
+ */
+/***********************************************************************
+ *
+ * DATA ACCESS
+ *
+ ***********************************************************************/
+static void _container_free(netsnmp_container *container);
+
+/**
+ * @internal
+ */
+static int
+_cache_load(netsnmp_cache *cache, void *vmagic)
+{
+    DEBUGMSGTL(("internal:sessionTable:_cache_load","called\n"));
+
+    if((NULL == cache) || (NULL == cache->magic)) {
+        snmp_log(LOG_ERR, "invalid cache for sessionTable_cache_load\n");
+        return -1;
+    }
+
+    /** should only be called for an invalid or expired cache */
+    netsnmp_assert((0 == cache->valid) || (1 == cache->expired));
+    
+    /*
+     * call user code
+     */
+    return sessionTable_container_load((netsnmp_container*)cache->magic);
+} /* _cache_load */
+
+/**
+ * @internal
+ */
+static void
+_cache_free(netsnmp_cache *cache, void *magic)
+{
+    netsnmp_container *container;
+
+    DEBUGMSGTL(("internal:sessionTable:_cache_free","called\n"));
+
+    if((NULL == cache) || (NULL == cache->magic)) {
+        snmp_log(LOG_ERR, "invalid cache in sessionTable_cache_free\n");
+        return;
+    }
+
+    container = (netsnmp_container*)cache->magic;
+
+    _container_free(container);
+} /* _cache_free */
+
+/**
+ * @internal
+ */
+static void
+_container_item_free(sessionTable_rowreq_ctx *rowreq_ctx, void *context)
+{
+    DEBUGMSGTL(("internal:sessionTable:_container_item_free","called\n"));
+
+    if(NULL == rowreq_ctx)
+        return;
+
+    sessionTable_release_rowreq_ctx(rowreq_ctx);
+} /* _container_item_free */
+
+/**
+ * @internal
+ */
+static void
+_container_free(netsnmp_container *container)
+{
+    DEBUGMSGTL(("internal:sessionTable:_container_free","called\n"));
+
+    if (NULL == container) {
+        snmp_log(LOG_ERR, "invalid container in sessionTable_container_free\n");
+        return;
+    }
+
+    /*
+     * call user code
+     */
+    sessionTable_container_free(container);
+    
+    /*
+     * free all items. inefficient, but easy.
+     */
+    CONTAINER_CLEAR(container,
+                    (netsnmp_container_obj_func *)_container_item_free,
+                    NULL);
+} /* _container_free */
+
+/**
+ * @internal
+ * initialize the container with functions or wrappers
+ */
+void
+_sessionTable_container_init(sessionTable_interface_ctx *if_ctx)
+{
+    DEBUGMSGTL(("internal:sessionTable:_sessionTable_container_init","called\n"));
+
+    /*
+     * cache init
+     */
+    if_ctx->cache = netsnmp_cache_create(30, /* timeout in seconds */
+                                         _cache_load, _cache_free,
+                                         sessionTable_oid,
+                                         sessionTable_oid_size);
+
+    if(NULL == if_ctx->cache) {
+        snmp_log(LOG_ERR, "error creating cache for sessionTable\n");
+        return;
+    }
+
+    if_ctx->cache->flags = NETSNMP_CACHE_DONT_INVALIDATE_ON_SET;
+
+    sessionTable_container_init(&if_ctx->container, if_ctx->cache);
+    if(NULL == if_ctx->container)
+        if_ctx->container = netsnmp_container_find("sessionTable:table_container");
+    if(NULL == if_ctx->container) {
+        snmp_log(LOG_ERR,"error creating container in "
+                 "sessionTable_container_init\n");
+        return;
+    }
+
+    if (NULL != if_ctx->cache)
+        if_ctx->cache->magic = (void*)if_ctx->container;
+} /* _sessionTable_container_init */
+
+/**
+ * @internal
+ * shutdown the container with functions or wrappers
+ */
+void
+_sessionTable_container_shutdown(sessionTable_interface_ctx *if_ctx)
+{
+    DEBUGMSGTL(("internal:sessionTable:_sessionTable_container_shutdown","called\n"));
+
+    sessionTable_container_shutdown(if_ctx->container);
+
+    _container_free(if_ctx->container);
+
+} /* _sessionTable_container_shutdown */
+
+
+sessionTable_rowreq_ctx *
+sessionTable_row_find_by_mib_index(sessionTable_mib_index *mib_idx)
+{
+    sessionTable_rowreq_ctx   *rowreq_ctx;
+    oid                      oid_tmp[MAX_OID_LEN];
+    netsnmp_index            oid_idx;
+    int                      rc;
+
+    /*
+     * set up storage for OID
+     */
+    oid_idx.oids = oid_tmp;
+    oid_idx.len = sizeof(oid_tmp)/sizeof(oid);
+
+    /*
+     * convert
+     */
+    rc = sessionTable_index_to_oid(&oid_idx, mib_idx);
+    if (MFD_SUCCESS != rc)
+        return NULL;
+
+    rowreq_ctx = CONTAINER_FIND(sessionTable_if_ctx.container, &oid_idx);
+
+    return rowreq_ctx;
+}
+
diff --git a/accel-pppd/extra/net-snmp/sessionTable_interface.h b/accel-pppd/extra/net-snmp/sessionTable_interface.h
new file mode 100644
index 00000000..ebd1143d
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable_interface.h
@@ -0,0 +1,84 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *       version : 15899 $ of $
+ *
+ * $Id:$
+ */
+/** @ingroup interface: Routines to interface to Net-SNMP
+ *
+ * \warning This code should not be modified, called directly,
+ *          or used to interpret functionality. It is subject to
+ *          change at any time.
+ * 
+ * @{
+ */
+/*
+ * *********************************************************************
+ * *********************************************************************
+ * *********************************************************************
+ * ***                                                               ***
+ * ***  NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE  ***
+ * ***                                                               ***
+ * ***                                                               ***
+ * ***       THIS FILE DOES NOT CONTAIN ANY USER EDITABLE CODE.      ***
+ * ***                                                               ***
+ * ***                                                               ***
+ * ***       THE GENERATED CODE IS INTERNAL IMPLEMENTATION, AND      ***
+ * ***                                                               ***
+ * ***                                                               ***
+ * ***    IS SUBJECT TO CHANGE WITHOUT WARNING IN FUTURE RELEASES.   ***
+ * ***                                                               ***
+ * ***                                                               ***
+ * *********************************************************************
+ * *********************************************************************
+ * *********************************************************************
+ */
+#ifndef SESSIONTABLE_INTERFACE_H
+#define SESSIONTABLE_INTERFACE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "sessionTable.h"
+
+
+/* ********************************************************************
+ * Table declarations
+ */
+
+/* PUBLIC interface initialization routine */
+void _sessionTable_initialize_interface(sessionTable_registration * user_ctx,
+                                    u_long flags);
+void _sessionTable_shutdown_interface(sessionTable_registration * user_ctx);
+
+sessionTable_registration *
+sessionTable_registration_get( void );
+
+sessionTable_registration *
+sessionTable_registration_set( sessionTable_registration * newreg );
+
+netsnmp_container *sessionTable_container_get( void );
+int sessionTable_container_size( void );
+
+    sessionTable_rowreq_ctx * sessionTable_allocate_rowreq_ctx(sessionTable_data *, void *);
+void sessionTable_release_rowreq_ctx(sessionTable_rowreq_ctx *rowreq_ctx);
+
+int sessionTable_index_to_oid(netsnmp_index *oid_idx,
+                            sessionTable_mib_index *mib_idx);
+int sessionTable_index_from_oid(netsnmp_index *oid_idx,
+                              sessionTable_mib_index *mib_idx);
+
+/*
+ * access to certain internals. use with caution!
+ */
+void sessionTable_valid_columns_set(netsnmp_column_info *vc);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SESSIONTABLE_INTERFACE_H */
+/** @} */
diff --git a/accel-pppd/extra/net-snmp/sessionTable_oids.h b/accel-pppd/extra/net-snmp/sessionTable_oids.h
new file mode 100644
index 00000000..42ec6e53
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/sessionTable_oids.h
@@ -0,0 +1,46 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *  : generic-table-oids.m2c 12855 2005-09-27 15:56:08Z rstory $
+ *
+ * $Id:$
+ */
+#ifndef SESSIONTABLE_OIDS_H
+#define SESSIONTABLE_OIDS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* column number definitions for table sessionTable */
+#define SESSIONTABLE_OID              1,3,6,1,4,1,8072,100,2,1
+
+#define COLUMN_SESSID         1
+    
+#define COLUMN_SESIFNAME         2
+    
+#define COLUMN_SESUSERNAME         3
+    
+#define COLUMN_SESIP         4
+    
+#define COLUMN_SESTYPE         5
+    
+#define COLUMN_SESSTATE         6
+    
+#define COLUMN_SESUPTIME         7
+    
+#define COLUMN_SESCALLINGSID         8
+    
+#define COLUMN_SESCALLEDSID         9
+    
+
+#define SESSIONTABLE_MIN_COL   COLUMN_SESSID
+#define SESSIONTABLE_MAX_COL   COLUMN_SESCALLEDSID
+    
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SESSIONTABLE_OIDS_H */
diff --git a/accel-pppd/extra/net-snmp/shutdown.c b/accel-pppd/extra/net-snmp/shutdown.c
new file mode 100644
index 00000000..82f85407
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/shutdown.c
@@ -0,0 +1,88 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include "shutdown.h"
+
+/** Initializes the shutdown module */
+void
+init_shutdown(void)
+{
+    static oid shutdown_oid[] = { 1,3,6,1,4,1,8072,100,3,2 };
+
+  DEBUGMSGTL(("shutdown", "Initializing\n"));
+
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("shutdown", handle_shutdown,
+                               shutdown_oid, OID_LENGTH(shutdown_oid),
+                               HANDLER_CAN_RWRITE
+        ));
+}
+
+int
+handle_shutdown(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int ret;
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE );
+            break;
+
+        /*
+         * SET REQUEST
+         *
+         * multiple states in the transaction.  See:
+         * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
+         */
+        case MODE_SET_RESERVE1:
+                /* or you could use netsnmp_check_vb_type_and_size instead */
+            ret = netsnmp_check_vb_type(requests->requestvb, ASN_INTEGER);
+            if ( ret != SNMP_ERR_NOERROR ) {
+                netsnmp_set_request_error(reqinfo, requests, ret );
+            }
+            break;
+
+        case MODE_SET_RESERVE2:
+            /* XXX malloc "undo" storage buffer */
+            break;
+
+        case MODE_SET_FREE:
+            /* XXX: free resources allocated in RESERVE1 and/or
+               RESERVE2.  Something failed somewhere, and the states
+               below won't be called. */
+            break;
+
+        case MODE_SET_ACTION:
+            /* XXX: perform the value change here */
+            break;
+
+        case MODE_SET_COMMIT:
+            /* XXX: delete temporary storage */
+            break;
+
+        case MODE_SET_UNDO:
+            /* XXX: UNDO and return to previous value for the object */
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_shutdown\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
diff --git a/accel-pppd/extra/net-snmp/shutdown.h b/accel-pppd/extra/net-snmp/shutdown.h
new file mode 100644
index 00000000..02bda945
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/shutdown.h
@@ -0,0 +1,12 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $
+ */
+#ifndef SHUTDOWN_H
+#define SHUTDOWN_H
+
+/* function declarations */
+void init_shutdown(void);
+Netsnmp_Node_Handler handle_shutdown;
+
+#endif /* SHUTDOWN_H */
diff --git a/accel-pppd/extra/net-snmp/statCore.c b/accel-pppd/extra/net-snmp/statCore.c
new file mode 100644
index 00000000..74a6b35b
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/statCore.c
@@ -0,0 +1,147 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $
+ */
+
+#include <time.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include "triton.h"
+#include "statCore.h"
+
+/** Initializes the statCore module */
+void
+init_statCore(void)
+{
+    static oid statCoreUpTime_oid[] = { 1,3,6,1,4,1,8072,100,1,1,1 };
+    static oid statCoreCPU_oid[] = { 1,3,6,1,4,1,8072,100,1,1,2 };
+    static oid statCoreMemRss_oid[] = { 1,3,6,1,4,1,8072,100,1,1,3 };
+
+  DEBUGMSGTL(("statCore", "Initializing\n"));
+
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("statCoreUpTime", handle_statCoreUpTime,
+                               statCoreUpTime_oid, OID_LENGTH(statCoreUpTime_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("statCoreCPU", handle_statCoreCPU,
+                               statCoreCPU_oid, OID_LENGTH(statCoreCPU_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("statCoreMemRss", handle_statCoreMemRss,
+                               statCoreMemRss_oid, OID_LENGTH(statCoreMemRss_oid),
+                               HANDLER_CAN_RONLY
+        ));
+}
+
+int
+handle_statCoreUpTime(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+		struct timespec ts;
+
+		clock_gettime(CLOCK_MONOTONIC, &ts);
+		ts.tv_sec -= triton_stat.start_time;
+
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
+                                     (u_char *)&ts.tv_sec /* XXX: a pointer to the scalar's data */,
+                                     sizeof(ts.tv_sec)/* XXX: the length of the data in bytes */);
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_statCoreUpTime\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_statCoreCPU(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+                                     (u_char *)&triton_stat.cpu /* XXX: a pointer to the scalar's data */,
+                                     sizeof(triton_stat.cpu)/* XXX: the length of the data in bytes */);
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_statCoreCPU\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_statCoreMemRss(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+	char statm_fname[128];
+	FILE *f;
+	unsigned long vmsize = 0, vmrss = 0;
+	unsigned long page_size = sysconf(_SC_PAGE_SIZE);
+
+	sprintf(statm_fname, "/proc/%i/statm", getpid());
+	f = fopen(statm_fname, "r");
+	if (f) {
+		fscanf(f, "%lu %lu", &vmsize, &vmrss);
+		fclose(f);
+	}
+	
+	vmrss *= page_size;
+
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+                                     (u_char *)&vmrss /* XXX: a pointer to the scalar's data */,
+                                     sizeof(vmrss)/* XXX: the length of the data in bytes */);
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_statCoreMemRss\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
diff --git a/accel-pppd/extra/net-snmp/statCore.h b/accel-pppd/extra/net-snmp/statCore.h
new file mode 100644
index 00000000..1a096854
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/statCore.h
@@ -0,0 +1,14 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $
+ */
+#ifndef STATCORE_H
+#define STATCORE_H
+
+/* function declarations */
+void init_statCore(void);
+Netsnmp_Node_Handler handle_statCoreUpTime;
+Netsnmp_Node_Handler handle_statCoreCPU;
+Netsnmp_Node_Handler handle_statCoreMemRss;
+
+#endif /* STATCORE_H */
diff --git a/accel-pppd/extra/net-snmp/statL2TP.c b/accel-pppd/extra/net-snmp/statL2TP.c
new file mode 100644
index 00000000..a91d336a
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/statL2TP.c
@@ -0,0 +1,94 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.int_watch.conf 13957 2005-12-20 15:33:08Z tanders $
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include "triton.h"
+#include "statL2TP.h"
+
+
+/*
+ * The variables we want to tie the relevant OIDs to.
+ * The agent will handle all GET and (if applicable) SET requests
+ * to these variables automatically, changing the values as needed.
+ */
+
+void l2tp_get_stat(unsigned int **, unsigned int **);
+
+static unsigned int *stat_starting;
+static unsigned int *stat_active;
+
+/*
+ * Our initialization routine, called automatically by the agent 
+ * (Note that the function name must match init_FILENAME()) 
+ */
+void
+init_statL2TP(void)
+{
+  netsnmp_handler_registration *reg;
+  netsnmp_watcher_info         *winfo;
+
+    static oid statL2TPStarting_oid[] = { 1,3,6,1,4,1,8072,100,1,4,1 };
+    static oid statL2TPActive_oid[] = { 1,3,6,1,4,1,8072,100,1,4,2 };
+
+  /*
+   * a debugging statement.  Run the agent with -DstatL2TP to see
+   * the output of this debugging statement. 
+   */
+  DEBUGMSGTL(("statL2TP", "Initializing the statL2TP module\n"));
+
+	if (!triton_module_loaded("l2tp"))
+		return;
+
+	l2tp_get_stat(&stat_starting, &stat_active);
+
+    /*
+     * Register scalar watchers for each of the MIB objects.
+     * The ASN type and RO/RW status are taken from the MIB definition,
+     * but can be adjusted if needed.
+     *
+     * In most circumstances, the scalar watcher will handle all
+     * of the necessary processing.  But the NULL parameter in the
+     * netsnmp_create_handler_registration() call can be used to
+     * supply a user-provided handler if necessary.
+     *
+     * This approach can also be used to handle Counter64, string-
+     * and OID-based watched scalars (although variable-sized writeable
+     * objects will need some more specialised initialisation).
+     */
+    DEBUGMSGTL(("statL2TP",
+                "Initializing statL2TPStarting scalar integer.  Default value = %d\n",
+                0));
+    reg = netsnmp_create_handler_registration(
+             "statL2TPStarting", NULL,
+              statL2TPStarting_oid, OID_LENGTH(statL2TPStarting_oid),
+              HANDLER_CAN_RONLY);
+    winfo = netsnmp_create_watcher_info(
+                stat_starting, sizeof(*stat_starting),
+                 ASN_INTEGER, WATCHER_FIXED_SIZE);
+    if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) {
+        snmp_log( LOG_ERR, "Failed to register watched statL2TPStarting" );
+    }
+
+    DEBUGMSGTL(("statL2TP",
+                "Initializing statL2TPActive scalar integer.  Default value = %d\n",
+                0));
+    reg = netsnmp_create_handler_registration(
+             "statL2TPActive", NULL,
+              statL2TPActive_oid, OID_LENGTH(statL2TPActive_oid),
+              HANDLER_CAN_RONLY);
+    winfo = netsnmp_create_watcher_info(
+                stat_active, sizeof(*stat_active),
+                 ASN_INTEGER, WATCHER_FIXED_SIZE);
+    if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) {
+        snmp_log( LOG_ERR, "Failed to register watched statL2TPActive" );
+    }
+
+
+  DEBUGMSGTL(("statL2TP",
+              "Done initalizing statL2TP module\n"));
+}
diff --git a/accel-pppd/extra/net-snmp/statL2TP.h b/accel-pppd/extra/net-snmp/statL2TP.h
new file mode 100644
index 00000000..e0389060
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/statL2TP.h
@@ -0,0 +1,11 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.int_watch.conf 13957 2005-12-20 15:33:08Z tanders $
+ */
+#ifndef STATL2TP_H
+#define STATL2TP_H
+
+/* function declarations */
+void init_statL2TP(void);
+
+#endif /* STATL2TP_H */
diff --git a/accel-pppd/extra/net-snmp/statPPP.c b/accel-pppd/extra/net-snmp/statPPP.c
new file mode 100644
index 00000000..7199b570
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/statPPP.c
@@ -0,0 +1,93 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.int_watch.conf 13957 2005-12-20 15:33:08Z tanders $
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include "statPPP.h"
+
+#include "ppp.h"
+
+/*
+ * Our initialization routine, called automatically by the agent 
+ * (Note that the function name must match init_FILENAME()) 
+ */
+void
+init_statPPP(void)
+{
+  netsnmp_handler_registration *reg;
+  netsnmp_watcher_info         *winfo;
+
+    static oid statPPPStarting_oid[] = { 1,3,6,1,4,1,8072,100,1,2,1 };
+    static oid statPPPActive_oid[] = { 1,3,6,1,4,1,8072,100,1,2,2 };
+    static oid statPPPFinishing_oid[] = { 1,3,6,1,4,1,8072,100,1,2,3 };
+
+  /*
+   * a debugging statement.  Run the agent with -DstatPPP to see
+   * the output of this debugging statement. 
+   */
+  DEBUGMSGTL(("statPPP", "Initializing the statPPP module\n"));
+
+
+    /*
+     * Register scalar watchers for each of the MIB objects.
+     * The ASN type and RO/RW status are taken from the MIB definition,
+     * but can be adjusted if needed.
+     *
+     * In most circumstances, the scalar watcher will handle all
+     * of the necessary processing.  But the NULL parameter in the
+     * netsnmp_create_handler_registration() call can be used to
+     * supply a user-provided handler if necessary.
+     *
+     * This approach can also be used to handle Counter64, string-
+     * and OID-based watched scalars (although variable-sized writeable
+     * objects will need some more specialised initialisation).
+     */
+    DEBUGMSGTL(("statPPP",
+                "Initializing statPPPStarting scalar integer.  Default value = %d\n",
+                0));
+    reg = netsnmp_create_handler_registration(
+             "statPPPStarting", NULL,
+              statPPPStarting_oid, OID_LENGTH(statPPPStarting_oid),
+              HANDLER_CAN_RONLY);
+    winfo = netsnmp_create_watcher_info(
+                &ppp_stat.starting, sizeof(ppp_stat.starting),
+                 ASN_INTEGER, WATCHER_FIXED_SIZE);
+    if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) {
+        snmp_log( LOG_ERR, "Failed to register watched statPPPStarting" );
+    }
+
+    DEBUGMSGTL(("statPPP",
+                "Initializing statPPPActive scalar integer.  Default value = %d\n",
+                0));
+    reg = netsnmp_create_handler_registration(
+             "statPPPActive", NULL,
+              statPPPActive_oid, OID_LENGTH(statPPPActive_oid),
+              HANDLER_CAN_RONLY);
+    winfo = netsnmp_create_watcher_info(
+                &ppp_stat.active, sizeof(ppp_stat.active),
+                 ASN_INTEGER, WATCHER_FIXED_SIZE);
+    if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) {
+        snmp_log( LOG_ERR, "Failed to register watched statPPPActive" );
+    }
+
+    DEBUGMSGTL(("statPPP",
+                "Initializing statPPPFinishing scalar integer.  Default value = %d\n",
+                0));
+    reg = netsnmp_create_handler_registration(
+             "statPPPFinishing", NULL,
+              statPPPFinishing_oid, OID_LENGTH(statPPPFinishing_oid),
+              HANDLER_CAN_RONLY);
+    winfo = netsnmp_create_watcher_info(
+                &ppp_stat.finishing, sizeof(ppp_stat.finishing),
+                 ASN_INTEGER, WATCHER_FIXED_SIZE);
+    if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) {
+        snmp_log( LOG_ERR, "Failed to register watched statPPPFinishing" );
+    }
+
+
+  DEBUGMSGTL(("statPPP",
+              "Done initalizing statPPP module\n"));
+}
diff --git a/accel-pppd/extra/net-snmp/statPPP.h b/accel-pppd/extra/net-snmp/statPPP.h
new file mode 100644
index 00000000..15a1bf36
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/statPPP.h
@@ -0,0 +1,11 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.int_watch.conf 13957 2005-12-20 15:33:08Z tanders $
+ */
+#ifndef STATPPP_H
+#define STATPPP_H
+
+/* function declarations */
+void init_statPPP(void);
+
+#endif /* STATPPP_H */
diff --git a/accel-pppd/extra/net-snmp/statPPPOE.c b/accel-pppd/extra/net-snmp/statPPPOE.c
new file mode 100644
index 00000000..0ca2dd86
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/statPPPOE.c
@@ -0,0 +1,93 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.int_watch.conf 13957 2005-12-20 15:33:08Z tanders $
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include "triton.h"
+#include "statPPPOE.h"
+
+/*
+ * The variables we want to tie the relevant OIDs to.
+ * The agent will handle all GET and (if applicable) SET requests
+ * to these variables automatically, changing the values as needed.
+ */
+
+void pppoe_get_stat(unsigned int **, unsigned int **);
+
+static unsigned int *stat_starting;
+static unsigned int *stat_active;
+
+/*
+ * Our initialization routine, called automatically by the agent 
+ * (Note that the function name must match init_FILENAME()) 
+ */
+void
+init_statPPPOE(void)
+{
+  netsnmp_handler_registration *reg;
+  netsnmp_watcher_info         *winfo;
+
+    static oid statPPPOEStarting_oid[] = { 1,3,6,1,4,1,8072,100,1,5,1 };
+    static oid statPPPOEActive_oid[] = { 1,3,6,1,4,1,8072,100,1,5,2 };
+
+  /*
+   * a debugging statement.  Run the agent with -DstatPPPOE to see
+   * the output of this debugging statement. 
+   */
+  DEBUGMSGTL(("statPPPOE", "Initializing the statPPPOE module\n"));
+
+	if (!triton_module_loaded("pppoe"))
+		return;
+
+	pppoe_get_stat(&stat_starting, &stat_active);
+
+    /*
+     * Register scalar watchers for each of the MIB objects.
+     * The ASN type and RO/RW status are taken from the MIB definition,
+     * but can be adjusted if needed.
+     *
+     * In most circumstances, the scalar watcher will handle all
+     * of the necessary processing.  But the NULL parameter in the
+     * netsnmp_create_handler_registration() call can be used to
+     * supply a user-provided handler if necessary.
+     *
+     * This approach can also be used to handle Counter64, string-
+     * and OID-based watched scalars (although variable-sized writeable
+     * objects will need some more specialised initialisation).
+     */
+    DEBUGMSGTL(("statPPPOE",
+                "Initializing statPPPOEStarting scalar integer.  Default value = %d\n",
+                0));
+    reg = netsnmp_create_handler_registration(
+             "statPPPOEStarting", NULL,
+              statPPPOEStarting_oid, OID_LENGTH(statPPPOEStarting_oid),
+              HANDLER_CAN_RONLY);
+    winfo = netsnmp_create_watcher_info(
+                stat_starting, sizeof(*stat_starting),
+                 ASN_INTEGER, WATCHER_FIXED_SIZE);
+    if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) {
+        snmp_log( LOG_ERR, "Failed to register watched statPPPOEStarting" );
+    }
+
+    DEBUGMSGTL(("statPPPOE",
+                "Initializing statPPPOEActive scalar integer.  Default value = %d\n",
+                0));
+    reg = netsnmp_create_handler_registration(
+             "statPPPOEActive", NULL,
+              statPPPOEActive_oid, OID_LENGTH(statPPPOEActive_oid),
+              HANDLER_CAN_RONLY);
+    winfo = netsnmp_create_watcher_info(
+                stat_active, sizeof(*stat_active),
+                 ASN_INTEGER, WATCHER_FIXED_SIZE);
+    if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) {
+        snmp_log( LOG_ERR, "Failed to register watched statPPPOEActive" );
+    }
+
+
+  DEBUGMSGTL(("statPPPOE",
+              "Done initalizing statPPPOE module\n"));
+}
diff --git a/accel-pppd/extra/net-snmp/statPPPOE.h b/accel-pppd/extra/net-snmp/statPPPOE.h
new file mode 100644
index 00000000..bb0bcc0b
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/statPPPOE.h
@@ -0,0 +1,11 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.int_watch.conf 13957 2005-12-20 15:33:08Z tanders $
+ */
+#ifndef STATPPPOE_H
+#define STATPPPOE_H
+
+/* function declarations */
+void init_statPPPOE(void);
+
+#endif /* STATPPPOE_H */
diff --git a/accel-pppd/extra/net-snmp/statPPTP.c b/accel-pppd/extra/net-snmp/statPPTP.c
new file mode 100644
index 00000000..1a13ad06
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/statPPTP.c
@@ -0,0 +1,92 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.int_watch.conf 13957 2005-12-20 15:33:08Z tanders $
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include "statPPTP.h"
+
+#include "triton.h"
+
+/*
+ * The variables we want to tie the relevant OIDs to.
+ * The agent will handle all GET and (if applicable) SET requests
+ * to these variables automatically, changing the values as needed.
+ */
+
+void pptp_get_stat(unsigned int **, unsigned int **);
+
+static unsigned int *stat_starting;
+static unsigned int *stat_active;
+
+/*
+ * Our initialization routine, called automatically by the agent 
+ * (Note that the function name must match init_FILENAME()) 
+ */
+void
+init_statPPTP(void)
+{
+  netsnmp_handler_registration *reg;
+  netsnmp_watcher_info         *winfo;
+
+    static oid statPPTPStarting_oid[] = { 1,3,6,1,4,1,8072,100,1,3,1 };
+    static oid statPPTPActive_oid[] = { 1,3,6,1,4,1,8072,100,1,3,2 };
+
+  /*
+   * a debugging statement.  Run the agent with -DstatPPTP to see
+   * the output of this debugging statement. 
+   */
+  DEBUGMSGTL(("statPPTP", "Initializing the statPPTP module\n"));
+
+	if (!triton_module_loaded("pptp"))
+		return;
+
+	pptp_get_stat(&stat_starting, &stat_active);
+    /*
+     * Register scalar watchers for each of the MIB objects.
+     * The ASN type and RO/RW status are taken from the MIB definition,
+     * but can be adjusted if needed.
+     *
+     * In most circumstances, the scalar watcher will handle all
+     * of the necessary processing.  But the NULL parameter in the
+     * netsnmp_create_handler_registration() call can be used to
+     * supply a user-provided handler if necessary.
+     *
+     * This approach can also be used to handle Counter64, string-
+     * and OID-based watched scalars (although variable-sized writeable
+     * objects will need some more specialised initialisation).
+     */
+    DEBUGMSGTL(("statPPTP",
+                "Initializing statPPTPStarting scalar integer.  Default value = %d\n",
+                0));
+    reg = netsnmp_create_handler_registration(
+             "statPPTPStarting", NULL,
+              statPPTPStarting_oid, OID_LENGTH(statPPTPStarting_oid),
+              HANDLER_CAN_RONLY);
+    winfo = netsnmp_create_watcher_info(
+                stat_starting, sizeof(*stat_starting),
+                 ASN_INTEGER, WATCHER_FIXED_SIZE);
+    if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) {
+        snmp_log( LOG_ERR, "Failed to register watched statPPTPStarting" );
+    }
+
+    DEBUGMSGTL(("statPPTP",
+                "Initializing statPPTPActive scalar integer.  Default value = %d\n",
+                0));
+    reg = netsnmp_create_handler_registration(
+             "statPPTPActive", NULL,
+              statPPTPActive_oid, OID_LENGTH(statPPTPActive_oid),
+              HANDLER_CAN_RONLY);
+    winfo = netsnmp_create_watcher_info(
+                stat_active, sizeof(*stat_active),
+                 ASN_INTEGER, WATCHER_FIXED_SIZE);
+    if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) {
+        snmp_log( LOG_ERR, "Failed to register watched statPPTPActive" );
+    }
+
+
+  DEBUGMSGTL(("statPPTP",
+              "Done initalizing statPPTP module\n"));
+}
diff --git a/accel-pppd/extra/net-snmp/statPPTP.h b/accel-pppd/extra/net-snmp/statPPTP.h
new file mode 100644
index 00000000..d3a9e0ac
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/statPPTP.h
@@ -0,0 +1,11 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.int_watch.conf 13957 2005-12-20 15:33:08Z tanders $
+ */
+#ifndef STATPPTP_H
+#define STATPPTP_H
+
+/* function declarations */
+void init_statPPTP(void);
+
+#endif /* STATPPTP_H */
diff --git a/accel-pppd/extra/net-snmp/terminate.c b/accel-pppd/extra/net-snmp/terminate.c
new file mode 100644
index 00000000..bd385772
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/terminate.c
@@ -0,0 +1,379 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $
+ */
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include "triton.h"
+#include "ppp.h"
+
+#include "terminate.h"
+
+static void __terminate(struct ppp_t *ppp)
+{
+	ppp_terminate(ppp, TERM_ADMIN_RESET, 0);
+}
+
+static void terminate_by_sid(const char *val)
+{
+	struct ppp_t *ppp;
+
+	pthread_rwlock_rdlock(&ppp_lock);
+	list_for_each_entry(ppp, &ppp_list, entry) {
+		if (strncmp(ppp->sessionid, val, PPP_SESSIONID_LEN))
+			continue;
+		triton_context_call(ppp->ctrl->ctx, (triton_event_func)__terminate, ppp);
+		break;
+	}
+	pthread_rwlock_unlock(&ppp_lock);
+}
+
+static void terminate_by_ifname(const char *val, size_t len)
+{
+	struct ppp_t *ppp;
+	size_t n;
+
+	pthread_rwlock_rdlock(&ppp_lock);
+	list_for_each_entry(ppp, &ppp_list, entry) {
+		n = strlen(ppp->ifname);
+		if (n != len)
+			continue;
+		if (strncmp(ppp->ifname, val, len))
+			continue;
+		triton_context_call(ppp->ctrl->ctx, (triton_event_func)__terminate, ppp);
+		break;
+	}
+	pthread_rwlock_unlock(&ppp_lock);
+}
+
+static void terminate_by_ip(const char *val, size_t len)
+{
+	char str[len + 1];
+	in_addr_t addr;
+	struct ppp_t *ppp;
+
+	strncpy(str, val, len);
+	str[len] = 0;
+
+	addr = inet_addr(str);
+	
+	pthread_rwlock_rdlock(&ppp_lock);
+	list_for_each_entry(ppp, &ppp_list, entry) {
+		if (ppp->peer_ipaddr != addr)
+			continue;
+		triton_context_call(ppp->ctrl->ctx, (triton_event_func)__terminate, ppp);
+		break;
+	}
+	pthread_rwlock_unlock(&ppp_lock);
+}
+
+static void terminate_by_username(const char *val, size_t len)
+{
+	struct ppp_t *ppp;
+	size_t n;
+
+	pthread_rwlock_rdlock(&ppp_lock);
+	list_for_each_entry(ppp, &ppp_list, entry) {
+		if (!ppp->username)
+			continue;
+		n = strlen(ppp->username);
+		if (n != len)
+			continue;
+		if (strncmp(ppp->username, val, len))
+			continue;
+		triton_context_call(ppp->ctrl->ctx, (triton_event_func)__terminate, ppp);
+	}
+	pthread_rwlock_unlock(&ppp_lock);
+}
+
+
+/** Initializes the terminate module */
+void
+init_terminate(void)
+{
+    static oid termBySID_oid[] = { 1,3,6,1,4,1,8072,100,3,1,1 };
+    static oid termByIfName_oid[] = { 1,3,6,1,4,1,8072,100,3,1,2 };
+    static oid termByIP_oid[] = { 1,3,6,1,4,1,8072,100,3,1,3 };
+    static oid termByUsername_oid[] = { 1,3,6,1,4,1,8072,100,3,1,4 };
+
+  DEBUGMSGTL(("terminate", "Initializing\n"));
+
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("termBySID", handle_termBySID,
+                               termBySID_oid, OID_LENGTH(termBySID_oid),
+                               HANDLER_CAN_RWRITE
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("termByIfName", handle_termByIfName,
+                               termByIfName_oid, OID_LENGTH(termByIfName_oid),
+                               HANDLER_CAN_RWRITE
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("termByIP", handle_termByIP,
+                               termByIP_oid, OID_LENGTH(termByIP_oid),
+                               HANDLER_CAN_RWRITE
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("termByUsername", handle_termByUsername,
+                               termByUsername_oid, OID_LENGTH(termByUsername_oid),
+                               HANDLER_CAN_RWRITE
+        ));
+}
+
+int
+handle_termBySID(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int ret;
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE );
+            break;
+
+        /*
+         * SET REQUEST
+         *
+         * multiple states in the transaction.  See:
+         * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
+         */
+        case MODE_SET_RESERVE1:
+                /* or you could use netsnmp_check_vb_type_and_size instead */
+            ret = netsnmp_check_vb_type_and_size(requests->requestvb, ASN_OCTET_STR, PPP_SESSIONID_LEN);
+            if ( ret != SNMP_ERR_NOERROR ) {
+                netsnmp_set_request_error(reqinfo, requests, ret );
+            }
+            break;
+
+        case MODE_SET_RESERVE2:
+            break;
+
+        case MODE_SET_FREE:
+            /* XXX: free resources allocated in RESERVE1 and/or
+               RESERVE2.  Something failed somewhere, and the states
+               below won't be called. */
+            break;
+
+        case MODE_SET_ACTION:
+						terminate_by_sid((char *)requests->requestvb->val.string);
+            /* XXX: perform the value change here */
+            break;
+
+        case MODE_SET_COMMIT:
+            break;
+
+        case MODE_SET_UNDO:
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_termBySID\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_termByIfName(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int ret;
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE );
+            break;
+
+        /*
+         * SET REQUEST
+         *
+         * multiple states in the transaction.  See:
+         * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
+         */
+        case MODE_SET_RESERVE1:
+                /* or you could use netsnmp_check_vb_type_and_size instead */
+            ret = netsnmp_check_vb_type(requests->requestvb, ASN_OCTET_STR);
+            if ( ret != SNMP_ERR_NOERROR ) {
+                netsnmp_set_request_error(reqinfo, requests, ret );
+            }
+            break;
+
+        case MODE_SET_RESERVE2:
+            /* XXX malloc "undo" storage buffer */
+            break;
+
+        case MODE_SET_FREE:
+            /* XXX: free resources allocated in RESERVE1 and/or
+               RESERVE2.  Something failed somewhere, and the states
+               below won't be called. */
+            break;
+
+        case MODE_SET_ACTION:
+						terminate_by_ifname((char *)requests->requestvb->val.string, requests->requestvb->val_len);
+            /* XXX: perform the value change here */
+            break;
+
+        case MODE_SET_COMMIT:
+            break;
+
+        case MODE_SET_UNDO:
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_termByIfName\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_termByIP(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int ret;
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE );
+            break;
+
+        /*
+         * SET REQUEST
+         *
+         * multiple states in the transaction.  See:
+         * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
+         */
+        case MODE_SET_RESERVE1:
+                /* or you could use netsnmp_check_vb_type_and_size instead */
+            ret = netsnmp_check_vb_type(requests->requestvb, ASN_OCTET_STR);
+            if ( ret != SNMP_ERR_NOERROR ) {
+                netsnmp_set_request_error(reqinfo, requests, ret );
+            }
+            break;
+
+        case MODE_SET_RESERVE2:
+            /* XXX malloc "undo" storage buffer */
+            break;
+
+        case MODE_SET_FREE:
+            /* XXX: free resources allocated in RESERVE1 and/or
+               RESERVE2.  Something failed somewhere, and the states
+               below won't be called. */
+            break;
+
+        case MODE_SET_ACTION:
+						terminate_by_ip((char *)requests->requestvb->val.string, requests->requestvb->val_len);
+            /* XXX: perform the value change here */
+            break;
+
+        case MODE_SET_COMMIT:
+            /* XXX: delete temporary storage */
+            break;
+
+        case MODE_SET_UNDO:
+            /* XXX: UNDO and return to previous value for the object */
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_termByIP\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_termByUsername(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int ret;
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE );
+            break;
+
+        /*
+         * SET REQUEST
+         *
+         * multiple states in the transaction.  See:
+         * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
+         */
+        case MODE_SET_RESERVE1:
+                /* or you could use netsnmp_check_vb_type_and_size instead */
+            ret = netsnmp_check_vb_type(requests->requestvb, ASN_OCTET_STR);
+            if ( ret != SNMP_ERR_NOERROR ) {
+                netsnmp_set_request_error(reqinfo, requests, ret );
+            }
+            break;
+
+        case MODE_SET_RESERVE2:
+            /* XXX malloc "undo" storage buffer */
+            break;
+
+        case MODE_SET_FREE:
+            /* XXX: free resources allocated in RESERVE1 and/or
+               RESERVE2.  Something failed somewhere, and the states
+               below won't be called. */
+            break;
+
+        case MODE_SET_ACTION:
+						terminate_by_username((char *)requests->requestvb->val.string, requests->requestvb->val_len);
+            /* XXX: perform the value change here */
+            break;
+
+        case MODE_SET_COMMIT:
+            /* XXX: delete temporary storage */
+            break;
+
+        case MODE_SET_UNDO:
+            /* XXX: UNDO and return to previous value for the object */
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_termByUsername\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
diff --git a/accel-pppd/extra/net-snmp/terminate.h b/accel-pppd/extra/net-snmp/terminate.h
new file mode 100644
index 00000000..70131823
--- /dev/null
+++ b/accel-pppd/extra/net-snmp/terminate.h
@@ -0,0 +1,15 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $
+ */
+#ifndef TERMINATE_H
+#define TERMINATE_H
+
+/* function declarations */
+void init_terminate(void);
+Netsnmp_Node_Handler handle_termBySID;
+Netsnmp_Node_Handler handle_termByIfName;
+Netsnmp_Node_Handler handle_termByIP;
+Netsnmp_Node_Handler handle_termByUsername;
+
+#endif /* TERMINATE_H */
diff --git a/accel-pppd/log.c b/accel-pppd/log.c
index 38f4bcea..53612e94 100644
--- a/accel-pppd/log.c
+++ b/accel-pppd/log.c
@@ -16,6 +16,15 @@
 
 #include "memdebug.h"
 
+#define LOG_MSG   0
+#define LOG_ERROR 1
+#define LOG_WARN  2
+#define LOG_INFO1 3
+#define LOG_INFO2 4
+#define LOG_DEBUG 5
+
+#define LOG_CHUNK_SIZE 128
+
 struct log_pd_t
 {
 	struct ppp_pd_t pd;
diff --git a/accel-pppd/log.h b/accel-pppd/log.h
index d87c42c0..3545cb10 100644
--- a/accel-pppd/log.h
+++ b/accel-pppd/log.h
@@ -5,14 +5,6 @@
 #include <sys/time.h>
 #include "list.h"
 
-#define LOG_MSG   0
-#define LOG_ERROR 1
-#define LOG_WARN  2
-#define LOG_INFO1 3
-#define LOG_INFO2 4
-#define LOG_DEBUG 5
-
-#define LOG_CHUNK_SIZE 128
 #define LOG_MAX_SIZE 4096
 
 struct ppp_t;
diff --git a/accel-pppd/ppp/ppp.c b/accel-pppd/ppp/ppp.c
index e62107f6..5c529489 100644
--- a/accel-pppd/ppp/ppp.c
+++ b/accel-pppd/ppp/ppp.c
@@ -44,7 +44,7 @@ static unsigned long long seq;
 static spinlock_t seq_lock;
 #endif
 
-struct ppp_stat_t ppp_stat;
+__export struct ppp_stat_t ppp_stat;
 
 struct layer_node_t
 {
@@ -400,7 +400,7 @@ void __export ppp_layer_started(struct ppp_t *ppp, struct ppp_layer_data_t *d)
 		list_for_each_entry(d, &n->items, entry) {
 			d->starting = 1;
 			if (d->layer->start(d)) {
-				ppp_terminate(ppp, TERM_NAS_ERROR, 0);
+				ppp_terminate(ppp, 1, TERM_NAS_ERROR);
 				return;
 			}
 		}
diff --git a/accel-pppd/ppp/ppp.h b/accel-pppd/ppp/ppp.h
index 9d2409ed..c0ebe834 100644
--- a/accel-pppd/ppp/ppp.h
+++ b/accel-pppd/ppp/ppp.h
@@ -56,12 +56,16 @@
 #define TERM_AUTH_ERROR 8
 #define TERM_LOST_CARRIER 9
 
+#define CTRL_TYPE_PPTP  1
+#define CTRL_TYPE_L2TP  2
+#define CTRL_TYPE_PPPOE 3
 
 struct ppp_t;
 
 struct ppp_ctrl_t
 {
 	struct triton_context_t *ctx;
+	int type;
 	const char *name;
 	int max_mtu;
 	char *calling_station_id;
diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c
index 0d9eb260..bcdce144 100644
--- a/accel-pppd/radius/serv.c
+++ b/accel-pppd/radius/serv.c
@@ -5,6 +5,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sched.h>
+#include <time.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -20,9 +21,12 @@ static LIST_HEAD(serv_list);
 struct rad_server_t *rad_server_get(int type)
 {
 	struct rad_server_t *s, *s0 = NULL;
+	struct timespec ts;
+	
+	clock_gettime(CLOCK_MONOTONIC, &ts);
 
 	list_for_each_entry(s, &serv_list, entry) {
-		if (s->fail_time && time(NULL) < s->fail_time)
+		if (s->fail_time && ts.tv_sec < s->fail_time)
 			continue;
 
 		if (type == 0 && !s->auth_addr)
@@ -54,12 +58,16 @@ void rad_server_put(struct rad_server_t *s)
 
 int rad_server_req_enter(struct rad_req_t *req)
 {
+	struct timespec ts;
+	
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	
 	if (!req->serv->max_req_cnt)
 		return 0;
 
 	pthread_mutex_lock(&req->serv->lock);
 	
-	if (time(NULL) < req->serv->fail_time) {
+	if (ts.tv_sec < req->serv->fail_time) {
 		pthread_mutex_unlock(&req->serv->lock);
 		return -1;
 	}
@@ -70,7 +78,7 @@ int rad_server_req_enter(struct rad_req_t *req)
 		triton_context_schedule();
 		pthread_mutex_lock(&req->serv->lock);
 
-		if (time(NULL) < req->serv->fail_time) {
+		if (ts.tv_sec < req->serv->fail_time) {
 			pthread_mutex_unlock(&req->serv->lock);
 			return -1;
 		}
@@ -130,13 +138,14 @@ int rad_server_realloc(struct rad_req_t *req, int type)
 void rad_server_fail(struct rad_server_t *s)
 {
 	struct rad_req_t *r;
-	time_t t;
+	struct timespec ts;
+	
+	clock_gettime(CLOCK_MONOTONIC, &ts);
 
 	pthread_mutex_lock(&s->lock);
-	t = time(NULL);
 
-	if (t > s->fail_time) {
-		s->fail_time = t + s->conf_fail_time;
+	if (ts.tv_sec > s->fail_time) {
+		s->fail_time = ts.tv_sec + s->conf_fail_time;
 		log_ppp_warn("radius: server not responding\n");
 		log_warn("radius: server noy responding\n");
 	}
diff --git a/accel-pppd/radius/stat_accm.c b/accel-pppd/radius/stat_accm.c
index 3de86fca..34935a15 100644
--- a/accel-pppd/radius/stat_accm.c
+++ b/accel-pppd/radius/stat_accm.c
@@ -38,11 +38,13 @@ struct stat_accm_t *stat_accm_create(unsigned int time)
 static void stat_accm_clean(struct stat_accm_t *s)
 {
 	struct item_t *it;
-	time_t ts = time(NULL);
+	struct timespec ts;
+	
+	clock_gettime(CLOCK_MONOTONIC, &ts);
 
 	while (!list_empty(&s->items)) {
 		it = list_entry(s->items.next, typeof(*it), entry);
-		if (ts - it->ts > s->time) {
+		if (ts.tv_sec - it->ts > s->time) {
 			list_del(&it->entry);
 			--s->items_cnt;
 			s->total -= it->val;
@@ -55,13 +57,16 @@ static void stat_accm_clean(struct stat_accm_t *s)
 void stat_accm_add(struct stat_accm_t *s, unsigned int val)
 {
 	struct item_t *it;
+	struct timespec ts;
+	
+	clock_gettime(CLOCK_MONOTONIC, &ts);
 
 	pthread_mutex_lock(&s->lock);
 	
 	stat_accm_clean(s);
 
 	it = mempool_alloc(item_pool);
-	it->ts = time(NULL);
+	it->ts = ts.tv_sec;
 	it->val = val;
 	list_add_tail(&it->entry, &s->items);
 	++s->items_cnt;
diff --git a/accel-pppd/triton/triton.c b/accel-pppd/triton/triton.c
index 4d3359bd..aa2183e6 100644
--- a/accel-pppd/triton/triton.c
+++ b/accel-pppd/triton/triton.c
@@ -517,8 +517,7 @@ static void ru_update(struct triton_timer_t *t)
 	val = (double)((rusage.ru_utime.tv_sec - ru_utime.tv_sec) * 1000000 + (rusage.ru_utime.tv_usec - ru_utime.tv_usec) + 
 	      (rusage.ru_stime.tv_sec - ru_stime.tv_sec) * 1000000 + (rusage.ru_stime.tv_usec - ru_stime.tv_usec)) / dt * 100;
 
-	if (val <= 100)
-		triton_stat.cpu = val;
+	triton_stat.cpu = val;
 
 	ru_timestamp = ts;
 	ru_utime = rusage.ru_utime;
@@ -563,6 +562,8 @@ int __export triton_init(const char *conf_file)
 	if (event_init())
 		return -1;
 
+	triton_context_register(&default_ctx, NULL);
+
 	return 0;
 }
 
@@ -600,6 +601,7 @@ void __export triton_run()
 	struct _triton_thread_t *t;
 	int i;
 	char *opt;
+	struct timespec ts;
 
 	opt = conf_get_opt("core", "thread-count");
 	if (opt && atoi(opt) > 0)
@@ -614,12 +616,12 @@ void __export triton_run()
 		pthread_mutex_unlock(&t->sleep_lock);
 	}
 
-	time(&triton_stat.start_time);
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	triton_stat.start_time = ts.tv_sec;
 
 	md_run();
 	timer_run();
 
-	triton_context_register(&default_ctx, NULL);
 	triton_context_wakeup(&default_ctx);
 }
 
-- 
cgit v1.2.3