summaryrefslogtreecommitdiff
path: root/agent/mibgroup/agentx/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/agentx/client.c')
-rw-r--r--agent/mibgroup/agentx/client.c492
1 files changed, 492 insertions, 0 deletions
diff --git a/agent/mibgroup/agentx/client.c b/agent/mibgroup/agentx/client.c
new file mode 100644
index 0000000..d36fe2d
--- /dev/null
+++ b/agent/mibgroup/agentx/client.c
@@ -0,0 +1,492 @@
+/*
+ * AgentX utility routines
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+
+#include <stdio.h>
+#include <errno.h>
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/agent/agent_index.h>
+
+#include "agentx/protocol.h"
+#include "agentx/client.h"
+#include "agentx/subagent.h"
+
+netsnmp_feature_require(set_agent_uptime)
+
+ /*
+ * AgentX handling utility routines
+ *
+ * Mostly wrappers round, or re-writes of
+ * the SNMP equivalents
+ */
+
+int
+agentx_synch_input(int op,
+ netsnmp_session * session,
+ int reqid, netsnmp_pdu *pdu, void *magic)
+{
+ struct synch_state *state = (struct synch_state *) magic;
+
+ if (!state || reqid != state->reqid) {
+ return handle_agentx_packet(op, session, reqid, pdu, magic);
+ }
+
+ DEBUGMSGTL(("agentx/subagent", "synching input, op 0x%02x\n", op));
+ state->waiting = 0;
+ if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
+ if (pdu->command == AGENTX_MSG_RESPONSE) {
+ state->pdu = snmp_clone_pdu(pdu);
+ state->status = STAT_SUCCESS;
+ session->s_snmp_errno = SNMPERR_SUCCESS;
+
+ /*
+ * Synchronise sysUpTime with the master agent
+ */
+ netsnmp_set_agent_uptime(pdu->time);
+ }
+ } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) {
+ state->pdu = NULL;
+ state->status = STAT_TIMEOUT;
+ session->s_snmp_errno = SNMPERR_TIMEOUT;
+ } else if (op == NETSNMP_CALLBACK_OP_DISCONNECT) {
+ return handle_agentx_packet(op, session, reqid, pdu, magic);
+ }
+
+ return 1;
+}
+
+
+
+int
+agentx_synch_response(netsnmp_session * ss, netsnmp_pdu *pdu,
+ netsnmp_pdu **response)
+{
+ return snmp_synch_response_cb(ss, pdu, response, agentx_synch_input);
+}
+
+
+ /*
+ * AgentX PofE convenience functions
+ */
+
+int
+agentx_open_session(netsnmp_session * ss)
+{
+ netsnmp_pdu *pdu, *response;
+ extern oid version_sysoid[];
+ extern int version_sysoid_len;
+ u_long timeout;
+
+ DEBUGMSGTL(("agentx/subagent", "opening session \n"));
+ if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
+ return 0;
+ }
+
+ pdu = snmp_pdu_create(AGENTX_MSG_OPEN);
+ if (pdu == NULL)
+ return 0;
+ timeout = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
+ NETSNMP_DS_AGENT_AGENTX_TIMEOUT);
+ if (timeout < 0)
+ pdu->time = 0;
+ else
+ /* for master TIMEOUT is usec, but Agentx Open specifies sec */
+ pdu->time = timeout/ONE_SEC;
+
+ snmp_add_var(pdu, version_sysoid, version_sysoid_len,
+ 's', "Net-SNMP AgentX sub-agent");
+
+ if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
+ return 0;
+
+ if (!response)
+ return 0;
+
+ if (response->errstat != SNMP_ERR_NOERROR) {
+ snmp_free_pdu(response);
+ return 0;
+ }
+
+ ss->sessid = response->sessid;
+ snmp_free_pdu(response);
+
+ DEBUGMSGTL(("agentx/subagent", "open \n"));
+ return 1;
+}
+
+int
+agentx_close_session(netsnmp_session * ss, int why)
+{
+ netsnmp_pdu *pdu, *response;
+ DEBUGMSGTL(("agentx/subagent", "closing session\n"));
+
+ if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
+ return 0;
+ }
+
+ pdu = snmp_pdu_create(AGENTX_MSG_CLOSE);
+ if (pdu == NULL)
+ return 0;
+ pdu->time = 0;
+ pdu->errstat = why;
+ pdu->sessid = ss->sessid;
+
+ if (agentx_synch_response(ss, pdu, &response) == STAT_SUCCESS)
+ snmp_free_pdu(response);
+ DEBUGMSGTL(("agentx/subagent", "closed\n"));
+
+ return 1;
+}
+
+int
+agentx_register(netsnmp_session * ss, oid start[], size_t startlen,
+ int priority, int range_subid, oid range_ubound,
+ int timeout, u_char flags, const char *contextName)
+{
+ netsnmp_pdu *pdu, *response;
+
+ DEBUGMSGTL(("agentx/subagent", "registering: "));
+ DEBUGMSGOIDRANGE(("agentx/subagent", start, startlen, range_subid,
+ range_ubound));
+ DEBUGMSG(("agentx/subagent", "\n"));
+
+ if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
+ return 0;
+ }
+
+ pdu = snmp_pdu_create(AGENTX_MSG_REGISTER);
+ if (pdu == NULL) {
+ return 0;
+ }
+ pdu->time = timeout;
+ pdu->priority = priority;
+ pdu->sessid = ss->sessid;
+ pdu->range_subid = range_subid;
+ if (contextName) {
+ pdu->flags |= AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT;
+ pdu->community = (u_char *) strdup(contextName);
+ pdu->community_len = strlen(contextName);
+ }
+
+ if (flags & FULLY_QUALIFIED_INSTANCE) {
+ pdu->flags |= AGENTX_MSG_FLAG_INSTANCE_REGISTER;
+ }
+
+ if (range_subid) {
+ snmp_pdu_add_variable(pdu, start, startlen, ASN_OBJECT_ID,
+ (u_char *) start, startlen * sizeof(oid));
+ pdu->variables->val.objid[range_subid - 1] = range_ubound;
+ } else {
+ snmp_add_null_var(pdu, start, startlen);
+ }
+
+ if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) {
+ DEBUGMSGTL(("agentx/subagent", "registering failed!\n"));
+ return 0;
+ }
+
+ if (response->errstat != SNMP_ERR_NOERROR) {
+ snmp_log(LOG_ERR,"registering pdu failed: %ld!\n", response->errstat);
+ snmp_free_pdu(response);
+ return 0;
+ }
+
+ snmp_free_pdu(response);
+ DEBUGMSGTL(("agentx/subagent", "registered\n"));
+ return 1;
+}
+
+int
+agentx_unregister(netsnmp_session * ss, oid start[], size_t startlen,
+ int priority, int range_subid, oid range_ubound,
+ const char *contextName)
+{
+ netsnmp_pdu *pdu, *response;
+
+ if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
+ return 0;
+ }
+
+ DEBUGMSGTL(("agentx/subagent", "unregistering: "));
+ DEBUGMSGOIDRANGE(("agentx/subagent", start, startlen, range_subid,
+ range_ubound));
+ DEBUGMSG(("agentx/subagent", "\n"));
+ pdu = snmp_pdu_create(AGENTX_MSG_UNREGISTER);
+ if (pdu == NULL) {
+ return 0;
+ }
+ pdu->time = 0;
+ pdu->priority = priority;
+ pdu->sessid = ss->sessid;
+ pdu->range_subid = range_subid;
+ if (contextName) {
+ pdu->flags |= AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT;
+ pdu->community = (u_char *) strdup(contextName);
+ pdu->community_len = strlen(contextName);
+ }
+
+ if (range_subid) {
+ snmp_pdu_add_variable(pdu, start, startlen, ASN_OBJECT_ID,
+ (u_char *) start, startlen * sizeof(oid));
+ pdu->variables->val.objid[range_subid - 1] = range_ubound;
+ } else {
+ snmp_add_null_var(pdu, start, startlen);
+ }
+
+ if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
+ return 0;
+
+ if (response->errstat != SNMP_ERR_NOERROR) {
+ snmp_free_pdu(response);
+ return 0;
+ }
+
+ snmp_free_pdu(response);
+ DEBUGMSGTL(("agentx/subagent", "unregistered\n"));
+ return 1;
+}
+
+netsnmp_variable_list *
+agentx_register_index(netsnmp_session * ss,
+ netsnmp_variable_list * varbind, int flags)
+{
+ netsnmp_pdu *pdu, *response;
+ netsnmp_variable_list *varbind2;
+
+ if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
+ return NULL;
+ }
+
+ /*
+ * Make a copy of the index request varbind
+ * for the AgentX request PDU
+ * (since the pdu structure will be freed)
+ */
+ varbind2 =
+ (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list));
+ if (varbind2 == NULL)
+ return NULL;
+ if (snmp_clone_var(varbind, varbind2)) {
+ snmp_free_varbind(varbind2);
+ return NULL;
+ }
+ if (varbind2->val.string == NULL)
+ varbind2->val.string = varbind2->buf; /* ensure it points somewhere */
+
+ pdu = snmp_pdu_create(AGENTX_MSG_INDEX_ALLOCATE);
+ if (pdu == NULL) {
+ snmp_free_varbind(varbind2);
+ return NULL;
+ }
+ pdu->time = 0;
+ pdu->sessid = ss->sessid;
+ if (flags == ALLOCATE_ANY_INDEX)
+ pdu->flags |= AGENTX_MSG_FLAG_ANY_INSTANCE;
+ if (flags == ALLOCATE_NEW_INDEX)
+ pdu->flags |= AGENTX_MSG_FLAG_NEW_INSTANCE;
+
+ /*
+ * Just send a single index request varbind.
+ * Although the AgentX protocol supports
+ * multiple index allocations in a single
+ * request, the model used in the net-snmp agent
+ * doesn't currently take advantage of this.
+ * I believe this is our prerogative - just as
+ * long as the master side Index request handler
+ * can cope with multiple index requests.
+ */
+ pdu->variables = varbind2;
+
+ if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
+ return NULL;
+
+ if (response->errstat != SNMP_ERR_NOERROR) {
+ snmp_free_pdu(response);
+ return NULL;
+ }
+
+ /*
+ * Unlink the (single) response varbind to return
+ * to the main driving index request routine.
+ *
+ * This is a memory leak, as nothing will ever
+ * release this varbind. If this becomes a problem,
+ * we'll need to keep a list of these here, and
+ * free the memory in the "index release" routine.
+ * But the master side never frees these either (by
+ * design, since it still needs them), so expecting
+ * the subagent to is discrimination, pure & simple :-)
+ */
+ varbind2 = response->variables;
+ response->variables = NULL;
+ snmp_free_pdu(response);
+ return varbind2;
+}
+
+int
+agentx_unregister_index(netsnmp_session * ss,
+ netsnmp_variable_list * varbind)
+{
+ netsnmp_pdu *pdu, *response;
+ netsnmp_variable_list *varbind2;
+
+ if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
+ return -1;
+ }
+
+ /*
+ * Make a copy of the index request varbind
+ * for the AgentX request PDU
+ * (since the pdu structure will be freed)
+ */
+ varbind2 =
+ (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list));
+ if (varbind2 == NULL)
+ return -1;
+ if (snmp_clone_var(varbind, varbind2)) {
+ snmp_free_varbind(varbind2);
+ return -1;
+ }
+
+ pdu = snmp_pdu_create(AGENTX_MSG_INDEX_DEALLOCATE);
+ if (pdu == NULL) {
+ snmp_free_varbind(varbind2);
+ return -1;
+ }
+ pdu->time = 0;
+ pdu->sessid = ss->sessid;
+
+ /*
+ * Just send a single index release varbind.
+ * (as above)
+ */
+ pdu->variables = varbind2;
+
+ if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
+ return -1;
+
+ if (response->errstat != SNMP_ERR_NOERROR) {
+ snmp_free_pdu(response);
+ return -1; /* XXX - say why */
+ }
+
+ snmp_free_pdu(response);
+ return SNMP_ERR_NOERROR;
+}
+
+int
+agentx_add_agentcaps(netsnmp_session * ss,
+ const oid * agent_cap, size_t agent_caplen,
+ const char *descr)
+{
+ netsnmp_pdu *pdu, *response;
+
+ if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
+ return 0;
+ }
+
+ pdu = snmp_pdu_create(AGENTX_MSG_ADD_AGENT_CAPS);
+ if (pdu == NULL)
+ return 0;
+ pdu->time = 0;
+ pdu->sessid = ss->sessid;
+ snmp_add_var(pdu, agent_cap, agent_caplen, 's', descr);
+
+ if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
+ return 0;
+
+ if (response->errstat != SNMP_ERR_NOERROR) {
+ snmp_free_pdu(response);
+ return 0;
+ }
+
+ snmp_free_pdu(response);
+ return 1;
+}
+
+int
+agentx_remove_agentcaps(netsnmp_session * ss,
+ const oid * agent_cap, size_t agent_caplen)
+{
+ netsnmp_pdu *pdu, *response;
+
+ if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
+ return 0;
+ }
+
+ pdu = snmp_pdu_create(AGENTX_MSG_REMOVE_AGENT_CAPS);
+ if (pdu == NULL)
+ return 0;
+ pdu->time = 0;
+ pdu->sessid = ss->sessid;
+ snmp_add_null_var(pdu, agent_cap, agent_caplen);
+
+ if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
+ return 0;
+
+ if (response->errstat != SNMP_ERR_NOERROR) {
+ snmp_free_pdu(response);
+ return 0;
+ }
+
+ snmp_free_pdu(response);
+ return 1;
+}
+
+int
+agentx_send_ping(netsnmp_session * ss)
+{
+ netsnmp_pdu *pdu, *response;
+
+ if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
+ return 0;
+ }
+
+ pdu = snmp_pdu_create(AGENTX_MSG_PING);
+ if (pdu == NULL)
+ return 0;
+ pdu->time = 0;
+ pdu->sessid = ss->sessid;
+
+ if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
+ return 0;
+
+ if (response->errstat != SNMP_ERR_NOERROR) {
+ snmp_free_pdu(response);
+ return 0;
+ }
+
+ snmp_free_pdu(response);
+ return 1;
+}