summaryrefslogtreecommitdiff
path: root/agent/helpers/bulk_to_next.c
blob: 4dd1914f24c509380ad47c70b0d7d66cda37311c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#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());
}
/**  @} */