int delayed_instance_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { DEBUGMSGTL(("delayed_instance", "Got request, mode = %d:\n", reqinfo->mode)); printf("delayed_instance_handler(%d)\n", reqinfo->mode); switch (reqinfo->mode) { /* * here we merely mention that we'll answer this request * later. we don't actually care about the mode type in this * example, but for certain cases you may, so I'll leave in the * otherwise useless switch and case statements */ default: /* * mark this variable as something that can't be handled now. * We'll answer it later. */ requests->delegated = 1; /* * register an alarm to update the results at a later * time. Normally, we might have to query something else * (like an external request sent to a different network * or system socket, etc), but for this example we'll do * something really simply and just insert an alarm for a * certain period of time */ snmp_alarm_register(delay_time, /* seconds */ 0, /* dont repeat. */ return_delayed_response, /* the function * to call */ /* * here we create a "cache" of useful * information that we'll want later * on. This argument is passed back * to us in the callback function for * an alarm */ (void *) netsnmp_create_delegated_cache(handler, reginfo, reqinfo, requests, NULL)); break; } return SNMP_ERR_NOERROR; }
//******************************************************************************** // Function: redirect_handler // // Description: Retrieve redirect count from Control Plane. //******************************************************************************** static int redirect_handler(netsnmp_mib_handler * handler, netsnmp_handler_registration * reginfo, netsnmp_agent_request_info * reqinfo, netsnmp_request_info * requests) { syslog(LOG_DEBUG, "Enter: handler, %s.", HANDLER_NAME); syslog(LOG_DEBUG, "handler mode = %d.", reqinfo->mode); requests->delegated = 1; snmp_alarm_register(0, 0, delayed_response, (void *) netsnmp_create_delegated_cache(handler, reginfo, reqinfo, requests, NULL)); syslog(LOG_DEBUG, "Exit: handler, %s.", HANDLER_NAME); return SNMP_ERR_NOERROR; }
/* * * AgentX State diagram. [mode] = internal mode it's mapped from: * * TESTSET -success-> COMMIT -success-> CLEANUP * [RESERVE1] [ACTION] [COMMIT] * | | * | \--failure-> UNDO * | [UNDO] * | * --failure-> CLEANUP * [FREE] */ int agentx_master_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_session *ax_session = (netsnmp_session *) handler->myvoid; netsnmp_request_info *request = requests; netsnmp_pdu *pdu; void *cb_data; int result; DEBUGMSGTL(("agentx/master", "agentx master handler starting, mode = 0x%02x\n", reqinfo->mode)); if (!ax_session) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR); return SNMP_ERR_NOERROR; } /* * build a new pdu based on the pdu type coming in */ switch (reqinfo->mode) { case MODE_GET: pdu = snmp_pdu_create(AGENTX_MSG_GET); break; case MODE_GETNEXT: pdu = snmp_pdu_create(AGENTX_MSG_GETNEXT); break; case MODE_GETBULK: /* WWWXXX */ pdu = snmp_pdu_create(AGENTX_MSG_GETNEXT); break; case MODE_SET_RESERVE1: pdu = snmp_pdu_create(AGENTX_MSG_TESTSET); break; case MODE_SET_RESERVE2: /* * don't do anything here for AgentX. Assume all is fine * and go on since AgentX only has one test phase. */ return SNMP_ERR_NOERROR; case MODE_SET_ACTION: pdu = snmp_pdu_create(AGENTX_MSG_COMMITSET); break; case MODE_SET_UNDO: pdu = snmp_pdu_create(AGENTX_MSG_UNDOSET); break; case MODE_SET_COMMIT: case MODE_SET_FREE: pdu = snmp_pdu_create(AGENTX_MSG_CLEANUPSET); break; default: snmp_log(LOG_WARNING, "unsupported mode for agentx/master called\n"); return SNMP_ERR_NOERROR; } if (!pdu) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR); return SNMP_ERR_NOERROR; } pdu->version = AGENTX_VERSION_1; pdu->reqid = snmp_get_next_transid(); pdu->transid = reqinfo->asp->pdu->transid; pdu->sessid = ax_session->subsession->sessid; if (reginfo->contextName) { pdu->community = (u_char *) strdup(reginfo->contextName); pdu->community_len = strlen(reginfo->contextName); pdu->flags |= AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT; } if (ax_session->subsession->flags & AGENTX_MSG_FLAG_NETWORK_BYTE_ORDER) pdu->flags |= AGENTX_MSG_FLAG_NETWORK_BYTE_ORDER; while (request) { size_t nlen = request->requestvb->name_length; oid *nptr = request->requestvb->name; DEBUGMSGTL(("agentx/master","request for variable (")); DEBUGMSGOID(("agentx/master", nptr, nlen)); DEBUGMSG(("agentx/master", ")\n")); /* * loop through all the requests and create agentx ones out of them */ if (reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK) { if (snmp_oid_compare(nptr, nlen, request->subtree->start_a, request->subtree->start_len) < 0) { DEBUGMSGTL(("agentx/master","inexact request preceeding region (")); DEBUGMSGOID(("agentx/master", request->subtree->start_a, request->subtree->start_len)); DEBUGMSG(("agentx/master", ")\n")); nptr = request->subtree->start_a; nlen = request->subtree->start_len; request->inclusive = 1; } if (request->inclusive) { DEBUGMSGTL(("agentx/master", "INCLUSIVE varbind ")); DEBUGMSGOID(("agentx/master", nptr, nlen)); DEBUGMSG(("agentx/master", " scoped to ")); DEBUGMSGOID(("agentx/master", request->range_end, request->range_end_len)); DEBUGMSG(("agentx/master", "\n")); snmp_pdu_add_variable(pdu, nptr, nlen, ASN_PRIV_INCL_RANGE, (u_char *) request->range_end, request->range_end_len * sizeof(oid)); request->inclusive = 0; } else { DEBUGMSGTL(("agentx/master", "EXCLUSIVE varbind ")); DEBUGMSGOID(("agentx/master", nptr, nlen)); DEBUGMSG(("agentx/master", " scoped to ")); DEBUGMSGOID(("agentx/master", request->range_end, request->range_end_len)); DEBUGMSG(("agentx/master", "\n")); snmp_pdu_add_variable(pdu, nptr, nlen, ASN_PRIV_EXCL_RANGE, (u_char *) request->range_end, request->range_end_len * sizeof(oid)); } } else { snmp_pdu_add_variable(pdu, request->requestvb->name, request->requestvb->name_length, request->requestvb->type, request->requestvb->val.string, request->requestvb->val_len); } /* * mark the request as delayed */ if (pdu->command != AGENTX_MSG_CLEANUPSET) request->delegated = REQUEST_IS_DELEGATED; else request->delegated = REQUEST_IS_NOT_DELEGATED; /* * next... */ request = request->next; } /* * When the master sends a CleanupSet PDU, it will never get a response * back from the subagent. So we shouldn't allocate the * netsnmp_delegated_cache structure in this case. */ if (pdu->command != AGENTX_MSG_CLEANUPSET) cb_data = netsnmp_create_delegated_cache(handler, reginfo, reqinfo, requests, (void *) ax_session); else cb_data = NULL; /* * send the requests out. */ DEBUGMSGTL(("agentx", "sending pdu (req=0x%x,trans=0x%x,sess=0x%x)\n", (unsigned)pdu->reqid, (unsigned)pdu->transid, (unsigned)pdu->sessid)); result = snmp_async_send(ax_session, pdu, agentx_got_response, cb_data); if (result == 0) { snmp_free_pdu(pdu); } return SNMP_ERR_NOERROR; }
/* * Configure special parameters on the session. * Currently takes the parameter configured and changes it if something * was configured. It becomes "-c" if the community string from the pdu * is placed on the session. */ int proxy_fill_in_session(netsnmp_mib_handler *handler, netsnmp_agent_request_info *reqinfo, void **configured) { netsnmp_session *session; struct simple_proxy *sp; sp = (struct simple_proxy *) handler->myvoid; if (!sp) { return 0; } session = sp->sess; if (!session) { return 0; } #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C) #if defined(DISABLE_SNMPV1) if (session->version == SNMP_VERSION_2c) { #else #if defined(DISABLE_SNMPV2C) if (session->version == SNMP_VERSION_1) { #else if (session->version == SNMP_VERSION_1 || session->version == SNMP_VERSION_2c) { #endif #endif /* * Check if session has community string defined for it. * If not, need to extract community string from the pdu. * Copy to session and set 'configured' to indicate this. */ if (session->community_len == 0) { DEBUGMSGTL(("proxy", "session has no community string\n")); if (reqinfo->asp == NULL || reqinfo->asp->pdu == NULL || reqinfo->asp->pdu->community_len == 0) { return 0; } *configured = malloc(strlen("-c") + 1); strcpy(*configured, "-c"); DEBUGMSGTL(("proxy", "pdu has community string\n")); session->community_len = reqinfo->asp->pdu->community_len; session->community = malloc(session->community_len + 1); strncpy((char *)session->community, (const char *)reqinfo->asp->pdu->community, session->community_len); } } #endif return 1; } /* * Free any specially configured parameters used on the session. */ void proxy_free_filled_in_session_args(netsnmp_session *session, void **configured) { /* Only do comparisions, etc., if something was configured */ if (*configured == NULL) { return; } /* If used community string from pdu, release it from session now */ if (strcmp((const char *)(*configured), "-c") == 0) { free(session->community); session->community = NULL; session->community_len = 0; } free((u_char *)(*configured)); *configured = NULL; } void init_proxy(void) { snmpd_register_config_handler("proxy", proxy_parse_config, proxy_free_config, "[snmpcmd args] host oid [remoteoid]"); } void shutdown_proxy(void) { proxy_free_config(); } int proxy_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_pdu *pdu; struct simple_proxy *sp; oid *ourname; size_t ourlength; netsnmp_request_info *request = requests; u_char *configured = NULL; DEBUGMSGTL(("proxy", "proxy handler starting, mode = %d\n", reqinfo->mode)); switch (reqinfo->mode) { case MODE_GET: case MODE_GETNEXT: case MODE_GETBULK: /* WWWXXX */ pdu = snmp_pdu_create(reqinfo->mode); break; case MODE_SET_ACTION: pdu = snmp_pdu_create(SNMP_MSG_SET); break; case MODE_SET_UNDO: /* * If we set successfully (status == NOERROR), * we can't back out again, so need to report the fact. * If we failed to set successfully, then we're fine. */ for (request = requests; request; request=request->next) { if (request->status == SNMP_ERR_NOERROR) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); return SNMP_ERR_UNDOFAILED; } } return SNMP_ERR_NOERROR; case MODE_SET_RESERVE1: case MODE_SET_RESERVE2: case MODE_SET_FREE: case MODE_SET_COMMIT: /* * Nothing to do in this pass */ return SNMP_ERR_NOERROR; default: snmp_log(LOG_WARNING, "unsupported mode for proxy called (%d)\n", reqinfo->mode); return SNMP_ERR_NOERROR; } sp = (struct simple_proxy *) handler->myvoid; if (!pdu || !sp) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR); return SNMP_ERR_NOERROR; } while (request) { ourname = request->requestvb->name; ourlength = request->requestvb->name_length; if (sp->base_len > 0) { if ((ourlength - sp->name_len + sp->base_len) > MAX_OID_LEN) { /* * too large */ snmp_log(LOG_ERR, "proxy oid request length is too long\n"); return SNMP_ERR_NOERROR; } /* * suffix appended? */ DEBUGMSGTL(("proxy", "length=%d, base_len=%d, name_len=%d\n", ourlength, sp->base_len, sp->name_len)); if (ourlength > (int) sp->name_len) memcpy(&(sp->base[sp->base_len]), &(ourname[sp->name_len]), sizeof(oid) * (ourlength - sp->name_len)); ourlength = ourlength - sp->name_len + sp->base_len; ourname = sp->base; } snmp_pdu_add_variable(pdu, ourname, ourlength, request->requestvb->type, request->requestvb->val.string, request->requestvb->val_len); request->delegated = 1; request = request->next; } /* * Customize session parameters based on request information */ if (!proxy_fill_in_session(handler, reqinfo, (void **)&configured)) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR); return SNMP_ERR_NOERROR; } /* * send the request out */ DEBUGMSGTL(("proxy", "sending pdu\n")); snmp_async_send(sp->sess, pdu, proxy_got_response, netsnmp_create_delegated_cache(handler, reginfo, reqinfo, requests, (void *) sp)); /* Free any special parameters generated on the session */ proxy_free_filled_in_session_args(sp->sess, (void **)&configured); return SNMP_ERR_NOERROR; }
int delayed_instance_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { /* This handler is called to handle SNMP GET and SNMP SET requests for the my_delayed_oid object. If it is called to handle SNMP GET requests, the handler does not need to handle a GETNEXT if it is registered as an instance handler. Instance handlers only deliver one request at a time, so we do not need to loop over a list of requests. */ DEBUGMSGTL(("demo_module_10", "Handler got request, mode = %d:\n", reqinfo->mode)); switch (reqinfo->mode) { /* * here we merely mention that we'll answer this request * later. we don't actually care about the mode type in this * example, but for certain cases you may, so I'll leave in the * otherwise useless switch and case statements */ default: /* * Mark this variable as something that cannot be handled now * by setting the delegated member of the requests structure * to 1. The agent queues the request to be handled at a later * time and continues responding to other client requests. * */ requests->delegated = 1; DEBUGMSGTL(("demo_module_10", "Delegated is %d\n", requests->delegated)); /* * Register an alarm to update the results at a later * time. Normally, we might have to query something else * (like an external request sent to a different network * or system socket, etc), but for this example we'll do * something really simply and just insert an alarm for a * certain period of time. */ snmp_alarm_register(alarm_time, /* seconds */ 0, /* dont repeat. */ get_status, /* the function */ /* to call */ /* * Create a "cache" of useful * information that can be retrieved * at a later time. This argument is * passed back to the module in the callback * function for an alarm. */ (void *) netsnmp_create_delegated_cache(handler, reginfo, reqinfo, requests, NULL)); break; } return SNMP_ERR_NOERROR; }
int proxy_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_pdu *pdu; struct simple_proxy *sp; oid *ourname; size_t ourlength; netsnmp_request_info *request = requests; DEBUGMSGTL(("proxy", "proxy handler starting, mode = %d\n", reqinfo->mode)); switch (reqinfo->mode) { case MODE_GET: case MODE_GETNEXT: case MODE_GETBULK: /* WWWXXX */ pdu = snmp_pdu_create(reqinfo->mode); break; case MODE_SET_COMMIT: pdu = snmp_pdu_create(SNMP_MSG_SET); break; default: snmp_log(LOG_WARNING, "unsupported mode for proxy called\n"); return SNMP_ERR_NOERROR; } sp = (struct simple_proxy *) handler->myvoid; if (!pdu || !sp) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR); return SNMP_ERR_NOERROR; } while (request) { ourname = request->requestvb->name; ourlength = request->requestvb->name_length; if (sp->base_len > 0) { if ((ourlength - sp->name_len + sp->base_len) > MAX_OID_LEN) { /* * too large */ snmp_log(LOG_ERR, "proxy oid request length is too long\n"); return SNMP_ERR_NOERROR; } /* * suffix appended? */ DEBUGMSGTL(("proxy", "length=%d, base_len=%d, name_len=%d\n", ourlength, sp->base_len, sp->name_len)); if (ourlength > (int) sp->name_len) memcpy(&(sp->base[sp->base_len]), &(ourname[sp->name_len]), sizeof(oid) * (ourlength - sp->name_len)); ourlength = ourlength - sp->name_len + sp->base_len; ourname = sp->base; } snmp_pdu_add_variable(pdu, ourname, ourlength, request->requestvb->type, request->requestvb->val.string, request->requestvb->val_len); request->delegated = 1; request = request->next; } /* * send the request out */ DEBUGMSGTL(("proxy", "sending pdu\n")); snmp_async_send(sp->sess, pdu, proxy_got_response, netsnmp_create_delegated_cache(handler, reginfo, reqinfo, requests, (void *) sp)); return SNMP_ERR_NOERROR; }