On Mon, 2011-02-28 at 17:31 +0100, Niels Baggesen wrote:
> On Mon, Feb 28, 2011 at 02:20:36PM +0000, Dave Shield wrote:
> > Niels' suggestion of hacking the main select loop would certainly
> > work, but this mechanism has been provided to avoid the need
> > to do this.
> 
> So many options, so little time - I have missed that option
> 
> >   We should perhaps look at re-working the SMUX module to
> > make use of this facility, but it's never been sufficiently high
> > priority to warrent the time involved.
> 
> Well, if that had been done, I would never have suggested what I did.
> Coding by example is still the most popular way.
> 
> Maybe I should hack that ...

I think that is a bad idea. There is nothing that prevents SMUX from
using the normal transports mechanism so using that specialty interface
is unnecessary.

See my attached half (or less) implementation. (No, I haven't updated
the patch with the feature code yet) 

The big trouble is how to handle the fact that the SMUX extension model
is completely at odds with the AgentX model that the rest of the agent
follows.

/MF
Index: clean/agent/snmpd.c
===================================================================
--- clean.orig/agent/snmpd.c	2010-04-06 23:56:37.000000000 +0200
+++ clean/agent/snmpd.c	2010-04-07 02:16:04.000000000 +0200
@@ -193,10 +193,6 @@
 extern char    *argvrestart;
 extern char    *argvrestartname;
 
-#ifdef USING_SMUX_MODULE
-#include <mibgroup/smux/smux.h>
-#endif /* USING_SMUX_MODULE */
-
 /*
  * Prototypes.
  */
@@ -1168,23 +1164,6 @@
             tvp = NULL;         /* block without timeout */
 	}
 
-#ifdef	USING_SMUX_MODULE
-        if (smux_listen_sd >= 0) {
-            NETSNMP_LARGE_FD_SET(smux_listen_sd, &readfds);
-            numfds =
-                smux_listen_sd >= numfds ? smux_listen_sd + 1 : numfds;
-
-            for (i = 0; i < smux_snmp_select_list_get_length(); i++) {
-                sd = smux_snmp_select_list_get_SD_from_List(i);
-                if (sd != 0)
-                {
-                   NETSNMP_LARGE_FD_SET(sd, &readfds);
-                   numfds = sd >= numfds ? sd + 1 : numfds;
-                }
-            }
-        }
-#endif                          /* USING_SMUX_MODULE */
-
         netsnmp_external_event_info2(&numfds, &readfds, &writefds, &exceptfds);
 
     reselect:
@@ -1197,30 +1176,6 @@
 
         if (count > 0) {
 
-#ifdef USING_SMUX_MODULE
-            /*
-             * handle the SMUX sd's 
-             */
-            if (smux_listen_sd >= 0) {
-                for (i = 0; i < smux_snmp_select_list_get_length(); i++) {
-                    sd = smux_snmp_select_list_get_SD_from_List(i);
-                    if (NETSNMP_LARGE_FD_ISSET(sd, &readfds)) {
-                        if (smux_process(sd) < 0) {
-                            smux_snmp_select_list_del(sd);
-                        }
-                    }
-                }
-                /*
-                 * new connection 
-                 */
-                if (NETSNMP_LARGE_FD_ISSET(smux_listen_sd, &readfds)) {
-                    if ((sd = smux_accept(smux_listen_sd)) >= 0) {
-                        smux_snmp_select_list_add(sd);
-                    }
-                }
-            }
-
-#endif                          /* USING_SMUX_MODULE */
             netsnmp_dispatch_external_events2(&count, &readfds,
                                               &writefds, &exceptfds);
             /* If there are still events leftover, process them */
Index: clean/agent/snmp_agent.c
===================================================================
--- clean.orig/agent/snmp_agent.c	2010-03-23 01:10:02.000000000 +0100
+++ clean/agent/snmp_agent.c	2010-04-07 02:16:04.000000000 +0200
@@ -103,10 +103,6 @@
 #include "agentx/master.h"
 #endif
 
-#ifdef USING_SMUX_MODULE
-#include "smux/smux.h"
-#endif
-
 NETSNMP_INLINE void
 netsnmp_agent_add_list_data(netsnmp_agent_request_info *ari,
                             netsnmp_data_list *node)
@@ -1309,10 +1305,6 @@
 			       NETSNMP_DS_AGENT_AGENTX_MASTER) == 1)
         real_init_master();
 #endif
-#ifdef USING_SMUX_MODULE
-    if(should_init("smux"))
-    real_init_smux();
-#endif
 
     return 0;
 }
Index: clean/agent/mibgroup/smux.h
===================================================================
--- clean.orig/agent/mibgroup/smux.h	2010-03-15 23:47:42.000000000 +0100
+++ clean/agent/mibgroup/smux.h	2010-04-07 02:16:04.000000000 +0200
@@ -1,4 +1,4 @@
 /*
  * smux.h: top level .h file to merely include the sub-module.
  */
-config_require(smux/smux)
+config_require(smux/smux_new)
Index: clean/agent/mibgroup/smux/smux_new.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ clean/agent/mibgroup/smux/smux_new.c	2010-04-07 02:16:04.000000000 +0200
@@ -0,0 +1,1434 @@
+/*
+ * Smux module authored by Rohit Dube.
+ * Rewritten by Nick Amato <[email protected]>.
+ * Rewritten another time by Magnus Fromreide <[email protected]>.
+ */
+
+#include <net-snmp/net-snmp-config.h>
+
+#include <sys/types.h>
+#include <ctype.h>
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/library/tools.h>
+
+#include "smux.h"
+
+#define SMUXPORT 199
+
+#define SMUXVERSION 0
+
+#define SMUX_OPEN 	(ASN_APPLICATION | ASN_CONSTRUCTOR | 0)
+#define SMUX_CLOSE      (ASN_APPLICATION | ASN_PRIMITIVE | 1)
+#define SMUX_RREQ       (ASN_APPLICATION | ASN_CONSTRUCTOR | 2)
+#define SMUX_RRSP       (ASN_APPLICATION | ASN_PRIMITIVE | 3)
+#define SMUX_SOUT       (ASN_APPLICATION | ASN_PRIMITIVE | 4)
+
+#define SMUX_GET        (ASN_CONTEXT | ASN_CONSTRUCTOR | 0)
+#define SMUX_GETNEXT    (ASN_CONTEXT | ASN_CONSTRUCTOR | 1)
+#define SMUX_GETRSP     (ASN_CONTEXT | ASN_CONSTRUCTOR | 2)
+#define SMUX_SET	(ASN_CONTEXT | ASN_CONSTRUCTOR | 3)
+#define SMUX_TRAP	(ASN_CONTEXT | ASN_CONSTRUCTOR | 4)
+
+#define SMUXC_GOINGDOWN                    0
+#define SMUXC_UNSUPPORTEDVERSION           1
+#define SMUXC_PACKETFORMAT                 2
+#define SMUXC_PROTOCOLERROR                3
+#define SMUXC_INTERNALERROR                4
+#define SMUXC_AUTHENTICATIONFAILURE        5
+
+#define SMUX_MAX_PRIORITY       2147483647
+
+#define SMUX_REGOP_DELETE		0
+#define SMUX_REGOP_REGISTER_RO		1
+#define SMUX_REGOP_REGISTER_RW		2
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+static int smux_startup(UNUSED int, UNUSED int, UNUSED void*, UNUSED void*);
+static void smux_close(netsnmp_session*, long int);
+static int smux_callback(int, netsnmp_session*, int, netsnmp_pdu*, void*);
+static int smux_parse(netsnmp_session *, netsnmp_pdu *, u_char *, size_t);
+
+static int
+smux_handler(netsnmp_mib_handler *handler,
+	     netsnmp_handler_registration *reginfo,
+	     netsnmp_agent_request_info *reqinfo,
+	     netsnmp_request_info *requests);
+
+typedef struct smux_peer_struct {
+    netsnmp_session* session;
+    struct smux_peer_struct* next;
+    long int prio;
+    int readonly;
+} smux_peer;
+
+typedef struct smux_reg_struct {
+    oid tree[MAX_OID_LEN];
+    size_t treelen;
+
+    struct smux_reg_struct* next;   /* in oid (tree) order */
+    struct smux_reg_struct* next_l; /* in mib (treelength, tree) order */
+
+    netsnmp_handler_registration* registration;
+
+    smux_peer* peer_regs;
+} smux_reg;
+
+static smux_reg* smux_registry = NULL; /* in oid (tree) order */
+static smux_reg* smux_registry_l = NULL; /* in mib (treelength, tree) order */
+
+#define SMUX_OID 1, 3, 6, 1, 4, 1, 4, 4
+
+/**
+ * Remove subtree tree with priority prio from session sess
+ * \arg sess session to remove from
+ * \arg tree oid to remove
+ * \arg treelen length of the oid that is to be removed
+ * \arg prio priority of the object to remove, -1 means to remove the
+ *           registration with highest priority for the current session
+ * \returns  priority of the removed registration or -1 on failure
+ */
+static long int
+smux_sub_reg(netsnmp_session* sess,
+	     oid tree[], size_t treelen, long int prio)
+{
+    smux_reg* cur = smux_registry;
+    smux_reg* prev = NULL;
+
+    while (cur != NULL &&
+	   snmp_oid_compare(tree, treelen, cur->tree, cur->treelen) > 0) {
+	prev = cur;
+	cur = cur->next;
+    }
+    if (cur == NULL ||
+	snmp_oid_compare(tree, treelen, cur->tree, cur->treelen) < 0) {
+	prio = -1;
+    } else {
+	smux_peer* cp = cur->peer_regs;
+	smux_peer* pp = NULL;
+	if (prio == -1) {
+	    while (cp != NULL && cp->session != sess) {
+		pp = cp;
+		cp = cp->next;
+	    }
+	} else
+	    while (cp != NULL && cp->prio < prio) {
+		pp = cp;
+		cp = cp->next;
+	    }
+	if (!cp || cp->session != sess)
+	    return -1; /* Nothing found or wrong session */
+	else if (pp)
+	    pp->next = cp->next;
+	else
+	    cur->peer_regs = cp->next;
+	prio = cp->prio;
+	free(cp);
+	if (cur->peer_regs != NULL) {
+	    /* Do nothing */
+	} else { /* This node should die */
+	    if (cur->registration) { /* We are registered, register lower */
+		smux_reg* tmp;
+		smux_reg* lastRegistered = NULL;
+		netsnmp_unregister_handler(cur->registration);
+		netsnmp_handler_registration_free(cur->registration);
+		cur->registration = NULL;
+		tmp = cur->next;
+		while (tmp != NULL &&
+		       snmp_oidtree_compare(tmp->tree, tmp->treelen,
+					    cur->tree, cur->treelen)) {
+		    if(!lastRegistered ||
+		       snmp_oidtree_compare(
+			       lastRegistered->tree, lastRegistered->treelen,
+			       tmp->tree, tmp->treelen) != 0) {
+			tmp->registration =
+			    netsnmp_create_handler_registration(
+				    "SMUX Handler", smux_handler,
+				    tmp->tree, tmp->treelen,
+				    HANDLER_CAN_RWRITE);
+			tmp->registration->my_reg_void = tmp;
+			netsnmp_register_handler(tmp->registration);
+			lastRegistered = tmp;
+		    }
+		    tmp = tmp->next;
+		}
+	    }
+	    if (prev)
+		prev->next = cur->next;
+	    else
+		smux_registry = cur->next;
+
+	    {
+		smux_reg* tmp = smux_registry_l;
+		prev = NULL;
+		while (tmp && tmp != cur) {
+		    prev = tmp;
+		    tmp = tmp->next;
+		}
+		if (prev)
+		    prev->next_l = cur->next_l;
+		else
+		    smux_registry_l = cur->next_l;
+	    }
+	    free(cur);
+	}
+    }
+    return prio;
+}
+
+/**
+ * Remove all registrations for sesson sess
+ * \arg sess session to remove all registrations for
+ * \returns  number of removed sessions
+ */
+static int
+smux_sub_session(netsnmp_session* sess)
+{
+    smux_reg* cur = smux_registry_l;
+    smux_reg* prev = NULL;
+    int res = 0;
+
+    while (cur) {
+	smux_peer* cp = cur->peer_regs;
+	smux_peer* pp = NULL;
+	while (cp != NULL) {
+	    if (cp->session == sess) {
+		smux_peer* tmp = cp;
+		if(pp)
+		    pp->next = cp = cp->next;
+		else
+		    cur->peer_regs = cp = cp->next;
+		++res;
+		free(tmp);
+	    } else {
+		pp = cp;
+		cp = cp->next;
+	    }
+	}
+	if (cur->peer_regs == NULL) { /* This node should die, but later */
+	    if (prev)
+		prev->next_l = cur = cur->next_l;
+	    else
+		smux_registry_l = cur = cur->next_l;
+	} else {
+	    prev = cur;
+	    cur = cur->next_l;
+	}
+    }
+
+    cur = smux_registry;
+    prev = NULL;
+
+    while (cur) {
+	if (cur->peer_regs == NULL) { /* This node should die */
+	    smux_reg* tmp;
+	    if (cur->registration) {
+		smux_reg* lastRegistered = NULL;
+		netsnmp_unregister_handler(cur->registration);
+		netsnmp_handler_registration_free(cur->registration);
+		cur->registration = NULL;
+		tmp = cur->next;
+		while (tmp != NULL &&
+		       snmp_oidtree_compare(tmp->tree, tmp->treelen,
+					    cur->tree, cur->treelen)) {
+		    if(!lastRegistered ||
+		       snmp_oidtree_compare(
+			       lastRegistered->tree, lastRegistered->treelen,
+			       tmp->tree, tmp->treelen) != 0) {
+			tmp->registration =
+			    netsnmp_create_handler_registration(
+				    "SMUX Handler", smux_handler,
+				    tmp->tree, tmp->treelen,
+				    HANDLER_CAN_RWRITE);
+			tmp->registration->my_reg_void = tmp;
+			netsnmp_register_handler(tmp->registration);
+			lastRegistered = tmp;
+		    }
+		    tmp = tmp->next;
+		}
+	    }
+	    tmp = cur;
+	    if (prev)
+		prev->next = cur = cur->next;
+	    else
+		smux_registry = cur = cur->next;
+
+	    free(tmp);
+	} else {
+	    prev = cur;
+	    cur = cur->next;
+	}
+    }
+    return res;
+}
+
+/**
+ * Remove all registrations
+ */
+static void
+smux_sub_all(void)
+{
+    smux_reg* cur;
+
+    while ((cur = smux_registry) != NULL) {
+	smux_peer* cp;
+	smux_registry = cur->next;
+	while ((cp = cur->peer_regs) != NULL) {
+	    cur->peer_regs = cp->next;
+	    free(cp);
+	}
+	if (cur->registration) {
+	    netsnmp_unregister_handler(cur->registration);
+	    netsnmp_handler_registration_free(cur->registration);
+	}
+	free(cur);
+    }
+    smux_registry_l = NULL;
+}
+
+/**
+ * Add a registration for session sess on subtree tree with priority prio
+ * \arg sess session to add to
+ * \arg tree oid to insert
+ * \arg treelen length of the oid that is to be inserted
+ * \arg prio priority of the object to insert, -1 means to register with the
+ *           highest posible priority
+ * \returns  registration priority, -1 on failure
+ */
+static long int
+smux_add_reg(netsnmp_session* sess,
+	     oid tree[], size_t treelen, long int prio, int readonly)
+{
+    smux_reg* cur = smux_registry;
+    {
+	smux_reg* prev = NULL;
+	smux_reg* prevRegistered = NULL;
+
+	while (cur != NULL) {
+	    if (cur->registration)
+		prevRegistered = cur;
+	    if(snmp_oid_compare(tree, treelen, cur->tree, cur->treelen) <= 0)
+		break;
+	    prev = cur;
+	    cur = cur->next;
+	}
+	if (cur == NULL ||
+	    snmp_oid_compare(tree, treelen, cur->tree, cur->treelen) < 0) {
+	    /* Needs new smux_reg */
+	    smux_reg* tmp = (smux_reg*)malloc(sizeof(smux_reg));
+	    memcpy(tmp->tree, tree, sizeof(oid) * treelen);
+	    tmp->treelen = treelen;
+	    tmp->next = cur;
+	    tmp->peer_regs = NULL;
+	    if(prev)
+		prev->next = tmp;
+	    else
+		smux_registry = tmp;
+	    if (prevRegistered == NULL ||
+		snmp_oidtree_compare(prevRegistered->tree,
+				     prevRegistered->treelen,
+				     tree, treelen) != 0) {
+		/* We should get registered, should something get
+		 * unregistered? */
+		cur = tmp->next;
+		while(cur != NULL &&
+		      snmp_oidtree_compare(tmp->tree, tmp->treelen,
+					   cur->tree, cur->treelen)) {
+		    if (cur->registration) {
+			netsnmp_unregister_handler(cur->registration);
+			netsnmp_handler_registration_free(cur->registration);
+			cur->registration = NULL;
+		    }
+		    cur = cur->next;
+		}
+		tmp->registration =
+		    netsnmp_create_handler_registration(
+			    "SMUX Handler", smux_handler,
+			    tmp->tree, tmp->treelen, HANDLER_CAN_RWRITE);
+		tmp->registration->my_reg_void = tmp;
+		netsnmp_register_handler(tmp->registration);
+	    } else
+		tmp->registration = NULL;
+	    cur = tmp;
+
+	    tmp = smux_registry_l;
+	    prev = NULL;
+	    while (tmp != NULL &&
+		   (tmp->treelen < cur->treelen ||
+		    (tmp->treelen == cur->treelen &&
+		     snmp_oid_compare(tmp->tree, tmp->treelen,
+				      cur->tree, cur->treelen) < 0))) {
+		prev = tmp;
+		tmp = tmp->next_l;
+	    }
+	    cur->next_l = tmp;
+	    if (prev)
+		prev->next_l = cur;
+	    else
+		smux_registry_l = cur;
+	}
+    }
+    {
+	smux_peer* cp = cur->peer_regs;
+	smux_peer* pp = NULL;
+
+	if (prio < 0)
+	    prio = 0;
+
+	while (cp != NULL && cp->prio < prio) {
+	    pp = cp;
+	    cp = cp->next;
+	}
+
+	while (cp != NULL && cp->prio == prio && prio != SMUX_MAX_PRIORITY) {
+	    pp = cp;
+	    cp = cp->next;
+	    ++prio;
+	}
+
+	if (cp != NULL && cp->prio == prio)
+	    prio = -1;
+	else {
+	    smux_peer* tt = (smux_peer*)malloc(sizeof(smux_peer));
+	    tt->session = sess;
+	    tt->next = cp;
+	    tt->prio = prio;
+	    tt->readonly = !!readonly;
+	    if (pp)
+		pp->next = tt;
+	    else
+		cur->peer_regs = tt;
+	}
+	return prio;
+    }
+}
+
+static void
+smux_parse_smux_socket(UNUSED const char *token, char *cptr)
+{
+    DEBUGMSGTL(("smux", "port spec: %s\n", cptr));
+    netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
+			  NETSNMP_DS_SMUX_SOCKET, cptr);
+}
+
+/**
+ * Authorized peers read from the config file
+ */
+typedef struct smux_peer_auth_struct {
+    oid                     oid[MAX_OID_LEN]; /**< name of peer */
+    size_t                  oid_len; /**< length of peer name */
+    char                   *passwd; /**< configured passwd */
+    netsnmp_session        *active; /**< the peer using this auth */
+    struct smux_peer_auth_struct *next; /**< next peer auth */
+} smux_peer_auth;
+
+static smux_peer_auth *Auths;   /**< Configured peers */
+
+static void
+smux_parse_peer_auth(UNUSED const char *token, char *cptr)
+{
+    smux_peer_auth *aptr;
+
+    if ((aptr =
+         (smux_peer_auth *) malloc(sizeof(smux_peer_auth))) == NULL) {
+        snmp_log_perror("smux_parse_peer_auth: malloc");
+        return;
+    }
+
+    aptr->active = NULL;
+
+    /*
+     * oid
+     */
+    aptr->oid_len = MAX_OID_LEN;
+    read_objid( cptr, aptr->oid, &aptr->oid_len );
+    DEBUGMSGTL(("smux_conf", "parsing registration for: %s\n", cptr));
+
+    /*
+     * password
+     */
+    cptr = skip_token(cptr);
+    DEBUGMSGTL(("smux_conf", "password is: %s\n", SNMP_STRORNULL(cptr)));
+
+    if (cptr)
+        aptr->passwd = strdup(cptr);
+    else
+	aptr->passwd = NULL; /* default is no password */
+
+    aptr->next = Auths;
+    Auths = aptr;
+}
+
+static void
+smux_free_peer_auth(void)
+{
+    while (Auths) {
+	smux_peer_auth *aptr = Auths;
+	Auths = Auths->next;
+	free(aptr->passwd);
+	free(aptr);
+    }
+}
+
+static int
+smux_auth_peer(netsnmp_session* sess,
+	       const oid* name, size_t namelen, const u_char* passwd)
+{
+    smux_peer_auth *aptr = Auths;
+    while (aptr != NULL &&
+	   (aptr->active ||
+	    snmp_oid_compare(name, namelen, aptr->oid, aptr->oid_len) ||
+	    (aptr->passwd && strcmp((const char*)passwd, aptr->passwd))))
+	aptr = aptr->next;
+    if (aptr) {
+	aptr->active = sess;
+	return 1;
+    } else
+	return 0;
+}
+
+static void
+smux_unauth_peer(netsnmp_session* sess)
+{
+    smux_peer_auth *aptr = Auths;
+    while (aptr != NULL && aptr->active != sess)
+	aptr = aptr->next;
+    if (aptr)
+	aptr->active = NULL;
+}
+
+#define SMUX_STATE_VALID 1
+#define SMUX_STATE_INVALID 2
+#define SMUX_STATE_CONNECTING 3
+
+typedef struct {
+    oid id[MAX_OID_LEN];
+    size_t idlen;
+    u_char* desc;
+    size_t desclen;
+    long int state;
+    netsnmp_table_row* row;
+} smux_state;
+
+/*
+ * column number definitions for table smuxPeerTable
+ */
+#define COLUMN_SMUXPINDEX		1
+#define COLUMN_SMUXPIDENTITY		2
+#define COLUMN_SMUXPDESCRIPTION		3
+#define COLUMN_SMUXPSTATUS		4
+
+static int
+smuxPeerTable_handler(UNUSED netsnmp_mib_handler *handler,
+                      UNUSED netsnmp_handler_registration *reginfo,
+                      netsnmp_agent_request_info *reqinfo,
+                      netsnmp_request_info *requests)
+{
+    netsnmp_request_info *request;
+    netsnmp_table_request_info *table_info;
+    netsnmp_session *table_entry;
+    smux_state *sms;
+
+    switch (reqinfo->mode) {
+        /*
+         * Read-support (also covers GetNext requests)
+         */
+    case MODE_GET:
+        for (request = requests; request; request = request->next) {
+            table_entry = (netsnmp_session *)
+                netsnmp_extract_table_row_data(request);
+            table_info = netsnmp_extract_table_info(request);
+
+            switch (table_info->colnum) {
+            case COLUMN_SMUXPINDEX:
+                snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
+                                         (u_char *) & table_entry->sessid,
+                                         sizeof(table_entry->sessid));
+                break;
+            case COLUMN_SMUXPIDENTITY:
+		sms = table_entry->myvoid;
+                snmp_set_var_typed_value(request->requestvb, ASN_OBJECT_ID,
+                                         (u_char *) sms->id,
+					 sms->idlen * sizeof(oid));
+                break;
+            case COLUMN_SMUXPDESCRIPTION:
+		sms = table_entry->myvoid;
+                snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
+                                         (u_char *) sms->desc, sms->desclen);
+                break;
+            case COLUMN_SMUXPSTATUS:
+		sms = table_entry->myvoid;
+                snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
+                                         (u_char *) & sms->state,
+					 sizeof(sms->state));
+                break;
+            }
+        }
+        break;
+
+        /*
+         * Write-support
+         */
+    case MODE_SET_RESERVE1:
+        for (request = requests; request; request = request->next) {
+            table_entry = (netsnmp_session *)
+                netsnmp_extract_table_row_data(request);
+            table_info = netsnmp_extract_table_info(request);
+
+            switch (table_info->colnum) {
+            case COLUMN_SMUXPSTATUS:
+                if (request->requestvb->type != ASN_INTEGER) {
+                    netsnmp_set_request_error(reqinfo, request,
+                                              SNMP_ERR_WRONGTYPE);
+                    return SNMP_ERR_NOERROR;
+                }
+                if (request->requestvb->val_len != sizeof(long)) {
+                    netsnmp_set_request_error(reqinfo, request,
+                                              SNMP_ERR_WRONGLENGTH);
+                    return SNMP_ERR_NOERROR;
+                }
+		switch (*request->requestvb->val.integer) {
+		case 1:
+		case 2:
+		    break;
+		default:
+		    netsnmp_set_request_error(reqinfo, request,
+					      SNMP_ERR_WRONGVALUE);
+		    return SNMP_ERR_NOERROR;
+		}
+                break;
+            default:
+                netsnmp_set_request_error(reqinfo, request,
+                                          SNMP_ERR_NOTWRITABLE);
+                return SNMP_ERR_NOERROR;
+            }
+        }
+        break;
+
+    case MODE_SET_RESERVE2:
+        break;
+
+    case MODE_SET_FREE:
+        break;
+
+    case MODE_SET_ACTION:
+        for (request = requests; request; request = request->next) {
+            table_entry = (netsnmp_session *)
+                netsnmp_extract_table_row_data(request);
+            table_info = netsnmp_extract_table_info(request);
+
+            switch (table_info->colnum) {
+            case COLUMN_SMUXPSTATUS:
+		sms = table_entry->myvoid;
+		if (*request->requestvb->val.integer == 2)
+		    /* XXX - Should be delayed */
+		    smux_close(table_entry, SMUXC_GOINGDOWN);
+                break;
+            }
+        }
+        break;
+
+    case MODE_SET_UNDO:
+        for (request = requests; request; request = request->next) {
+            table_info = netsnmp_extract_table_info(request);
+
+            switch (table_info->colnum) {
+            case COLUMN_SMUXPSTATUS:
+                netsnmp_set_request_error(reqinfo, request,
+                                          SNMP_ERR_UNDOFAILED);
+                return SNMP_ERR_NOERROR;
+            }
+        }
+        break;
+
+    case MODE_SET_COMMIT:
+        break;
+    }
+    return SNMP_ERR_NOERROR;
+}
+
+static netsnmp_table_data *smuxPeerTable_data = NULL;
+
+static void
+initialize_table_smuxPeerTable(void)
+{
+    static oid      smuxPeerTable_oid[] = { SMUX_OID, 1 };
+    netsnmp_handler_registration *smuxPeerTable_reg;
+    netsnmp_table_registration_info *smuxPeerTable_info;
+
+    smuxPeerTable_reg =
+	netsnmp_create_handler_registration("smuxPeerTable",
+					    smuxPeerTable_handler,
+					    smuxPeerTable_oid,
+					    OID_LENGTH(smuxPeerTable_oid),
+					    HANDLER_CAN_RWRITE);
+    smuxPeerTable_info =
+	SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
+
+    netsnmp_table_helper_add_indexes(smuxPeerTable_info,
+				     ASN_INTEGER,   /* index: smuxPindex */
+                                     0);
+    smuxPeerTable_info->min_column = COLUMN_SMUXPINDEX;
+    smuxPeerTable_info->max_column = COLUMN_SMUXPSTATUS;
+
+    smuxPeerTable_data = netsnmp_create_table_data("smuxPeerTable");
+    netsnmp_register_table_data(smuxPeerTable_reg, smuxPeerTable_data,
+				smuxPeerTable_info);
+}
+
+static int
+smuxPeerTable_insertEntry(netsnmp_table_data *table_data,
+			  netsnmp_session *session)
+{
+    netsnmp_table_row *row;
+    smux_state *sms = session->myvoid;
+
+    if (table_data == NULL)
+	return 0;
+
+    row = netsnmp_create_table_data_row();
+    if (!row) {
+        return -1;
+    }
+
+    row->data = session;
+    netsnmp_table_row_add_index(row, ASN_INTEGER,
+                                &(session->sessid), sizeof(session->sessid));
+    netsnmp_table_data_add_row(table_data, row);
+    sms->row = row;
+    return 0;
+}
+
+static void
+smuxPeerTable_removeEntry(netsnmp_table_data *table_data,
+                          netsnmp_session *session)
+{
+    smux_state *sms = session->myvoid;
+    smux_sub_session(session);
+    if (!sms || !sms->row)
+        return;
+    netsnmp_table_data_remove_and_delete_row(table_data, sms->row);
+}
+
+/*
+ * column number definitions for table smuxTreeTable
+ */
+#define COLUMN_SMUXTSUBTREE		1
+#define COLUMN_SMUXTPRIORITY		2
+#define COLUMN_SMUXTINDEX		3
+#define COLUMN_SMUXTSTATUS		4
+
+static int
+smuxTreeTable_handler(UNUSED netsnmp_mib_handler *handler,
+                      netsnmp_handler_registration *reginfo,
+                      netsnmp_agent_request_info *reqinfo,
+                      netsnmp_request_info *requests)
+{
+    netsnmp_request_info *request;
+    long int exact;
+
+    switch (reqinfo->mode) {
+    case MODE_SET_BEGIN:
+    case MODE_SET_RESERVE2:
+    case MODE_SET_COMMIT:
+    case MODE_SET_FREE:
+	return SNMP_ERR_NOERROR;
+
+    case MODE_GET:
+    case MODE_SET_RESERVE1:
+    case MODE_SET_ACTION:
+	break;
+
+    case MODE_GETNEXT:
+	for (request = requests; request; request = request->next) {
+	    long int i;
+	    smux_peer* cp = NULL;
+	    netsnmp_table_request_info *info =
+		netsnmp_extract_table_info(request);
+	    smux_reg* cur = smux_registry_l;
+	    if (info->number_indexes > 0) {
+		size_t xlen = info->indexes->val_len / sizeof(oid);
+		oid*   xtree = info->indexes->val.objid;
+		while (cur != NULL &&
+		       (cur->treelen < xlen ||
+			(cur->treelen == xlen &&
+			 snmp_oid_compare(cur->tree, cur->treelen,
+					  xtree, xlen) < 0))) {
+		    cur = cur->next_l;
+		}
+	    }
+	    if (cur != NULL)
+		cp = cur->peer_regs;
+
+	    if (info->number_indexes > 1) {
+		long int prio = *info->indexes->next_variable->val.integer;
+		while (cp && cp->prio <= prio)
+		    cp = cp->next;
+	    }
+
+	    if (cp == NULL && cur != NULL) {
+		cur = cur->next_l;
+		if (cur != NULL)
+		    cp = cur->peer_regs;
+	    }
+
+	    if (cp == NULL) {
+		netsnmp_set_request_error(reqinfo, request,
+					  SNMP_ENDOFMIBVIEW);
+	    } else {
+		oid name[MAX_OID_LEN];
+		size_t namelen = 0;
+
+		namelen = reginfo->rootoid_len;
+		memcpy(name, reginfo->rootoid, namelen * sizeof(oid));
+		name[namelen++] = 1;
+		name[namelen++] = info->colnum;
+		name[namelen++] = cur->treelen;
+		memcpy(name + namelen, cur->tree, cur->treelen * sizeof(oid));
+		namelen += cur->treelen;
+		name[namelen++] = cp->prio;
+		snmp_set_var_objid(request->requestvb, name, namelen);
+
+		switch(info->colnum) {
+		case COLUMN_SMUXTSUBTREE:
+		    snmp_set_var_typed_value(request->requestvb, ASN_OBJECT_ID,
+					     (u_char *) cur->tree,
+					     cur->treelen * sizeof(oid));
+		    break;
+		case COLUMN_SMUXTPRIORITY:
+		    snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
+					     (u_char *) & cp->prio,
+					     sizeof(cp->prio));
+		    break;
+		case COLUMN_SMUXTINDEX:
+		    snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
+					     (u_char *) & cp->session->sessid,
+					     sizeof(cp->session->sessid));
+		    break;
+		case COLUMN_SMUXTSTATUS:
+		    i = 1;
+		    snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
+					     (u_char *) & i, sizeof(i));
+		    break;
+		}
+	    }
+	}
+	return SNMP_ERR_NOERROR;
+
+    default:
+	printf("mode = %d\n", reqinfo->mode);
+	abort();
+    }
+
+    for (request = requests; request; request = request->next) {
+	long int i;
+	smux_peer* cp;
+	netsnmp_table_request_info *info =
+	    netsnmp_extract_table_info(request);
+	smux_reg* cur = smux_registry;
+	while (cur && (i = snmp_oid_compare(cur->tree, cur->treelen,
+					    info->indexes[0].val.objid,
+					    info->indexes[0].val_len)) < 0)
+	    cur = cur->next;
+	cp = cur->peer_regs;
+	while (cp && cp->prio < *info->indexes[1].val.integer)
+	    cp = cp->next;
+	if (cp && cp->prio != *info->indexes[1].val.integer)
+	    cp = NULL;
+
+	switch (reqinfo->mode) {
+	case MODE_GET:
+	    if (!cp) {
+		netsnmp_set_request_error(reqinfo, request,
+					  SNMP_NOSUCHINSTANCE);
+		return SNMP_ERR_NOERROR;
+	    }
+            switch (info->colnum) {
+            case COLUMN_SMUXTSUBTREE:
+                snmp_set_var_typed_value(request->requestvb, ASN_OBJECT_ID,
+                                         (u_char *) cur->tree,
+					 cur->treelen * sizeof(oid));
+                break;
+            case COLUMN_SMUXTPRIORITY:
+                snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
+                                         (u_char *) & cp->prio,
+					 sizeof(cp->prio));
+                break;
+            case COLUMN_SMUXTINDEX:
+                snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
+                                         (u_char *) & cp->session->sessid,
+                                         sizeof(cp->session->sessid));
+                break;
+            case COLUMN_SMUXTSTATUS:
+		exact = 1;
+                snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
+                                         (u_char *) & exact, sizeof(exact));
+                break;
+            }
+	    break;
+
+	case MODE_GETNEXT:
+	    break;
+
+	    /*
+	     * Write-support
+	     */
+	case MODE_SET_RESERVE1:
+            switch (info->colnum) {
+            case COLUMN_SMUXTSTATUS:
+                if (request->requestvb->type != ASN_INTEGER) {
+                    netsnmp_set_request_error(reqinfo, request,
+                                              SNMP_ERR_WRONGTYPE);
+                    return SNMP_ERR_NOERROR;
+                }
+                if (request->requestvb->val_len != sizeof(long)) {
+                    netsnmp_set_request_error(reqinfo, request,
+                                              SNMP_ERR_WRONGLENGTH);
+                    return SNMP_ERR_NOERROR;
+                }
+                switch (*request->requestvb->val.integer) {
+		case 1:
+		case 2:
+		    break;
+		default:
+                    netsnmp_set_request_error(reqinfo, request,
+                                              SNMP_ERR_WRONGVALUE);
+                    return SNMP_ERR_NOERROR;
+                }
+		if (!cp) {
+		    netsnmp_set_request_error(reqinfo, request,
+					      SNMP_ERR_INCONSISTENTNAME);
+		    return SNMP_ERR_NOERROR;
+		}
+                break;
+            default:
+                netsnmp_set_request_error(reqinfo, request,
+                                          SNMP_ERR_NOTWRITABLE);
+                return SNMP_ERR_NOERROR;
+            }
+	    break;
+
+	case MODE_SET_ACTION:
+            switch (info->colnum) {
+            case COLUMN_SMUXTSTATUS:
+		if (cp && *request->requestvb->val.integer == 2)
+		    smux_sub_reg (cp->session, cur->tree, cur->treelen,
+				  cp->prio);
+                break;
+            }
+	    break;
+
+	case MODE_SET_UNDO:
+            switch (info->colnum) {
+            case COLUMN_SMUXTSTATUS:
+                netsnmp_set_request_error(reqinfo, request,
+                                          SNMP_ERR_UNDOFAILED);
+                return SNMP_ERR_NOERROR;
+            }
+	    break;
+	}
+    }
+    return SNMP_ERR_NOERROR;
+}
+
+static void
+initialize_table_smuxTreeTable(void)
+{
+    static oid      smuxTreeTable_oid[] = { SMUX_OID, 2 };
+    size_t          smuxTreeTable_oid_len = OID_LENGTH(smuxTreeTable_oid);
+
+    netsnmp_handler_registration *smuxTreeTable_reg;
+    netsnmp_table_registration_info *smuxTreeTable_info;
+
+    smuxTreeTable_reg =
+        netsnmp_create_handler_registration("smuxTreeTable",
+                                            smuxTreeTable_handler,
+                                            smuxTreeTable_oid,
+                                            smuxTreeTable_oid_len,
+                                            HANDLER_CAN_RWRITE);
+
+    smuxTreeTable_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
+    netsnmp_table_helper_add_indexes(smuxTreeTable_info,
+				     ASN_OBJECT_ID, /* index: smuxTsubtree */
+                                     ASN_INTEGER,   /* index: smuxTpriority */
+                                     0);
+    smuxTreeTable_info->min_column = COLUMN_SMUXTSUBTREE;
+    smuxTreeTable_info->max_column = COLUMN_SMUXTSTATUS;
+
+    netsnmp_register_table(smuxTreeTable_reg, smuxTreeTable_info);
+}
+
+static int
+smux_check_packet(u_char * pkt, size_t len)
+{
+    if (len < 2)
+        return 0;               /* always too short */
+
+
+    switch (*pkt) {
+    case SMUX_OPEN:
+    case SMUX_CLOSE:
+    case SMUX_RREQ:
+    case SMUX_GETRSP:
+    case SMUX_TRAP:
+	break;
+    default:
+        return -1;              /* wrong type */
+    }
+
+    if (*(pkt + 1) & 0x80) {
+        /* long length */
+        u_long asn_length;
+        if ((int) len < (int) (*(pkt + 1) & ~0x80) + 2)
+            return 0;           /* still to short, incomplete length */
+        asn_parse_length(pkt + 1, &asn_length);
+        return (asn_length + 2 + (*(pkt + 1) & ~0x80));
+    } else {
+        /* short length */
+        return (*(pkt + 1) + 2);
+    }
+}
+
+void
+init_smux(void)
+{
+    initialize_table_smuxPeerTable();
+    initialize_table_smuxTreeTable();
+
+    netsnmp_register_default_domain("smux", "tcp");
+    netsnmp_register_default_target("smux", "tcp",
+#ifdef NETSNMP_LOCAL_SMUX
+				    "127.0.0.1"
+#endif
+#define val(x) __STRING(x)
+				    ":" val(SMUXPORT)
+#undef val
+				    );
+
+    snmpd_register_config_handler("smuxpeer", smux_parse_peer_auth,
+                                  smux_free_peer_auth,
+                                  "OID-IDENTITY PASSWORD");
+    snmpd_register_config_handler("smuxsocket",
+                                  smux_parse_smux_socket, NULL,
+                                  "SMUX bind address");
+
+    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
+                           SNMP_CALLBACK_POST_READ_CONFIG,
+                           &smux_startup, NULL);
+}
+
+static int
+smux_startup(UNUSED int p1, UNUSED int p2, UNUSED void* p3, UNUSED void* p4)
+{
+    const char        *smux_socket;
+    netsnmp_session   *session, sess;
+    netsnmp_transport *sesstr;
+
+    snmp_sess_init(&sess);
+    sess.version = SMUXVERSION;
+    sess.flags |= SNMP_FLAGS_STREAM_SOCKET;
+    sess.timeout = 5;
+    sess.callback = smux_callback;
+
+    smux_socket = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
+					NETSNMP_DS_SMUX_SOCKET);
+    if (!smux_socket)
+	smux_socket = "";
+
+    sesstr = netsnmp_transport_open_server("smux", smux_socket);
+
+    if (sesstr == NULL) {
+        snmp_log_perror("[init_smux] failed to create server");
+        return 0;
+    }
+
+    session = snmp_add_full(&sess, sesstr,
+			    NULL, smux_parse, NULL,
+			    NULL, NULL,
+			    smux_check_packet, NULL);
+
+    DEBUGMSGTL(("smux", "[smux_init] done; smux listen\n"));
+
+    return 0;
+}
+
+void
+shutdown_smux(void)
+{
+    smux_sub_all();
+    smux_free_peer_auth();
+}
+
+static void
+smux_send_int(netsnmp_session *pss, u_char type, long int val)
+{
+    u_char pktbuf[32];
+    u_char *pkt = pktbuf;
+    size_t pkt_len = sizeof(pktbuf);
+    size_t offset = 0;
+    void* opaque = NULL;
+    int olength = 0;
+    netsnmp_transport *transport =
+	snmp_sess_transport(snmp_sess_pointer(pss));
+
+    if(asn_realloc_rbuild_int(&pkt, &pkt_len, &offset, 0,
+			      type, &val, sizeof(val)))
+	transport->f_send(transport, pkt + pkt_len - offset, offset,
+			  &opaque, &olength);
+}
+
+static void
+smux_close(netsnmp_session *pss, long int reason)
+{
+    smux_state* sms;
+    netsnmp_transport *transport =
+	snmp_sess_transport(snmp_sess_pointer(pss));
+
+    smux_send_int(pss, SMUX_CLOSE, reason);
+
+    smuxPeerTable_removeEntry(smuxPeerTable_data, pss);
+    smux_unauth_peer(pss);
+    sms = pss->myvoid;
+    free(sms->desc);
+    free(sms);
+    DEBUGMSGTL(("smux", "deleted myvoid %p\n", pss->myvoid ));
+    pss->myvoid = NULL;
+    netsnmp_remove_delegated_requests_for_session(pss);
+    transport->f_close(transport);
+}
+
+static int
+smux_callback(int op, netsnmp_session* session,
+	      UNUSED int reqid, UNUSED netsnmp_pdu* pdu,
+	      UNUSED void* magic)
+{
+    smux_state* sms;
+
+    switch(op) {
+    case NETSNMP_CALLBACK_OP_CONNECT:
+	session->myvoid = sms = SNMP_MALLOC_TYPEDEF(smux_state);
+	DEBUGMSGTL(("smux", "created myvoid %p\n", session->myvoid ));
+	sms->state = SMUX_STATE_CONNECTING;
+	smuxPeerTable_insertEntry(smuxPeerTable_data, session);
+	break;
+    case NETSNMP_CALLBACK_OP_DISCONNECT:
+	smuxPeerTable_removeEntry(smuxPeerTable_data, session);
+	smux_unauth_peer(session);
+	if (session->myvoid) {
+	    sms = session->myvoid;
+	    free(sms->desc);
+	    free(sms);
+	    DEBUGMSGTL(("smux", "deleted myvoid %p\n", session->myvoid ));
+	    session->myvoid = NULL;
+	}
+	break;
+    }
+    return 1;
+}
+
+static int
+smux_parse_open(netsnmp_session *pss, u_char **data, size_t *length)
+{
+    long int version;
+    oid id[MAX_OID_LEN];
+    size_t idlen = MAX_OID_LEN;
+    u_char desc[256];
+    size_t desclen = 256;
+    u_char type;
+    smux_state *sms = pss->myvoid;
+
+    *data = asn_parse_int(*data, length, &type, &version, sizeof(version));
+    if (*data == NULL || type != ASN_INTEGER || version != SMUXVERSION) {
+	smux_close(pss, SMUXC_PACKETFORMAT);
+	return -1;
+    }
+    *data = asn_parse_objid(*data, length, &type, id, &idlen);
+    if (*data == NULL || type != ASN_OBJECT_ID) {
+	smux_close(pss, SMUXC_PACKETFORMAT);
+	return -1;
+    }
+    *data = asn_parse_string(*data, length, &type, desc, &desclen);
+    if (*data == NULL || type != ASN_OCTET_STR) {
+	smux_close(pss, SMUXC_PACKETFORMAT);
+	return -1;
+    }
+    {
+	u_char* pwd;
+	u_long tmplen = *length;
+	size_t pwdlen;
+	asn_parse_length(*data, &tmplen);
+	pwdlen = tmplen + 1;
+	pwd = malloc(pwdlen);
+	*data = asn_parse_string(*data, length, &type, pwd, &pwdlen);
+	if (*data == NULL || type != ASN_OCTET_STR || *length > 0) {
+	    free(pwd);
+	    smux_close(pss, SMUXC_PACKETFORMAT);
+	    return -1;
+	}
+
+	/* Check state */
+
+	if (sms->state != SMUX_STATE_CONNECTING) {
+	    free(pwd);
+	    smux_close(pss, SMUXC_PROTOCOLERROR);
+	    return -1;
+	}
+
+	/* Check password */
+
+	if(!smux_auth_peer(pss, id, idlen, pwd)) {
+	    smux_close(pss, SMUXC_AUTHENTICATIONFAILURE);
+	    free(pwd);
+	    return -1;
+	} else
+	    free(pwd);
+    }
+
+    DEBUGMSGTL(("smux", "smux-open, password accepted\n" ));
+
+    /* Check for forbidden registrations */
+    {
+	static const oid smux_oid[] = { SMUX_OID };
+	static const oid snmp_oid[] = { 1, 3, 6, 1, 2, 1, 11 };
+	typedef struct {
+	    size_t len;
+	    const oid *name;
+	} black_entry;
+	static black_entry const black_list[] = {
+	    { OID_LENGTH(smux_oid), smux_oid },
+	    { OID_LENGTH(snmp_oid), snmp_oid },
+	    { 0, NULL }
+	};
+
+	const black_entry *cur = black_list;
+	while(cur->name) {
+	    if(snmp_oidtree_compare(id, idlen, cur->name, cur->len) == 0) {
+		smux_close(pss, SMUXC_PROTOCOLERROR);
+		return -1;
+	    }
+	    ++cur;
+	}
+    }
+
+    /* All ok, finish session */
+
+    DEBUGMSGTL(("smux", "smux-open, oid accepted\n" ));
+
+    memcpy(sms->id, id, idlen * sizeof(oid));
+    sms->idlen = idlen;
+    sms->desc = memcpy(malloc(desclen), desc, desclen);
+    sms->desclen = desclen;
+    sms->state = SMUX_STATE_VALID;
+    return 0;
+}
+
+static int
+smux_parse_close(netsnmp_session *pss, u_char **data, size_t *length)
+{
+    long int result;
+    u_char type;
+    smux_state *sms = pss->myvoid;
+
+    *data = asn_parse_int(*data, length, &type, &result, sizeof(result));
+    if (*data == NULL || type != SMUX_CLOSE || result < 0 || result > 5) {
+	smux_close(pss, SMUXC_PACKETFORMAT);
+	return -1;
+    }
+    sms->state = SMUX_STATE_INVALID;
+    return 0;
+}
+
+static int
+smux_parse_rreq(netsnmp_session *pss, u_char **data, size_t *length)
+{
+    oid tree[MAX_OID_LEN];
+    size_t treelen = MAX_OID_LEN;
+    long int prio;
+    long int op;
+    long int res;
+    u_char type;
+
+    *data = asn_parse_objid(*data, length, &type, tree, &treelen);
+    if (*data == NULL || type != ASN_OBJECT_ID) {
+	smux_close(pss, SMUXC_PACKETFORMAT);
+	return -1;
+    }
+    *data = asn_parse_int(*data, length, &type, &prio, sizeof(prio));
+    if (*data == NULL || type != ASN_INTEGER || prio < -1) {
+	smux_close(pss, SMUXC_PACKETFORMAT);
+	return -1;
+    }
+    *data = asn_parse_int(*data, length, &type, &op, sizeof(op));
+    if (*data == NULL || type != ASN_INTEGER || op < 0 || op > 2 ||
+	*length > 0) {
+	smux_close(pss, SMUXC_PACKETFORMAT);
+	return -1;
+    }
+
+    DEBUGMSGTL(("smux",
+                "smux-rreq, tree: ..., prio: %ld, op: %ld\n", prio, op ));
+
+    if(op == SMUX_REGOP_DELETE)
+	res = smux_sub_reg(pss, tree, treelen, prio);
+    else
+	res = smux_add_reg(pss, tree, treelen, prio,
+			   op == SMUX_REGOP_REGISTER_RO);
+
+    smux_send_int(pss, SMUX_RRSP, res);
+    return 0;
+}
+
+static int
+smux_parse(netsnmp_session *pss, netsnmp_pdu *pdu, u_char *data, size_t length)
+{
+    u_char type;
+    u_char* save = data;
+    size_t savelen = length;
+
+    data = asn_parse_header(data, &length, &type);
+    if (data == NULL) {
+	smux_close(pss, SMUXC_PACKETFORMAT);
+    } else switch (type) {
+    case SMUX_OPEN:
+	if (smux_parse_open(pss, &data, &length) < 0)
+	    return -1;
+	break;
+    case SMUX_CLOSE:
+	data = save;
+	length = savelen;
+	if (smux_parse_close(pss, &data, &length) < 0)
+	    return -1;
+	break;
+    case SMUX_RREQ:
+	if (smux_parse_rreq(pss, &data, &length) < 0)
+	    return -1;
+	break;
+    case SMUX_TRAP:
+	data = save;
+	length = savelen;
+	if (snmp_pdu_parse(pdu, data, &length) < 0) {
+	    smux_close(pss, SMUXC_PACKETFORMAT);
+	    return -1;
+	} else {
+	    /* OK, the trap functions suck big time, why can't I just forward
+	     * my trap pdu and have it converted???
+	     *
+	     * This slices of the agent address but is the best I can do for
+	     * now
+	     */
+	    netsnmp_pdu* v2 = convert_v1pdu_to_v2(pdu);
+	    send_trap_pdu(v2);
+	    snmp_free_pdu(v2);
+	}
+	break;
+    case SMUX_GETRSP:
+	data = save;
+	length = savelen;
+	DEBUGMSGHEX(("smux", data, length));
+	DEBUGMSG(("smux", "\n"));
+	if (snmp_pdu_parse(pdu, data, &length) < 0) {
+	    smux_close(pss, SMUXC_PACKETFORMAT);
+	    return -1;
+	} else {
+	    return 0;
+	}
+	break;
+    default:
+	smux_close(pss, SMUXC_PROTOCOLERROR);
+	return -1;
+    }
+    return SNMP_ERR_NOERROR;
+}
+
+static int
+smux_handler(netsnmp_mib_handler *handler,
+	     netsnmp_handler_registration *reginfo,
+	     netsnmp_agent_request_info *reqinfo,
+	     netsnmp_request_info *requests)
+{
+    smux_reg *registration = (smux_reg*)reginfo->my_reg_void;
+    int mode;
+
+    switch(reqinfo->mode) {
+    case MODE_SET_BEGIN:
+    case MODE_SET_RESERVE2:
+    case MODE_SET_ACTION:
+	return SNMP_ERR_NOERROR;
+    }
+
+    mode = reqinfo->mode;
+
+    switch(reqinfo->mode) {
+    case MODE_GET:
+    case MODE_GETNEXT:
+	/* forward request to registration->peer_regs->session */
+	{
+	    netsnmp_request_info *request;
+	    u_char pktbuf[4096];
+	    u_char *pkt = pktbuf;
+	    size_t pkt_len = sizeof(pktbuf);
+	    size_t offset = 0;
+	    long int tmp = 0;
+	    void* opaque = NULL;
+	    int olength = 0;
+	    netsnmp_transport *transport =
+		snmp_sess_transport(snmp_sess_pointer(registration->
+						      peer_regs->session));
+
+	    for(request = requests; request; request = request->next) {
+		snmp_realloc_rbuild_var_op(&pkt, &pkt_len, &offset, 1,
+					   request->requestvb->name,
+					   &request->requestvb->name_length,
+					   request->requestvb->type,
+					   request->requestvb->val.string,
+					   request->requestvb->val_len);
+		request->delegated = 1;
+	    }
+	    asn_realloc_rbuild_sequence(&pkt, &pkt_len, &offset, 0,
+					(ASN_SEQUENCE | ASN_CONSTRUCTOR),
+					offset);
+	    asn_realloc_rbuild_int(&pkt, &pkt_len, &offset, 0,
+				   ASN_INTEGER, &tmp, sizeof(tmp));
+	    asn_realloc_rbuild_int(&pkt, &pkt_len, &offset, 0,
+				   ASN_INTEGER, &tmp, sizeof(tmp));
+	    asn_realloc_rbuild_int(&pkt, &pkt_len, &offset, 0,
+				   ASN_INTEGER, &tmp, sizeof(tmp));
+	    asn_realloc_rbuild_sequence(&pkt, &pkt_len, &offset, 0,
+					mode, offset);
+	    DEBUGMSGHEX(("smux", pkt + pkt_len - offset, offset));
+	    DEBUGMSG(("smux", "\n"));
+	    transport->f_send(transport, pkt + pkt_len - offset, offset,
+			      &opaque, &olength);
+	}
+	break;
+    case MODE_SET_RESERVE1:
+        mode = SNMP_MSG_SET;
+	if (registration->peer_regs->readonly)
+	    netsnmp_request_set_error_all(requests, SNMP_ERR_NOTWRITABLE);
+	break;
+    case MODE_SET_COMMIT:
+	smux_send_int(registration->peer_regs->session, SMUX_SOUT, 0);
+	break;
+    case MODE_SET_UNDO:
+	smux_send_int(registration->peer_regs->session, SMUX_SOUT, 1);
+	break;
+    case MODE_SET_FREE:
+	break;
+    }
+    return SNMP_ERR_NOERROR;
+}
Index: clean/agent/mibgroup/smux/smux_new.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ clean/agent/mibgroup/smux/smux_new.h	2010-04-07 02:16:04.000000000 +0200
@@ -0,0 +1,9 @@
+/*
+ * Smux module authored by Rohit Dube.
+ * Rewritten by Nick Amato <[email protected]>.
+ * Rewritten another time by Magnus Fromreide <[email protected]>.
+ */
+config_add_mib(SMUX-MIB)
+
+extern void     init_smux(void);
+extern void     shutdown_smux(void);
Index: clean/mibs/SMUX-MIB.txt
===================================================================
--- clean.orig/mibs/SMUX-MIB.txt	2010-03-15 23:47:42.000000000 +0100
+++ clean/mibs/SMUX-MIB.txt	2010-04-07 02:16:04.000000000 +0200
@@ -4,7 +4,9 @@
         enterprises
                 FROM RFC1155-SMI
         OBJECT-TYPE
-                FROM RFC1212;
+                FROM RFC1212
+	DisplayString
+		FROM RFC1213-MIB;
 
 unix    OBJECT IDENTIFIER ::= { enterprises 4 }
 
------------------------------------------------------------------------------
Free Software Download: Index, Search & Analyze Logs and other IT data in 
Real-Time with Splunk. Collect, index and harness all the fast moving IT data 
generated by your applications, servers and devices whether physical, virtual
or in the cloud. Deliver compliance at lower cost and gain new business 
insights. http://p.sf.net/sfu/splunk-dev2dev 
_______________________________________________
Net-snmp-coders mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders

Reply via email to