blob: d7baffdcc5737be5c9f1b80cf7e655f9a1035253 [file] [log] [blame]
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-features.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
netsnmp_feature_provide(stash_to_next)
netsnmp_feature_child_of(stash_to_next, mib_helpers)
#ifdef NETSNMP_FEATURE_REQUIRE_STASH_TO_NEXT
netsnmp_feature_require(oid_stash)
netsnmp_feature_require(oid_stash_add_data)
#endif
#ifndef NETSNMP_FEATURE_REMOVE_STASH_TO_NEXT
#include <net-snmp/agent/stash_to_next.h>
#include <net-snmp/agent/stash_cache.h>
/** @defgroup stash_to_next stash_to_next
* Convert GET_STASH requests into GETNEXT requests for the handler.
* The purpose of this handler is to convert a GET_STASH auto-cache request
* to a series of GETNEXT requests. It can be inserted into a handler chain
* where the lower-level handlers don't process such requests themselves.
* @ingroup utilities
* @{
*/
/** returns a stash_to_next handler that can be injected into a given
* handler chain.
*/
netsnmp_mib_handler *
netsnmp_get_stash_to_next_handler(void)
{
netsnmp_mib_handler *handler =
netsnmp_create_handler("stash_to_next",
netsnmp_stash_to_next_helper);
if (NULL != handler)
handler->flags |= MIB_HANDLER_AUTO_NEXT;
return handler;
}
/** @internal Implements the stash_to_next handler */
int
netsnmp_stash_to_next_helper(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
int ret = SNMP_ERR_NOERROR;
int namelen;
int finished = 0;
netsnmp_oid_stash_node **cinfo;
netsnmp_variable_list *vb;
netsnmp_request_info *reqtmp;
/*
* this code depends on AUTO_NEXT being set
*/
netsnmp_assert(handler->flags & MIB_HANDLER_AUTO_NEXT);
/*
* Don't do anything for any modes except GET_STASH. Just return,
* and the agent will call the next handler (AUTO_NEXT).
*
* If the handler chain already supports GET_STASH, we don't
* need to do anything here either. Once again, we just return
* and the agent will call the next handler (AUTO_NEXT).
*
* Otherwise, we munge the mode to GET_NEXT, and call the
* next handler ourselves, repeatedly until we've retrieved the
* full contents of the table or subtree.
* Then restore the mode and return to the calling handler
* (setting AUTO_NEXT_OVERRRIDE so the agent knows what we did).
*/
if (MODE_GET_STASH == reqinfo->mode) {
if ( reginfo->modes & HANDLER_CAN_STASH ) {
return ret;
}
cinfo = netsnmp_extract_stash_cache( reqinfo );
reqtmp = SNMP_MALLOC_TYPEDEF(netsnmp_request_info);
vb = reqtmp->requestvb = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
vb->type = ASN_NULL;
snmp_set_var_objid( vb, reginfo->rootoid, reginfo->rootoid_len );
reqinfo->mode = MODE_GETNEXT;
while (!finished) {
ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, reqtmp);
namelen = SNMP_MIN(vb->name_length, reginfo->rootoid_len);
if ( !snmp_oid_compare( reginfo->rootoid, reginfo->rootoid_len,
vb->name, namelen) &&
vb->type != ASN_NULL && vb->type != SNMP_ENDOFMIBVIEW ) {
/*
* This result is relevant so save it, and prepare
* the request varbind for the next query.
*/
netsnmp_oid_stash_add_data( cinfo, vb->name, vb->name_length,
snmp_clone_varbind( vb ));
/*
* Tidy up the response structure,
* ready for retrieving the next entry
*/
netsnmp_free_all_list_data(reqtmp->parent_data);
reqtmp->parent_data = NULL;
reqtmp->processed = 0;
vb->type = ASN_NULL;
} else {
finished = 1;
}
}
reqinfo->mode = MODE_GET_STASH;
/*
* let the handler chain processing know that we've already
* called the next handler
*/
handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
}
return ret;
}
/** @} */
#else /* ! NETSNMP_FEATURE_REMOVE_STASH_TO_NEXT */
netsnmp_feature_unused(stash_to_next);
#endif /* ! NETSNMP_FEATURE_REMOVE_STASH_TO_NEXT */