4
* Simple Network Management Protocol (RFC 1067).
6
/* Portions of this file are subject to the following copyright(s). See
7
* the Net-SNMP's COPYING file for more details and other copyrights
10
/* Portions of this file are subject to the following copyrights. See
11
* the Net-SNMP's COPYING file for more details and other copyrights
14
/***********************************************************
15
Copyright 1988, 1989 by Carnegie Mellon University
19
Permission to use, copy, modify, and distribute this software and its
20
documentation for any purpose and without fee is hereby granted,
21
provided that the above copyright notice appear in all copies and that
22
both that copyright notice and this permission notice appear in
23
supporting documentation, and that the name of CMU not be
24
used in advertising or publicity pertaining to distribution of the
25
software without specific, written prior permission.
27
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
28
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
29
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
30
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
31
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
32
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
34
******************************************************************/
36
* Portions of this file are copyrighted by:
37
* Copyright � 2003 Sun Microsystems, Inc. All rights
38
* reserved. Use is subject to license terms specified in the
39
* COPYING file distributed with the Net-SNMP package.
41
/** @defgroup snmp_agent net-snmp agent related processing
46
#include <net-snmp/net-snmp-config.h>
47
#include <net-snmp/net-snmp-features.h>
49
#include <sys/types.h>
62
#if TIME_WITH_SYS_TIME
63
# include <sys/time.h>
67
# include <sys/time.h>
73
#include <sys/select.h>
76
#include <netinet/in.h>
80
#define SNMP_NEED_REQUEST_LIST
81
#include <net-snmp/net-snmp-includes.h>
82
#include <net-snmp/agent/net-snmp-agent-includes.h>
83
#include <net-snmp/library/snmp_assert.h>
89
#ifdef NETSNMP_USE_LIBWRAP
91
int allow_severity = LOG_INFO;
92
int deny_severity = LOG_WARNING;
96
#include <net-snmp/agent/mib_module_config.h>
97
#include <net-snmp/agent/mib_modules.h>
99
#ifdef USING_AGENTX_PROTOCOL_MODULE
100
#include "agentx/protocol.h"
103
#ifdef USING_AGENTX_MASTER_MODULE
104
#include "agentx/master.h"
107
#ifdef USING_SMUX_MODULE
108
#include "smux/smux.h"
111
netsnmp_feature_child_of(snmp_agent, libnetsnmpagent)
112
netsnmp_feature_child_of(agent_debugging_utilities, libnetsnmpagent)
114
netsnmp_feature_child_of(allocate_globalcacheid, snmp_agent)
115
netsnmp_feature_child_of(free_agent_snmp_session_by_session, snmp_agent)
116
netsnmp_feature_child_of(check_all_requests_error, snmp_agent)
117
netsnmp_feature_child_of(check_requests_error, snmp_agent)
118
netsnmp_feature_child_of(request_set_error_idx, snmp_agent)
119
netsnmp_feature_child_of(set_agent_uptime, snmp_agent)
120
netsnmp_feature_child_of(agent_check_and_process, snmp_agent)
122
netsnmp_feature_child_of(dump_sess_list, agent_debugging_utilities)
124
netsnmp_feature_child_of(agent_remove_list_data, netsnmp_unused)
125
netsnmp_feature_child_of(set_all_requests_error, netsnmp_unused)
126
netsnmp_feature_child_of(addrcache_age, netsnmp_unused)
127
netsnmp_feature_child_of(delete_subtree_cache, netsnmp_unused)
131
netsnmp_agent_add_list_data(netsnmp_agent_request_info *ari,
132
netsnmp_data_list *node)
135
if (ari->agent_data) {
136
netsnmp_add_list_data(&ari->agent_data, node);
138
ari->agent_data = node;
143
#ifndef NETSNMP_FEATURE_REMOVE_AGENT_REMOVE_LIST_DATA
145
netsnmp_agent_remove_list_data(netsnmp_agent_request_info *ari,
148
if ((NULL == ari) || (NULL == ari->agent_data))
151
return netsnmp_remove_list_node(&ari->agent_data, name);
153
#endif /* NETSNMP_FEATURE_REMOVE_AGENT_REMOVE_LIST_DATA */
155
NETSNMP_INLINE void *
156
netsnmp_agent_get_list_data(netsnmp_agent_request_info *ari,
160
return netsnmp_get_list_data(ari->agent_data, name);
166
netsnmp_free_agent_data_set(netsnmp_agent_request_info *ari)
169
netsnmp_free_list_data(ari->agent_data);
174
netsnmp_free_agent_data_sets(netsnmp_agent_request_info *ari)
177
netsnmp_free_all_list_data(ari->agent_data);
182
netsnmp_free_agent_request_info(netsnmp_agent_request_info *ari)
185
if (ari->agent_data) {
186
netsnmp_free_all_list_data(ari->agent_data);
192
oid version_sysoid[] = { NETSNMP_SYSTEM_MIB };
193
int version_sysoid_len = OID_LENGTH(version_sysoid);
195
#define SNMP_ADDRCACHE_SIZE 10
196
#define SNMP_ADDRCACHE_MAXAGE 300 /* in seconds */
199
SNMP_ADDRCACHE_UNUSED = 0,
200
SNMP_ADDRCACHE_USED = 1
206
struct timeval lastHitM;
209
static struct addrCache addrCache[SNMP_ADDRCACHE_SIZE];
210
int log_addresses = 0;
214
typedef struct _agent_nsap {
216
netsnmp_transport *t;
217
void *s; /* Opaque internal session pointer. */
218
struct _agent_nsap *next;
221
static agent_nsap *agent_nsap_list = NULL;
222
static netsnmp_agent_session *agent_session_list = NULL;
223
netsnmp_agent_session *netsnmp_processing_set = NULL;
224
netsnmp_agent_session *agent_delegated_list = NULL;
225
netsnmp_agent_session *netsnmp_agent_queued_list = NULL;
228
int netsnmp_agent_check_packet(netsnmp_session *,
229
struct netsnmp_transport_s *,
231
int netsnmp_agent_check_parse(netsnmp_session *, netsnmp_pdu *,
233
void delete_subnetsnmp_tree_cache(netsnmp_agent_session *asp);
234
int handle_pdu(netsnmp_agent_session *asp);
235
int netsnmp_handle_request(netsnmp_agent_session *asp,
237
int netsnmp_wrap_up_request(netsnmp_agent_session *asp,
239
int check_delayed_request(netsnmp_agent_session *asp);
240
int handle_getnext_loop(netsnmp_agent_session *asp);
241
int handle_set_loop(netsnmp_agent_session *asp);
243
int netsnmp_check_queued_chain_for(netsnmp_agent_session *asp);
244
int netsnmp_add_queued(netsnmp_agent_session *asp);
245
int netsnmp_remove_from_delegated(netsnmp_agent_session *asp);
248
static int current_globalid = 0;
250
int netsnmp_running = 1;
252
#ifndef NETSNMP_FEATURE_REMOVE_ALLOCATE_GLOBALCACHEID
254
netsnmp_allocate_globalcacheid(void)
256
return ++current_globalid;
258
#endif /* NETSNMP_FEATURE_REMOVE_ALLOCATE_GLOBALCACHEID */
261
netsnmp_get_local_cachid(netsnmp_cachemap *cache_store, int globalid)
263
while (cache_store != NULL) {
264
if (cache_store->globalid == globalid)
265
return cache_store->cacheid;
266
cache_store = cache_store->next;
272
netsnmp_get_or_add_local_cachid(netsnmp_cachemap **cache_store,
273
int globalid, int localid)
275
netsnmp_cachemap *tmpp;
277
tmpp = SNMP_MALLOC_TYPEDEF(netsnmp_cachemap);
280
tmpp->next = *cache_store;
286
tmpp->globalid = globalid;
287
tmpp->cacheid = localid;
293
netsnmp_free_cachemap(netsnmp_cachemap *cache_store)
295
netsnmp_cachemap *tmpp;
296
while (cache_store) {
298
cache_store = cache_store->next;
304
typedef struct agent_set_cache_s {
309
netsnmp_session *sess;
314
netsnmp_tree_cache *treecache;
319
netsnmp_request_info *requests;
320
netsnmp_variable_list *saved_vars;
321
netsnmp_data_list *agent_data;
326
struct agent_set_cache_s *next;
329
static agent_set_cache *Sets = NULL;
332
save_set_cache(netsnmp_agent_session *asp)
334
agent_set_cache *ptr;
336
if (!asp || !asp->reqinfo || !asp->pdu)
339
ptr = SNMP_MALLOC_TYPEDEF(agent_set_cache);
344
* Save the important information
346
DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p saved in cache (mode %d)\n",
347
asp, asp->reqinfo, asp->pdu->command));
348
ptr->transID = asp->pdu->transid;
349
ptr->sess = asp->session;
350
ptr->treecache = asp->treecache;
351
ptr->treecache_len = asp->treecache_len;
352
ptr->treecache_num = asp->treecache_num;
353
ptr->agent_data = asp->reqinfo->agent_data;
354
ptr->requests = asp->requests;
355
ptr->saved_vars = asp->pdu->variables; /* requests contains pointers to variables */
356
ptr->vbcount = asp->vbcount;
359
* make the agent forget about what we've saved
361
asp->treecache = NULL;
362
asp->reqinfo->agent_data = NULL;
363
asp->pdu->variables = NULL;
364
asp->requests = NULL;
373
get_set_cache(netsnmp_agent_session *asp)
375
agent_set_cache *ptr, *prev = NULL;
377
for (ptr = Sets; ptr != NULL; ptr = ptr->next) {
378
if (ptr->sess == asp->session && ptr->transID == asp->pdu->transid) {
380
* remove this item from list
383
prev->next = ptr->next;
388
* found it. Get the needed data
390
asp->treecache = ptr->treecache;
391
asp->treecache_len = ptr->treecache_len;
392
asp->treecache_num = ptr->treecache_num;
395
* Free previously allocated requests before overwriting by
396
* cached ones, otherwise memory leaks!
400
* I don't think this case should ever happen. Please email
401
* the net-snmp-coders@lists.sourceforge.net if you have
402
* a test case that hits this condition. -- rstory
405
netsnmp_assert(NULL == asp->requests); /* see note above */
406
for (i = 0; i < asp->vbcount; i++) {
407
netsnmp_free_request_data_sets(&asp->requests[i]);
412
* If we replace asp->requests with the info from the set cache,
413
* we should replace asp->pdu->variables also with the cached
414
* info, as asp->requests contains pointers to them. And we
415
* should also free the current asp->pdu->variables list...
417
if (ptr->saved_vars) {
418
if (asp->pdu->variables)
419
snmp_free_varbind(asp->pdu->variables);
420
asp->pdu->variables = ptr->saved_vars;
421
asp->vbcount = ptr->vbcount;
424
* when would we not have saved variables? someone
425
* let me know if they hit this condition. -- rstory
427
netsnmp_assert(NULL != ptr->saved_vars);
429
asp->requests = ptr->requests;
431
netsnmp_assert(NULL != asp->reqinfo);
432
asp->reqinfo->asp = asp;
433
asp->reqinfo->agent_data = ptr->agent_data;
436
* update request reqinfo, if it's out of date.
437
* yyy-rks: investigate when/why sometimes they match,
438
* sometimes they don't.
440
if(asp->requests->agent_req_info != asp->reqinfo) {
442
* - one don't match case: agentx subagents. prev asp & reqinfo
443
* freed, request reqinfo ptrs not cleared.
445
netsnmp_request_info *tmp = asp->requests;
446
DEBUGMSGTL(("verbose:asp",
447
" reqinfo %p doesn't match cached reqinfo %p\n",
448
asp->reqinfo, asp->requests->agent_req_info));
449
for(; tmp; tmp = tmp->next)
450
tmp->agent_req_info = asp->reqinfo;
455
DEBUGMSGTL(("verbose:asp",
456
" reqinfo %p matches cached reqinfo %p\n",
457
asp->reqinfo, asp->requests->agent_req_info));
461
return SNMP_ERR_NOERROR;
465
return SNMP_ERR_GENERR;
468
/* Bulkcache holds the values for the *repeating* varbinds (only),
469
* but ordered "by column" - i.e. the repetitions for each
470
* repeating varbind follow on immediately from one another,
471
* rather than being interleaved, as required by the protocol.
473
* So we need to rearrange the varbind list so it's ordered "by row".
475
* In the following code chunk:
476
* n = # non-repeating varbinds
477
* r = # repeating varbinds
478
* asp->vbcount = # varbinds in the incoming PDU
479
* (So asp->vbcount = n+r)
481
* repeats = Desired # of repetitions (of 'r' varbinds)
483
NETSNMP_STATIC_INLINE void
484
_reorder_getbulk(netsnmp_agent_session *asp)
487
int repeats = asp->pdu->errindex;
490
netsnmp_variable_list *prev = NULL, *curr;
492
if (asp->vbcount == 0) /* Nothing to do! */
495
if (asp->pdu->errstat < asp->vbcount) {
496
n = asp->pdu->errstat;
500
if ((r = asp->vbcount - n) < 0) {
504
/* we do nothing if there is nothing repeated */
508
/* Fix endOfMibView entries. */
509
for (i = 0; i < r; i++) {
511
for (j = 0; j < repeats; j++) {
512
curr = asp->bulkcache[i * repeats + j];
514
* If we don't have a valid name for a given repetition
515
* (and probably for all the ones that follow as well),
516
* extend the previous result to indicate 'endOfMibView'.
517
* Or if the repetition already has type endOfMibView make
518
* sure it has the correct objid (i.e. that of the previous
519
* entry or that of the original request).
521
if (curr->name_length == 0 || curr->type == SNMP_ENDOFMIBVIEW) {
523
/* Use objid from original pdu. */
524
prev = asp->orig_pdu->variables;
525
for (k = i; prev && k > 0; k--)
526
prev = prev->next_variable;
529
snmp_set_var_objid(curr, prev->name, prev->name_length);
530
snmp_set_var_typed_value(curr, SNMP_ENDOFMIBVIEW, NULL, 0);
538
* For each of the original repeating varbinds (except the last),
539
* go through the block of results for that varbind,
540
* and link each instance to the corresponding instance
543
for (i = 0; i < r - 1; i++) {
544
for (j = 0; j < repeats; j++) {
545
asp->bulkcache[i * repeats + j]->next_variable =
546
asp->bulkcache[(i + 1) * repeats + j];
551
* For the last of the original repeating varbinds,
552
* go through that block of results, and link each
553
* instance to the *next* instance in the *first* block.
555
* The very last instance of this block is left untouched
556
* since it (correctly) points to the end of the list.
558
for (j = 0; j < repeats - 1; j++) {
559
asp->bulkcache[(r - 1) * repeats + j]->next_variable =
560
asp->bulkcache[j + 1];
564
* If we've got a full row of endOfMibViews, then we
565
* can truncate the result varbind list after that.
567
* Look for endOfMibView exception values in the list of
568
* repetitions for the first varbind, and check the
569
* corresponding instances for the other varbinds
570
* (following the next_variable links).
572
* If they're all endOfMibView too, then we can terminate
573
* the linked list there, and free any redundant varbinds.
576
for (i = 0; i < repeats; i++) {
577
if (asp->bulkcache[i]->type == SNMP_ENDOFMIBVIEW) {
579
for (j = 1, prev=asp->bulkcache[i];
581
j++, prev=prev->next_variable) {
582
if (prev->type != SNMP_ENDOFMIBVIEW) {
584
break; /* Found a real value */
589
* This is indeed a full endOfMibView row.
590
* Terminate the list here & free the rest.
592
snmp_free_varbind( prev->next_variable );
593
prev->next_variable = NULL;
601
/* EndOfMibView replies to a GETNEXT request should according to RFC3416
602
* have the object ID set to that of the request. Our tree search
603
* algorithm will sometimes break that requirement. This function will
606
NETSNMP_STATIC_INLINE void
607
_fix_endofmibview(netsnmp_agent_session *asp)
609
netsnmp_variable_list *vb, *ovb;
611
if (asp->vbcount == 0) /* Nothing to do! */
614
for (vb = asp->pdu->variables, ovb = asp->orig_pdu->variables;
615
vb && ovb; vb = vb->next_variable, ovb = ovb->next_variable) {
616
if (vb->type == SNMP_ENDOFMIBVIEW)
617
snmp_set_var_objid(vb, ovb->name, ovb->name_length);
621
#ifndef NETSNMP_FEATURE_REMOVE_AGENT_CHECK_AND_PROCESS
623
* This function checks for packets arriving on the SNMP port and
624
* processes them(snmp_read) if some are found, using the select(). If block
625
* is non zero, the function call blocks until a packet arrives
627
* @param block used to control blocking in the select() function, 1 = block
628
* forever, and 0 = don't block
630
* @return Returns a positive integer if packets were processed, and -1 if an
635
agent_check_and_process(int block)
639
struct timeval timeout = { LONG_MAX, 0 }, *tvp = &timeout;
645
snmp_select_info(&numfds, &fdset, tvp, &fakeblock);
646
if (block != 0 && fakeblock != 0) {
648
* There are no alarms registered, and the caller asked for blocking, so
649
* let select() block forever.
653
} else if (block != 0 && fakeblock == 0) {
655
* The caller asked for blocking, but there is an alarm due sooner than
656
* LONG_MAX seconds from now, so use the modified timeout returned by
657
* snmp_select_info as the timeout for select().
660
} else if (block == 0) {
662
* The caller does not want us to block at all.
668
count = select(numfds, &fdset, NULL, NULL, tvp);
672
* packets found, process them
681
if (errno != EINTR) {
682
snmp_log_perror("select");
686
snmp_log(LOG_ERR, "select returned %d\n", count);
688
} /* endif -- count>0 */
691
* see if persistent store needs to be saved
693
snmp_store_if_needed();
696
* Run requested alarms.
700
netsnmp_check_outstanding_agent_requests();
704
#endif /* NETSNMP_FEATURE_REMOVE_AGENT_CHECK_AND_PROCESS */
707
* Set up the address cache.
710
netsnmp_addrcache_initialise(void)
714
for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
715
addrCache[i].addr = NULL;
716
addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
720
void netsnmp_addrcache_destroy(void)
724
for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
725
if (addrCache[i].status == SNMP_ADDRCACHE_USED) {
726
free(addrCache[i].addr);
727
addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
733
* Adds a new entry to the cache of addresses that
734
* have recently made connections to the agent.
735
* Returns 0 if the entry already exists (but updates
736
* the entry with a new timestamp) and 1 if the
737
* entry did not previously exist.
739
* Implements a simple LRU cache replacement
740
* policy. Uses a linear search, which should be
741
* okay, as long as SNMP_ADDRCACHE_SIZE remains
744
* @retval 0 : updated existing entry
745
* @retval 1 : added new entry
748
netsnmp_addrcache_add(const char *addr)
750
int oldest = -1; /* Index of the oldest cache entry */
751
int unused = -1; /* Index of the first free cache entry */
752
int i; /* Looping variable */
754
struct timeval now; /* What time is it now? */
755
struct timeval aged; /* Oldest allowable cache entry */
758
* First get the current and oldest allowable timestamps
760
netsnmp_get_monotonic_clock(&now);
761
aged.tv_sec = now.tv_sec - SNMP_ADDRCACHE_MAXAGE;
762
aged.tv_usec = now.tv_usec;
765
* Now look for a place to put this thing
767
for(i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
768
if (addrCache[i].status == SNMP_ADDRCACHE_UNUSED) { /* If unused */
770
* remember this location, in case addr isn't in the cache
776
if ((NULL != addr) && (strcmp(addrCache[i].addr, addr) == 0)) {
780
addrCache[i].lastHitM = now;
781
if (timercmp(&addrCache[i].lastHitM, &aged, <))
782
rc = 1; /* should have expired, so is new */
784
rc = 0; /* not expired, so is existing entry */
789
* Used, but not this address. check if it's stale.
791
if (timercmp(&addrCache[i].lastHitM, &aged, <)) {
795
SNMP_FREE(addrCache[i].addr);
796
addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
798
* remember this location, in case addr isn't in the cache
805
* Still fresh, but a candidate for LRU replacement
809
else if (timercmp(&addrCache[i].lastHitM,
810
&addrCache[oldest].lastHitM, <))
813
} /* used, no match */
817
if ((-1 == rc) && (NULL != addr)) {
819
* We didn't find the entry in the cache
823
* If we have a slot free anyway, use it
825
addrCache[unused].addr = strdup(addr);
826
addrCache[unused].status = SNMP_ADDRCACHE_USED;
827
addrCache[unused].lastHitM = now;
829
else { /* Otherwise, replace oldest entry */
830
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
831
NETSNMP_DS_AGENT_VERBOSE))
832
snmp_log(LOG_INFO, "Purging address from address cache: %s",
833
addrCache[oldest].addr);
835
free(addrCache[oldest].addr);
836
addrCache[oldest].addr = strdup(addr);
837
addrCache[oldest].lastHitM = now;
841
if ((log_addresses && (1 == rc)) ||
842
netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
843
NETSNMP_DS_AGENT_VERBOSE)) {
844
snmp_log(LOG_INFO, "Received SNMP packet(s) from %s\n", addr);
851
* Age the entries in the address cache.
853
* backwards compatability; not used anywhere
855
#ifndef NETSNMP_FEATURE_REMOVE_ADDRCACHE_AGE
857
netsnmp_addrcache_age(void)
859
(void)netsnmp_addrcache_add(NULL);
861
#endif /* NETSNMP_FEATURE_REMOVE_ADDRCACHE_AGE */
863
/*******************************************************************-o-******
864
* netsnmp_agent_check_packet
867
* session, transport, transport_data, transport_data_length
873
* Handler for all incoming messages (a.k.a. packets) for the agent. If using
874
* the libwrap utility, log the connection and deny/allow the access. Print
875
* output when appropriate, and increment the incoming counter.
880
netsnmp_agent_check_packet(netsnmp_session * session,
881
netsnmp_transport *transport,
882
void *transport_data, int transport_data_length)
884
char *addr_string = NULL;
885
#ifdef NETSNMP_USE_LIBWRAP
886
char *tcpudpaddr = NULL, *name;
887
short not_log_connection;
889
name = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
890
NETSNMP_DS_LIB_APPTYPE);
892
/* not_log_connection will be 1 if we should skip the messages */
893
not_log_connection = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
894
NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS);
897
* handle the error case
898
* default to logging the messages
900
if (not_log_connection == SNMPERR_GENERR) not_log_connection = 0;
904
* Log the message and/or dump the message.
905
* Optionally cache the network address of the sender.
908
if (transport != NULL && transport->f_fmtaddr != NULL) {
910
* Okay I do know how to format this address for logging.
912
addr_string = transport->f_fmtaddr(transport, transport_data,
913
transport_data_length);
915
* Don't forget to free() it.
918
#ifdef NETSNMP_USE_LIBWRAP
919
/* Catch udp,udp6,tcp,tcp6 transports using "[" */
921
tcpudpaddr = strstr(addr_string, "[");
922
if ( tcpudpaddr != 0 ) {
926
strlcpy(sbuf, tcpudpaddr + 1, sizeof(sbuf));
927
xp = strstr(sbuf, "]");
931
if (hosts_ctl(name, STRING_UNKNOWN, sbuf, STRING_UNKNOWN)) {
932
if (!not_log_connection) {
933
snmp_log(allow_severity, "Connection from %s\n", addr_string);
936
snmp_log(deny_severity, "Connection from %s REFUSED\n",
938
SNMP_FREE(addr_string);
943
* don't log callback connections.
944
* What about 'Local IPC', 'IPX' and 'AAL5 PVC'?
946
if (0 == strncmp(addr_string, "callback", 8))
948
else if (hosts_ctl(name, STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN)){
949
if (!not_log_connection) {
950
snmp_log(allow_severity, "Connection from <UNKNOWN> (%s)\n", addr_string);
952
SNMP_FREE(addr_string);
953
addr_string = strdup("<UNKNOWN>");
955
snmp_log(deny_severity, "Connection from <UNKNOWN> (%s) REFUSED\n", addr_string);
956
SNMP_FREE(addr_string);
960
#endif /*NETSNMP_USE_LIBWRAP */
962
snmp_increment_statistic(STAT_SNMPINPKTS);
964
if (addr_string != NULL) {
965
netsnmp_addrcache_add(addr_string);
966
SNMP_FREE(addr_string);
973
netsnmp_agent_check_parse(netsnmp_session * session, netsnmp_pdu *pdu,
977
if (snmp_get_do_logging() &&
978
netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
979
NETSNMP_DS_AGENT_VERBOSE)) {
980
netsnmp_variable_list *var_ptr;
982
switch (pdu->command) {
984
snmp_log(LOG_DEBUG, " GET message\n");
986
case SNMP_MSG_GETNEXT:
987
snmp_log(LOG_DEBUG, " GETNEXT message\n");
989
case SNMP_MSG_RESPONSE:
990
snmp_log(LOG_DEBUG, " RESPONSE message\n");
992
#ifndef NETSNMP_NO_WRITE_SUPPORT
994
snmp_log(LOG_DEBUG, " SET message\n");
996
#endif /* NETSNMP_NO_WRITE_SUPPORT */
998
snmp_log(LOG_DEBUG, " TRAP message\n");
1000
case SNMP_MSG_GETBULK:
1001
snmp_log(LOG_DEBUG, " GETBULK message, non-rep=%ld, max_rep=%ld\n",
1002
pdu->errstat, pdu->errindex);
1004
case SNMP_MSG_INFORM:
1005
snmp_log(LOG_DEBUG, " INFORM message\n");
1007
case SNMP_MSG_TRAP2:
1008
snmp_log(LOG_DEBUG, " TRAP2 message\n");
1010
case SNMP_MSG_REPORT:
1011
snmp_log(LOG_DEBUG, " REPORT message\n");
1014
#ifndef NETSNMP_NO_WRITE_SUPPORT
1015
case SNMP_MSG_INTERNAL_SET_RESERVE1:
1016
snmp_log(LOG_DEBUG, " INTERNAL RESERVE1 message\n");
1019
case SNMP_MSG_INTERNAL_SET_RESERVE2:
1020
snmp_log(LOG_DEBUG, " INTERNAL RESERVE2 message\n");
1023
case SNMP_MSG_INTERNAL_SET_ACTION:
1024
snmp_log(LOG_DEBUG, " INTERNAL ACTION message\n");
1027
case SNMP_MSG_INTERNAL_SET_COMMIT:
1028
snmp_log(LOG_DEBUG, " INTERNAL COMMIT message\n");
1031
case SNMP_MSG_INTERNAL_SET_FREE:
1032
snmp_log(LOG_DEBUG, " INTERNAL FREE message\n");
1035
case SNMP_MSG_INTERNAL_SET_UNDO:
1036
snmp_log(LOG_DEBUG, " INTERNAL UNDO message\n");
1038
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1041
snmp_log(LOG_DEBUG, " UNKNOWN message, type=%02X\n",
1043
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
1047
for (var_ptr = pdu->variables; var_ptr != NULL;
1048
var_ptr = var_ptr->next_variable) {
1049
size_t c_oidlen = 256, c_outlen = 0;
1050
u_char *c_oid = (u_char *) malloc(c_oidlen);
1053
if (!sprint_realloc_objid
1054
(&c_oid, &c_oidlen, &c_outlen, 1, var_ptr->name,
1055
var_ptr->name_length)) {
1056
snmp_log(LOG_DEBUG, " -- %s [TRUNCATED]\n",
1059
snmp_log(LOG_DEBUG, " -- %s\n", c_oid);
1067
return 0; /* XXX: does it matter what the return value
1068
* is? Yes: if we return 0, then the PDU is
1074
* Global access to the primary session structure for this agent.
1075
* for Index Allocation use initially.
1079
* I don't understand what this is for at the moment. AFAICS as long as it
1080
* gets set and points at a session, that's fine. ???
1083
netsnmp_session *main_session = NULL;
1088
* Set up an agent session on the given transport. Return a handle
1089
* which may later be used to de-register this transport. A return
1090
* value of -1 indicates an error.
1094
netsnmp_register_agent_nsap(netsnmp_transport *t)
1096
netsnmp_session *s, *sp = NULL;
1097
agent_nsap *a = NULL, *n = NULL, **prevNext = &agent_nsap_list;
1105
DEBUGMSGTL(("netsnmp_register_agent_nsap", "fd %d\n", t->sock));
1107
n = (agent_nsap *) malloc(sizeof(agent_nsap));
1111
s = (netsnmp_session *) malloc(sizeof(netsnmp_session));
1116
memset(s, 0, sizeof(netsnmp_session));
1120
* Set up the session appropriately for an agent.
1123
s->version = SNMP_DEFAULT_VERSION;
1124
s->callback = handle_snmp_packet;
1125
s->authenticator = NULL;
1126
s->flags = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
1127
NETSNMP_DS_AGENT_FLAGS);
1128
s->isAuthoritative = SNMP_SESS_AUTHORITATIVE;
1130
/* Optional supplimental transport configuration information and
1131
final call to actually open the transport */
1132
if (netsnmp_sess_config_transport(s->transport_configuration, t)
1133
!= SNMPERR_SUCCESS) {
1149
t->flags |= NETSNMP_TRANSPORT_FLAG_OPENED;
1151
sp = snmp_add(s, t, netsnmp_agent_check_packet,
1152
netsnmp_agent_check_parse);
1159
isp = snmp_sess_pointer(sp);
1160
if (isp == NULL) { /* over-cautious */
1169
if (main_session == NULL) {
1170
main_session = snmp_sess_session(isp);
1173
for (a = agent_nsap_list; a != NULL && handle + 1 >= a->handle;
1176
prevNext = &(a->next);
1179
if (handle < INT_MAX) {
1180
n->handle = handle + 1;
1193
netsnmp_deregister_agent_nsap(int handle)
1195
agent_nsap *a = NULL, **prevNext = &agent_nsap_list;
1196
int main_session_deregistered = 0;
1198
DEBUGMSGTL(("netsnmp_deregister_agent_nsap", "handle %d\n", handle));
1200
for (a = agent_nsap_list; a != NULL && a->handle < handle; a = a->next) {
1201
prevNext = &(a->next);
1204
if (a != NULL && a->handle == handle) {
1205
*prevNext = a->next;
1206
if (snmp_sess_session_lookup(a->s)) {
1207
if (main_session == snmp_sess_session(a->s)) {
1208
main_session_deregistered = 1;
1210
snmp_close(snmp_sess_session(a->s));
1212
* The above free()s the transport and session pointers.
1219
* If we've deregistered the session that main_session used to point to,
1220
* then make it point to another one, or in the last resort, make it equal
1221
* to NULL. Basically this shouldn't ever happen in normal operation
1222
* because main_session starts off pointing at the first session added by
1223
* init_master_agent(), which then discards the handle.
1226
if (main_session_deregistered) {
1227
if (agent_nsap_list != NULL) {
1228
DEBUGMSGTL(("snmp_agent",
1229
"WARNING: main_session ptr changed from %p to %p\n",
1230
main_session, snmp_sess_session(agent_nsap_list->s)));
1231
main_session = snmp_sess_session(agent_nsap_list->s);
1233
DEBUGMSGTL(("snmp_agent",
1234
"WARNING: main_session ptr changed from %p to NULL\n",
1236
main_session = NULL;
1245
* This function has been modified to use the experimental
1246
* netsnmp_register_agent_nsap interface. The major responsibility of this
1247
* function now is to interpret a string specified to the agent (via -p on the
1248
* command line, or from a configuration file) as a list of agent NSAPs on
1249
* which to listen for SNMP packets. Typically, when you add a new transport
1250
* domain "foo", you add code here such that if the "foo" code is compiled
1251
* into the agent (SNMP_TRANSPORT_FOO_DOMAIN is defined), then a token of the
1252
* form "foo:bletch-3a0054ef%wob&wob" gets turned into the appropriate
1253
* transport descriptor. netsnmp_register_agent_nsap is then called with that
1254
* transport descriptor and sets up a listening agent session on it.
1256
* Everything then works much as normal: the agent runs in an infinite loop
1257
* (in the snmpd.c/receive()routine), which calls snmp_read() when a request
1258
* is readable on any of the given transports. This routine then traverses
1259
* the library 'Sessions' list to identify the relevant session and eventually
1260
* invokes '_sess_read'. This then processes the incoming packet, calling the
1261
* pre_parse, parse, post_parse and callback routines in turn.
1267
init_master_agent(void)
1269
netsnmp_transport *transport;
1274
/* default to a default cache size */
1275
netsnmp_set_lookup_cache_size(-1);
1277
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1278
NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
1279
DEBUGMSGTL(("snmp_agent",
1280
"init_master_agent; not master agent\n"));
1282
netsnmp_assert("agent role !master && !sub_agent");
1284
return 0; /* No error if ! MASTER_AGENT */
1287
#ifndef NETSNMP_NO_LISTEN_SUPPORT
1289
* Have specific agent ports been specified?
1291
cptr = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
1292
NETSNMP_DS_AGENT_PORTS);
1298
"Error processing transport \"%s\"\n", cptr);
1303
* No, so just specify the default port.
1308
DEBUGMSGTL(("snmp_agent", "final port spec: \"%s\"\n", buf));
1312
* Specification format:
1314
* NONE: (a pseudo-transport)
1315
* UDP:[address:]port (also default if no transport is specified)
1316
* TCP:[address:]port (if supported)
1317
* Unix:pathname (if supported)
1318
* AAL5PVC:itf.vpi.vci (if supported)
1319
* IPX:[network]:node[/port] (if supported)
1324
st = strchr(st, ',');
1328
DEBUGMSGTL(("snmp_agent", "installing master agent on port %s\n",
1331
if (strncasecmp(cptr, "none", 4) == 0) {
1332
DEBUGMSGTL(("snmp_agent",
1333
"init_master_agent; pseudo-transport \"none\" "
1337
transport = netsnmp_transport_open_server("snmp", cptr);
1339
if (transport == NULL) {
1340
snmp_log(LOG_ERR, "Error opening specified endpoint \"%s\"\n",
1345
if (netsnmp_register_agent_nsap(transport) == 0) {
1347
"Error registering specified transport \"%s\" as an "
1348
"agent NSAP\n", cptr);
1351
DEBUGMSGTL(("snmp_agent",
1352
"init_master_agent; \"%s\" registered as an agent "
1355
} while(st && *st != '\0');
1357
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
1359
#ifdef USING_AGENTX_MASTER_MODULE
1360
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1361
NETSNMP_DS_AGENT_AGENTX_MASTER) == 1)
1364
#ifdef USING_SMUX_MODULE
1365
if(should_init("smux"))
1373
clear_nsap_list(void)
1375
DEBUGMSGTL(("clear_nsap_list", "clear the nsap list\n"));
1377
while (agent_nsap_list != NULL)
1378
netsnmp_deregister_agent_nsap(agent_nsap_list->handle);
1382
shutdown_master_agent(void)
1388
netsnmp_agent_session *
1389
init_agent_snmp_session(netsnmp_session * session, netsnmp_pdu *pdu)
1391
netsnmp_agent_session *asp = (netsnmp_agent_session *)
1392
calloc(1, sizeof(netsnmp_agent_session));
1398
DEBUGMSGTL(("snmp_agent","agent_sesion %8p created\n", asp));
1399
asp->session = session;
1400
asp->pdu = snmp_clone_pdu(pdu);
1401
asp->orig_pdu = snmp_clone_pdu(pdu);
1405
asp->mode = RESERVE1;
1406
asp->status = SNMP_ERR_NOERROR;
1409
asp->treecache_num = -1;
1410
asp->treecache_len = 0;
1411
asp->reqinfo = SNMP_MALLOC_TYPEDEF(netsnmp_agent_request_info);
1412
DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p created\n",
1413
asp, asp->reqinfo));
1419
free_agent_snmp_session(netsnmp_agent_session *asp)
1424
DEBUGMSGTL(("snmp_agent","agent_session %8p released\n", asp));
1426
netsnmp_remove_from_delegated(asp);
1428
DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p freed\n",
1429
asp, asp->reqinfo));
1431
snmp_free_pdu(asp->orig_pdu);
1433
snmp_free_pdu(asp->pdu);
1435
netsnmp_free_agent_request_info(asp->reqinfo);
1436
SNMP_FREE(asp->treecache);
1437
SNMP_FREE(asp->bulkcache);
1438
if (asp->requests) {
1440
for (i = 0; i < asp->vbcount; i++) {
1441
netsnmp_free_request_data_sets(&asp->requests[i]);
1443
SNMP_FREE(asp->requests);
1445
if (asp->cache_store) {
1446
netsnmp_free_cachemap(asp->cache_store);
1447
asp->cache_store = NULL;
1453
netsnmp_check_for_delegated(netsnmp_agent_session *asp)
1456
netsnmp_request_info *request;
1458
if (NULL == asp->treecache)
1461
for (i = 0; i <= asp->treecache_num; i++) {
1462
for (request = asp->treecache[i].requests_begin; request;
1463
request = request->next) {
1464
if (request->delegated)
1472
netsnmp_check_delegated_chain_for(netsnmp_agent_session *asp)
1474
netsnmp_agent_session *asptmp;
1475
for (asptmp = agent_delegated_list; asptmp; asptmp = asptmp->next) {
1483
netsnmp_check_for_delegated_and_add(netsnmp_agent_session *asp)
1485
if (netsnmp_check_for_delegated(asp)) {
1486
if (!netsnmp_check_delegated_chain_for(asp)) {
1488
* add to delegated request chain
1490
asp->next = agent_delegated_list;
1491
agent_delegated_list = asp;
1492
DEBUGMSGTL(("snmp_agent", "delegate session == %8p\n", asp));
1500
netsnmp_remove_from_delegated(netsnmp_agent_session *asp)
1502
netsnmp_agent_session *curr, *prev = NULL;
1504
for (curr = agent_delegated_list; curr; prev = curr, curr = curr->next) {
1515
prev->next = asp->next;
1517
agent_delegated_list = asp->next;
1519
DEBUGMSGTL(("snmp_agent", "remove delegated session == %8p\n", asp));
1528
* netsnmp_remove_delegated_requests_for_session
1530
* called when a session is being closed. Check all delegated requests to
1531
* see if the are waiting on this session, and if set, set the status for
1532
* that request to GENERR.
1535
netsnmp_remove_delegated_requests_for_session(netsnmp_session *sess)
1537
netsnmp_agent_session *asp;
1540
for (asp = agent_delegated_list; asp; asp = asp->next) {
1542
* check each request
1544
netsnmp_request_info *request;
1545
for(request = asp->requests; request; request = request->next) {
1549
netsnmp_assert(NULL!=request->subtree);
1550
if(request->subtree->session != sess)
1554
* matched! mark request as done
1556
netsnmp_request_set_error(request, SNMP_ERR_GENERR);
1562
* if we found any, that request may be finished now
1565
DEBUGMSGTL(("snmp_agent", "removed %d delegated request(s) for session "
1566
"%8p\n", count, sess));
1567
netsnmp_check_outstanding_agent_requests();
1574
netsnmp_check_queued_chain_for(netsnmp_agent_session *asp)
1576
netsnmp_agent_session *asptmp;
1577
for (asptmp = netsnmp_agent_queued_list; asptmp; asptmp = asptmp->next) {
1585
netsnmp_add_queued(netsnmp_agent_session *asp)
1587
netsnmp_agent_session *asp_tmp;
1592
if (NULL == netsnmp_agent_queued_list) {
1593
netsnmp_agent_queued_list = asp;
1599
* add to end of queued request chain
1601
asp_tmp = netsnmp_agent_queued_list;
1602
for (; asp_tmp; asp_tmp = asp_tmp->next) {
1612
if (NULL == asp_tmp->next)
1613
asp_tmp->next = asp;
1620
netsnmp_wrap_up_request(netsnmp_agent_session *asp, int status)
1623
* if this request was a set, clear the global now that we are
1626
if (asp == netsnmp_processing_set) {
1627
DEBUGMSGTL(("snmp_agent", "SET request complete, asp = %8p\n",
1629
netsnmp_processing_set = NULL;
1634
* If we've got an error status, then this needs to be
1635
* passed back up to the higher levels....
1637
if ( status != 0 && asp->status == 0 )
1638
asp->status = status;
1640
switch (asp->pdu->command) {
1641
#ifndef NETSNMP_NO_WRITE_SUPPORT
1642
case SNMP_MSG_INTERNAL_SET_BEGIN:
1643
case SNMP_MSG_INTERNAL_SET_RESERVE1:
1644
case SNMP_MSG_INTERNAL_SET_RESERVE2:
1645
case SNMP_MSG_INTERNAL_SET_ACTION:
1647
* some stuff needs to be saved in special subagent cases
1649
save_set_cache(asp);
1651
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1653
case SNMP_MSG_GETNEXT:
1654
_fix_endofmibview(asp);
1657
case SNMP_MSG_GETBULK:
1659
* for a GETBULK response we need to rearrange the varbinds
1661
_reorder_getbulk(asp);
1666
* May need to "dumb down" a SET error status for a
1667
* v1 query. See RFC2576 - section 4.3
1669
#ifndef NETSNMP_DISABLE_SNMPV1
1670
#ifndef NETSNMP_NO_WRITE_SUPPORT
1671
if ((asp->pdu->command == SNMP_MSG_SET) &&
1672
(asp->pdu->version == SNMP_VERSION_1)) {
1673
switch (asp->status) {
1674
case SNMP_ERR_WRONGVALUE:
1675
case SNMP_ERR_WRONGENCODING:
1676
case SNMP_ERR_WRONGTYPE:
1677
case SNMP_ERR_WRONGLENGTH:
1678
case SNMP_ERR_INCONSISTENTVALUE:
1679
status = SNMP_ERR_BADVALUE;
1680
asp->status = SNMP_ERR_BADVALUE;
1682
case SNMP_ERR_NOACCESS:
1683
case SNMP_ERR_NOTWRITABLE:
1684
case SNMP_ERR_NOCREATION:
1685
case SNMP_ERR_INCONSISTENTNAME:
1686
case SNMP_ERR_AUTHORIZATIONERROR:
1687
status = SNMP_ERR_NOSUCHNAME;
1688
asp->status = SNMP_ERR_NOSUCHNAME;
1690
case SNMP_ERR_RESOURCEUNAVAILABLE:
1691
case SNMP_ERR_COMMITFAILED:
1692
case SNMP_ERR_UNDOFAILED:
1693
status = SNMP_ERR_GENERR;
1694
asp->status = SNMP_ERR_GENERR;
1699
* Similarly we may need to "dumb down" v2 exception
1700
* types to throw an error for a v1 query.
1701
* See RFC2576 - section 4.1.2.3
1703
if ((asp->pdu->command != SNMP_MSG_SET) &&
1704
(asp->pdu->version == SNMP_VERSION_1)) {
1705
netsnmp_variable_list *var_ptr = asp->pdu->variables;
1708
while (var_ptr != NULL) {
1709
switch (var_ptr->type) {
1710
case SNMP_NOSUCHOBJECT:
1711
case SNMP_NOSUCHINSTANCE:
1712
case SNMP_ENDOFMIBVIEW:
1714
status = SNMP_ERR_NOSUCHNAME;
1715
asp->status = SNMP_ERR_NOSUCHNAME;
1719
var_ptr = var_ptr->next_variable;
1723
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1724
#endif /* snmpv1 support */
1725
} /** if asp->pdu */
1728
* Update the snmp error-count statistics
1729
* XXX - should we include the V2 errors in this or not?
1731
#define INCLUDE_V2ERRORS_IN_V1STATS
1734
#ifdef INCLUDE_V2ERRORS_IN_V1STATS
1735
case SNMP_ERR_WRONGVALUE:
1736
case SNMP_ERR_WRONGENCODING:
1737
case SNMP_ERR_WRONGTYPE:
1738
case SNMP_ERR_WRONGLENGTH:
1739
case SNMP_ERR_INCONSISTENTVALUE:
1741
case SNMP_ERR_BADVALUE:
1742
snmp_increment_statistic(STAT_SNMPOUTBADVALUES);
1744
#ifdef INCLUDE_V2ERRORS_IN_V1STATS
1745
case SNMP_ERR_NOACCESS:
1746
case SNMP_ERR_NOTWRITABLE:
1747
case SNMP_ERR_NOCREATION:
1748
case SNMP_ERR_INCONSISTENTNAME:
1749
case SNMP_ERR_AUTHORIZATIONERROR:
1751
case SNMP_ERR_NOSUCHNAME:
1752
snmp_increment_statistic(STAT_SNMPOUTNOSUCHNAMES);
1754
#ifdef INCLUDE_V2ERRORS_IN_V1STATS
1755
case SNMP_ERR_RESOURCEUNAVAILABLE:
1756
case SNMP_ERR_COMMITFAILED:
1757
case SNMP_ERR_UNDOFAILED:
1759
case SNMP_ERR_GENERR:
1760
snmp_increment_statistic(STAT_SNMPOUTGENERRS);
1763
case SNMP_ERR_TOOBIG:
1764
snmp_increment_statistic(STAT_SNMPOUTTOOBIGS);
1768
if ((status == SNMP_ERR_NOERROR) && (asp->pdu)) {
1769
#ifndef NETSNMP_NO_WRITE_SUPPORT
1770
snmp_increment_statistic_by((asp->pdu->command == SNMP_MSG_SET ?
1771
STAT_SNMPINTOTALSETVARS :
1772
STAT_SNMPINTOTALREQVARS),
1773
count_varbinds(asp->pdu->variables));
1774
#else /* NETSNMP_NO_WRITE_SUPPORT */
1775
snmp_increment_statistic_by(STAT_SNMPINTOTALREQVARS,
1776
count_varbinds(asp->pdu->variables));
1777
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1781
* Use a copy of the original request
1782
* to report failures.
1784
snmp_free_pdu(asp->pdu);
1785
asp->pdu = asp->orig_pdu;
1786
asp->orig_pdu = NULL;
1789
asp->pdu->command = SNMP_MSG_RESPONSE;
1790
asp->pdu->errstat = asp->status;
1791
asp->pdu->errindex = asp->index;
1792
if (!snmp_send(asp->session, asp->pdu) &&
1793
asp->session->s_snmp_errno != SNMPERR_SUCCESS) {
1794
netsnmp_variable_list *var_ptr;
1795
snmp_perror("send response");
1796
for (var_ptr = asp->pdu->variables; var_ptr != NULL;
1797
var_ptr = var_ptr->next_variable) {
1798
size_t c_oidlen = 256, c_outlen = 0;
1799
u_char *c_oid = (u_char *) malloc(c_oidlen);
1802
if (!sprint_realloc_objid (&c_oid, &c_oidlen, &c_outlen, 1,
1804
var_ptr->name_length)) {
1805
snmp_log(LOG_ERR, " -- %s [TRUNCATED]\n", c_oid);
1807
snmp_log(LOG_ERR, " -- %s\n", c_oid);
1812
snmp_free_pdu(asp->pdu);
1815
snmp_increment_statistic(STAT_SNMPOUTPKTS);
1816
snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES);
1817
asp->pdu = NULL; /* yyy-rks: redundant, no? */
1818
netsnmp_remove_and_free_agent_snmp_session(asp);
1823
#ifndef NETSNMP_FEATURE_REMOVE_DUMP_SESS_LIST
1825
dump_sess_list(void)
1827
netsnmp_agent_session *a;
1829
DEBUGMSGTL(("snmp_agent", "DUMP agent_sess_list -> "));
1830
for (a = agent_session_list; a != NULL; a = a->next) {
1831
DEBUGMSG(("snmp_agent", "%8p[session %8p] -> ", a, a->session));
1833
DEBUGMSG(("snmp_agent", "[NIL]\n"));
1835
#endif /* NETSNMP_FEATURE_REMOVE_DUMP_SESS_LIST */
1838
netsnmp_remove_and_free_agent_snmp_session(netsnmp_agent_session *asp)
1840
netsnmp_agent_session *a, **prevNext = &agent_session_list;
1842
DEBUGMSGTL(("snmp_agent", "REMOVE session == %8p\n", asp));
1844
for (a = agent_session_list; a != NULL; a = *prevNext) {
1846
*prevNext = a->next;
1848
free_agent_snmp_session(a);
1852
prevNext = &(a->next);
1856
if (a == NULL && asp != NULL) {
1858
* We coulnd't find it on the list, so free it anyway.
1860
free_agent_snmp_session(asp);
1864
#ifndef NETSNMP_FEATURE_REMOVE_FREE_AGENT_SNMP_SESSION_BY_SESSION
1866
netsnmp_free_agent_snmp_session_by_session(netsnmp_session * sess,
1867
void (*free_request)
1868
(netsnmp_request_list *))
1870
netsnmp_agent_session *a, *next, **prevNext = &agent_session_list;
1872
DEBUGMSGTL(("snmp_agent", "REMOVE session == %8p\n", sess));
1874
for (a = agent_session_list; a != NULL; a = next) {
1875
if (a->session == sess) {
1876
*prevNext = a->next;
1878
free_agent_snmp_session(a);
1880
prevNext = &(a->next);
1885
#endif /* NETSNMP_FEATURE_REMOVE_FREE_AGENT_SNMP_SESSION_BY_SESSION */
1887
/** handles an incoming SNMP packet into the agent */
1889
handle_snmp_packet(int op, netsnmp_session * session, int reqid,
1890
netsnmp_pdu *pdu, void *magic)
1892
netsnmp_agent_session *asp;
1893
int status, access_ret, rc;
1896
* We only support receiving here.
1898
if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
1903
* RESPONSE messages won't get this far, but TRAP-like messages
1906
if (pdu->command == SNMP_MSG_TRAP || pdu->command == SNMP_MSG_INFORM ||
1907
pdu->command == SNMP_MSG_TRAP2) {
1908
DEBUGMSGTL(("snmp_agent", "received trap-like PDU (%02x)\n",
1910
pdu->command = SNMP_MSG_TRAP2;
1911
snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS);
1916
* send snmpv3 authfail trap.
1918
if (pdu->version == SNMP_VERSION_3 &&
1919
session->s_snmp_errno == SNMPERR_USM_AUTHENTICATIONFAILURE) {
1920
send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
1924
if (magic == NULL) {
1925
asp = init_agent_snmp_session(session, pdu);
1926
status = SNMP_ERR_NOERROR;
1928
asp = (netsnmp_agent_session *) magic;
1929
status = asp->status;
1932
if ((access_ret = check_access(asp->pdu)) != 0) {
1933
if (access_ret == VACM_NOSUCHCONTEXT) {
1935
* rfc3413 section 3.2, step 5 says that we increment the
1936
* counter but don't return a response of any kind
1940
* we currently don't support unavailable contexts, as
1941
* there is no reason to that I currently know of
1943
snmp_increment_statistic(STAT_SNMPUNKNOWNCONTEXTS);
1948
netsnmp_remove_and_free_agent_snmp_session(asp);
1952
* access control setup is incorrect
1954
send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
1955
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1956
#if defined(NETSNMP_DISABLE_SNMPV1)
1957
if (asp->pdu->version != SNMP_VERSION_2c) {
1959
#if defined(NETSNMP_DISABLE_SNMPV2C)
1960
if (asp->pdu->version != SNMP_VERSION_1) {
1962
if (asp->pdu->version != SNMP_VERSION_1
1963
&& asp->pdu->version != SNMP_VERSION_2c) {
1966
asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR;
1967
asp->pdu->command = SNMP_MSG_RESPONSE;
1968
snmp_increment_statistic(STAT_SNMPOUTPKTS);
1969
if (!snmp_send(asp->session, asp->pdu))
1970
snmp_free_pdu(asp->pdu);
1972
netsnmp_remove_and_free_agent_snmp_session(asp);
1975
#endif /* support for community based SNMP */
1979
netsnmp_remove_and_free_agent_snmp_session(asp);
1981
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1983
#endif /* support for community based SNMP */
1987
rc = netsnmp_handle_request(asp, status);
1992
DEBUGMSGTL(("snmp_agent", "end of handle_snmp_packet, asp = %8p\n",
1997
netsnmp_request_info *
1998
netsnmp_add_varbind_to_cache(netsnmp_agent_session *asp, int vbcount,
1999
netsnmp_variable_list * varbind_ptr,
2000
netsnmp_subtree *tp)
2002
netsnmp_request_info *request = NULL;
2004
DEBUGMSGTL(("snmp_agent", "add_vb_to_cache(%8p, %d, ", asp, vbcount));
2005
DEBUGMSGOID(("snmp_agent", varbind_ptr->name,
2006
varbind_ptr->name_length));
2007
DEBUGMSG(("snmp_agent", ", %8p)\n", tp));
2010
(asp->pdu->command == SNMP_MSG_GETNEXT ||
2011
asp->pdu->command == SNMP_MSG_GETBULK)) {
2015
prefix_len = netsnmp_oid_find_prefix(tp->start_a,
2017
tp->end_a, tp->end_len);
2018
if (prefix_len < 1) {
2019
result = VACM_NOTINVIEW; /* ack... bad bad thing happened */
2022
netsnmp_acm_check_subtree(asp->pdu, tp->start_a, prefix_len);
2025
while (result == VACM_NOTINVIEW) {
2026
/* the entire subtree is not in view. Skip it. */
2027
/** @todo make this be more intelligent about ranges.
2028
Right now we merely take the highest level
2029
commonality of a registration range and use that.
2030
At times we might be able to be smarter about
2031
checking the range itself as opposed to the node
2032
above where the range exists, but I doubt this will
2033
come up all that frequently. */
2036
prefix_len = netsnmp_oid_find_prefix(tp->start_a,
2040
if (prefix_len < 1) {
2041
/* ack... bad bad thing happened */
2042
result = VACM_NOTINVIEW;
2045
netsnmp_acm_check_subtree(asp->pdu,
2046
tp->start_a, prefix_len);
2055
* no appropriate registration found
2058
* make up the response ourselves
2060
switch (asp->pdu->command) {
2061
case SNMP_MSG_GETNEXT:
2062
case SNMP_MSG_GETBULK:
2063
varbind_ptr->type = SNMP_ENDOFMIBVIEW;
2066
#ifndef NETSNMP_NO_WRITE_SUPPORT
2068
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2070
varbind_ptr->type = SNMP_NOSUCHOBJECT;
2074
return NULL; /* shouldn't get here */
2079
DEBUGMSGTL(("snmp_agent", "tp->start "));
2080
DEBUGMSGOID(("snmp_agent", tp->start_a, tp->start_len));
2081
DEBUGMSG(("snmp_agent", ", tp->end "));
2082
DEBUGMSGOID(("snmp_agent", tp->end_a, tp->end_len));
2083
DEBUGMSG(("snmp_agent", ", \n"));
2086
* malloc the request structure
2088
request = &(asp->requests[vbcount - 1]);
2089
request->index = vbcount;
2090
request->delegated = 0;
2091
request->processed = 0;
2092
request->status = 0;
2093
request->subtree = tp;
2094
request->agent_req_info = asp->reqinfo;
2095
if (request->parent_data) {
2096
netsnmp_free_request_data_sets(request);
2098
DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n",
2099
asp, asp->reqinfo));
2102
* for non-SET modes, set the type to NULL
2104
#ifndef NETSNMP_NO_WRITE_SUPPORT
2105
if (!MODE_IS_SET(asp->pdu->command)) {
2106
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2107
DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n",
2108
asp, asp->reqinfo));
2109
if (varbind_ptr->type == ASN_PRIV_INCL_RANGE) {
2110
DEBUGMSGTL(("snmp_agent", "varbind %d is inclusive\n",
2112
request->inclusive = 1;
2114
varbind_ptr->type = ASN_NULL;
2115
#ifndef NETSNMP_NO_WRITE_SUPPORT
2117
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2120
* place them in a cache
2122
if (tp->global_cacheid) {
2124
* we need to merge all marked subtrees together
2126
if (asp->cache_store && -1 !=
2127
(cacheid = netsnmp_get_local_cachid(asp->cache_store,
2128
tp->global_cacheid))) {
2130
cacheid = ++(asp->treecache_num);
2131
netsnmp_get_or_add_local_cachid(&asp->cache_store,
2134
goto mallocslot; /* XXX: ick */
2136
} else if (tp->cacheid > -1 && tp->cacheid <= asp->treecache_num &&
2137
asp->treecache[tp->cacheid].subtree == tp) {
2139
* we have already added a request to this tree
2142
cacheid = tp->cacheid;
2144
cacheid = ++(asp->treecache_num);
2149
if (asp->treecache_num >= asp->treecache_len) {
2151
* exapand cache array
2154
* WWW: non-linear expansion needed (with cap)
2156
#define CACHE_GROW_SIZE 16
2157
asp->treecache_len =
2158
(asp->treecache_len + CACHE_GROW_SIZE);
2160
(netsnmp_tree_cache *)realloc(asp->treecache,
2161
sizeof(netsnmp_tree_cache) *
2162
asp->treecache_len);
2163
if (asp->treecache == NULL)
2165
memset(&(asp->treecache[cacheid]), 0x00,
2166
sizeof(netsnmp_tree_cache) * (CACHE_GROW_SIZE));
2168
asp->treecache[cacheid].subtree = tp;
2169
asp->treecache[cacheid].requests_begin = request;
2170
tp->cacheid = cacheid;
2174
* if this is a search type, get the ending range oid as well
2176
if (asp->pdu->command == SNMP_MSG_GETNEXT ||
2177
asp->pdu->command == SNMP_MSG_GETBULK) {
2178
request->range_end = tp->end_a;
2179
request->range_end_len = tp->end_len;
2181
request->range_end = NULL;
2182
request->range_end_len = 0;
2188
if (asp->treecache[cacheid].requests_end)
2189
asp->treecache[cacheid].requests_end->next = request;
2190
request->next = NULL;
2191
request->prev = asp->treecache[cacheid].requests_end;
2192
asp->treecache[cacheid].requests_end = request;
2195
* add the given request to the list of requests they need
2196
* to handle results for
2198
request->requestvb = request->requestvb_start = varbind_ptr;
2204
* check the ACM(s) for the results on each of the varbinds.
2205
* If ACM disallows it, replace the value with type
2207
* Returns number of varbinds with ACM errors
2210
check_acm(netsnmp_agent_session *asp, u_char type)
2214
netsnmp_request_info *request;
2216
netsnmp_variable_list *vb, *vb2, *vbc;
2219
for (i = 0; i <= asp->treecache_num; i++) {
2220
for (request = asp->treecache[i].requests_begin;
2221
request; request = request->next) {
2223
* for each request, run it through in_a_view()
2226
for(j = request->repeat, vb = request->requestvb_start;
2228
j--, vb = vb->next_variable) {
2229
if (vb->type != ASN_NULL &&
2230
vb->type != ASN_PRIV_RETRY) { /* not yet processed */
2232
in_a_view(vb->name, &vb->name_length,
2233
asp->pdu, vb->type);
2236
* if a ACM error occurs, mark it as type passed in
2238
if (view != VACM_SUCCESS) {
2240
if (request->repeat < request->orig_repeat) {
2241
/* basically this means a GETBULK */
2244
request->requestvb = vb;
2248
/* ugh. if a whole now exists, we need to
2249
move the contents up the chain and fill
2250
in at the end else we won't end up
2251
lexographically sorted properly */
2252
if (j > -1 && vb->next_variable &&
2253
vb->next_variable->type != ASN_NULL &&
2254
vb->next_variable->type != ASN_PRIV_RETRY) {
2255
for(k = j, vbc = vb, vb2 = vb->next_variable;
2256
k > -2 && vbc && vb2;
2257
k--, vbc = vb2, vb2 = vb2->next_variable) {
2258
/* clone next into the current */
2259
snmp_clone_var(vb2, vbc);
2260
vbc->next_variable = vb2;
2264
snmp_set_var_typed_value(vb, type, NULL, 0);
2275
netsnmp_create_subtree_cache(netsnmp_agent_session *asp)
2277
netsnmp_subtree *tp;
2278
netsnmp_variable_list *varbind_ptr, *vbsave, *vbptr, **prevNext;
2281
int bulkcount = 0, bulkrep = 0;
2282
int i = 0, n = 0, r = 0;
2283
netsnmp_request_info *request;
2285
if (asp->treecache == NULL && asp->treecache_len == 0) {
2286
asp->treecache_len = SNMP_MAX(1 + asp->vbcount / 4, 16);
2288
(netsnmp_tree_cache *)calloc(asp->treecache_len, sizeof(netsnmp_tree_cache));
2289
if (asp->treecache == NULL)
2290
return SNMP_ERR_GENERR;
2292
asp->treecache_num = -1;
2294
if (asp->pdu->command == SNMP_MSG_GETBULK) {
2298
int count = count_varbinds(asp->pdu->variables);
2299
if (asp->pdu->errstat < 0) {
2300
asp->pdu->errstat = 0;
2302
if (asp->pdu->errindex < 0) {
2303
asp->pdu->errindex = 0;
2306
if (asp->pdu->errstat < count) {
2307
n = asp->pdu->errstat;
2311
if ((r = count - n) <= 0) {
2313
asp->bulkcache = NULL;
2316
netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
2317
NETSNMP_DS_AGENT_MAX_GETBULKREPEATS);
2319
netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
2320
NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES);
2322
if (maxresponses == 0)
2323
maxresponses = 100; /* more than reasonable default */
2325
/* ensure that the total number of responses fits in a mallocable
2328
if (maxresponses < 0 ||
2329
maxresponses > (int)(INT_MAX / sizeof(struct varbind_list *)))
2330
maxresponses = (int)(INT_MAX / sizeof(struct varbind_list *));
2332
/* ensure that the maximum number of repetitions will fit in the
2335
if (maxbulk <= 0 || maxbulk > maxresponses / r)
2336
maxbulk = maxresponses / r;
2338
/* limit getbulk number of repeats to a configured size */
2339
if (asp->pdu->errindex > maxbulk) {
2340
asp->pdu->errindex = maxbulk;
2341
DEBUGMSGTL(("snmp_agent",
2342
"truncating number of getbulk repeats to %ld\n",
2343
asp->pdu->errindex));
2347
(netsnmp_variable_list **) malloc(
2348
(n + asp->pdu->errindex * r) * sizeof(struct varbind_list *));
2350
if (!asp->bulkcache) {
2351
DEBUGMSGTL(("snmp_agent", "Bulkcache malloc failed\n"));
2352
return SNMP_ERR_GENERR;
2355
DEBUGMSGTL(("snmp_agent", "GETBULK N = %d, M = %ld, R = %d\n",
2356
n, asp->pdu->errindex, r));
2360
* collect varbinds into their registered trees
2362
prevNext = &(asp->pdu->variables);
2363
for (varbind_ptr = asp->pdu->variables; varbind_ptr;
2364
varbind_ptr = vbsave) {
2367
* getbulk mess with this pointer, so save it
2369
vbsave = varbind_ptr->next_variable;
2371
if (asp->pdu->command == SNMP_MSG_GETBULK) {
2376
* repeate request varbinds on GETBULK. These will
2377
* have to be properly rearranged later though as
2378
* responses are supposed to actually be interlaced
2379
* with each other. This is done with the asp->bulkcache.
2381
bulkrep = asp->pdu->errindex - 1;
2382
if (asp->pdu->errindex > 0) {
2383
vbptr = varbind_ptr;
2384
asp->bulkcache[bulkcount++] = vbptr;
2386
for (i = 1; i < asp->pdu->errindex; i++) {
2387
vbptr->next_variable =
2388
SNMP_MALLOC_STRUCT(variable_list);
2390
* don't clone the oid as it's got to be
2391
* overwritten anyway
2393
if (!vbptr->next_variable) {
2397
DEBUGMSGTL(("snmp_agent", "NextVar malloc failed\n"));
2399
vbptr = vbptr->next_variable;
2400
vbptr->name_length = 0;
2401
vbptr->type = ASN_NULL;
2402
asp->bulkcache[bulkcount++] = vbptr;
2405
vbptr->next_variable = vbsave;
2408
* 0 repeats requested for this varbind, so take it off
2411
vbptr = varbind_ptr;
2412
*prevNext = vbptr->next_variable;
2413
vbptr->next_variable = NULL;
2414
snmp_free_varbind(vbptr);
2422
* count the varbinds
2427
* find the owning tree
2429
tp = netsnmp_subtree_find(varbind_ptr->name, varbind_ptr->name_length,
2430
NULL, asp->pdu->contextName);
2433
* check access control
2435
switch (asp->pdu->command) {
2437
view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
2438
asp->pdu, varbind_ptr->type);
2439
if (view != VACM_SUCCESS)
2440
snmp_set_var_typed_value(varbind_ptr, SNMP_NOSUCHOBJECT,
2444
#ifndef NETSNMP_NO_WRITE_SUPPORT
2446
view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
2447
asp->pdu, varbind_ptr->type);
2448
if (view != VACM_SUCCESS) {
2449
asp->index = vbcount;
2450
return SNMP_ERR_NOACCESS;
2453
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2455
case SNMP_MSG_GETNEXT:
2456
case SNMP_MSG_GETBULK:
2458
view = VACM_SUCCESS;
2460
* XXXWWW: check VACM here to see if "tp" is even worthwhile
2463
if (view == VACM_SUCCESS) {
2464
request = netsnmp_add_varbind_to_cache(asp, vbcount, varbind_ptr,
2466
if (request && asp->pdu->command == SNMP_MSG_GETBULK) {
2467
request->repeat = request->orig_repeat = bulkrep;
2471
prevNext = &(varbind_ptr->next_variable);
2474
return SNMPERR_SUCCESS;
2478
* this function is only applicable in getnext like contexts
2481
netsnmp_reassign_requests(netsnmp_agent_session *asp)
2484
* assume all the requests have been filled or rejected by the
2485
* subtrees, so reassign the rejected ones to the next subtree in
2494
netsnmp_tree_cache *old_treecache = asp->treecache;
2500
(netsnmp_tree_cache *) calloc(asp->treecache_len,
2501
sizeof(netsnmp_tree_cache));
2503
if (asp->treecache == NULL)
2504
return SNMP_ERR_GENERR;
2506
asp->treecache_num = -1;
2507
if (asp->cache_store) {
2508
netsnmp_free_cachemap(asp->cache_store);
2509
asp->cache_store = NULL;
2512
for (i = 0; i < asp->vbcount; i++) {
2513
if (asp->requests[i].requestvb == NULL) {
2515
* Occurs when there's a mixture of still active
2516
* and "endOfMibView" repetitions
2520
if (asp->requests[i].requestvb->type == ASN_NULL) {
2521
if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index,
2522
asp->requests[i].requestvb,
2523
asp->requests[i].subtree->next)) {
2524
SNMP_FREE(old_treecache);
2526
} else if (asp->requests[i].requestvb->type == ASN_PRIV_RETRY) {
2528
* re-add the same subtree
2530
asp->requests[i].requestvb->type = ASN_NULL;
2531
if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index,
2532
asp->requests[i].requestvb,
2533
asp->requests[i].subtree)) {
2534
SNMP_FREE(old_treecache);
2539
SNMP_FREE(old_treecache);
2540
return SNMP_ERR_NOERROR;
2544
netsnmp_delete_request_infos(netsnmp_request_info *reqlist)
2547
netsnmp_free_request_data_sets(reqlist);
2548
reqlist = reqlist->next;
2552
#ifndef NETSNMP_FEATURE_REMOVE_DELETE_SUBTREE_CACHE
2554
netsnmp_delete_subtree_cache(netsnmp_agent_session *asp)
2556
while (asp->treecache_num >= 0) {
2558
* don't delete subtrees
2560
netsnmp_delete_request_infos(asp->treecache[asp->treecache_num].
2562
asp->treecache_num--;
2565
#endif /* NETSNMP_FEATURE_REMOVE_DELETE_SUBTREE_CACHE */
2567
#ifndef NETSNMP_FEATURE_REMOVE_CHECK_ALL_REQUESTS_ERROR
2569
* check all requests for errors
2572
* This function is a little different from the others in that
2573
* it does not use any linked lists, instead using the original
2574
* asp requests array. This is of particular importance for
2575
* cases where the linked lists are unreliable. One known instance
2576
* of this scenario occurs when the row_merge helper is used, which
2577
* may temporarily disrupts linked lists during its (and its childrens)
2578
* handling of requests.
2581
netsnmp_check_all_requests_error(netsnmp_agent_session *asp,
2582
int look_for_specific)
2587
* find any errors marked in the requests
2589
for( i = 0; i < asp->vbcount; ++i ) {
2590
if ((SNMP_ERR_NOERROR != asp->requests[i].status) &&
2591
(!look_for_specific ||
2592
asp->requests[i].status == look_for_specific))
2593
return asp->requests[i].status;
2596
return SNMP_ERR_NOERROR;
2598
#endif /* NETSNMP_FEATURE_REMOVE_CHECK_ALL_REQUESTS_ERROR */
2600
#ifndef NETSNMP_FEATURE_REMOVE_CHECK_REQUESTS_ERROR
2602
netsnmp_check_requests_error(netsnmp_request_info *requests)
2605
* find any errors marked in the requests
2607
for (;requests;requests = requests->next) {
2608
if (requests->status != SNMP_ERR_NOERROR)
2609
return requests->status;
2611
return SNMP_ERR_NOERROR;
2613
#endif /* NETSNMP_FEATURE_REMOVE_CHECK_REQUESTS_ERROR */
2616
netsnmp_check_requests_status(netsnmp_agent_session *asp,
2617
netsnmp_request_info *requests,
2618
int look_for_specific)
2621
* find any errors marked in the requests
2624
if(requests->agent_req_info != asp->reqinfo) {
2625
DEBUGMSGTL(("verbose:asp",
2626
"**reqinfo %p doesn't match cached reqinfo %p\n",
2627
asp->reqinfo, requests->agent_req_info));
2629
if (requests->status != SNMP_ERR_NOERROR &&
2630
(!look_for_specific || requests->status == look_for_specific)
2631
&& (look_for_specific || asp->index == 0
2632
|| requests->index < asp->index)) {
2633
asp->index = requests->index;
2634
asp->status = requests->status;
2636
requests = requests->next;
2642
netsnmp_check_all_requests_status(netsnmp_agent_session *asp,
2643
int look_for_specific)
2646
for (i = 0; i <= asp->treecache_num; i++) {
2647
netsnmp_check_requests_status(asp,
2648
asp->treecache[i].requests_begin,
2655
handle_var_requests(netsnmp_agent_session *asp)
2657
int i, retstatus = SNMP_ERR_NOERROR,
2658
status = SNMP_ERR_NOERROR, final_status = SNMP_ERR_NOERROR;
2659
netsnmp_handler_registration *reginfo;
2661
asp->reqinfo->asp = asp;
2662
asp->reqinfo->mode = asp->mode;
2665
* now, have the subtrees in the cache go search for their results
2667
for (i = 0; i <= asp->treecache_num; i++) {
2669
* don't call handlers w/null reginfo.
2670
* - when is this? sub agent disconnected while request processing?
2671
* - should this case encompass more of this subroutine?
2672
* - does check_request_status make send if handlers weren't called?
2674
if(NULL != asp->treecache[i].subtree->reginfo) {
2675
reginfo = asp->treecache[i].subtree->reginfo;
2676
status = netsnmp_call_handlers(reginfo, asp->reqinfo,
2677
asp->treecache[i].requests_begin);
2680
status = SNMP_ERR_GENERR;
2683
* find any errors marked in the requests. For later parts of
2684
* SET processing, only check for new errors specific to that
2685
* set processing directive (which must superceed the previous
2688
switch (asp->mode) {
2689
#ifndef NETSNMP_NO_WRITE_SUPPORT
2690
case MODE_SET_COMMIT:
2691
retstatus = netsnmp_check_requests_status(asp,
2694
SNMP_ERR_COMMITFAILED);
2698
retstatus = netsnmp_check_requests_status(asp,
2701
SNMP_ERR_UNDOFAILED);
2703
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2706
retstatus = netsnmp_check_requests_status(asp,
2713
* always take lowest varbind if possible
2715
if (retstatus != SNMP_ERR_NOERROR) {
2720
* other things we know less about (no index)
2723
* WWW: drop support for this?
2725
if (final_status == SNMP_ERR_NOERROR && status != SNMP_ERR_NOERROR) {
2727
* we can't break here, since some processing needs to be
2728
* done for all requests anyway (IE, SET handling for UNDO
2729
* needs to be called regardless of previous status
2731
* WWW: This should be predictable though and
2732
* breaking should be possible in some cases (eg GET,
2735
final_status = status;
2739
return final_status;
2743
* loop through our sessions known delegated sessions and check to see
2744
* if they've completed yet. If there are no more delegated sessions,
2745
* check for and process any queued requests
2748
netsnmp_check_outstanding_agent_requests(void)
2750
netsnmp_agent_session *asp, *prev_asp = NULL, *next_asp = NULL;
2753
* deal with delegated requests
2755
for (asp = agent_delegated_list; asp; asp = next_asp) {
2756
next_asp = asp->next; /* save in case we clean up asp */
2757
if (!netsnmp_check_for_delegated(asp)) {
2760
* we're done with this one, remove from queue
2762
if (prev_asp != NULL)
2763
prev_asp->next = asp->next;
2765
agent_delegated_list = asp->next;
2769
* check request status
2771
netsnmp_check_all_requests_status(asp, 0);
2774
* continue processing or finish up
2776
check_delayed_request(asp);
2779
* if head was removed, don't drop it if it
2782
if ((prev_asp == NULL) && (agent_delegated_list == asp)) {
2788
* asp is still on the queue
2795
* if we are processing a set and there are more delegated
2796
* requests, keep waiting before getting to queued requests.
2798
if (netsnmp_processing_set && (NULL != agent_delegated_list))
2801
while (netsnmp_agent_queued_list) {
2804
* if we are processing a set, the first item better be
2805
* the set being (or waiting to be) processed.
2807
netsnmp_assert((!netsnmp_processing_set) ||
2808
(netsnmp_processing_set == netsnmp_agent_queued_list));
2811
* if the top request is a set, don't pop it
2812
* off if there are delegated requests
2814
#ifndef NETSNMP_NO_WRITE_SUPPORT
2815
if ((netsnmp_agent_queued_list->pdu->command == SNMP_MSG_SET) &&
2816
(agent_delegated_list)) {
2818
netsnmp_assert(netsnmp_processing_set == NULL);
2820
netsnmp_processing_set = netsnmp_agent_queued_list;
2821
DEBUGMSGTL(("snmp_agent", "SET request remains queued while "
2822
"delegated requests finish, asp = %8p\n", asp));
2825
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2828
* pop the first request and process it
2830
asp = netsnmp_agent_queued_list;
2831
netsnmp_agent_queued_list = asp->next;
2832
DEBUGMSGTL(("snmp_agent",
2833
"processing queued request, asp = %8p\n", asp));
2835
netsnmp_handle_request(asp, asp->status);
2838
* if we hit a set, stop
2840
if (NULL != netsnmp_processing_set)
2845
/** Decide if the requested transaction_id is still being processed
2846
within the agent. This is used to validate whether a delayed cache
2847
(containing possibly freed pointers) is still usable.
2849
returns SNMPERR_SUCCESS if it's still valid, or SNMPERR_GENERR if not. */
2851
netsnmp_check_transaction_id(int transaction_id)
2853
netsnmp_agent_session *asp;
2855
for (asp = agent_delegated_list; asp; asp = asp->next) {
2856
if (asp->pdu->transid == transaction_id)
2857
return SNMPERR_SUCCESS;
2859
return SNMPERR_GENERR;
2864
* check_delayed_request(asp)
2866
* Called to rexamine a set of requests and continue processing them
2867
* once all the previous (delayed) requests have been handled one way
2872
check_delayed_request(netsnmp_agent_session *asp)
2874
int status = SNMP_ERR_NOERROR;
2876
DEBUGMSGTL(("snmp_agent", "processing delegated request, asp = %8p\n",
2879
switch (asp->mode) {
2880
case SNMP_MSG_GETBULK:
2881
case SNMP_MSG_GETNEXT:
2882
netsnmp_check_all_requests_status(asp, 0);
2883
handle_getnext_loop(asp);
2884
if (netsnmp_check_for_delegated(asp) &&
2885
netsnmp_check_transaction_id(asp->pdu->transid) !=
2888
* add to delegated request chain
2890
if (!netsnmp_check_delegated_chain_for(asp)) {
2891
asp->next = agent_delegated_list;
2892
agent_delegated_list = asp;
2897
#ifndef NETSNMP_NO_WRITE_SUPPORT
2898
case MODE_SET_COMMIT:
2899
netsnmp_check_all_requests_status(asp, SNMP_ERR_COMMITFAILED);
2903
netsnmp_check_all_requests_status(asp, SNMP_ERR_UNDOFAILED);
2906
case MODE_SET_BEGIN:
2907
case MODE_SET_RESERVE1:
2908
case MODE_SET_RESERVE2:
2909
case MODE_SET_ACTION:
2912
/* If we should do only one pass, this mean we */
2913
/* should not reenter this function */
2914
if ((asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) {
2915
/* We should have finished the processing after the first */
2916
/* handle_set_loop, so just wrap up */
2919
handle_set_loop(asp);
2920
if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) {
2922
if (netsnmp_check_for_delegated_and_add(asp)) {
2924
* add to delegated request chain
2927
asp->status = status;
2930
return SNMP_ERR_NOERROR;
2933
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2940
* if we don't have anything outstanding (delegated), wrap up
2942
if (!netsnmp_check_for_delegated(asp))
2943
return netsnmp_wrap_up_request(asp, status);
2948
/** returns 1 if there are valid GETNEXT requests left. Returns 0 if not. */
2950
check_getnext_results(netsnmp_agent_session *asp)
2955
netsnmp_tree_cache *old_treecache = asp->treecache;
2956
int old_treecache_num = asp->treecache_num;
2959
netsnmp_request_info *request;
2961
if (asp->mode == SNMP_MSG_GET) {
2963
* Special case for doing INCLUSIVE getNext operations in
2966
DEBUGMSGTL(("snmp_agent",
2967
"asp->mode == SNMP_MSG_GET in ch_getnext\n"));
2968
asp->mode = asp->oldmode;
2972
for (i = 0; i <= old_treecache_num; i++) {
2973
for (request = old_treecache[i].requests_begin; request;
2974
request = request->next) {
2977
* If we have just done the special case AgentX GET, then any
2978
* requests which were not INCLUSIVE will now have a wrong
2979
* response, so junk them and retry from the same place (except
2980
* that this time the handler will be called in "inexact"
2985
if (!request->inclusive) {
2986
DEBUGMSGTL(("snmp_agent",
2987
"request %d wasn't inclusive\n",
2989
snmp_set_var_typed_value(request->requestvb,
2990
ASN_PRIV_RETRY, NULL, 0);
2991
} else if (request->requestvb->type == ASN_NULL ||
2992
request->requestvb->type == SNMP_NOSUCHINSTANCE ||
2993
request->requestvb->type == SNMP_NOSUCHOBJECT) {
2995
* it was inclusive, but no results. Still retry this
2998
snmp_set_var_typed_value(request->requestvb,
2999
ASN_PRIV_RETRY, NULL, 0);
3006
if (snmp_oid_compare(request->requestvb->name,
3007
request->requestvb->name_length,
3009
request->range_end_len) >= 0) {
3011
* ack, it's beyond the accepted end of range.
3014
* fix it by setting the oid to the end of range oid instead
3016
DEBUGMSGTL(("check_getnext_results",
3017
"request response %d out of range\n",
3020
* I'm not sure why inclusive is set unconditionally here (see
3021
* comments for revision 1.161), but it causes a problem for
3022
* GETBULK over an overridden variable. The bulk-to-next
3023
* handler re-uses the same request for multiple varbinds,
3024
* and once inclusive was set, it was never cleared. So, a
3025
* hack. Instead of setting it to 1, set it to 2, so bulk-to
3026
* next can clear it later. As of the time of this hack, all
3027
* checks of this var are boolean checks (not == 1), so this
3028
* should be safe. Cross your fingers.
3030
request->inclusive = 2;
3032
* XXX: should set this to the original OID?
3034
snmp_set_var_objid(request->requestvb,
3036
request->range_end_len);
3037
snmp_set_var_typed_value(request->requestvb, ASN_NULL,
3042
* mark any existent requests with illegal results as NULL
3044
if (request->requestvb->type == SNMP_ENDOFMIBVIEW) {
3046
* illegal response from a subagent. Change it back to NULL
3047
* xxx-rks: err, how do we know this is a subagent?
3049
request->requestvb->type = ASN_NULL;
3050
request->inclusive = 1;
3053
if (request->requestvb->type == ASN_NULL ||
3054
request->requestvb->type == ASN_PRIV_RETRY ||
3055
(asp->reqinfo->mode == MODE_GETBULK
3056
&& request->repeat > 0))
3063
/** repeatedly calls getnext handlers looking for an answer till all
3064
requests are satisified. It's expected that one pass has been made
3065
before entering this function */
3067
handle_getnext_loop(netsnmp_agent_session *asp)
3070
netsnmp_variable_list *var_ptr;
3075
while (netsnmp_running) {
3078
* bail for now if anything is delegated.
3080
if (netsnmp_check_for_delegated(asp)) {
3081
return SNMP_ERR_NOERROR;
3085
* check vacm against results
3087
check_acm(asp, ASN_PRIV_RETRY);
3090
* need to keep going we're not done yet.
3092
if (!check_getnext_results(asp))
3094
* nothing left, quit now
3099
* never had a request (empty pdu), quit now
3102
* XXXWWW: huh? this would be too late, no? shouldn't we
3103
* catch this earlier?
3110
DEBUGIF("results") {
3111
DEBUGMSGTL(("results",
3112
"getnext results, before next pass:\n"));
3113
for (var_ptr = asp->pdu->variables; var_ptr;
3114
var_ptr = var_ptr->next_variable) {
3115
DEBUGMSGTL(("results", "\t"));
3116
DEBUGMSGVAR(("results", var_ptr));
3117
DEBUGMSG(("results", "\n"));
3121
netsnmp_reassign_requests(asp);
3122
status = handle_var_requests(asp);
3123
if (status != SNMP_ERR_NOERROR) {
3124
return status; /* should never really happen */
3127
return SNMP_ERR_NOERROR;
3130
#ifndef NETSNMP_NO_WRITE_SUPPORT
3132
handle_set(netsnmp_agent_session *asp)
3136
* SETS require 3-4 passes through the var_op_list.
3138
* passes verify that all types, lengths, and values are valid
3139
* and may reserve resources and the third does the set and a
3140
* fourth executes any actions. Then the identical GET RESPONSE
3141
* packet is returned.
3142
* If either of the first two passes returns an error, another
3143
* pass is made so that any reserved resources can be freed.
3144
* If the third pass returns an error, another pass is
3146
* any changes can be reversed.
3147
* If the fourth pass (or any of the error handling passes)
3148
* return an error, we'd rather not know about it!
3150
if (!(asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) {
3151
switch (asp->mode) {
3152
case MODE_SET_BEGIN:
3153
snmp_increment_statistic(STAT_SNMPINSETREQUESTS);
3154
asp->rw = WRITE; /* WWW: still needed? */
3155
asp->mode = MODE_SET_RESERVE1;
3156
asp->status = SNMP_ERR_NOERROR;
3159
case MODE_SET_RESERVE1:
3161
if (asp->status != SNMP_ERR_NOERROR)
3162
asp->mode = MODE_SET_FREE;
3164
asp->mode = MODE_SET_RESERVE2;
3167
case MODE_SET_RESERVE2:
3168
if (asp->status != SNMP_ERR_NOERROR)
3169
asp->mode = MODE_SET_FREE;
3171
asp->mode = MODE_SET_ACTION;
3174
case MODE_SET_ACTION:
3175
if (asp->status != SNMP_ERR_NOERROR)
3176
asp->mode = MODE_SET_UNDO;
3178
asp->mode = MODE_SET_COMMIT;
3181
case MODE_SET_COMMIT:
3182
if (asp->status != SNMP_ERR_NOERROR) {
3183
asp->mode = FINISHED_FAILURE;
3185
asp->mode = FINISHED_SUCCESS;
3190
asp->mode = FINISHED_FAILURE;
3194
asp->mode = FINISHED_FAILURE;
3199
if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) {
3200
DEBUGMSGTL(("agent_set", "doing set mode = %d (%s)\n", asp->mode,
3201
se_find_label_in_slist("agent_mode", asp->mode)));
3202
status = handle_var_requests(asp);
3203
DEBUGMSGTL(("agent_set", "did set mode = %d, status = %d\n",
3204
asp->mode, status));
3205
if ((status != SNMP_ERR_NOERROR && asp->status == SNMP_ERR_NOERROR) ||
3206
status == SNMP_ERR_COMMITFAILED ||
3207
status == SNMP_ERR_UNDOFAILED) {
3208
asp->status = status;
3215
handle_set_loop(netsnmp_agent_session *asp)
3217
while (asp->mode != FINISHED_FAILURE && asp->mode != FINISHED_SUCCESS) {
3219
if (netsnmp_check_for_delegated(asp)) {
3220
return SNMP_ERR_NOERROR;
3222
if (asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY) {
3228
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3231
netsnmp_handle_request(netsnmp_agent_session *asp, int status)
3234
* if this isn't a delegated request trying to finish,
3235
* processing of a set request should not start until all
3236
* delegated requests have completed, and no other new requests
3237
* should be processed until the set request completes.
3239
if ((0 == netsnmp_check_delegated_chain_for(asp)) &&
3240
(asp != netsnmp_processing_set)) {
3242
* if we are processing a set and this is not a delegated
3243
* request, queue the request
3245
if (netsnmp_processing_set) {
3246
netsnmp_add_queued(asp);
3247
DEBUGMSGTL(("snmp_agent",
3248
"request queued while processing set, "
3249
"asp = %8p\n", asp));
3254
* check for set request
3256
#ifndef NETSNMP_NO_WRITE_SUPPORT
3257
if (asp->pdu->command == SNMP_MSG_SET) {
3258
netsnmp_processing_set = asp;
3261
* if there are delegated requests, we must wait for them
3264
if (agent_delegated_list) {
3265
DEBUGMSGTL(("snmp_agent", "SET request queued while "
3266
"delegated requests finish, asp = %8p\n",
3268
netsnmp_add_queued(asp);
3272
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3276
* process the request
3278
status = handle_pdu(asp);
3281
* print the results in appropriate debugging mode
3283
DEBUGIF("results") {
3284
netsnmp_variable_list *var_ptr;
3285
DEBUGMSGTL(("results", "request results (status = %d):\n",
3287
for (var_ptr = asp->pdu->variables; var_ptr;
3288
var_ptr = var_ptr->next_variable) {
3289
DEBUGMSGTL(("results", "\t"));
3290
DEBUGMSGVAR(("results", var_ptr));
3291
DEBUGMSG(("results", "\n"));
3296
* check for uncompleted requests
3298
if (netsnmp_check_for_delegated_and_add(asp)) {
3300
* add to delegated request chain
3302
asp->status = status;
3305
* if we don't have anything outstanding (delegated), wrap up
3307
return netsnmp_wrap_up_request(asp, status);
3314
handle_pdu(netsnmp_agent_session *asp)
3316
int status, inclusives = 0;
3317
netsnmp_variable_list *v = NULL;
3320
* for illegal requests, mark all nodes as ASN_NULL
3322
switch (asp->pdu->command) {
3324
#ifndef NETSNMP_NO_WRITE_SUPPORT
3325
case SNMP_MSG_INTERNAL_SET_RESERVE2:
3326
case SNMP_MSG_INTERNAL_SET_ACTION:
3327
case SNMP_MSG_INTERNAL_SET_COMMIT:
3328
case SNMP_MSG_INTERNAL_SET_FREE:
3329
case SNMP_MSG_INTERNAL_SET_UNDO:
3330
status = get_set_cache(asp);
3331
if (status != SNMP_ERR_NOERROR)
3334
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3337
case SNMP_MSG_GETNEXT:
3338
case SNMP_MSG_GETBULK:
3339
for (v = asp->pdu->variables; v != NULL; v = v->next_variable) {
3340
if (v->type == ASN_PRIV_INCL_RANGE) {
3342
* Leave the type for now (it gets set to
3343
* ASN_NULL in netsnmp_add_varbind_to_cache,
3344
* called by create_subnetsnmp_tree_cache below).
3345
* If we set it to ASN_NULL now, we wouldn't be
3346
* able to distinguish INCLUSIVE search
3351
snmp_set_var_typed_value(v, ASN_NULL, NULL, 0);
3358
#ifndef NETSNMP_NO_WRITE_SUPPORT
3359
case SNMP_MSG_INTERNAL_SET_BEGIN:
3360
case SNMP_MSG_INTERNAL_SET_RESERVE1:
3361
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3363
asp->vbcount = count_varbinds(asp->pdu->variables);
3364
if (asp->vbcount) /* efence doesn't like 0 size allocs */
3365
asp->requests = (netsnmp_request_info *)
3366
calloc(asp->vbcount, sizeof(netsnmp_request_info));
3370
status = netsnmp_create_subtree_cache(asp);
3371
if (status != SNMP_ERR_NOERROR)
3375
asp->mode = asp->pdu->command;
3376
switch (asp->mode) {
3379
* increment the message type counter
3381
snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
3384
* check vacm ahead of time
3386
check_acm(asp, SNMP_NOSUCHOBJECT);
3391
status = handle_var_requests(asp);
3394
* Deal with unhandled results -> noSuchInstance (rather
3395
* than noSuchObject -- in that case, the type will
3396
* already have been set to noSuchObject when we realised
3397
* we couldn't find an appropriate tree).
3399
if (status == SNMP_ERR_NOERROR)
3400
snmp_replace_var_types(asp->pdu->variables, ASN_NULL,
3401
SNMP_NOSUCHINSTANCE);
3404
case SNMP_MSG_GETNEXT:
3405
snmp_increment_statistic(STAT_SNMPINGETNEXTS);
3410
case SNMP_MSG_GETBULK: /* note: there is no getbulk stat */
3412
* loop through our mib tree till we find an
3413
* appropriate response to return to the caller.
3418
* This is a special case for AgentX INCLUSIVE getNext
3419
* requests where a result lexi-equal to the request is okay
3420
* but if such a result does not exist, we still want the
3421
* lexi-next one. So basically we do a GET first, and if any
3422
* of the INCLUSIVE requests are satisfied, we use that
3423
* value. Then, unsatisfied INCLUSIVE requests, and
3424
* non-INCLUSIVE requests get done as normal.
3427
DEBUGMSGTL(("snmp_agent", "inclusive range(s) in getNext\n"));
3428
asp->oldmode = asp->mode;
3429
asp->mode = SNMP_MSG_GET;
3435
status = handle_var_requests(asp);
3436
if (status != SNMP_ERR_NOERROR) {
3438
return status; /* should never really happen */
3440
asp->status = SNMP_ERR_NOERROR;
3444
* loop through our mib tree till we find an
3445
* appropriate response to return to the caller.
3448
status = handle_getnext_loop(asp);
3451
#ifndef NETSNMP_NO_WRITE_SUPPORT
3453
#ifdef NETSNMP_DISABLE_SET_SUPPORT
3454
return SNMP_ERR_NOTWRITABLE;
3457
* check access permissions first
3459
if (check_acm(asp, SNMP_NOSUCHOBJECT))
3460
return SNMP_ERR_NOTWRITABLE;
3462
asp->mode = MODE_SET_BEGIN;
3463
status = handle_set_loop(asp);
3467
case SNMP_MSG_INTERNAL_SET_BEGIN:
3468
case SNMP_MSG_INTERNAL_SET_RESERVE1:
3469
case SNMP_MSG_INTERNAL_SET_RESERVE2:
3470
case SNMP_MSG_INTERNAL_SET_ACTION:
3471
case SNMP_MSG_INTERNAL_SET_COMMIT:
3472
case SNMP_MSG_INTERNAL_SET_FREE:
3473
case SNMP_MSG_INTERNAL_SET_UNDO:
3474
asp->pdu->flags |= UCD_MSG_FLAG_ONE_PASS_ONLY;
3475
status = handle_set_loop(asp);
3477
* asp related cache is saved in cleanup
3480
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3482
case SNMP_MSG_RESPONSE:
3483
snmp_increment_statistic(STAT_SNMPINGETRESPONSES);
3484
return SNMP_ERR_NOERROR;
3487
case SNMP_MSG_TRAP2:
3488
snmp_increment_statistic(STAT_SNMPINTRAPS);
3489
return SNMP_ERR_NOERROR;
3493
* WWW: are reports counted somewhere ?
3495
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3496
return SNMPERR_GENERR; /* shouldn't get here */
3504
/** set error for a request
3505
* \internal external interface: netsnmp_request_set_error
3507
NETSNMP_STATIC_INLINE int
3508
_request_set_error(netsnmp_request_info *request, int mode, int error_value)
3511
return SNMPERR_NO_VARS;
3513
request->processed = 1;
3514
request->delegated = REQUEST_IS_NOT_DELEGATED;
3516
switch (error_value) {
3517
case SNMP_NOSUCHOBJECT:
3518
case SNMP_NOSUCHINSTANCE:
3519
case SNMP_ENDOFMIBVIEW:
3521
* these are exceptions that should be put in the varbind
3522
* in the case of a GET but should be translated for a SET
3523
* into a real error status code and put in the request
3529
request->requestvb->type = error_value;
3533
* These are technically illegal to set by the
3534
* client APIs for these modes. But accepting
3535
* them here allows the 'sparse_table' helper to
3536
* provide some common table handling processing
3538
snmp_log(LOG_ERR, "Illegal error_value %d for mode %d ignored\n",
3540
return SNMPERR_VALUE;
3543
#ifndef NETSNMP_NO_WRITE_SUPPORT
3544
case SNMP_MSG_INTERNAL_SET_RESERVE1:
3545
request->status = SNMP_ERR_NOCREATION;
3547
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3550
request->status = SNMP_ERR_NOSUCHNAME; /* WWW: correct? */
3553
break; /* never get here */
3556
if (error_value < 0) {
3558
* illegal local error code. translate to generr
3561
* WWW: full translation map?
3563
snmp_log(LOG_ERR, "Illegal error_value %d translated to %d\n",
3564
error_value, SNMP_ERR_GENERR);
3565
request->status = SNMP_ERR_GENERR;
3568
* WWW: translations and mode checking?
3570
request->status = error_value;
3574
return SNMPERR_SUCCESS;
3577
/** set error for a request
3578
* @param request request which has error
3579
* @param error_value error value for request
3582
netsnmp_request_set_error(netsnmp_request_info *request, int error_value)
3584
if (!request || !request->agent_req_info)
3585
return SNMPERR_NO_VARS;
3587
return _request_set_error(request, request->agent_req_info->mode,
3591
#ifndef NETSNMP_FEATURE_REMOVE_REQUEST_SET_ERROR_IDX
3592
/** set error for a request within a request list
3593
* @param request head of the request list
3594
* @param error_value error value for request
3595
* @param idx index of the request which has the error
3598
netsnmp_request_set_error_idx(netsnmp_request_info *request,
3599
int error_value, int idx)
3602
netsnmp_request_info *req = request;
3604
if (!request || !request->agent_req_info)
3605
return SNMPERR_NO_VARS;
3608
* Skip to the indicated varbind
3610
for ( i=2; i<idx; i++) {
3613
return SNMPERR_NO_VARS;
3616
return _request_set_error(req, request->agent_req_info->mode,
3619
#endif /* NETSNMP_FEATURE_REMOVE_REQUEST_SET_ERROR_IDX */
3621
/** set error for all requests
3622
* @param requests request list
3623
* @param error error value for requests
3624
* @return SNMPERR_SUCCESS, or an error code
3627
netsnmp_request_set_error_all( netsnmp_request_info *requests, int error)
3629
int mode, rc, result = SNMPERR_SUCCESS;
3631
if((NULL == requests) || (NULL == requests->agent_req_info))
3632
return SNMPERR_NO_VARS;
3634
mode = requests->agent_req_info->mode; /* every req has same mode */
3636
for(; requests ; requests = requests->next) {
3638
/** paranoid sanity checks */
3639
netsnmp_assert(NULL != requests->agent_req_info);
3640
netsnmp_assert(mode == requests->agent_req_info->mode);
3643
* set error for this request. Log any errors, save the last
3644
* to return to the user.
3646
if((rc = _request_set_error(requests, mode, error))) {
3647
snmp_log(LOG_WARNING,"got %d while setting request error\n", rc);
3655
* Return the difference between pm and the agent start time in hundredths of
3657
* \deprecated Don't use in new code.
3659
* @param[in] pm An absolute time as e.g. reported by gettimeofday().
3662
netsnmp_marker_uptime(marker_t pm)
3665
const_marker_t start = netsnmp_get_agent_starttime();
3667
res = uatime_hdiff(start, pm);
3672
* Return the difference between tv and the agent start time in hundredths of
3675
* \deprecated Use netsnmp_get_agent_uptime() instead.
3677
* @param[in] tv An absolute time as e.g. reported by gettimeofday().
3680
netsnmp_timeval_uptime(struct timeval * tv)
3682
return netsnmp_marker_uptime((marker_t) tv);
3686
struct timeval starttime;
3687
static struct timeval starttimeM;
3690
* Return a pointer to the variable in which the Net-SNMP start time has
3693
* @note Use netsnmp_get_agent_runtime() instead of this function if you need
3694
* to know how much time elapsed since netsnmp_set_agent_starttime() has been
3698
netsnmp_get_agent_starttime(void)
3704
* Report the time that elapsed since the agent start time in hundredths of a
3707
* @see See also netsnmp_set_agent_starttime().
3710
netsnmp_get_agent_runtime(void)
3712
struct timeval now, delta;
3714
netsnmp_get_monotonic_clock(&now);
3715
NETSNMP_TIMERSUB(&now, &starttimeM, &delta);
3716
return delta.tv_sec * (uint64_t)100 + delta.tv_usec / 10000;
3720
* Set the time at which Net-SNMP started either to the current time
3721
* (if s == NULL) or to *s (if s is not NULL).
3723
* @see See also netsnmp_set_agent_uptime().
3726
netsnmp_set_agent_starttime(marker_t s)
3729
struct timeval nowA, nowM;
3731
starttime = *(struct timeval*)s;
3732
gettimeofday(&nowA, NULL);
3733
netsnmp_get_monotonic_clock(&nowM);
3734
NETSNMP_TIMERSUB(&starttime, &nowA, &starttimeM);
3735
NETSNMP_TIMERADD(&starttimeM, &nowM, &starttimeM);
3737
gettimeofday(&starttime, NULL);
3738
netsnmp_get_monotonic_clock(&starttimeM);
3744
* Return the current value of 'sysUpTime'
3747
netsnmp_get_agent_uptime(void)
3749
struct timeval now, delta;
3751
netsnmp_get_monotonic_clock(&now);
3752
NETSNMP_TIMERSUB(&now, &starttimeM, &delta);
3753
return delta.tv_sec * 100UL + delta.tv_usec / 10000;
3756
#ifndef NETSNMP_FEATURE_REMOVE_SET_AGENT_UPTIME
3758
* Set the start time from which 'sysUpTime' is computed.
3760
* @param[in] hsec New sysUpTime in hundredths of a second.
3762
* @see See also netsnmp_set_agent_starttime().
3765
netsnmp_set_agent_uptime(u_long hsec)
3767
struct timeval nowA, nowM;
3768
struct timeval new_uptime;
3770
gettimeofday(&nowA, NULL);
3771
netsnmp_get_monotonic_clock(&nowM);
3772
new_uptime.tv_sec = hsec / 100;
3773
new_uptime.tv_usec = (uint32_t)(hsec - new_uptime.tv_sec * 100) * 10000L;
3774
NETSNMP_TIMERSUB(&nowA, &new_uptime, &starttime);
3775
NETSNMP_TIMERSUB(&nowM, &new_uptime, &starttimeM);
3777
#endif /* NETSNMP_FEATURE_REMOVE_SET_AGENT_UPTIME */
3780
/*************************************************************************
3782
* deprecated functions
3786
/** set error for a request
3787
* \deprecated, use netsnmp_request_set_error instead
3788
* @param reqinfo agent_request_info pointer for request
3789
* @param request request_info pointer
3790
* @param error_value error value for requests
3791
* @return error_value
3794
netsnmp_set_request_error(netsnmp_agent_request_info *reqinfo,
3795
netsnmp_request_info *request, int error_value)
3797
if (!request || !reqinfo)
3800
_request_set_error(request, reqinfo->mode, error_value);
3805
/** set error for a request
3806
* \deprecated, use netsnmp_request_set_error instead
3807
* @param mode Net-SNMP agent processing mode
3808
* @param request request_info pointer
3809
* @param error_value error value for requests
3810
* @return error_value
3813
netsnmp_set_mode_request_error(int mode, netsnmp_request_info *request,
3816
_request_set_error(request, mode, error_value);
3821
/** set error for all request
3822
* \deprecated use netsnmp_request_set_error_all
3823
* @param reqinfo agent_request_info pointer for requests
3824
* @param requests request list
3825
* @param error_value error value for requests
3826
* @return error_value
3828
#ifndef NETSNMP_FEATURE_REMOVE_SET_ALL_REQUESTS_ERROR
3830
netsnmp_set_all_requests_error(netsnmp_agent_request_info *reqinfo,
3831
netsnmp_request_info *requests,
3834
netsnmp_request_set_error_all(requests, error_value);
3837
#endif /* NETSNMP_FEATURE_REMOVE_SET_ALL_REQUESTS_ERROR */