4 * Simple Network Management Protocol (RFC 1067).
6 /***********************************************************
7 Copyright 1988, 1989 by Carnegie Mellon University
11 Permission to use, copy, modify, and distribute this software and its
12 documentation for any purpose and without fee is hereby granted,
13 provided that the above copyright notice appear in all copies and that
14 both that copyright notice and this permission notice appear in
15 supporting documentation, and that the name of CMU not be
16 used in advertising or publicity pertaining to distribution of the
17 software without specific, written prior permission.
19 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26 ******************************************************************/
28 #include <net-snmp/net-snmp-config.h>
30 #include <sys/types.h>
43 #if TIME_WITH_SYS_TIME
45 # include <sys/timeb.h>
47 # include <sys/time.h>
52 # include <sys/time.h>
58 #include <sys/select.h>
61 #include <netinet/in.h>
72 #define SNMP_NEED_REQUEST_LIST
73 #include <net-snmp/net-snmp-includes.h>
74 #include <net-snmp/agent/net-snmp-agent-includes.h>
75 #include <net-snmp/library/snmp_assert.h>
80 int allow_severity = LOG_INFO;
81 int deny_severity = LOG_WARNING;
85 #include "mibgroup/struct.h"
86 #include "mibgroup/util_funcs.h"
87 #include <net-snmp/agent/mib_module_config.h>
89 #ifdef USING_AGENTX_PROTOCOL_MODULE
90 #include "agentx/protocol.h"
93 #ifdef USING_AGENTX_MASTER_MODULE
94 #include "agentx/master.h"
97 #define SNMP_ADDRCACHE_SIZE 10
101 enum { SNMP_ADDRCACHE_UNUSED = 0,
102 SNMP_ADDRCACHE_USED = 1,
103 SNMP_ADDRCACHE_OLD = 2
107 static struct addrCache addrCache[SNMP_ADDRCACHE_SIZE];
109 int log_addresses = 0;
113 typedef struct _agent_nsap {
115 netsnmp_transport *t;
116 void *s; /* Opaque internal session pointer. */
117 struct _agent_nsap *next;
120 static agent_nsap *agent_nsap_list = NULL;
121 static netsnmp_agent_session *agent_session_list = NULL;
122 static netsnmp_agent_session *netsnmp_processing_set = NULL;
123 netsnmp_agent_session *agent_delegated_list = NULL;
124 netsnmp_agent_session *netsnmp_agent_queued_list = NULL;
127 int netsnmp_agent_check_packet(netsnmp_session *,
128 struct netsnmp_transport_s *,
130 int netsnmp_agent_check_parse(netsnmp_session *, netsnmp_pdu *,
132 void delete_subnetsnmp_tree_cache(netsnmp_agent_session *asp);
133 int handle_pdu(netsnmp_agent_session *asp);
134 int netsnmp_handle_request(netsnmp_agent_session *asp,
136 int netsnmp_wrap_up_request(netsnmp_agent_session *asp,
138 int check_delayed_request(netsnmp_agent_session *asp);
139 int handle_getnext_loop(netsnmp_agent_session *asp);
140 int handle_set_loop(netsnmp_agent_session *asp);
142 int netsnmp_check_queued_chain_for(netsnmp_agent_session *asp);
143 int netsnmp_add_queued(netsnmp_agent_session *asp);
144 int netsnmp_remove_from_delegated(netsnmp_agent_session *asp);
147 static int current_globalid = 0;
150 netsnmp_allocate_globalcacheid(void)
152 return ++current_globalid;
156 netsnmp_get_local_cachid(netsnmp_cachemap *cache_store, int globalid)
158 while (cache_store != NULL) {
159 if (cache_store->globalid == globalid)
160 return cache_store->cacheid;
161 cache_store = cache_store->next;
167 netsnmp_get_or_add_local_cachid(netsnmp_cachemap **cache_store,
168 int globalid, int localid)
170 netsnmp_cachemap *tmpp;
172 tmpp = SNMP_MALLOC_TYPEDEF(netsnmp_cachemap);
174 tmpp->next = *cache_store;
180 tmpp->globalid = globalid;
181 tmpp->cacheid = localid;
186 netsnmp_free_cachemap(netsnmp_cachemap *cache_store)
188 netsnmp_cachemap *tmpp;
189 while (cache_store) {
191 cache_store = cache_store->next;
197 typedef struct agent_set_cache_s {
202 netsnmp_session *sess;
207 netsnmp_tree_cache *treecache;
212 netsnmp_request_info *requests;
213 netsnmp_data_list *agent_data;
218 struct agent_set_cache_s *next;
221 static agent_set_cache *Sets = NULL;
224 save_set_cache(netsnmp_agent_session *asp)
226 agent_set_cache *ptr;
228 if (!asp->reqinfo || !asp->pdu)
231 ptr = SNMP_MALLOC_TYPEDEF(agent_set_cache);
236 * Save the important information
238 ptr->transID = asp->pdu->transid;
239 ptr->sess = asp->session;
240 ptr->treecache = asp->treecache;
241 ptr->treecache_len = asp->treecache_len;
242 ptr->treecache_num = asp->treecache_num;
243 ptr->agent_data = asp->reqinfo->agent_data;
244 ptr->requests = asp->requests;
245 ptr->vbcount = asp->vbcount;
248 * make the agent forget about what we've saved
250 asp->treecache = NULL;
251 asp->reqinfo->agent_data = NULL;
252 asp->pdu->variables = NULL;
253 asp->requests = NULL;
262 get_set_cache(netsnmp_agent_session *asp)
264 agent_set_cache *ptr, *prev = NULL;
266 for (ptr = Sets; ptr != NULL; ptr = ptr->next) {
267 if (ptr->sess == asp->session && ptr->transID == asp->pdu->transid) {
269 prev->next = ptr->next;
274 * found it. Get the needed data
276 asp->treecache = ptr->treecache;
277 asp->treecache_len = ptr->treecache_len;
278 asp->treecache_num = ptr->treecache_num;
279 asp->requests = ptr->requests;
280 asp->vbcount = ptr->vbcount;
283 SNMP_MALLOC_TYPEDEF(netsnmp_agent_request_info);
285 asp->reqinfo->asp = asp;
286 asp->reqinfo->agent_data = ptr->agent_data;
290 return SNMP_ERR_NOERROR;
294 return SNMP_ERR_GENERR;
300 static int SessionID = 0;
306 agent_check_and_process(int block)
310 struct timeval timeout = { LONG_MAX, 0 }, *tvp = &timeout;
316 snmp_select_info(&numfds, &fdset, tvp, &fakeblock);
317 if (block != 0 && fakeblock != 0) {
319 * There are no alarms registered, and the caller asked for blocking, so
320 * let select() block forever.
324 } else if (block != 0 && fakeblock == 0) {
326 * The caller asked for blocking, but there is an alarm due sooner than
327 * LONG_MAX seconds from now, so use the modified timeout returned by
328 * snmp_select_info as the timeout for select().
331 } else if (block == 0) {
333 * The caller does not want us to block at all.
340 count = select(numfds, &fdset, 0, 0, tvp);
344 * packets found, process them
353 if (errno != EINTR) {
354 snmp_log_perror("select");
358 snmp_log(LOG_ERR, "select returned %d\n", count);
360 } /* endif -- count>0 */
363 * Run requested alarms.
373 * Set up the address cache.
376 netsnmp_addrcache_initialise(void)
380 for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
381 addrCache[i].addr = NULL;
382 addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
389 * Age the entries in the address cache.
393 netsnmp_addrcache_age(void)
398 for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
399 if (addrCache[i].status == SNMP_ADDRCACHE_OLD) {
400 addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
401 if (addrCache[i].addr != NULL) {
402 free(addrCache[i].addr);
403 addrCache[i].addr = NULL;
406 if (addrCache[i].status == SNMP_ADDRCACHE_USED) {
407 addrCache[i].status = SNMP_ADDRCACHE_OLD;
412 /*******************************************************************-o-******
413 * netsnmp_agent_check_packet
416 * session, transport, transport_data, transport_data_length
422 * Handler for all incoming messages (a.k.a. packets) for the agent. If using
423 * the libwrap utility, log the connection and deny/allow the access. Print
424 * output when appropriate, and increment the incoming counter.
427 #if BRCM_SNMP_SUPPORT
429 netsnmp_agent_check_packet(netsnmp_session * session,
430 netsnmp_transport *transport,
431 void *transport_data, int transport_data_length)
433 char *addr_string = NULL;
437 * Log the message and/or dump the message.
438 * Optionally cache the network address of the sender.
441 if (transport != NULL && transport->f_fmtaddr != NULL) {
443 * Okay I do know how to format this address for logging.
445 addr_string = transport->f_fmtaddr(transport, transport_data,
446 transport_data_length);
448 * Don't forget to free() it.
452 if (addr_string != NULL) {
453 if (hosts_ctl("snmpd", STRING_UNKNOWN, addr_string, STRING_UNKNOWN)) {
454 snmp_log(allow_severity, "Connection from %s\n", addr_string);
456 snmp_log(deny_severity, "Connection from %s REFUSED\n",
462 if (hosts_ctl("snmp", STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN)){
463 snmp_log(allow_severity, "Connection from <UNKNOWN>\n");
464 addr_string = strdup("<UNKNOWN>");
466 snmp_log(deny_severity, "Connection from <UNKNOWN> REFUSED\n");
470 #endif /*USE_LIBWRAP */
472 snmp_increment_statistic(STAT_SNMPINPKTS);
474 if (log_addresses || netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
475 NETSNMP_DS_AGENT_VERBOSE)) {
476 for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
477 if ((addrCache[i].status != SNMP_ADDRCACHE_UNUSED) &&
478 (strcmp(addrCache[i].addr, addr_string) == 0)) {
483 if (i >= SNMP_ADDRCACHE_SIZE ||
484 netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
485 NETSNMP_DS_AGENT_VERBOSE)) {
487 * Address wasn't in the cache, so log the packet...
489 snmp_log(LOG_INFO, "Received SNMP packet(s) from %s\n",
492 * ...and try to cache the address.
494 for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
495 if (addrCache[i].status == SNMP_ADDRCACHE_UNUSED) {
496 if (addrCache[i].addr != NULL) {
497 free(addrCache[i].addr);
499 addrCache[i].addr = addr_string;
500 addrCache[i].status = SNMP_ADDRCACHE_USED;
501 addr_string = NULL; /* Don't free this 'temporary' string
502 * since it's now part of the cache */
506 if (i >= SNMP_ADDRCACHE_SIZE) {
508 * We didn't find a free slot to cache the address. Perhaps
509 * we should be using an LRU replacement policy here or
510 * something. Oh well.
512 DEBUGMSGTL(("netsnmp_agent_check_packet",
516 addrCache[i].status = SNMP_ADDRCACHE_USED;
520 if (addr_string != NULL) {
529 netsnmp_agent_check_parse(netsnmp_session * session, netsnmp_pdu *pdu,
533 if (snmp_get_do_logging() &&
534 netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
535 NETSNMP_DS_AGENT_VERBOSE)) {
536 netsnmp_variable_list *var_ptr;
538 switch (pdu->command) {
540 snmp_log(LOG_DEBUG, " GET message\n");
542 case SNMP_MSG_GETNEXT:
543 snmp_log(LOG_DEBUG, " GETNEXT message\n");
545 case SNMP_MSG_RESPONSE:
546 snmp_log(LOG_DEBUG, " RESPONSE message\n");
549 snmp_log(LOG_DEBUG, " SET message\n");
552 snmp_log(LOG_DEBUG, " TRAP message\n");
554 case SNMP_MSG_GETBULK:
555 snmp_log(LOG_DEBUG, " GETBULK message, non-rep=%d, max_rep=%d\n",
556 pdu->errstat, pdu->errindex);
558 case SNMP_MSG_INFORM:
559 snmp_log(LOG_DEBUG, " INFORM message\n");
562 snmp_log(LOG_DEBUG, " TRAP2 message\n");
564 case SNMP_MSG_REPORT:
565 snmp_log(LOG_DEBUG, " REPORT message\n");
568 case SNMP_MSG_INTERNAL_SET_RESERVE1:
569 snmp_log(LOG_DEBUG, " INTERNAL RESERVE1 message\n");
572 case SNMP_MSG_INTERNAL_SET_RESERVE2:
573 snmp_log(LOG_DEBUG, " INTERNAL RESERVE2 message\n");
576 case SNMP_MSG_INTERNAL_SET_ACTION:
577 snmp_log(LOG_DEBUG, " INTERNAL ACTION message\n");
580 case SNMP_MSG_INTERNAL_SET_COMMIT:
581 snmp_log(LOG_DEBUG, " INTERNAL COMMIT message\n");
584 case SNMP_MSG_INTERNAL_SET_FREE:
585 snmp_log(LOG_DEBUG, " INTERNAL FREE message\n");
588 case SNMP_MSG_INTERNAL_SET_UNDO:
589 snmp_log(LOG_DEBUG, " INTERNAL UNDO message\n");
593 snmp_log(LOG_DEBUG, " UNKNOWN message, type=%02X\n",
595 snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
599 for (var_ptr = pdu->variables; var_ptr != NULL;
600 var_ptr = var_ptr->next_variable) {
601 size_t c_oidlen = 256, c_outlen = 0;
602 u_char *c_oid = (u_char *) malloc(c_oidlen);
605 if (!sprint_realloc_objid
606 (&c_oid, &c_oidlen, &c_outlen, 1, var_ptr->name,
607 var_ptr->name_length)) {
608 snmp_log(LOG_DEBUG, " -- %s [TRUNCATED]\n",
611 snmp_log(LOG_DEBUG, " -- %s\n", c_oid);
619 return 0; /* XXX: does it matter what the return value
620 * is? Yes: if we return 0, then the PDU is
623 #endif /* BRCM_SNMP_SUPPORT */
626 * Global access to the primary session structure for this agent.
627 * for Index Allocation use initially.
631 * I don't understand what this is for at the moment. AFAICS as long as it
632 * gets set and points at a session, that's fine. ???
635 netsnmp_session *main_session = NULL;
640 * Set up an agent session on the given transport. Return a handle
641 * which may later be used to de-register this transport. A return
642 * value of -1 indicates an error.
646 netsnmp_register_agent_nsap(netsnmp_transport *t)
648 netsnmp_session *s, *sp = NULL;
649 agent_nsap *a = NULL, *n = NULL, **prevNext = &agent_nsap_list;
657 DEBUGMSGTL(("netsnmp_register_agent_nsap", "fd %d\n", t->sock));
659 n = (agent_nsap *) malloc(sizeof(agent_nsap));
663 s = (netsnmp_session *) malloc(sizeof(netsnmp_session));
668 memset(s, 0, sizeof(netsnmp_session));
672 * Set up the session appropriately for an agent.
675 s->version = SNMP_DEFAULT_VERSION;
676 s->callback = handle_snmp_packet;
677 s->authenticator = NULL;
678 s->flags = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
679 NETSNMP_DS_AGENT_FLAGS);
680 s->isAuthoritative = SNMP_SESS_AUTHORITATIVE;
682 #ifdef BRCM_SNMP_SUPPORT
683 sp = snmp_add(s, t, netsnmp_agent_check_packet,
684 netsnmp_agent_check_parse);
686 sp = snmp_add(s, t, NULL,NULL);
694 isp = snmp_sess_pointer(sp);
695 if (isp == NULL) { /* over-cautious */
704 if (main_session == NULL) {
705 main_session = snmp_sess_session(isp);
708 for (a = agent_nsap_list; a != NULL && handle + 1 >= a->handle;
711 prevNext = &(a->next);
714 if (handle < INT_MAX) {
715 n->handle = handle + 1;
728 netsnmp_deregister_agent_nsap(int handle)
730 agent_nsap *a = NULL, **prevNext = &agent_nsap_list;
731 int main_session_deregistered = 0;
733 DEBUGMSGTL(("netsnmp_deregister_agent_nsap", "handle %d\n", handle));
735 for (a = agent_nsap_list; a != NULL && a->handle < handle; a = a->next) {
736 prevNext = &(a->next);
739 if (a != NULL && a->handle == handle) {
741 if (main_session == snmp_sess_session(a->s)) {
742 main_session_deregistered = 1;
744 snmp_close(snmp_sess_session(a->s));
746 * The above free()s the transport and session pointers.
752 * If we've deregistered the session that main_session used to point to,
753 * then make it point to another one, or in the last resort, make it equal
754 * to NULL. Basically this shouldn't ever happen in normal operation
755 * because main_session starts off pointing at the first session added by
756 * init_master_agent(), which then discards the handle.
759 if (main_session_deregistered) {
760 if (agent_nsap_list != NULL) {
761 DEBUGMSGTL(("snmp_agent",
762 "WARNING: main_session ptr changed from %p to %p\n",
763 main_session, snmp_sess_session(agent_nsap_list->s)));
764 main_session = snmp_sess_session(agent_nsap_list->s);
766 DEBUGMSGTL(("snmp_agent",
767 "WARNING: main_session ptr changed from %p to NULL\n",
778 * This function has been modified to use the experimental
779 * netsnmp_register_agent_nsap interface. The major responsibility of this
780 * function now is to interpret a string specified to the agent (via -p on the
781 * command line, or from a configuration file) as a list of agent NSAPs on
782 * which to listen for SNMP packets. Typically, when you add a new transport
783 * domain "foo", you add code here such that if the "foo" code is compiled
784 * into the agent (SNMP_TRANSPORT_FOO_DOMAIN is defined), then a token of the
785 * form "foo:bletch-3a0054ef%wob&wob" gets turned into the appropriate
786 * transport descriptor. netsnmp_register_agent_nsap is then called with that
787 * transport descriptor and sets up a listening agent session on it.
789 * Everything then works much as normal: the agent runs in an infinite loop
790 * (in the snmpd.c/receive()routine), which calls snmp_read() when a request
791 * is readable on any of the given transports. This routine then traverses
792 * the library 'Sessions' list to identify the relevant session and eventually
793 * invokes '_sess_read'. This then processes the incoming packet, calling the
794 * pre_parse, parse, post_parse and callback routines in turn.
800 init_master_agent(void)
802 netsnmp_transport *transport;
804 char buf[SPRINT_MAX_LEN];
806 /* default to turning off lookup caching */
807 netsnmp_set_lookup_cache_size(0);
809 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
810 NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
811 DEBUGMSGTL(("snmp_agent",
812 "init_master_agent; not master agent\n"));
813 return 0; /* No error if ! MASTER_AGENT */
815 #ifdef USING_AGENTX_MASTER_MODULE
816 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
817 NETSNMP_DS_AGENT_AGENTX_MASTER) == 1)
822 * Have specific agent ports been specified?
824 cptr = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
825 NETSNMP_DS_AGENT_PORTS);
828 snprintf(buf, sizeof(buf), "%s", cptr);
829 buf[ sizeof(buf)-1 ] = 0;
832 * No, so just specify the default port.
834 if (netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_FLAGS) & SNMP_FLAGS_STREAM_SOCKET) {
835 sprintf(buf, "tcp:%d", SNMP_PORT);
837 sprintf(buf, "udp:%d", SNMP_PORT);
841 DEBUGMSGTL(("snmp_agent", "final port spec: %s\n", buf));
842 cptr = strtok(buf, ",");
845 * Specification format:
847 * NONE: (a pseudo-transport)
848 * UDP:[address:]port (also default if no transport is specified)
849 * TCP:[address:]port (if supported)
850 * Unix:pathname (if supported)
851 * AAL5PVC:itf.vpi.vci (if supported)
852 * IPX:[network]:node[/port] (if supported)
856 DEBUGMSGTL(("snmp_agent", "installing master agent on port %s\n",
859 if (!cptr || !(*cptr)) {
860 snmp_log(LOG_ERR, "improper port specification\n");
864 if (strncasecmp(cptr, "none", 4) == 0) {
865 DEBUGMSGTL(("snmp_agent",
866 "init_master_agent; pseudo-transport \"none\" requested\n"));
869 transport = netsnmp_tdomain_transport(cptr, 1, "udp");
871 if (transport == NULL) {
872 snmp_log(LOG_ERR, "Error opening specified endpoint \"%s\"\n",
877 if (netsnmp_register_agent_nsap(transport) == 0) {
879 "Error registering specified transport \"%s\" as an agent NSAP\n",
883 DEBUGMSGTL(("snmp_agent",
884 "init_master_agent; \"%s\" registered as an agent NSAP\n",
889 * Next transport please...
891 cptr = strtok(NULL, ",");
899 netsnmp_agent_session *
900 init_agent_snmp_session(netsnmp_session * session, netsnmp_pdu *pdu)
902 netsnmp_agent_session *asp = (netsnmp_agent_session *)
903 calloc(1, sizeof(netsnmp_agent_session));
909 DEBUGMSGTL(("snmp_agent","agent_sesion %08p created\n", asp));
910 asp->session = session;
911 asp->pdu = snmp_clone_pdu(pdu);
912 asp->orig_pdu = snmp_clone_pdu(pdu);
916 asp->mode = RESERVE1;
917 asp->status = SNMP_ERR_NOERROR;
920 asp->treecache_num = -1;
921 asp->treecache_len = 0;
927 free_agent_snmp_session(netsnmp_agent_session *asp)
932 DEBUGMSGTL(("snmp_agent","agent_sesion %08p released\n", asp));
934 netsnmp_remove_from_delegated(asp);
937 snmp_free_pdu(asp->orig_pdu);
939 snmp_free_pdu(asp->pdu);
941 netsnmp_free_agent_request_info(asp->reqinfo);
942 if (asp->treecache) {
943 free(asp->treecache);
945 if (asp->bulkcache) {
946 free(asp->bulkcache);
950 for (i = 0; i < asp->vbcount; i++) {
951 netsnmp_free_request_data_sets(&asp->requests[i]);
957 if (asp->cache_store) {
958 netsnmp_free_cachemap(asp->cache_store);
959 asp->cache_store = NULL;
965 netsnmp_check_for_delegated(netsnmp_agent_session *asp)
968 netsnmp_request_info *request;
970 if (NULL == asp->treecache)
973 for (i = 0; i <= asp->treecache_num; i++) {
974 for (request = asp->treecache[i].requests_begin; request;
975 request = request->next) {
976 if (request->delegated)
984 netsnmp_check_delegated_chain_for(netsnmp_agent_session *asp)
986 netsnmp_agent_session *asptmp;
987 for (asptmp = agent_delegated_list; asptmp; asptmp = asptmp->next) {
995 netsnmp_check_for_delegated_and_add(netsnmp_agent_session *asp)
997 if (netsnmp_check_for_delegated(asp)) {
998 if (!netsnmp_check_delegated_chain_for(asp)) {
1000 * add to delegated request chain
1002 asp->next = agent_delegated_list;
1003 agent_delegated_list = asp;
1004 DEBUGMSGTL(("snmp_agent", "delegate session == %08p\n", asp));
1012 netsnmp_remove_from_delegated(netsnmp_agent_session *asp)
1014 netsnmp_agent_session *curr, *prev = NULL;
1016 for (curr = agent_delegated_list; curr; prev = curr, curr = curr->next) {
1027 prev->next = asp->next;
1029 agent_delegated_list = asp->next;
1031 DEBUGMSGTL(("snmp_agent", "remove delegated session == %08p\n", asp));
1040 * netsnmp_remove_delegated_requests_for_session
1042 * called when a session is being closed. Check all delegated requests to
1043 * see if the are waiting on this session, and if set, set the status for
1044 * that request to GENERR.
1047 netsnmp_remove_delegated_requests_for_session(netsnmp_session *sess)
1049 netsnmp_agent_session *asp;
1052 for (asp = agent_delegated_list; asp; asp = asp->next) {
1054 * check each request
1056 netsnmp_request_info *request;
1057 for(request = asp->requests; request; request = request->next) {
1061 netsnmp_assert(NULL!=request->subtree);
1062 if(request->subtree->session != sess)
1066 * matched! mark request as done
1068 netsnmp_set_mode_request_error(MODE_SET_BEGIN, request,
1075 * if we found any, that request may be finished now
1078 DEBUGMSGTL(("snmp_agent", "removed %d delegated request(s) for session "
1079 "%08p\n", count, sess));
1080 netsnmp_check_outstanding_agent_requests();
1087 netsnmp_check_queued_chain_for(netsnmp_agent_session *asp)
1089 netsnmp_agent_session *asptmp;
1090 for (asptmp = netsnmp_agent_queued_list; asptmp; asptmp = asptmp->next) {
1098 netsnmp_add_queued(netsnmp_agent_session *asp)
1100 netsnmp_agent_session *asp_tmp;
1105 if (NULL == netsnmp_agent_queued_list) {
1106 netsnmp_agent_queued_list = asp;
1112 * add to end of queued request chain
1114 asp_tmp = netsnmp_agent_queued_list;
1115 for (; asp_tmp; asp_tmp = asp_tmp->next) {
1125 if (NULL == asp_tmp->next)
1126 asp_tmp->next = asp;
1133 netsnmp_wrap_up_request(netsnmp_agent_session *asp, int status)
1135 netsnmp_variable_list *var_ptr;
1136 int i, n = 0, r = 0;
1139 * if this request was a set, clear the global now that we are
1142 if (asp == netsnmp_processing_set) {
1143 DEBUGMSGTL(("snmp_agent", "SET request complete, asp = %08p\n",
1145 netsnmp_processing_set = NULL;
1149 * some stuff needs to be saved in special subagent cases
1153 switch (asp->pdu->command) {
1154 case SNMP_MSG_INTERNAL_SET_BEGIN:
1155 case SNMP_MSG_INTERNAL_SET_RESERVE1:
1156 case SNMP_MSG_INTERNAL_SET_RESERVE2:
1157 case SNMP_MSG_INTERNAL_SET_ACTION:
1158 save_set_cache(asp);
1163 * if this is a GETBULK response we need to rearrange the varbinds
1165 if (asp->pdu->command == SNMP_MSG_GETBULK) {
1166 int repeats = asp->pdu->errindex;
1169 if (asp->pdu->errstat < asp->vbcount) {
1170 n = asp->pdu->errstat;
1174 if ((r = asp->vbcount - n) < 0) {
1178 for (i = 0; i < r - 1; i++) {
1179 for (j = 0; j < repeats; j++) {
1180 asp->bulkcache[i * repeats + j]->next_variable =
1181 asp->bulkcache[(i + 1) * repeats + j];
1185 for (j = 0; j < repeats - 1; j++) {
1186 asp->bulkcache[(r - 1) * repeats + j]->next_variable =
1187 asp->bulkcache[j + 1];
1193 * May need to "dumb down" a SET error status for a
1194 * v1 query. See RFC2576 - section 4.3
1196 if ((asp->pdu->command == SNMP_MSG_SET) &&
1197 (asp->pdu->version == SNMP_VERSION_1)) {
1199 case SNMP_ERR_WRONGVALUE:
1200 case SNMP_ERR_WRONGENCODING:
1201 case SNMP_ERR_WRONGTYPE:
1202 case SNMP_ERR_WRONGLENGTH:
1203 case SNMP_ERR_INCONSISTENTVALUE:
1204 status = SNMP_ERR_BADVALUE;
1205 asp->status = SNMP_ERR_BADVALUE;
1207 case SNMP_ERR_NOACCESS:
1208 case SNMP_ERR_NOTWRITABLE:
1209 case SNMP_ERR_NOCREATION:
1210 case SNMP_ERR_INCONSISTENTNAME:
1211 case SNMP_ERR_AUTHORIZATIONERROR:
1212 status = SNMP_ERR_NOSUCHNAME;
1213 asp->status = SNMP_ERR_NOSUCHNAME;
1215 case SNMP_ERR_RESOURCEUNAVAILABLE:
1216 case SNMP_ERR_COMMITFAILED:
1217 case SNMP_ERR_UNDOFAILED:
1218 status = SNMP_ERR_GENERR;
1219 asp->status = SNMP_ERR_GENERR;
1224 * Similarly we may need to "dumb down" v2 exception
1225 * types to throw an error for a v1 query.
1226 * See RFC2576 - section 4.1.2.3
1228 if ((asp->pdu->command != SNMP_MSG_SET) &&
1229 (asp->pdu->version == SNMP_VERSION_1)) {
1230 for (var_ptr = asp->pdu->variables, i = 1;
1231 var_ptr != NULL; var_ptr = var_ptr->next_variable, i++) {
1232 switch (var_ptr->type) {
1233 case SNMP_NOSUCHOBJECT:
1234 case SNMP_NOSUCHINSTANCE:
1235 case SNMP_ENDOFMIBVIEW:
1237 status = SNMP_ERR_NOSUCHNAME;
1238 asp->status = SNMP_ERR_NOSUCHNAME;
1244 } /** if asp->pdu */
1247 * Update the snmp error-count statistics
1248 * XXX - should we include the V2 errors in this or not?
1250 #define INCLUDE_V2ERRORS_IN_V1STATS
1253 #ifdef INCLUDE_V2ERRORS_IN_V1STATS
1254 case SNMP_ERR_WRONGVALUE:
1255 case SNMP_ERR_WRONGENCODING:
1256 case SNMP_ERR_WRONGTYPE:
1257 case SNMP_ERR_WRONGLENGTH:
1258 case SNMP_ERR_INCONSISTENTVALUE:
1260 case SNMP_ERR_BADVALUE:
1261 snmp_increment_statistic(STAT_SNMPOUTBADVALUES);
1263 #ifdef INCLUDE_V2ERRORS_IN_V1STATS
1264 case SNMP_ERR_NOACCESS:
1265 case SNMP_ERR_NOTWRITABLE:
1266 case SNMP_ERR_NOCREATION:
1267 case SNMP_ERR_INCONSISTENTNAME:
1268 case SNMP_ERR_AUTHORIZATIONERROR:
1270 case SNMP_ERR_NOSUCHNAME:
1271 snmp_increment_statistic(STAT_SNMPOUTNOSUCHNAMES);
1273 #ifdef INCLUDE_V2ERRORS_IN_V1STATS
1274 case SNMP_ERR_RESOURCEUNAVAILABLE:
1275 case SNMP_ERR_COMMITFAILED:
1276 case SNMP_ERR_UNDOFAILED:
1278 case SNMP_ERR_GENERR:
1279 snmp_increment_statistic(STAT_SNMPOUTGENERRS);
1282 case SNMP_ERR_TOOBIG:
1283 snmp_increment_statistic(STAT_SNMPOUTTOOBIGS);
1287 if ((status == SNMP_ERR_NOERROR) && (asp->pdu)) {
1288 snmp_increment_statistic_by((asp->pdu->command == SNMP_MSG_SET ?
1289 STAT_SNMPINTOTALSETVARS :
1290 STAT_SNMPINTOTALREQVARS),
1291 count_varbinds(asp->pdu->variables));
1294 * Use a copy of the original request
1295 * to report failures.
1297 snmp_free_pdu(asp->pdu);
1298 asp->pdu = asp->orig_pdu;
1299 asp->orig_pdu = NULL;
1302 asp->pdu->command = SNMP_MSG_RESPONSE;
1303 asp->pdu->errstat = asp->status;
1304 asp->pdu->errindex = asp->index;
1305 if (!snmp_send(asp->session, asp->pdu)) {
1306 snmp_free_pdu(asp->pdu);
1309 snmp_increment_statistic(STAT_SNMPOUTPKTS);
1310 snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES);
1312 netsnmp_remove_and_free_agent_snmp_session(asp);
1318 dump_sess_list(void)
1320 netsnmp_agent_session *a;
1322 DEBUGMSGTL(("snmp_agent", "DUMP agent_sess_list -> "));
1323 for (a = agent_session_list; a != NULL; a = a->next) {
1324 DEBUGMSG(("snmp_agent", "%08p[session %08p] -> ", a, a->session));
1326 DEBUGMSG(("snmp_agent", "[NIL]\n"));
1330 netsnmp_remove_and_free_agent_snmp_session(netsnmp_agent_session *asp)
1332 netsnmp_agent_session *a, **prevNext = &agent_session_list;
1334 DEBUGMSGTL(("snmp_agent", "REMOVE session == %08p\n", asp));
1336 for (a = agent_session_list; a != NULL; a = *prevNext) {
1338 *prevNext = a->next;
1340 free_agent_snmp_session(a);
1344 prevNext = &(a->next);
1348 if (a == NULL && asp != NULL) {
1350 * We coulnd't find it on the list, so free it anyway.
1352 free_agent_snmp_session(asp);
1357 netsnmp_free_agent_snmp_session_by_session(netsnmp_session * sess,
1358 void (*free_request)
1359 (netsnmp_request_list *))
1361 netsnmp_agent_session *a, *next, **prevNext = &agent_session_list;
1363 DEBUGMSGTL(("snmp_agent", "REMOVE session == %08p\n", sess));
1365 for (a = agent_session_list; a != NULL; a = next) {
1366 if (a->session == sess) {
1367 *prevNext = a->next;
1369 free_agent_snmp_session(a);
1371 prevNext = &(a->next);
1377 /** handles an incoming SNMP packet into the agent */
1379 handle_snmp_packet(int op, netsnmp_session * session, int reqid,
1380 netsnmp_pdu *pdu, void *magic)
1382 netsnmp_agent_session *asp;
1383 int status, access_ret, rc;
1386 * We only support receiving here.
1388 if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
1393 * RESPONSE messages won't get this far, but TRAP-like messages
1396 if (pdu->command == SNMP_MSG_TRAP || pdu->command == SNMP_MSG_INFORM ||
1397 pdu->command == SNMP_MSG_TRAP2) {
1398 DEBUGMSGTL(("snmp_agent", "received trap-like PDU (%02x)\n",
1400 pdu->command = SNMP_MSG_TRAP2;
1401 snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS);
1405 if (magic == NULL) {
1406 asp = init_agent_snmp_session(session, pdu);
1407 status = SNMP_ERR_NOERROR;
1409 asp = (netsnmp_agent_session *) magic;
1410 status = asp->status;
1413 if ((access_ret = check_access(pdu)) != 0) {
1414 if (access_ret == VACM_NOSUCHCONTEXT) {
1416 * rfc2573 section 3.2, step 5 says that we increment the
1417 * counter but don't return a response of any kind
1421 * we currently don't support unavailable contexts, as
1422 * there is no reason to that I currently know of
1424 snmp_increment_statistic(STAT_SNMPUNKNOWNCONTEXTS);
1429 netsnmp_remove_and_free_agent_snmp_session(asp);
1433 * access control setup is incorrect
1435 send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
1436 if (asp->pdu->version != SNMP_VERSION_1
1437 && asp->pdu->version != SNMP_VERSION_2c) {
1438 asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR;
1439 asp->pdu->command = SNMP_MSG_RESPONSE;
1440 snmp_increment_statistic(STAT_SNMPOUTPKTS);
1441 if (!snmp_send(asp->session, asp->pdu))
1442 snmp_free_pdu(asp->pdu);
1444 netsnmp_remove_and_free_agent_snmp_session(asp);
1450 netsnmp_remove_and_free_agent_snmp_session(asp);
1456 rc = netsnmp_handle_request(asp, status);
1461 DEBUGMSGTL(("snmp_agent", "end of handle_snmp_packet, asp = %08p\n",
1466 netsnmp_request_info *
1467 netsnmp_add_varbind_to_cache(netsnmp_agent_session *asp, int vbcount,
1468 netsnmp_variable_list * varbind_ptr,
1469 netsnmp_subtree *tp)
1471 netsnmp_request_info *request = NULL;
1474 DEBUGMSGTL(("snmp_agent", "add_vb_to_cache(%8p, %d, ", asp, vbcount));
1475 DEBUGMSGOID(("snmp_agent", varbind_ptr->name,
1476 varbind_ptr->name_length));
1477 DEBUGMSG(("snmp_agent", ", %8p)\n", tp));
1480 (asp->pdu->command == SNMP_MSG_GETNEXT ||
1481 asp->pdu->command == SNMP_MSG_GETBULK)) {
1485 prefix_len = netsnmp_oid_find_prefix(tp->start_a,
1487 tp->end_a, tp->end_len);
1489 netsnmp_acm_check_subtree(asp->pdu, tp->start_a, prefix_len);
1491 while (result == VACM_NOTINVIEW) {
1492 /* the entire subtree is not in view. Skip it. */
1493 /** @todo make this be more intelligent about ranges.
1494 Right now we merely take the highest level
1495 commonality of a registration range and use that.
1496 At times we might be able to be smarter about
1497 checking the range itself as opposed to the node
1498 above where the range exists, but I doubt this will
1499 come up all that frequently. */
1502 prefix_len = netsnmp_oid_find_prefix(tp->start_a,
1507 netsnmp_acm_check_subtree(asp->pdu,
1508 tp->start_a, prefix_len);
1514 * no appropriate registration found
1517 * make up the response ourselves
1519 switch (asp->pdu->command) {
1520 case SNMP_MSG_GETNEXT:
1521 case SNMP_MSG_GETBULK:
1522 varbind_ptr->type = SNMP_ENDOFMIBVIEW;
1526 varbind_ptr->type = SNMP_NOSUCHOBJECT;
1530 varbind_ptr->type = SNMP_NOSUCHOBJECT;
1534 return NULL; /* shouldn't get here */
1537 DEBUGMSGTL(("snmp_agent", "tp->start "));
1538 DEBUGMSGOID(("snmp_agent", tp->start_a, tp->start_len));
1539 DEBUGMSG(("snmp_agent", ", tp->end "));
1540 DEBUGMSGOID(("snmp_agent", tp->end_a, tp->end_len));
1541 DEBUGMSG(("snmp_agent", ", \n"));
1544 * malloc the request structure
1546 request = &(asp->requests[vbcount - 1]);
1547 request->index = vbcount;
1548 request->delegated = 0;
1549 request->processed = 0;
1550 request->status = 0;
1551 request->subtree = tp;
1552 if (request->parent_data) {
1553 netsnmp_free_request_data_sets(request);
1557 * for non-SET modes, set the type to NULL
1559 if (!MODE_IS_SET(asp->pdu->command)) {
1560 if (varbind_ptr->type == ASN_PRIV_INCL_RANGE) {
1561 DEBUGMSGTL(("snmp_agent", "varbind %d is inclusive\n",
1563 request->inclusive = 1;
1565 varbind_ptr->type = ASN_NULL;
1569 * place them in a cache
1571 if (tp->global_cacheid) {
1573 * we need to merge all marked subtrees together
1575 if (asp->cache_store && -1 !=
1576 (cacheid = netsnmp_get_local_cachid(asp->cache_store,
1577 tp->global_cacheid))) {
1579 cacheid = ++(asp->treecache_num);
1580 netsnmp_get_or_add_local_cachid(&asp->cache_store,
1583 goto mallocslot; /* XXX: ick */
1585 } else if (tp->cacheid > -1 && tp->cacheid <= asp->treecache_num &&
1586 asp->treecache[tp->cacheid].subtree == tp) {
1588 * we have already added a request to this tree
1591 cacheid = tp->cacheid;
1593 cacheid = ++(asp->treecache_num);
1598 if (asp->treecache_num >= asp->treecache_len) {
1600 * exapand cache array
1603 * WWW: non-linear expansion needed (with cap)
1605 #define CACHE_GROW_SIZE 16
1606 asp->treecache_len =
1607 (asp->treecache_len + CACHE_GROW_SIZE);
1609 realloc(asp->treecache,
1610 sizeof(netsnmp_tree_cache) *
1611 asp->treecache_len);
1612 if (asp->treecache == NULL)
1614 memset(&(asp->treecache[cacheid]), 0x00,
1615 sizeof(netsnmp_tree_cache) * (CACHE_GROW_SIZE));
1617 asp->treecache[cacheid].subtree = tp;
1618 asp->treecache[cacheid].requests_begin = request;
1619 tp->cacheid = cacheid;
1623 * if this is a search type, get the ending range oid as well
1625 if (asp->pdu->command == SNMP_MSG_GETNEXT ||
1626 asp->pdu->command == SNMP_MSG_GETBULK) {
1627 request->range_end = tp->end_a;
1628 request->range_end_len = tp->end_len;
1630 request->range_end = NULL;
1631 request->range_end_len = 0;
1637 if (asp->treecache[cacheid].requests_end)
1638 asp->treecache[cacheid].requests_end->next = request;
1639 request->next = NULL;
1640 request->prev = asp->treecache[cacheid].requests_end;
1641 asp->treecache[cacheid].requests_end = request;
1644 * add the given request to the list of requests they need
1645 * to handle results for
1647 request->requestvb = varbind_ptr;
1653 * check the ACM(s) for the results on each of the varbinds.
1654 * If ACM disallows it, replace the value with type
1656 * Returns number of varbinds with ACM errors
1659 check_acm(netsnmp_agent_session *asp, u_char type)
1663 netsnmp_request_info *request;
1665 netsnmp_variable_list *vb;
1667 for (i = 0; i <= asp->treecache_num; i++) {
1668 for (request = asp->treecache[i].requests_begin;
1669 request; request = request->next) {
1671 * for each request, run it through in_a_view()
1673 vb = request->requestvb;
1674 if (vb->type == ASN_NULL) /* not yet processed */
1677 in_a_view(vb->name, &vb->name_length, asp->pdu, vb->type);
1680 * if a ACM error occurs, mark it as type passed in
1682 if (view != VACM_SUCCESS) {
1684 snmp_set_var_typed_value(vb, type, NULL, 0);
1693 netsnmp_create_subtree_cache(netsnmp_agent_session *asp)
1695 netsnmp_subtree *tp;
1696 netsnmp_variable_list *varbind_ptr, *vbsave, *vbptr, **prevNext;
1699 int bulkcount = 0, bulkrep = 0;
1700 int i = 0, n = 0, r = 0;
1701 netsnmp_request_info *request;
1703 if (asp->treecache == NULL && asp->treecache_len == 0) {
1704 asp->treecache_len = SNMP_MAX(1 + asp->vbcount / 4, 16);
1706 calloc(asp->treecache_len, sizeof(netsnmp_tree_cache));
1707 if (asp->treecache == NULL)
1708 return SNMP_ERR_GENERR;
1710 asp->treecache_num = -1;
1712 if (asp->pdu->command == SNMP_MSG_GETBULK) {
1716 int count = count_varbinds(asp->pdu->variables);
1718 if (asp->pdu->errstat < 0) {
1719 asp->pdu->errstat = 0;
1721 if (asp->pdu->errindex < 0) {
1722 asp->pdu->errindex = 0;
1725 if (asp->pdu->errstat < count) {
1726 n = asp->pdu->errstat;
1730 if ((r = count - n) < 0) {
1732 asp->bulkcache = NULL;
1735 (netsnmp_variable_list **) malloc(asp->pdu->errindex * r *
1739 DEBUGMSGTL(("snmp_agent", "GETBULK N = %d, M = %d, R = %d\n",
1740 n, asp->pdu->errindex, r));
1744 * collect varbinds into their registered trees
1746 prevNext = &(asp->pdu->variables);
1747 for (varbind_ptr = asp->pdu->variables; varbind_ptr;
1748 varbind_ptr = vbsave) {
1751 * getbulk mess with this pointer, so save it
1753 vbsave = varbind_ptr->next_variable;
1755 if (asp->pdu->command == SNMP_MSG_GETBULK) {
1760 * repeate request varbinds on GETBULK. These will
1761 * have to be properly rearranged later though as
1762 * responses are supposed to actually be interlaced
1763 * with each other. This is done with the asp->bulkcache.
1765 bulkrep = asp->pdu->errindex - 1;
1766 if (asp->pdu->errindex > 0) {
1767 vbptr = varbind_ptr;
1768 asp->bulkcache[bulkcount++] = vbptr;
1770 for (i = 1; i < asp->pdu->errindex; i++) {
1771 vbptr->next_variable =
1772 SNMP_MALLOC_STRUCT(variable_list);
1774 * don't clone the oid as it's got to be
1775 * overwwritten anyway
1777 if (!vbptr->next_variable) {
1782 vbptr = vbptr->next_variable;
1783 vbptr->name_length = 0;
1784 vbptr->type = ASN_NULL;
1785 asp->bulkcache[bulkcount++] = vbptr;
1788 vbptr->next_variable = vbsave;
1791 * 0 repeats requested for this varbind, so take it off
1794 vbptr = varbind_ptr;
1795 *prevNext = vbptr->next_variable;
1796 vbptr->next_variable = NULL;
1797 snmp_free_varbind(vbptr);
1805 * count the varbinds
1810 * find the owning tree
1812 tp = netsnmp_subtree_find(varbind_ptr->name, varbind_ptr->name_length,
1813 NULL, asp->pdu->contextName);
1816 * check access control
1818 switch (asp->pdu->command) {
1820 view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
1821 asp->pdu, varbind_ptr->type);
1822 if (view != VACM_SUCCESS)
1823 snmp_set_var_typed_value(varbind_ptr, SNMP_NOSUCHOBJECT,
1828 view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
1829 asp->pdu, varbind_ptr->type);
1830 if (view != VACM_SUCCESS)
1831 return SNMP_ERR_NOTWRITABLE;
1834 case SNMP_MSG_GETNEXT:
1835 case SNMP_MSG_GETBULK:
1837 view = VACM_SUCCESS;
1839 * XXXWWW: check VACM here to see if "tp" is even worthwhile
1842 if (view == VACM_SUCCESS) {
1843 request = netsnmp_add_varbind_to_cache(asp, vbcount, varbind_ptr,
1845 if (request && asp->pdu->command == SNMP_MSG_GETBULK) {
1846 request->repeat = bulkrep;
1849 return SNMP_ERR_GENERR;
1852 prevNext = &(varbind_ptr->next_variable);
1855 return SNMPERR_SUCCESS;
1859 * this function is only applicable in getnext like contexts
1862 netsnmp_reassign_requests(netsnmp_agent_session *asp)
1865 * assume all the requests have been filled or rejected by the
1866 * subtrees, so reassign the rejected ones to the next subtree in
1875 netsnmp_tree_cache *old_treecache = asp->treecache;
1881 (netsnmp_tree_cache *) calloc(asp->treecache_len,
1882 sizeof(netsnmp_tree_cache));
1883 asp->treecache_num = -1;
1884 if (asp->cache_store) {
1885 netsnmp_free_cachemap(asp->cache_store);
1886 asp->cache_store = NULL;
1889 for (i = 0; i < asp->vbcount; i++) {
1890 if (asp->requests[i].requestvb->type == ASN_NULL) {
1891 if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index,
1892 asp->requests[i].requestvb,
1893 asp->requests[i].subtree->next)) {
1894 if (old_treecache != NULL) {
1895 free(old_treecache);
1897 return SNMP_ERR_GENERR;
1899 } else if (asp->requests[i].requestvb->type == ASN_PRIV_RETRY) {
1901 * re-add the same subtree
1903 asp->requests[i].requestvb->type = ASN_NULL;
1904 if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index,
1905 asp->requests[i].requestvb,
1906 asp->requests[i].subtree)) {
1907 if (old_treecache != NULL) {
1908 free(old_treecache);
1910 return SNMP_ERR_GENERR;
1915 if (old_treecache != NULL) {
1916 free(old_treecache);
1918 return SNMP_ERR_NOERROR;
1922 netsnmp_delete_request_infos(netsnmp_request_info *reqlist)
1925 netsnmp_free_request_data_sets(reqlist);
1926 reqlist = reqlist->next;
1931 netsnmp_delete_subtree_cache(netsnmp_agent_session *asp)
1933 while (asp->treecache_num >= 0) {
1935 * don't delete subtrees
1937 netsnmp_delete_request_infos(asp->treecache[asp->treecache_num].
1939 asp->treecache_num--;
1944 netsnmp_check_requests_status(netsnmp_agent_session *asp,
1945 netsnmp_request_info *requests,
1946 int look_for_specific)
1949 * find any errors marked in the requests
1952 if (requests->status != SNMP_ERR_NOERROR &&
1953 (!look_for_specific || requests->status == look_for_specific)
1954 && (look_for_specific || asp->index == 0
1955 || requests->index < asp->index)) {
1956 asp->index = requests->index;
1957 asp->status = requests->status;
1959 requests = requests->next;
1965 netsnmp_check_all_requests_status(netsnmp_agent_session *asp,
1966 int look_for_specific)
1969 for (i = 0; i <= asp->treecache_num; i++) {
1970 netsnmp_check_requests_status(asp,
1971 asp->treecache[i].requests_begin,
1978 handle_var_requests(netsnmp_agent_session *asp)
1980 int i, retstatus = SNMP_ERR_NOERROR,
1981 status = SNMP_ERR_NOERROR, final_status = SNMP_ERR_NOERROR;
1982 netsnmp_handler_registration *reginfo;
1985 * create the netsnmp_agent_request_info data
1987 if (!asp->reqinfo) {
1988 asp->reqinfo = SNMP_MALLOC_TYPEDEF(netsnmp_agent_request_info);
1990 return SNMP_ERR_GENERR;
1993 asp->reqinfo->asp = asp;
1994 asp->reqinfo->mode = asp->mode;
1997 * now, have the subtrees in the cache go search for their results
1999 for (i = 0; i <= asp->treecache_num; i++) {
2000 reginfo = asp->treecache[i].subtree->reginfo;
2001 status = netsnmp_call_handlers(reginfo, asp->reqinfo,
2002 asp->treecache[i].requests_begin);
2005 * find any errors marked in the requests. For later parts of
2006 * SET processing, only check for new errors specific to that
2007 * set processing directive (which must superceed the previous
2010 switch (asp->mode) {
2011 case MODE_SET_COMMIT:
2012 retstatus = netsnmp_check_requests_status(asp,
2015 SNMP_ERR_COMMITFAILED);
2019 retstatus = netsnmp_check_requests_status(asp,
2022 SNMP_ERR_UNDOFAILED);
2026 retstatus = netsnmp_check_requests_status(asp,
2033 * always take lowest varbind if possible
2035 if (retstatus != SNMP_ERR_NOERROR) {
2040 * other things we know less about (no index)
2043 * WWW: drop support for this?
2045 if (final_status == SNMP_ERR_NOERROR && status != SNMP_ERR_NOERROR) {
2047 * we can't break here, since some processing needs to be
2048 * done for all requests anyway (IE, SET handling for UNDO
2049 * needs to be called regardless of previous status
2051 * WWW: This should be predictable though and
2052 * breaking should be possible in some cases (eg GET,
2055 final_status = status;
2059 return final_status;
2063 * loop through our sessions known delegated sessions and check to see
2064 * if they've completed yet. If there are no more delegated sessions,
2065 * check for and process any queued requests
2068 netsnmp_check_outstanding_agent_requests(void)
2070 netsnmp_agent_session *asp, *prev_asp = NULL, *next_asp = NULL;
2073 * deal with delegated requests
2075 for (asp = agent_delegated_list; asp; prev_asp = asp, asp = next_asp) {
2076 next_asp = asp->next; /* save in case we clean up asp */
2077 if (!netsnmp_check_for_delegated(asp)) {
2080 * we're done with this one, remove from queue
2082 if (prev_asp != NULL)
2083 prev_asp->next = asp->next;
2085 agent_delegated_list = asp->next;
2088 * check request status
2090 netsnmp_check_all_requests_status(asp, 0);
2093 * continue processing or finish up
2095 check_delayed_request(asp);
2100 * if we are processing a set and there are more delegated
2101 * requests, keep waiting before getting to queued requests.
2103 if (netsnmp_processing_set && (NULL != agent_delegated_list))
2106 while (netsnmp_agent_queued_list) {
2109 * if we are processing a set, the first item better be
2110 * the set being (or waiting to be) processed.
2112 netsnmp_assert((!netsnmp_processing_set) ||
2113 (netsnmp_processing_set == netsnmp_agent_queued_list));
2116 * if the top request is a set, don't pop it
2117 * off if there are delegated requests
2119 if ((netsnmp_agent_queued_list->pdu->command == SNMP_MSG_SET) &&
2120 (agent_delegated_list)) {
2122 netsnmp_assert(netsnmp_processing_set == NULL);
2124 netsnmp_processing_set = netsnmp_agent_queued_list;
2125 DEBUGMSGTL(("snmp_agent", "SET request remains queued while "
2126 "delegated requests finish, asp = %08p\n", asp));
2131 * pop the first request and process it
2133 asp = netsnmp_agent_queued_list;
2134 netsnmp_agent_queued_list = asp->next;
2135 DEBUGMSGTL(("snmp_agent",
2136 "processing queued request, asp = %08p\n", asp));
2138 netsnmp_handle_request(asp, asp->status);
2141 * if we hit a set, stop
2143 if (NULL != netsnmp_processing_set)
2148 /** Decide if the requested transaction_id is still being processed
2149 within the agent. This is used to validate whether a delayed cache
2150 (containing possibly freed pointers) is still usable.
2152 returns SNMPERR_SUCCESS if it's still valid, or SNMPERR_GENERR if not. */
2154 netsnmp_check_transaction_id(int transaction_id)
2156 netsnmp_agent_session *asp, *prev_asp = NULL;
2158 for (asp = agent_delegated_list; asp; prev_asp = asp, asp = asp->next) {
2159 if (asp->pdu->transid == transaction_id)
2160 return SNMPERR_SUCCESS;
2162 return SNMPERR_GENERR;
2167 * check_delayed_request(asp)
2169 * Called to rexamine a set of requests and continue processing them
2170 * once all the previous (delayed) requests have been handled one way
2175 check_delayed_request(netsnmp_agent_session *asp)
2177 int status = SNMP_ERR_NOERROR;
2179 DEBUGMSGTL(("snmp_agent", "processing delegated request, asp = %08p\n",
2182 switch (asp->mode) {
2183 case SNMP_MSG_GETBULK:
2184 case SNMP_MSG_GETNEXT:
2185 netsnmp_check_all_requests_status(asp, 0);
2186 handle_getnext_loop(asp);
2187 if (netsnmp_check_for_delegated(asp) &&
2188 netsnmp_check_transaction_id(asp->pdu->transid) !=
2191 * add to delegated request chain
2193 if (!netsnmp_check_delegated_chain_for(asp)) {
2194 asp->next = agent_delegated_list;
2195 agent_delegated_list = asp;
2200 case MODE_SET_COMMIT:
2201 netsnmp_check_all_requests_status(asp, SNMP_ERR_COMMITFAILED);
2205 netsnmp_check_all_requests_status(asp, SNMP_ERR_UNDOFAILED);
2208 case MODE_SET_BEGIN:
2209 case MODE_SET_RESERVE1:
2210 case MODE_SET_RESERVE2:
2211 case MODE_SET_ACTION:
2214 handle_set_loop(asp);
2215 if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) {
2217 if (netsnmp_check_for_delegated_and_add(asp)) {
2219 * add to delegated request chain
2222 asp->status = status;
2225 return SNMP_ERR_NOERROR;
2234 * if we don't have anything outstanding (delegated), wrap up
2236 if (!netsnmp_check_for_delegated(asp))
2237 return netsnmp_wrap_up_request(asp, status);
2242 /** returns 1 if there are valid GETNEXT requests left. Returns 0 if not. */
2244 check_getnext_results(netsnmp_agent_session *asp)
2249 netsnmp_tree_cache *old_treecache = asp->treecache;
2250 int old_treecache_num = asp->treecache_num;
2253 netsnmp_request_info *request;
2255 if (asp->mode == SNMP_MSG_GET) {
2257 * Special case for doing INCLUSIVE getNext operations in
2260 DEBUGMSGTL(("snmp_agent",
2261 "asp->mode == SNMP_MSG_GET in ch_getnext\n"));
2262 asp->mode = asp->oldmode;
2266 for (i = 0; i <= old_treecache_num; i++) {
2267 for (request = old_treecache[i].requests_begin; request;
2268 request = request->next) {
2271 * If we have just done the special case AgentX GET, then any
2272 * requests which were not INCLUSIVE will now have a wrong
2273 * response, so junk them and retry from the same place (except
2274 * that this time the handler will be called in "inexact"
2279 if (!request->inclusive) {
2280 DEBUGMSGTL(("snmp_agent",
2281 "request %d wasn't inclusive\n",
2283 snmp_set_var_typed_value(request->requestvb,
2284 ASN_PRIV_RETRY, NULL, 0);
2285 } else if (request->requestvb->type == ASN_NULL ||
2286 request->requestvb->type == SNMP_NOSUCHINSTANCE ||
2287 request->requestvb->type == SNMP_NOSUCHOBJECT) {
2289 * it was inclusive, but no results. Still retry this
2292 snmp_set_var_typed_value(request->requestvb,
2293 ASN_PRIV_RETRY, NULL, 0);
2300 if (snmp_oid_compare(request->requestvb->name,
2301 request->requestvb->name_length,
2303 request->range_end_len) >= 0) {
2305 * ack, it's beyond the accepted end of range.
2308 * fix it by setting the oid to the end of range oid instead
2310 DEBUGMSGTL(("check_getnext_results",
2311 "request response %d out of range\n",
2313 request->inclusive = 1;
2315 * XXX: should set this to the original OID?
2317 snmp_set_var_objid(request->requestvb,
2319 request->range_end_len);
2320 snmp_set_var_typed_value(request->requestvb, ASN_NULL,
2325 * mark any existent requests with illegal results as NULL
2327 if (request->requestvb->type == SNMP_ENDOFMIBVIEW) {
2329 * illegal response from a subagent. Change it back to NULL
2331 request->requestvb->type = ASN_NULL;
2332 request->inclusive = 1;
2335 if (request->requestvb->type == ASN_NULL ||
2336 request->requestvb->type == ASN_PRIV_RETRY ||
2337 (asp->reqinfo->mode == MODE_GETBULK
2338 && request->repeat > 0))
2345 /** repeatedly calls getnext handlers looking for an answer till all
2346 requests are satisified. It's expected that one pass has been made
2347 before entering this function */
2349 handle_getnext_loop(netsnmp_agent_session *asp)
2352 netsnmp_variable_list *var_ptr;
2360 * bail for now if anything is delegated.
2362 if (netsnmp_check_for_delegated(asp)) {
2363 return SNMP_ERR_NOERROR;
2367 * check vacm against results
2369 check_acm(asp, ASN_PRIV_RETRY);
2372 * need to keep going we're not done yet.
2374 if (!check_getnext_results(asp))
2376 * nothing left, quit now
2381 * never had a request (empty pdu), quit now
2384 * XXXWWW: huh? this would be too late, no? shouldn't we
2385 * catch this earlier?
2392 DEBUGIF("results") {
2393 DEBUGMSGTL(("results",
2394 "getnext results, before next pass:\n"));
2395 for (var_ptr = asp->pdu->variables; var_ptr;
2396 var_ptr = var_ptr->next_variable) {
2397 DEBUGMSGTL(("results", "\t"));
2398 DEBUGMSGVAR(("results", var_ptr));
2399 DEBUGMSG(("results", "\n"));
2403 netsnmp_reassign_requests(asp);
2404 status = handle_var_requests(asp);
2405 if (status != SNMP_ERR_NOERROR) {
2406 return status; /* should never really happen */
2409 return SNMP_ERR_NOERROR;
2413 handle_set(netsnmp_agent_session *asp)
2417 * SETS require 3-4 passes through the var_op_list.
2419 * passes verify that all types, lengths, and values are valid
2420 * and may reserve resources and the third does the set and a
2421 * fourth executes any actions. Then the identical GET RESPONSE
2422 * packet is returned.
2423 * If either of the first two passes returns an error, another
2424 * pass is made so that any reserved resources can be freed.
2425 * If the third pass returns an error, another pass is
2427 * any changes can be reversed.
2428 * If the fourth pass (or any of the error handling passes)
2429 * return an error, we'd rather not know about it!
2431 if (!(asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) {
2432 switch (asp->mode) {
2433 case MODE_SET_BEGIN:
2434 snmp_increment_statistic(STAT_SNMPINSETREQUESTS);
2435 asp->rw = WRITE; /* WWW: still needed? */
2436 asp->mode = MODE_SET_RESERVE1;
2437 asp->status = SNMP_ERR_NOERROR;
2440 case MODE_SET_RESERVE1:
2442 if (asp->status != SNMP_ERR_NOERROR)
2443 asp->mode = MODE_SET_FREE;
2445 asp->mode = MODE_SET_RESERVE2;
2448 case MODE_SET_RESERVE2:
2449 if (asp->status != SNMP_ERR_NOERROR)
2450 asp->mode = MODE_SET_FREE;
2452 asp->mode = MODE_SET_ACTION;
2455 case MODE_SET_ACTION:
2456 if (asp->status != SNMP_ERR_NOERROR)
2457 asp->mode = MODE_SET_UNDO;
2459 asp->mode = MODE_SET_COMMIT;
2462 case MODE_SET_COMMIT:
2463 if (asp->status != SNMP_ERR_NOERROR) {
2464 asp->mode = FINISHED_FAILURE;
2466 asp->mode = FINISHED_SUCCESS;
2471 asp->mode = FINISHED_FAILURE;
2475 asp->mode = FINISHED_FAILURE;
2480 if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) {
2481 DEBUGMSGTL(("agent_set", "doing set mode = %d (%s)\n", asp->mode,
2482 se_find_label_in_slist("agent_mode", asp->mode)));
2483 status = handle_var_requests(asp);
2484 DEBUGMSGTL(("agent_set", "did set mode = %d, status = %d\n",
2485 asp->mode, status));
2486 if ((status != SNMP_ERR_NOERROR && asp->status == SNMP_ERR_NOERROR) ||
2487 status == SNMP_ERR_COMMITFAILED ||
2488 status == SNMP_ERR_UNDOFAILED) {
2489 asp->status = status;
2496 handle_set_loop(netsnmp_agent_session *asp)
2498 while (asp->mode != FINISHED_FAILURE && asp->mode != FINISHED_SUCCESS) {
2500 if (netsnmp_check_for_delegated(asp)) {
2501 return SNMP_ERR_NOERROR;
2503 if (asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY) {
2511 netsnmp_handle_request(netsnmp_agent_session *asp, int status)
2514 * if this isn't a delegated request trying to finish,
2515 * processing of a set request should not start until all
2516 * delegated requests have completed, and no other new requests
2517 * should be processed until the set request completes.
2519 if ((0 == netsnmp_check_delegated_chain_for(asp)) &&
2520 (asp != netsnmp_processing_set)) {
2522 * if we are processing a set and this is not a delegated
2523 * request, queue the request
2525 if (netsnmp_processing_set) {
2526 netsnmp_add_queued(asp);
2527 DEBUGMSGTL(("snmp_agent",
2528 "request queued while processing set, "
2529 "asp = %08p\n", asp));
2534 * check for set request
2536 if (asp->pdu->command == SNMP_MSG_SET) {
2537 netsnmp_processing_set = asp;
2540 * if there are delegated requests, we must wait for them
2543 if (agent_delegated_list) {
2544 DEBUGMSGTL(("snmp_agent", "SET request queued while "
2545 "delegated requests finish, asp = %08p\n",
2547 netsnmp_add_queued(asp);
2554 * process the request
2556 status = handle_pdu(asp);
2559 * print the results in appropriate debugging mode
2561 DEBUGIF("results") {
2562 netsnmp_variable_list *var_ptr;
2563 DEBUGMSGTL(("results", "request results (status = %d):\n",
2565 for (var_ptr = asp->pdu->variables; var_ptr;
2566 var_ptr = var_ptr->next_variable) {
2567 DEBUGMSGTL(("results", "\t"));
2568 DEBUGMSGVAR(("results", var_ptr));
2569 DEBUGMSG(("results", "\n"));
2574 * check for uncompleted requests
2576 if (netsnmp_check_for_delegated_and_add(asp)) {
2578 * add to delegated request chain
2580 asp->status = status;
2583 * if we don't have anything outstanding (delegated), wrap up
2585 return netsnmp_wrap_up_request(asp, status);
2592 handle_pdu(netsnmp_agent_session *asp)
2594 int status, inclusives = 0;
2595 netsnmp_variable_list *v = NULL;
2598 * for illegal requests, mark all nodes as ASN_NULL
2600 switch (asp->pdu->command) {
2602 case SNMP_MSG_INTERNAL_SET_RESERVE2:
2603 case SNMP_MSG_INTERNAL_SET_ACTION:
2604 case SNMP_MSG_INTERNAL_SET_COMMIT:
2605 case SNMP_MSG_INTERNAL_SET_FREE:
2606 case SNMP_MSG_INTERNAL_SET_UNDO:
2607 status = get_set_cache(asp);
2608 if (status != SNMP_ERR_NOERROR)
2613 case SNMP_MSG_GETNEXT:
2614 case SNMP_MSG_GETBULK:
2615 for (v = asp->pdu->variables; v != NULL; v = v->next_variable) {
2616 if (v->type == ASN_PRIV_INCL_RANGE) {
2618 * Leave the type for now (it gets set to
2619 * ASN_NULL in netsnmp_add_varbind_to_cache,
2620 * called by create_subnetsnmp_tree_cache below).
2621 * If we set it to ASN_NULL now, we wouldn't be
2622 * able to distinguish INCLUSIVE search
2627 snmp_set_var_typed_value(v, ASN_NULL, NULL, 0);
2634 case SNMP_MSG_INTERNAL_SET_BEGIN:
2635 case SNMP_MSG_INTERNAL_SET_RESERVE1:
2637 asp->vbcount = count_varbinds(asp->pdu->variables);
2638 if (asp->vbcount) /* efence doesn't like 0 size allocs */
2639 asp->requests = (netsnmp_request_info *)
2640 calloc(asp->vbcount, sizeof(netsnmp_request_info));
2644 status = netsnmp_create_subtree_cache(asp);
2645 if (status != SNMP_ERR_NOERROR)
2649 asp->mode = asp->pdu->command;
2650 switch (asp->mode) {
2653 * increment the message type counter
2655 snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
2658 * check vacm ahead of time
2660 check_acm(asp, SNMP_NOSUCHOBJECT);
2665 status = handle_var_requests(asp);
2668 * Deal with unhandled results -> noSuchInstance (rather
2669 * than noSuchObject -- in that case, the type will
2670 * already have been set to noSuchObject when we realised
2671 * we couldn't find an appropriate tree).
2673 if (status == SNMP_ERR_NOERROR)
2674 snmp_replace_var_types(asp->pdu->variables, ASN_NULL,
2675 SNMP_NOSUCHINSTANCE);
2678 case SNMP_MSG_GETNEXT:
2679 snmp_increment_statistic(STAT_SNMPINGETNEXTS);
2684 case SNMP_MSG_GETBULK: /* note: there is no getbulk stat */
2686 * loop through our mib tree till we find an
2687 * appropriate response to return to the caller.
2692 * This is a special case for AgentX INCLUSIVE getNext
2693 * requests where a result lexi-equal to the request is okay
2694 * but if such a result does not exist, we still want the
2695 * lexi-next one. So basically we do a GET first, and if any
2696 * of the INCLUSIVE requests are satisfied, we use that
2697 * value. Then, unsatisfied INCLUSIVE requests, and
2698 * non-INCLUSIVE requests get done as normal.
2701 DEBUGMSGTL(("snmp_agent", "inclusive range(s) in getNext\n"));
2702 asp->oldmode = asp->mode;
2703 asp->mode = SNMP_MSG_GET;
2709 status = handle_var_requests(asp);
2710 if (status != SNMP_ERR_NOERROR) {
2712 return status; /* should never really happen */
2714 asp->status = SNMP_ERR_NOERROR;
2718 * loop through our mib tree till we find an
2719 * appropriate response to return to the caller.
2722 status = handle_getnext_loop(asp);
2727 * check access permissions first
2729 if (check_acm(asp, SNMP_NOSUCHOBJECT))
2730 return SNMP_ERR_NOTWRITABLE;
2732 asp->mode = MODE_SET_BEGIN;
2733 status = handle_set_loop(asp);
2737 case SNMP_MSG_INTERNAL_SET_BEGIN:
2738 case SNMP_MSG_INTERNAL_SET_RESERVE1:
2739 case SNMP_MSG_INTERNAL_SET_RESERVE2:
2740 case SNMP_MSG_INTERNAL_SET_ACTION:
2741 case SNMP_MSG_INTERNAL_SET_COMMIT:
2742 case SNMP_MSG_INTERNAL_SET_FREE:
2743 case SNMP_MSG_INTERNAL_SET_UNDO:
2744 asp->pdu->flags |= UCD_MSG_FLAG_ONE_PASS_ONLY;
2745 status = handle_set_loop(asp);
2747 * asp related cache is saved in cleanup
2751 case SNMP_MSG_RESPONSE:
2752 snmp_increment_statistic(STAT_SNMPINGETRESPONSES);
2753 return SNMP_ERR_NOERROR;
2756 case SNMP_MSG_TRAP2:
2757 snmp_increment_statistic(STAT_SNMPINTRAPS);
2758 return SNMP_ERR_NOERROR;
2762 * WWW: are reports counted somewhere ?
2764 snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
2765 return SNMPERR_GENERR; /* shouldn't get here */
2774 netsnmp_set_request_error(netsnmp_agent_request_info *reqinfo,
2775 netsnmp_request_info *request, int error_value)
2777 if (!request || !reqinfo)
2780 return netsnmp_set_mode_request_error(reqinfo->mode, request,
2785 netsnmp_set_mode_request_error(int mode, netsnmp_request_info *request,
2791 request->processed = 1;
2792 request->delegated = REQUEST_IS_NOT_DELEGATED;
2794 switch (error_value) {
2795 case SNMP_NOSUCHOBJECT:
2796 case SNMP_NOSUCHINSTANCE:
2797 case SNMP_ENDOFMIBVIEW:
2799 * these are exceptions that should be put in the varbind
2800 * in the case of a GET but should be translated for a SET
2801 * into a real error status code and put in the request
2805 request->requestvb->type = error_value;
2811 * ignore these. They're illegal to set by the
2812 * client APIs for these modes
2814 snmp_log(LOG_ERR, "Illegal error_value %d for mode %d ignored\n",
2819 request->status = SNMP_ERR_NOSUCHNAME; /* WWW: correct? */
2822 break; /* never get here */
2825 if (request->status < 0) {
2827 * illegal local error code. translate to generr
2830 * WWW: full translation map?
2832 snmp_log(LOG_ERR, "Illegal error_value %d translated to %d\n",
2833 error_value, SNMP_ERR_GENERR);
2834 request->status = SNMP_ERR_GENERR;
2837 * WWW: translations and mode checking?
2839 request->status = error_value;
2847 netsnmp_set_all_requests_error(netsnmp_agent_request_info *reqinfo,
2848 netsnmp_request_info *requests,
2852 netsnmp_set_request_error(reqinfo, requests, error_value);
2853 requests = requests->next;
2858 extern struct timeval starttime;
2861 * Return the value of 'sysUpTime' at the given marker
2864 netsnmp_marker_uptime(marker_t pm)
2867 marker_t start = (marker_t) & starttime;
2869 res = uatime_hdiff(start, pm);
2870 return res; /* atime_diff works in msec, not csec */
2874 * struct timeval equivalents of these
2877 netsnmp_timeval_uptime(struct timeval * tv)
2879 return netsnmp_marker_uptime((marker_t) tv);
2883 * Return the current value of 'sysUpTime'
2886 netsnmp_get_agent_uptime(void)
2889 gettimeofday(&now, NULL);
2891 return netsnmp_timeval_uptime(&now);
2897 netsnmp_agent_add_list_data(netsnmp_agent_request_info *ari,
2898 netsnmp_data_list *node)
2901 if (ari->agent_data) {
2902 netsnmp_add_list_data(&ari->agent_data, node);
2904 ari->agent_data = node;
2909 NETSNMP_INLINE void *
2910 netsnmp_agent_get_list_data(netsnmp_agent_request_info *ari,
2914 return netsnmp_get_list_data(ari->agent_data, name);
2920 netsnmp_free_agent_data_set(netsnmp_agent_request_info *ari)
2923 netsnmp_free_list_data(ari->agent_data);
2928 netsnmp_free_agent_data_sets(netsnmp_agent_request_info *ari)
2931 netsnmp_free_all_list_data(ari->agent_data);
2936 netsnmp_free_agent_request_info(netsnmp_agent_request_info *ari)
2939 if (ari->agent_data) {
2940 netsnmp_free_all_list_data(ari->agent_data);