blob: 4dd1914f24c509380ad47c70b0d7d66cda37311c [file] [log] [blame]
#include <net-snmp/net-snmp-config.h>
#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/agent/bulk_to_next.h>
/** @defgroup bulk_to_next bulk_to_next
* Convert GETBULK requests into GETNEXT requests for the handler.
* The only purpose of this handler is to convert a GETBULK request
* to a GETNEXT request. It is inserted into handler chains where
* the handler has not set the HANDLER_CAN_GETBULK flag.
* @ingroup utilities
* @{
*/
/** returns a bulk_to_next handler that can be injected into a given
* handler chain.
*/
netsnmp_mib_handler *
netsnmp_get_bulk_to_next_handler(void)
{
netsnmp_mib_handler *handler =
netsnmp_create_handler("bulk_to_next",
netsnmp_bulk_to_next_helper);
if (NULL != handler)
handler->flags |= MIB_HANDLER_AUTO_NEXT;
return handler;
}
/** takes answered requests and decrements the repeat count and
* updates the requests to the next to-do varbind in the list */
void
netsnmp_bulk_to_next_fix_requests(netsnmp_request_info *requests)
{
netsnmp_request_info *request;
/*
* Make sure that:
* - repeats remain
* - last handler provided an answer
* - answer didn't exceed range end (ala check_getnext_results)
* - there is a next variable
* then
* update the varbinds for the next request series
*/
for (request = requests; request; request = request->next) {
if (request->repeat > 0 &&
request->requestvb->type != ASN_NULL &&
request->requestvb->type != ASN_PRIV_RETRY &&
(snmp_oid_compare(request->requestvb->name,
request->requestvb->name_length,
request->range_end,
request->range_end_len) < 0) &&
request->requestvb->next_variable ) {
request->repeat--;
snmp_set_var_objid(request->requestvb->next_variable,
request->requestvb->name,
request->requestvb->name_length);
request->requestvb = request->requestvb->next_variable;
request->requestvb->type = ASN_PRIV_RETRY;
/*
* if inclusive == 2, it was set in check_getnext_results for
* the previous requestvb. Now that we've moved on, clear it.
*/
if (2 == request->inclusive)
request->inclusive = 0;
}
}
}
/** @internal Implements the bulk_to_next handler */
int
netsnmp_bulk_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;
/*
* this code depends on AUTO_NEXT being set
*/
netsnmp_assert(handler->flags & MIB_HANDLER_AUTO_NEXT);
/*
* don't do anything for any modes besides GETBULK. Just return, and
* the agent will call the next handler (AUTO_NEXT).
*
* for GETBULK, we munge the mode, call the next handler ourselves
* (setting AUTO_NEXT_OVERRRIDE so the agent knows what we did),
* restore the mode and fix up the requests.
*/
if(MODE_GETBULK == reqinfo->mode) {
DEBUGIF("bulk_to_next") {
netsnmp_request_info *req = requests;
while(req) {
DEBUGMSGTL(("bulk_to_next", "Got request: "));
DEBUGMSGOID(("bulk_to_next", req->requestvb->name,
req->requestvb->name_length));
DEBUGMSG(("bulk_to_next", "\n"));
req = req->next;
}
}
reqinfo->mode = MODE_GETNEXT;
ret =
netsnmp_call_next_handler(handler, reginfo, reqinfo, requests);
reqinfo->mode = MODE_GETBULK;
/*
* update the varbinds for the next request series
*/
netsnmp_bulk_to_next_fix_requests(requests);
/*
* let agent handler know that we've already called next handler
*/
handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
}
return ret;
}
/** initializes the bulk_to_next helper which then registers a bulk_to_next
* handler as a run-time injectable handler for configuration file
* use.
*/
void
netsnmp_init_bulk_to_next_helper(void)
{
netsnmp_register_handler_by_name("bulk_to_next",
netsnmp_get_bulk_to_next_handler());
}
/** @} */