/* * Portions of this file are subject to the following copyright(s). See * the Net-SNMP's COPYING file for more details and other copyrights * that may apply: * * Portions of this file are copyrighted by: * Copyright (c) 2016 VMware, Inc. All rights reserved. * Use is subject to license terms specified in the COPYING file * distributed with the Net-SNMP package. */ #include #include #include #include /** @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_mib_handler *hnd = netsnmp_get_bulk_to_next_handler(); if (!hnd) return; netsnmp_register_handler_by_name("bulk_to_next", hnd); } /** @} */