net-snmp  5.4.1
snmp_agent.c
00001 /*
00002  * snmp_agent.c
00003  *
00004  * Simple Network Management Protocol (RFC 1067).
00005  */
00006 /* Portions of this file are subject to the following copyright(s).  See
00007  * the Net-SNMP's COPYING file for more details and other copyrights
00008  * that may apply:
00009  */
00010 /* Portions of this file are subject to the following copyrights.  See
00011  * the Net-SNMP's COPYING file for more details and other copyrights
00012  * that may apply:
00013  */
00014 /***********************************************************
00015         Copyright 1988, 1989 by Carnegie Mellon University
00016 
00017                       All Rights Reserved
00018 
00019 Permission to use, copy, modify, and distribute this software and its 
00020 documentation for any purpose and without fee is hereby granted, 
00021 provided that the above copyright notice appear in all copies and that
00022 both that copyright notice and this permission notice appear in 
00023 supporting documentation, and that the name of CMU not be
00024 used in advertising or publicity pertaining to distribution of the
00025 software without specific, written prior permission.  
00026 
00027 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00028 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00029 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00030 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00031 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00032 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00033 SOFTWARE.
00034 ******************************************************************/
00035 /*
00036  * Portions of this file are copyrighted by:
00037  * Copyright © 2003 Sun Microsystems, Inc. All rights 
00038  * reserved.  Use is subject to license terms specified in the 
00039  * COPYING file distributed with the Net-SNMP package.
00040  */
00046 #include <net-snmp/net-snmp-config.h>
00047 
00048 #include <sys/types.h>
00049 #ifdef HAVE_LIMITS_H
00050 #include <limits.h>
00051 #endif
00052 #ifdef HAVE_STDLIB_H
00053 #include <stdlib.h>
00054 #endif
00055 #if HAVE_UNISTD_H
00056 #include <unistd.h>
00057 #endif
00058 #if HAVE_STRING_H
00059 #include <string.h>
00060 #endif
00061 #if TIME_WITH_SYS_TIME
00062 # ifdef WIN32
00063 #  include <sys/timeb.h>
00064 # else
00065 #  include <sys/time.h>
00066 # endif
00067 # include <time.h>
00068 #else
00069 # if HAVE_SYS_TIME_H
00070 #  include <sys/time.h>
00071 # else
00072 #  include <time.h>
00073 # endif
00074 #endif
00075 #if HAVE_SYS_SELECT_H
00076 #include <sys/select.h>
00077 #endif
00078 #if HAVE_NETINET_IN_H
00079 #include <netinet/in.h>
00080 #endif
00081 #include <errno.h>
00082 #if HAVE_WINSOCK_H
00083 #include <winsock.h>
00084 #endif
00085 
00086 #define SNMP_NEED_REQUEST_LIST
00087 #include <net-snmp/net-snmp-includes.h>
00088 #include <net-snmp/agent/net-snmp-agent-includes.h>
00089 #include <net-snmp/library/snmp_assert.h>
00090 
00091 #if HAVE_SYSLOG_H
00092 #include <syslog.h>
00093 #endif
00094 
00095 #ifdef NETSNMP_USE_LIBWRAP
00096 #include <tcpd.h>
00097 int             allow_severity = LOG_INFO;
00098 int             deny_severity = LOG_WARNING;
00099 #endif
00100 
00101 #include "snmpd.h"
00102 #include "mibgroup/struct.h"
00103 #include "mibgroup/util_funcs.h"
00104 #include <net-snmp/agent/mib_module_config.h>
00105 #include <net-snmp/agent/mib_modules.h>
00106 
00107 #ifdef USING_AGENTX_PROTOCOL_MODULE
00108 #include "agentx/protocol.h"
00109 #endif
00110 
00111 #ifdef USING_AGENTX_MASTER_MODULE
00112 #include "agentx/master.h"
00113 #endif
00114 
00115 #ifdef USING_SMUX_MODULE
00116 #include "smux/smux.h"
00117 #endif
00118 
00119 oid      version_sysoid[] = { NETSNMP_SYSTEM_MIB };
00120 int      version_sysoid_len = OID_LENGTH(version_sysoid);
00121 
00122 #define SNMP_ADDRCACHE_SIZE 10
00123 #define SNMP_ADDRCACHE_MAXAGE 300 /* in seconds */
00124 
00125 enum {
00126     SNMP_ADDRCACHE_UNUSED = 0,
00127     SNMP_ADDRCACHE_USED = 1
00128 };
00129 
00130 struct addrCache {
00131     char           *addr;
00132     int            status;
00133     struct timeval lastHit;
00134 };
00135 
00136 static struct addrCache addrCache[SNMP_ADDRCACHE_SIZE];
00137 int             log_addresses = 0;
00138 
00139 
00140 
00141 typedef struct _agent_nsap {
00142     int             handle;
00143     netsnmp_transport *t;
00144     void           *s;          /*  Opaque internal session pointer.  */
00145     struct _agent_nsap *next;
00146 } agent_nsap;
00147 
00148 static agent_nsap *agent_nsap_list = NULL;
00149 static netsnmp_agent_session *agent_session_list = NULL;
00150 netsnmp_agent_session *netsnmp_processing_set = NULL;
00151 netsnmp_agent_session *agent_delegated_list = NULL;
00152 netsnmp_agent_session *netsnmp_agent_queued_list = NULL;
00153 
00154 
00155 int             netsnmp_agent_check_packet(netsnmp_session *,
00156                                            struct netsnmp_transport_s *,
00157                                            void *, int);
00158 int             netsnmp_agent_check_parse(netsnmp_session *, netsnmp_pdu *,
00159                                           int);
00160 void            delete_subnetsnmp_tree_cache(netsnmp_agent_session *asp);
00161 int             handle_pdu(netsnmp_agent_session *asp);
00162 int             netsnmp_handle_request(netsnmp_agent_session *asp,
00163                                        int status);
00164 int             netsnmp_wrap_up_request(netsnmp_agent_session *asp,
00165                                         int status);
00166 int             check_delayed_request(netsnmp_agent_session *asp);
00167 int             handle_getnext_loop(netsnmp_agent_session *asp);
00168 int             handle_set_loop(netsnmp_agent_session *asp);
00169 
00170 int             netsnmp_check_queued_chain_for(netsnmp_agent_session *asp);
00171 int             netsnmp_add_queued(netsnmp_agent_session *asp);
00172 int             netsnmp_remove_from_delegated(netsnmp_agent_session *asp);
00173 
00174 
00175 static int      current_globalid = 0;
00176 
00177 int      netsnmp_running = 1;
00178 
00179 int
00180 netsnmp_allocate_globalcacheid(void)
00181 {
00182     return ++current_globalid;
00183 }
00184 
00185 int
00186 netsnmp_get_local_cachid(netsnmp_cachemap *cache_store, int globalid)
00187 {
00188     while (cache_store != NULL) {
00189         if (cache_store->globalid == globalid)
00190             return cache_store->cacheid;
00191         cache_store = cache_store->next;
00192     }
00193     return -1;
00194 }
00195 
00196 netsnmp_cachemap *
00197 netsnmp_get_or_add_local_cachid(netsnmp_cachemap **cache_store,
00198                                 int globalid, int localid)
00199 {
00200     netsnmp_cachemap *tmpp;
00201 
00202     tmpp = SNMP_MALLOC_TYPEDEF(netsnmp_cachemap);
00203     if (*cache_store) {
00204         tmpp->next = *cache_store;
00205         *cache_store = tmpp;
00206     } else {
00207         *cache_store = tmpp;
00208     }
00209 
00210     tmpp->globalid = globalid;
00211     tmpp->cacheid = localid;
00212     return tmpp;
00213 }
00214 
00215 void
00216 netsnmp_free_cachemap(netsnmp_cachemap *cache_store)
00217 {
00218     netsnmp_cachemap *tmpp;
00219     while (cache_store) {
00220         tmpp = cache_store;
00221         cache_store = cache_store->next;
00222         SNMP_FREE(tmpp);
00223     }
00224 }
00225 
00226 
00227 typedef struct agent_set_cache_s {
00228     /*
00229      * match on these 2 
00230      */
00231     int             transID;
00232     netsnmp_session *sess;
00233 
00234     /*
00235      * store this info 
00236      */
00237     netsnmp_tree_cache *treecache;
00238     int             treecache_len;
00239     int             treecache_num;
00240 
00241     int             vbcount;
00242     netsnmp_request_info *requests;
00243     netsnmp_variable_list *saved_vars;
00244     netsnmp_data_list *agent_data;
00245 
00246     /*
00247      * list 
00248      */
00249     struct agent_set_cache_s *next;
00250 } agent_set_cache;
00251 
00252 static agent_set_cache *Sets = NULL;
00253 
00254 agent_set_cache *
00255 save_set_cache(netsnmp_agent_session *asp)
00256 {
00257     agent_set_cache *ptr;
00258 
00259     if (!asp || !asp->reqinfo || !asp->pdu)
00260         return NULL;
00261 
00262     ptr = SNMP_MALLOC_TYPEDEF(agent_set_cache);
00263     if (ptr == NULL)
00264         return NULL;
00265 
00266     /*
00267      * Save the important information 
00268      */
00269     DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p saved in cache (mode %d)\n",
00270                 asp, asp->reqinfo, asp->pdu->command));
00271     ptr->transID = asp->pdu->transid;
00272     ptr->sess = asp->session;
00273     ptr->treecache = asp->treecache;
00274     ptr->treecache_len = asp->treecache_len;
00275     ptr->treecache_num = asp->treecache_num;
00276     ptr->agent_data = asp->reqinfo->agent_data;
00277     ptr->requests = asp->requests;
00278     ptr->saved_vars = asp->pdu->variables; /* requests contains pointers to variables */
00279     ptr->vbcount = asp->vbcount;
00280 
00281     /*
00282      * make the agent forget about what we've saved 
00283      */
00284     asp->treecache = NULL;
00285     asp->reqinfo->agent_data = NULL;
00286     asp->pdu->variables = NULL;
00287     asp->requests = NULL;
00288 
00289     ptr->next = Sets;
00290     Sets = ptr;
00291 
00292     return ptr;
00293 }
00294 
00295 int
00296 get_set_cache(netsnmp_agent_session *asp)
00297 {
00298     agent_set_cache *ptr, *prev = NULL;
00299 
00300     for (ptr = Sets; ptr != NULL; ptr = ptr->next) {
00301         if (ptr->sess == asp->session && ptr->transID == asp->pdu->transid) {
00302             /*
00303              * remove this item from list
00304              */
00305             if (prev)
00306                 prev->next = ptr->next;
00307             else
00308                 Sets = ptr->next;
00309 
00310             /*
00311              * found it.  Get the needed data 
00312              */
00313             asp->treecache = ptr->treecache;
00314             asp->treecache_len = ptr->treecache_len;
00315             asp->treecache_num = ptr->treecache_num;
00316 
00317             /*
00318              * Free previously allocated requests before overwriting by
00319              * cached ones, otherwise memory leaks!
00320              */
00321             if (asp->requests) {
00322                 /*
00323                  * I don't think this case should ever happen. Please email
00324                  * the net-snmp-coders@lists.sourceforge.net if you have
00325                  * a test case that hits this assert. -- rstory
00326                  */
00327                 int i;
00328                 netsnmp_assert(NULL == asp->requests); /* see note above */
00329                 for (i = 0; i < asp->vbcount; i++) {
00330                     netsnmp_free_request_data_sets(&asp->requests[i]);
00331                 }
00332                 free(asp->requests);
00333             }
00334             /*
00335              * If we replace asp->requests with the info from the set cache,
00336              * we should replace asp->pdu->variables also with the cached
00337              * info, as asp->requests contains pointers to them.  And we
00338              * should also free the current asp->pdu->variables list...
00339              */
00340             if (ptr->saved_vars) {
00341                 if (asp->pdu->variables)
00342                     snmp_free_varbind(asp->pdu->variables);
00343                 asp->pdu->variables = ptr->saved_vars;
00344                 asp->vbcount = ptr->vbcount;
00345             } else {
00346                 /*
00347                  * when would we not have saved variables? someone
00348                  * let me know if they hit this assert. -- rstory
00349                  */
00350                 netsnmp_assert(NULL != ptr->saved_vars);
00351             }
00352             asp->requests = ptr->requests;
00353 
00354             netsnmp_assert(NULL != asp->reqinfo);
00355             asp->reqinfo->asp = asp;
00356             asp->reqinfo->agent_data = ptr->agent_data;
00357             
00358             /*
00359              * update request reqinfo, if it's out of date.
00360              * yyy-rks: investigate when/why sometimes they match,
00361              * sometimes they don't.
00362              */
00363             if(asp->requests->agent_req_info != asp->reqinfo) {
00364                 /*
00365                  * - one don't match case: agentx subagents. prev asp & reqinfo
00366                  *   freed, request reqinfo ptrs not cleared.
00367                  */
00368                 netsnmp_request_info *tmp = asp->requests;
00369                 DEBUGMSGTL(("verbose:asp",
00370                             "  reqinfo %p doesn't match cached reqinfo %p\n",
00371                             asp->reqinfo, asp->requests->agent_req_info));
00372                 for(; tmp; tmp = tmp->next)
00373                     tmp->agent_req_info = asp->reqinfo;
00374             } else {
00375                 /*
00376                  * - match case: ?
00377                  */
00378                 DEBUGMSGTL(("verbose:asp",
00379                             "  reqinfo %p matches cached reqinfo %p\n",
00380                             asp->reqinfo, asp->requests->agent_req_info));
00381             }
00382 
00383             SNMP_FREE(ptr);
00384             return SNMP_ERR_NOERROR;
00385         }
00386         prev = ptr;
00387     }
00388     return SNMP_ERR_GENERR;
00389 }
00390 
00391 /* Bulkcache holds the values for the *repeating* varbinds (only),
00392  *   but ordered "by column" - i.e. the repetitions for each
00393  *   repeating varbind follow on immediately from one another,
00394  *   rather than being interleaved, as required by the protocol.
00395  *
00396  * So we need to rearrange the varbind list so it's ordered "by row".
00397  *
00398  * In the following code chunk:
00399  *     n            = # non-repeating varbinds
00400  *     r            = # repeating varbinds
00401  *     asp->vbcount = # varbinds in the incoming PDU
00402  *         (So asp->vbcount = n+r)
00403  *
00404  *     repeats = Desired # of repetitions (of 'r' varbinds)
00405  */
00406 NETSNMP_STATIC_INLINE void
00407 _reorder_getbulk(netsnmp_agent_session *asp)
00408 {
00409     int             i, n = 0, r = 0;
00410     int             repeats = asp->pdu->errindex;
00411     int             j, k;
00412     int             all_eoMib;
00413     netsnmp_variable_list *prev = NULL, *curr;
00414             
00415     if (asp->vbcount == 0)  /* Nothing to do! */
00416         return;
00417 
00418     if (asp->pdu->errstat < asp->vbcount) {
00419         n = asp->pdu->errstat;
00420     } else {
00421         n = asp->vbcount;
00422     }
00423     if ((r = asp->vbcount - n) < 0) {
00424         r = 0;
00425     }
00426 
00427     /* we do nothing if there is nothing repeated */
00428     if (r == 0)
00429         return;
00430             
00431     /* Fix endOfMibView entries. */
00432     for (i = 0; i < r; i++) {
00433         prev = NULL;
00434         for (j = 0; j < repeats; j++) {
00435             curr = asp->bulkcache[i * repeats + j];
00436             /*
00437              *  If we don't have a valid name for a given repetition
00438              *   (and probably for all the ones that follow as well),
00439              *   extend the previous result to indicate 'endOfMibView'.
00440              *  Or if the repetition already has type endOfMibView make
00441              *   sure it has the correct objid (i.e. that of the previous
00442              *   entry or that of the original request).
00443              */
00444             if (curr->name_length == 0 || curr->type == SNMP_ENDOFMIBVIEW) {
00445                 if (prev == NULL) {
00446                     /* Use objid from original pdu. */
00447                     prev = asp->orig_pdu->variables;
00448                     for (k = i; prev && k > 0; k--)
00449                         prev = prev->next_variable;
00450                 }
00451                 if (prev) {
00452                     snmp_set_var_objid(curr, prev->name, prev->name_length);
00453                     snmp_set_var_typed_value(curr, SNMP_ENDOFMIBVIEW, NULL, 0);
00454                 }
00455             }
00456             prev = curr;
00457         }
00458     }
00459 
00460     /*
00461      * For each of the original repeating varbinds (except the last),
00462      *  go through the block of results for that varbind,
00463      *  and link each instance to the corresponding instance
00464      *  in the next block.
00465      */
00466     for (i = 0; i < r - 1; i++) {
00467         for (j = 0; j < repeats; j++) {
00468             asp->bulkcache[i * repeats + j]->next_variable =
00469                 asp->bulkcache[(i + 1) * repeats + j];
00470         }
00471     }
00472 
00473     /*
00474      * For the last of the original repeating varbinds,
00475      *  go through that block of results, and link each
00476      *  instance to the *next* instance in the *first* block.
00477      *
00478      * The very last instance of this block is left untouched
00479      *  since it (correctly) points to the end of the list.
00480      */
00481     for (j = 0; j < repeats - 1; j++) {
00482         asp->bulkcache[(r - 1) * repeats + j]->next_variable = 
00483             asp->bulkcache[j + 1];
00484     }
00485 
00486     /*
00487      * If we've got a full row of endOfMibViews, then we
00488      *  can truncate the result varbind list after that.
00489      *
00490      * Look for endOfMibView exception values in the list of
00491      *  repetitions for the first varbind, and check the 
00492      *  corresponding instances for the other varbinds
00493      *  (following the next_variable links).
00494      *
00495      * If they're all endOfMibView too, then we can terminate
00496      *  the linked list there, and free any redundant varbinds.
00497      */
00498     all_eoMib = 0;
00499     for (i = 0; i < repeats; i++) {
00500         if (asp->bulkcache[i]->type == SNMP_ENDOFMIBVIEW) {
00501             all_eoMib = 1;
00502             for (j = 1, prev=asp->bulkcache[i];
00503                  j < r;
00504                  j++, prev=prev->next_variable) {
00505                 if (prev->type != SNMP_ENDOFMIBVIEW) {
00506                     all_eoMib = 0;
00507                     break;      /* Found a real value */
00508                 }
00509             }
00510             if (all_eoMib) {
00511                 /*
00512                  * This is indeed a full endOfMibView row.
00513                  * Terminate the list here & free the rest.
00514                  */
00515                 snmp_free_varbind( prev->next_variable );
00516                 prev->next_variable = NULL;
00517                 break;
00518             }
00519         }
00520     }
00521 }
00522 
00523 
00524 /* EndOfMibView replies to a GETNEXT request should according to RFC3416
00525  *  have the object ID set to that of the request. Our tree search 
00526  *  algorithm will sometimes break that requirement. This function will
00527  *  fix that.
00528  */
00529 NETSNMP_STATIC_INLINE void
00530 _fix_endofmibview(netsnmp_agent_session *asp)
00531 {
00532     netsnmp_variable_list *vb, *ovb;
00533 
00534     if (asp->vbcount == 0)  /* Nothing to do! */
00535         return;
00536 
00537     for (vb = asp->pdu->variables, ovb = asp->orig_pdu->variables;
00538          vb && ovb; vb = vb->next_variable, ovb = ovb->next_variable) {
00539         if (vb->type == SNMP_ENDOFMIBVIEW)
00540             snmp_set_var_objid(vb, ovb->name, ovb->name_length);
00541     }
00542 }
00543 
00544 
00545 int
00546 getNextSessID()
00547 {
00548     static int      SessionID = 0;
00549 
00550     return ++SessionID;
00551 }
00552 
00565 int
00566 agent_check_and_process(int block)
00567 {
00568     int             numfds;
00569     fd_set          fdset;
00570     struct timeval  timeout = { LONG_MAX, 0 }, *tvp = &timeout;
00571     int             count;
00572     int             fakeblock = 0;
00573 
00574     numfds = 0;
00575     FD_ZERO(&fdset);
00576     snmp_select_info(&numfds, &fdset, tvp, &fakeblock);
00577     if (block != 0 && fakeblock != 0) {
00578         /*
00579          * There are no alarms registered, and the caller asked for blocking, so
00580          * let select() block forever.  
00581          */
00582 
00583         tvp = NULL;
00584     } else if (block != 0 && fakeblock == 0) {
00585         /*
00586          * The caller asked for blocking, but there is an alarm due sooner than
00587          * LONG_MAX seconds from now, so use the modified timeout returned by
00588          * snmp_select_info as the timeout for select().  
00589          */
00590 
00591     } else if (block == 0) {
00592         /*
00593          * The caller does not want us to block at all.  
00594          */
00595 
00596         tvp->tv_sec = 0;
00597         tvp->tv_usec = 0;
00598     }
00599 
00600     count = select(numfds, &fdset, 0, 0, tvp);
00601 
00602     if (count > 0) {
00603         /*
00604          * packets found, process them 
00605          */
00606         snmp_read(&fdset);
00607     } else
00608         switch (count) {
00609         case 0:
00610             snmp_timeout();
00611             break;
00612         case -1:
00613             if (errno != EINTR) {
00614                 snmp_log_perror("select");
00615             }
00616             return -1;
00617         default:
00618             snmp_log(LOG_ERR, "select returned %d\n", count);
00619             return -1;
00620         }                       /* endif -- count>0 */
00621 
00622     /*
00623      * Run requested alarms.  
00624      */
00625     run_alarms();
00626 
00627     netsnmp_check_outstanding_agent_requests();
00628 
00629     return count;
00630 }
00631 
00632 
00633 /*
00634  * Set up the address cache.  
00635  */
00636 void
00637 netsnmp_addrcache_initialise(void)
00638 {
00639     int             i = 0;
00640 
00641     for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
00642         addrCache[i].addr = NULL;
00643         addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
00644     }
00645 }
00646 
00647 /*
00648  * Adds a new entry to the cache of addresses that
00649  * have recently made connections to the agent.
00650  * Returns 0 if the entry already exists (but updates
00651  * the entry with a new timestamp) and 1 if the
00652  * entry did not previously exist.
00653  *
00654  * Implements a simple LRU cache replacement
00655  * policy. Uses a linear search, which should be
00656  * okay, as long as SNMP_ADDRCACHE_SIZE remains
00657  * relatively small.
00658  *
00659  * @retval 0 : updated existing entry
00660  * @retval 1 : added new entry
00661  */
00662 int
00663 netsnmp_addrcache_add(const char *addr)
00664 {
00665     int oldest = -1; /* Index of the oldest cache entry */
00666     int unused = -1; /* Index of the first free cache entry */
00667     int i; /* Looping variable */
00668     int rc = -1;
00669     struct timeval now; /* What time is it now? */
00670     struct timeval aged; /* Oldest allowable cache entry */
00671 
00672     /*
00673      * First get the current and oldest allowable timestamps
00674      */
00675     gettimeofday(&now, (struct timezone*) NULL);
00676     aged.tv_sec = now.tv_sec - SNMP_ADDRCACHE_MAXAGE;
00677     aged.tv_usec = now.tv_usec;
00678 
00679     /*
00680      * Now look for a place to put this thing
00681      */
00682     for(i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
00683         if (addrCache[i].status == SNMP_ADDRCACHE_UNUSED) { /* If unused */
00684             /*
00685              * remember this location, in case addr isn't in the cache
00686              */
00687             if (unused < 0)
00688                 unused = i;
00689         }
00690         else { /* If used */
00691             if ((NULL != addr) && (strcmp(addrCache[i].addr, addr) == 0)) {
00692                 /*
00693                  * found a match
00694                  */
00695                 memcpy(&addrCache[i].lastHit, &now, sizeof(struct timeval));
00696                 if (timercmp(&addrCache[i].lastHit, &aged, <))
00697                     rc = 1; /* should have expired, so is new */
00698                 else
00699                     rc = 0; /* not expired, so is existing entry */
00700                 break;
00701             }
00702             else {
00703                 /*
00704                  * Used, but not this address. check if it's stale.
00705                  */
00706                 if (timercmp(&addrCache[i].lastHit, &aged, <)) {
00707                     /*
00708                      * Stale, reuse
00709                      */
00710                     SNMP_FREE(addrCache[i].addr);
00711                     addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
00712                     /*
00713                      * remember this location, in case addr isn't in the cache
00714                      */
00715                     if (unused < 0)
00716                         unused = i;
00717                 }
00718                 else {
00719                     /*
00720                      * Still fresh, but a candidate for LRU replacement
00721                      */
00722                     if (oldest < 0)
00723                         oldest = i;
00724                     else if (timercmp(&addrCache[i].lastHit,
00725                                       &addrCache[oldest].lastHit, <))
00726                         oldest = i;
00727                 } /* fresh */
00728             } /* used, no match */
00729         } /* used */
00730     } /* for loop */
00731 
00732     if ((-1 == rc) && (NULL != addr)) {
00733         /*
00734          * We didn't find the entry in the cache
00735          */
00736         if (unused >= 0) {
00737             /*
00738              * If we have a slot free anyway, use it
00739              */
00740             addrCache[unused].addr = strdup(addr);
00741             addrCache[unused].status = SNMP_ADDRCACHE_USED;
00742             memcpy(&addrCache[unused].lastHit, &now, sizeof(struct timeval));
00743         }
00744         else { /* Otherwise, replace oldest entry */
00745             if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
00746                                        NETSNMP_DS_AGENT_VERBOSE))
00747                 snmp_log(LOG_INFO, "Purging address from address cache: %s",
00748                          addrCache[oldest].addr);
00749             
00750             free(addrCache[oldest].addr);
00751             addrCache[oldest].addr = strdup(addr);
00752             memcpy(&addrCache[oldest].lastHit, &now, sizeof(struct timeval));
00753         }
00754         rc = 1;
00755     }
00756     if ((log_addresses && (1 == rc)) ||
00757         netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
00758                                NETSNMP_DS_AGENT_VERBOSE)) {
00759         snmp_log(LOG_INFO, "Received SNMP packet(s) from %s\n", addr);
00760      }
00761 
00762     return rc;
00763 }
00764 
00765 /*
00766  * Age the entries in the address cache.  
00767  *
00768  * backwards compatability; not used anywhere
00769  */
00770 void
00771 netsnmp_addrcache_age(void)
00772 {
00773     (void)netsnmp_addrcache_add(NULL);
00774 }
00775 
00776 /*******************************************************************-o-******
00777  * netsnmp_agent_check_packet
00778  *
00779  * Parameters:
00780  *      session, transport, transport_data, transport_data_length
00781  *      
00782  * Returns:
00783  *      1       On success.
00784  *      0       On error.
00785  *
00786  * Handler for all incoming messages (a.k.a. packets) for the agent.  If using
00787  * the libwrap utility, log the connection and deny/allow the access. Print
00788  * output when appropriate, and increment the incoming counter.
00789  *
00790  */
00791 
00792 int
00793 netsnmp_agent_check_packet(netsnmp_session * session,
00794                            netsnmp_transport *transport,
00795                            void *transport_data, int transport_data_length)
00796 {
00797     char           *addr_string = NULL;
00798 #ifdef  NETSNMP_USE_LIBWRAP
00799     char *tcpudpaddr, *name;
00800     short not_log_connection;
00801 
00802     name = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
00803                                  NETSNMP_DS_LIB_APPTYPE);
00804 
00805     /* not_log_connection will be 1 if we should skip the messages */
00806     not_log_connection = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
00807                                                 NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS);
00808 
00809     /*
00810      * handle the error case
00811      * default to logging the messages
00812      */
00813     if (not_log_connection == SNMPERR_GENERR) not_log_connection = 0;
00814 #endif
00815 
00816     /*
00817      * Log the message and/or dump the message.
00818      * Optionally cache the network address of the sender.
00819      */
00820 
00821     if (transport != NULL && transport->f_fmtaddr != NULL) {
00822         /*
00823          * Okay I do know how to format this address for logging.  
00824          */
00825         addr_string = transport->f_fmtaddr(transport, transport_data,
00826                                            transport_data_length);
00827         /*
00828          * Don't forget to free() it.  
00829          */
00830     }
00831 #ifdef  NETSNMP_USE_LIBWRAP
00832     /* Catch udp,udp6,tcp,tcp6 transports using "[" */
00833     tcpudpaddr = strstr(addr_string, "[");
00834     if ( tcpudpaddr != 0 ) {
00835         char sbuf[64];
00836         char *xp;
00837         strncpy(sbuf, tcpudpaddr + 1, sizeof(sbuf));
00838         sbuf[sizeof(sbuf)-1] = '\0';
00839         xp = strstr(sbuf, "]");
00840         if (xp)
00841             *xp = '\0';
00842  
00843         if (hosts_ctl(name, STRING_UNKNOWN, sbuf, STRING_UNKNOWN)) {
00844             if (!not_log_connection) {
00845                 snmp_log(allow_severity, "Connection from %s\n", addr_string);
00846             }
00847         } else {
00848             snmp_log(deny_severity, "Connection from %s REFUSED\n",
00849                      addr_string);
00850             SNMP_FREE(addr_string);
00851             return 0;
00852         }
00853     } else {
00854         /*
00855          * don't log callback connections.
00856          * What about 'Local IPC', 'IPX' and 'AAL5 PVC'?
00857          */
00858         if (0 == strncmp(addr_string, "callback", 8))
00859             ;
00860         else if (hosts_ctl(name, STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN)){
00861             if (!not_log_connection) {
00862                 snmp_log(allow_severity, "Connection from <UNKNOWN> (%s)\n", addr_string);
00863             };
00864             SNMP_FREE(addr_string);
00865             addr_string = strdup("<UNKNOWN>");
00866         } else {
00867             snmp_log(deny_severity, "Connection from <UNKNOWN> (%s) REFUSED\n", addr_string);
00868             SNMP_FREE(addr_string);
00869             return 0;
00870         }
00871     }
00872 #endif                          /*NETSNMP_USE_LIBWRAP */
00873 
00874     snmp_increment_statistic(STAT_SNMPINPKTS);
00875 
00876     if (addr_string != NULL) {
00877         netsnmp_addrcache_add(addr_string);
00878         SNMP_FREE(addr_string);
00879     }
00880     return 1;
00881 }
00882 
00883 
00884 int
00885 netsnmp_agent_check_parse(netsnmp_session * session, netsnmp_pdu *pdu,
00886                           int result)
00887 {
00888     if (result == 0) {
00889         if (snmp_get_do_logging() &&
00890             netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
00891                                    NETSNMP_DS_AGENT_VERBOSE)) {
00892             netsnmp_variable_list *var_ptr;
00893 
00894             switch (pdu->command) {
00895             case SNMP_MSG_GET:
00896                 snmp_log(LOG_DEBUG, "  GET message\n");
00897                 break;
00898             case SNMP_MSG_GETNEXT:
00899                 snmp_log(LOG_DEBUG, "  GETNEXT message\n");
00900                 break;
00901             case SNMP_MSG_RESPONSE:
00902                 snmp_log(LOG_DEBUG, "  RESPONSE message\n");
00903                 break;
00904             case SNMP_MSG_SET:
00905                 snmp_log(LOG_DEBUG, "  SET message\n");
00906                 break;
00907             case SNMP_MSG_TRAP:
00908                 snmp_log(LOG_DEBUG, "  TRAP message\n");
00909                 break;
00910             case SNMP_MSG_GETBULK:
00911                 snmp_log(LOG_DEBUG, "  GETBULK message, non-rep=%ld, max_rep=%ld\n",
00912                          pdu->errstat, pdu->errindex);
00913                 break;
00914             case SNMP_MSG_INFORM:
00915                 snmp_log(LOG_DEBUG, "  INFORM message\n");
00916                 break;
00917             case SNMP_MSG_TRAP2:
00918                 snmp_log(LOG_DEBUG, "  TRAP2 message\n");
00919                 break;
00920             case SNMP_MSG_REPORT:
00921                 snmp_log(LOG_DEBUG, "  REPORT message\n");
00922                 break;
00923 
00924             case SNMP_MSG_INTERNAL_SET_RESERVE1:
00925                 snmp_log(LOG_DEBUG, "  INTERNAL RESERVE1 message\n");
00926                 break;
00927 
00928             case SNMP_MSG_INTERNAL_SET_RESERVE2:
00929                 snmp_log(LOG_DEBUG, "  INTERNAL RESERVE2 message\n");
00930                 break;
00931 
00932             case SNMP_MSG_INTERNAL_SET_ACTION:
00933                 snmp_log(LOG_DEBUG, "  INTERNAL ACTION message\n");
00934                 break;
00935 
00936             case SNMP_MSG_INTERNAL_SET_COMMIT:
00937                 snmp_log(LOG_DEBUG, "  INTERNAL COMMIT message\n");
00938                 break;
00939 
00940             case SNMP_MSG_INTERNAL_SET_FREE:
00941                 snmp_log(LOG_DEBUG, "  INTERNAL FREE message\n");
00942                 break;
00943 
00944             case SNMP_MSG_INTERNAL_SET_UNDO:
00945                 snmp_log(LOG_DEBUG, "  INTERNAL UNDO message\n");
00946                 break;
00947 
00948             default:
00949                 snmp_log(LOG_DEBUG, "  UNKNOWN message, type=%02X\n",
00950                          pdu->command);
00951                 snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
00952                 return 0;
00953             }
00954 
00955             for (var_ptr = pdu->variables; var_ptr != NULL;
00956                  var_ptr = var_ptr->next_variable) {
00957                 size_t          c_oidlen = 256, c_outlen = 0;
00958                 u_char         *c_oid = (u_char *) malloc(c_oidlen);
00959 
00960                 if (c_oid) {
00961                     if (!sprint_realloc_objid
00962                         (&c_oid, &c_oidlen, &c_outlen, 1, var_ptr->name,
00963                          var_ptr->name_length)) {
00964                         snmp_log(LOG_DEBUG, "    -- %s [TRUNCATED]\n",
00965                                  c_oid);
00966                     } else {
00967                         snmp_log(LOG_DEBUG, "    -- %s\n", c_oid);
00968                     }
00969                     SNMP_FREE(c_oid);
00970                 }
00971             }
00972         }
00973         return 1;
00974     }
00975     return 0;                   /* XXX: does it matter what the return value
00976                                  * is?  Yes: if we return 0, then the PDU is
00977                                  * dumped.  */
00978 }
00979 
00980 
00981 /*
00982  * Global access to the primary session structure for this agent.
00983  * for Index Allocation use initially. 
00984  */
00985 
00986 /*
00987  * I don't understand what this is for at the moment.  AFAICS as long as it
00988  * gets set and points at a session, that's fine.  ???  
00989  */
00990 
00991 netsnmp_session *main_session = NULL;
00992 
00993 
00994 
00995 /*
00996  * Set up an agent session on the given transport.  Return a handle
00997  * which may later be used to de-register this transport.  A return
00998  * value of -1 indicates an error.  
00999  */
01000 
01001 int
01002 netsnmp_register_agent_nsap(netsnmp_transport *t)
01003 {
01004     netsnmp_session *s, *sp = NULL;
01005     agent_nsap     *a = NULL, *n = NULL, **prevNext = &agent_nsap_list;
01006     int             handle = 0;
01007     void           *isp = NULL;
01008 
01009     if (t == NULL) {
01010         return -1;
01011     }
01012 
01013     DEBUGMSGTL(("netsnmp_register_agent_nsap", "fd %d\n", t->sock));
01014 
01015     n = (agent_nsap *) malloc(sizeof(agent_nsap));
01016     if (n == NULL) {
01017         return -1;
01018     }
01019     s = (netsnmp_session *) malloc(sizeof(netsnmp_session));
01020     if (s == NULL) {
01021         SNMP_FREE(n);
01022         return -1;
01023     }
01024     memset(s, 0, sizeof(netsnmp_session));
01025     snmp_sess_init(s);
01026 
01027     /*
01028      * Set up the session appropriately for an agent.  
01029      */
01030 
01031     s->version = SNMP_DEFAULT_VERSION;
01032     s->callback = handle_snmp_packet;
01033     s->authenticator = NULL;
01034     s->flags = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
01035                                   NETSNMP_DS_AGENT_FLAGS);
01036     s->isAuthoritative = SNMP_SESS_AUTHORITATIVE;
01037 
01038     sp = snmp_add(s, t, netsnmp_agent_check_packet,
01039                   netsnmp_agent_check_parse);
01040     if (sp == NULL) {
01041         SNMP_FREE(s);
01042         SNMP_FREE(n);
01043         return -1;
01044     }
01045 
01046     isp = snmp_sess_pointer(sp);
01047     if (isp == NULL) {          /*  over-cautious  */
01048         SNMP_FREE(s);
01049         SNMP_FREE(n);
01050         return -1;
01051     }
01052 
01053     n->s = isp;
01054     n->t = t;
01055 
01056     if (main_session == NULL) {
01057         main_session = snmp_sess_session(isp);
01058     }
01059 
01060     for (a = agent_nsap_list; a != NULL && handle + 1 >= a->handle;
01061          a = a->next) {
01062         handle = a->handle;
01063         prevNext = &(a->next);
01064     }
01065 
01066     if (handle < INT_MAX) {
01067         n->handle = handle + 1;
01068         n->next = a;
01069         *prevNext = n;
01070         SNMP_FREE(s);
01071         return n->handle;
01072     } else {
01073         SNMP_FREE(s);
01074         SNMP_FREE(n);
01075         return -1;
01076     }
01077 }
01078 
01079 void
01080 netsnmp_deregister_agent_nsap(int handle)
01081 {
01082     agent_nsap     *a = NULL, **prevNext = &agent_nsap_list;
01083     int             main_session_deregistered = 0;
01084 
01085     DEBUGMSGTL(("netsnmp_deregister_agent_nsap", "handle %d\n", handle));
01086 
01087     for (a = agent_nsap_list; a != NULL && a->handle < handle; a = a->next) {
01088         prevNext = &(a->next);
01089     }
01090 
01091     if (a != NULL && a->handle == handle) {
01092         *prevNext = a->next;
01093         if (main_session == snmp_sess_session(a->s)) {
01094             main_session_deregistered = 1;
01095         }
01096         snmp_close(snmp_sess_session(a->s));
01097         /*
01098          * The above free()s the transport and session pointers.  
01099          */
01100         SNMP_FREE(a);
01101     }
01102 
01103     /*
01104      * If we've deregistered the session that main_session used to point to,
01105      * then make it point to another one, or in the last resort, make it equal
01106      * to NULL.  Basically this shouldn't ever happen in normal operation
01107      * because main_session starts off pointing at the first session added by
01108      * init_master_agent(), which then discards the handle.  
01109      */
01110 
01111     if (main_session_deregistered) {
01112         if (agent_nsap_list != NULL) {
01113             DEBUGMSGTL(("snmp_agent",
01114                         "WARNING: main_session ptr changed from %p to %p\n",
01115                         main_session, snmp_sess_session(agent_nsap_list->s)));
01116             main_session = snmp_sess_session(agent_nsap_list->s);
01117         } else {
01118             DEBUGMSGTL(("snmp_agent",
01119                         "WARNING: main_session ptr changed from %p to NULL\n",
01120                         main_session));
01121             main_session = NULL;
01122         }
01123     }
01124 }
01125 
01126 
01127 
01128 /*
01129  * 
01130  * This function has been modified to use the experimental
01131  * netsnmp_register_agent_nsap interface.  The major responsibility of this
01132  * function now is to interpret a string specified to the agent (via -p on the
01133  * command line, or from a configuration file) as a list of agent NSAPs on
01134  * which to listen for SNMP packets.  Typically, when you add a new transport
01135  * domain "foo", you add code here such that if the "foo" code is compiled
01136  * into the agent (SNMP_TRANSPORT_FOO_DOMAIN is defined), then a token of the
01137  * form "foo:bletch-3a0054ef%wob&wob" gets turned into the appropriate
01138  * transport descriptor.  netsnmp_register_agent_nsap is then called with that
01139  * transport descriptor and sets up a listening agent session on it.
01140  * 
01141  * Everything then works much as normal: the agent runs in an infinite loop
01142  * (in the snmpd.c/receive()routine), which calls snmp_read() when a request
01143  * is readable on any of the given transports.  This routine then traverses
01144  * the library 'Sessions' list to identify the relevant session and eventually
01145  * invokes '_sess_read'.  This then processes the incoming packet, calling the
01146  * pre_parse, parse, post_parse and callback routines in turn.
01147  * 
01148  * JBPN 20001117
01149  */
01150 
01151 int
01152 init_master_agent(void)
01153 {
01154     netsnmp_transport *transport;
01155     char           *cptr;
01156     char            buf[SPRINT_MAX_LEN];
01157     char           *st;
01158 
01159     /* default to a default cache size */
01160     netsnmp_set_lookup_cache_size(-1);
01161 
01162     if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
01163                                NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
01164         DEBUGMSGTL(("snmp_agent",
01165                     "init_master_agent; not master agent\n"));
01166 
01167         netsnmp_assert("agent role !master && !sub_agent");
01168         
01169         return 0;               /*  No error if ! MASTER_AGENT  */
01170     }
01171 #ifdef USING_AGENTX_MASTER_MODULE
01172     if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
01173                                NETSNMP_DS_AGENT_AGENTX_MASTER) == 1)
01174         real_init_master();
01175 #endif
01176 #ifdef USING_SMUX_MODULE
01177     if(should_init("smux"))
01178     real_init_smux();
01179 #endif
01180 
01181     /*
01182      * Have specific agent ports been specified?  
01183      */
01184     cptr = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
01185                                  NETSNMP_DS_AGENT_PORTS);
01186 
01187     if (cptr) {
01188         snprintf(buf, sizeof(buf), "%s", cptr);
01189         buf[ sizeof(buf)-1 ] = 0;
01190     } else {
01191         /*
01192          * No, so just specify the default port.  
01193          */
01194         buf[0] = 0;
01195     }
01196 
01197     DEBUGMSGTL(("snmp_agent", "final port spec: \"%s\"\n", buf));
01198     st = buf;
01199     do {
01200         /*
01201          * Specification format: 
01202          * 
01203          * NONE:                      (a pseudo-transport)
01204          * UDP:[address:]port        (also default if no transport is specified)
01205          * TCP:[address:]port         (if supported)
01206          * Unix:pathname              (if supported)
01207          * AAL5PVC:itf.vpi.vci        (if supported)
01208          * IPX:[network]:node[/port] (if supported)
01209          * 
01210          */
01211 
01212         cptr = st;
01213         st = strchr(st, ',');
01214         if (st)
01215             *st++ = '\0';
01216 
01217         DEBUGMSGTL(("snmp_agent", "installing master agent on port %s\n",
01218                     cptr));
01219 
01220         if (strncasecmp(cptr, "none", 4) == 0) {
01221             DEBUGMSGTL(("snmp_agent",
01222                         "init_master_agent; pseudo-transport \"none\" "
01223                         "requested\n"));
01224             return 0;
01225         }
01226         transport = netsnmp_transport_open_server("snmp", cptr);
01227 
01228         if (transport == NULL) {
01229             snmp_log(LOG_ERR, "Error opening specified endpoint \"%s\"\n",
01230                      cptr);
01231             return 1;
01232         }
01233 
01234         if (netsnmp_register_agent_nsap(transport) == 0) {
01235             snmp_log(LOG_ERR,
01236                      "Error registering specified transport \"%s\" as an "
01237                      "agent NSAP\n", cptr);
01238             return 1;
01239         } else {
01240             DEBUGMSGTL(("snmp_agent",
01241                         "init_master_agent; \"%s\" registered as an agent "
01242                         "NSAP\n", cptr));
01243         }
01244     } while(st && *st != '\0');
01245 
01246     return 0;
01247 }
01248 
01249 void
01250 clear_nsap_list(void)
01251 {
01252     DEBUGMSGTL(("clear_nsap_list", "clear the nsap list\n"));
01253 
01254     while (agent_nsap_list != NULL)
01255         netsnmp_deregister_agent_nsap(agent_nsap_list->handle);
01256 }
01257 
01258 void
01259 shutdown_master_agent(void)
01260 {
01261     clear_nsap_list();
01262 }
01263 
01264 
01265 netsnmp_agent_session *
01266 init_agent_snmp_session(netsnmp_session * session, netsnmp_pdu *pdu)
01267 {
01268     netsnmp_agent_session *asp = (netsnmp_agent_session *)
01269         calloc(1, sizeof(netsnmp_agent_session));
01270 
01271     if (asp == NULL) {
01272         return NULL;
01273     }
01274 
01275     DEBUGMSGTL(("snmp_agent","agent_sesion %08p created\n", asp));
01276     asp->session = session;
01277     asp->pdu = snmp_clone_pdu(pdu);
01278     asp->orig_pdu = snmp_clone_pdu(pdu);
01279     asp->rw = READ;
01280     asp->exact = TRUE;
01281     asp->next = NULL;
01282     asp->mode = RESERVE1;
01283     asp->status = SNMP_ERR_NOERROR;
01284     asp->index = 0;
01285     asp->oldmode = 0;
01286     asp->treecache_num = -1;
01287     asp->treecache_len = 0;
01288     asp->reqinfo = SNMP_MALLOC_TYPEDEF(netsnmp_agent_request_info);
01289     asp->flags = SNMP_AGENT_FLAGS_NONE;
01290     DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p created\n",
01291                 asp, asp->reqinfo));
01292 
01293     return asp;
01294 }
01295 
01296 void
01297 free_agent_snmp_session(netsnmp_agent_session *asp)
01298 {
01299     if (!asp)
01300         return;
01301 
01302     DEBUGMSGTL(("snmp_agent","agent_session %08p released\n", asp));
01303 
01304     netsnmp_remove_from_delegated(asp);
01305     
01306     DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p freed\n",
01307                 asp, asp->reqinfo));
01308     if (asp->orig_pdu)
01309         snmp_free_pdu(asp->orig_pdu);
01310     if (asp->pdu)
01311         snmp_free_pdu(asp->pdu);
01312     if (asp->reqinfo)
01313         netsnmp_free_agent_request_info(asp->reqinfo);
01314     if (asp->treecache) {
01315         SNMP_FREE(asp->treecache);
01316     }
01317     if (asp->bulkcache) {
01318         SNMP_FREE(asp->bulkcache);
01319     }
01320     if (asp->requests) {
01321         int             i;
01322         for (i = 0; i < asp->vbcount; i++) {
01323             netsnmp_free_request_data_sets(&asp->requests[i]);
01324         }
01325         SNMP_FREE(asp->requests);
01326     }
01327     if (asp->cache_store) {
01328         netsnmp_free_cachemap(asp->cache_store);
01329         asp->cache_store = NULL;
01330     }
01331     SNMP_FREE(asp);
01332 }
01333 
01334 int
01335 netsnmp_check_for_delegated(netsnmp_agent_session *asp)
01336 {
01337     int             i;
01338     netsnmp_request_info *request;
01339 
01340     if (NULL == asp->treecache)
01341         return 0;
01342 
01343     if (asp->flags & SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS)
01344         return 0;
01345     
01346     for (i = 0; i <= asp->treecache_num; i++) {
01347         for (request = asp->treecache[i].requests_begin; request;
01348              request = request->next) {
01349             if (request->delegated)
01350                 return 1;
01351         }
01352     }
01353     return 0;
01354 }
01355 
01356 int
01357 netsnmp_check_delegated_chain_for(netsnmp_agent_session *asp)
01358 {
01359     netsnmp_agent_session *asptmp;
01360     for (asptmp = agent_delegated_list; asptmp; asptmp = asptmp->next) {
01361         if (asptmp == asp)
01362             return 1;
01363     }
01364     return 0;
01365 }
01366 
01367 int
01368 netsnmp_check_for_delegated_and_add(netsnmp_agent_session *asp)
01369 {
01370     if (netsnmp_check_for_delegated(asp)) {
01371         if (!netsnmp_check_delegated_chain_for(asp)) {
01372             /*
01373              * add to delegated request chain 
01374              */
01375             asp->next = agent_delegated_list;
01376             agent_delegated_list = asp;
01377             DEBUGMSGTL(("snmp_agent", "delegate session == %08p\n", asp));
01378         }
01379         return 1;
01380     }
01381     return 0;
01382 }
01383 
01384 int
01385 netsnmp_remove_from_delegated(netsnmp_agent_session *asp)
01386 {
01387     netsnmp_agent_session *curr, *prev = NULL;
01388     
01389     for (curr = agent_delegated_list; curr; prev = curr, curr = curr->next) {
01390         /*
01391          * is this us?
01392          */
01393         if (curr != asp)
01394             continue;
01395         
01396         /*
01397          * remove from queue 
01398          */
01399         if (prev != NULL)
01400             prev->next = asp->next;
01401         else
01402             agent_delegated_list = asp->next;
01403 
01404         DEBUGMSGTL(("snmp_agent", "remove delegated session == %08p\n", asp));
01405 
01406         return 1;
01407     }
01408 
01409     return 0;
01410 }
01411 
01412 /*
01413  * netsnmp_remove_delegated_requests_for_session
01414  *
01415  * called when a session is being closed. Check all delegated requests to
01416  * see if the are waiting on this session, and if set, set the status for
01417  * that request to GENERR.
01418  */
01419 int
01420 netsnmp_remove_delegated_requests_for_session(netsnmp_session *sess)
01421 {
01422     netsnmp_agent_session *asp;
01423     int total_count = 0;
01424     
01425     for (asp = agent_delegated_list; asp; asp = asp->next) {
01426         /*
01427          * check each request
01428          */
01429         int i;
01430         int count = 0;
01431         netsnmp_request_info *request;
01432         for (i = 0; i <= asp->treecache_num; i++) {
01433             for (request = asp->treecache[i].requests_begin; request;
01434                 request = request->next) {
01435                 /*
01436                  * check session
01437                  */
01438                 netsnmp_assert(NULL!=request->subtree);
01439                 if(request->subtree->session != sess)
01440                     continue;
01441 
01442                 /*
01443                  * matched! mark request as done
01444                  */
01445                 netsnmp_request_set_error(request, SNMP_ERR_GENERR);
01446                 ++count;
01447             }
01448         }
01449         if (count) {
01450             asp->flags |= SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS;
01451             total_count += count;
01452         }
01453     }
01454 
01455     /*
01456      * if we found any, that request may be finished now
01457      */
01458     if(total_count) {
01459         DEBUGMSGTL(("snmp_agent", "removed %d delegated request(s) for session "
01460                     "%08p\n", total_count, sess));
01461         netsnmp_check_delegated_requests();
01462     }
01463     
01464     return total_count;
01465 }
01466 
01467 int
01468 netsnmp_check_queued_chain_for(netsnmp_agent_session *asp)
01469 {
01470     netsnmp_agent_session *asptmp;
01471     for (asptmp = netsnmp_agent_queued_list; asptmp; asptmp = asptmp->next) {
01472         if (asptmp == asp)
01473             return 1;
01474     }
01475     return 0;
01476 }
01477 
01478 int
01479 netsnmp_add_queued(netsnmp_agent_session *asp)
01480 {
01481     netsnmp_agent_session *asp_tmp;
01482 
01483     /*
01484      * first item?
01485      */
01486     if (NULL == netsnmp_agent_queued_list) {
01487         netsnmp_agent_queued_list = asp;
01488         return 1;
01489     }
01490 
01491 
01492     /*
01493      * add to end of queued request chain 
01494      */
01495     asp_tmp = netsnmp_agent_queued_list;
01496     for (; asp_tmp; asp_tmp = asp_tmp->next) {
01497         /*
01498          * already in queue?
01499          */
01500         if (asp_tmp == asp)
01501             break;
01502 
01503         /*
01504          * end of queue?
01505          */
01506         if (NULL == asp_tmp->next)
01507             asp_tmp->next = asp;
01508     }
01509     return 1;
01510 }
01511 
01512 
01513 int
01514 netsnmp_wrap_up_request(netsnmp_agent_session *asp, int status)
01515 {
01516     netsnmp_variable_list *var_ptr;
01517     int             i;
01518 
01519     /*
01520      * if this request was a set, clear the global now that we are
01521      * done.
01522      */
01523     if (asp == netsnmp_processing_set) {
01524         DEBUGMSGTL(("snmp_agent", "SET request complete, asp = %08p\n",
01525                     asp));
01526         netsnmp_processing_set = NULL;
01527     }
01528 
01529     if (asp->pdu) {
01530         /*
01531          * If we've got an error status, then this needs to be
01532          *  passed back up to the higher levels....
01533          */
01534         if ( status != 0  && asp->status == 0 )
01535             asp->status = status;
01536 
01537         switch (asp->pdu->command) {
01538             case SNMP_MSG_INTERNAL_SET_BEGIN:
01539             case SNMP_MSG_INTERNAL_SET_RESERVE1:
01540             case SNMP_MSG_INTERNAL_SET_RESERVE2:
01541             case SNMP_MSG_INTERNAL_SET_ACTION:
01542                 /*
01543                  * some stuff needs to be saved in special subagent cases 
01544                  */
01545                 save_set_cache(asp);
01546                 break;
01547 
01548             case SNMP_MSG_GETNEXT:
01549                 _fix_endofmibview(asp);
01550                 break;
01551 
01552             case SNMP_MSG_GETBULK:
01553                 /*
01554                  * for a GETBULK response we need to rearrange the varbinds 
01555                  */
01556                 _reorder_getbulk(asp);
01557                 break;
01558         }
01559 
01560         /*
01561          * May need to "dumb down" a SET error status for a
01562          * v1 query.  See RFC2576 - section 4.3
01563          */
01564 #ifndef NETSNMP_DISABLE_SNMPV1
01565         if ((asp->pdu->command == SNMP_MSG_SET) &&
01566             (asp->pdu->version == SNMP_VERSION_1)) {
01567             switch (asp->status) {
01568                 case SNMP_ERR_WRONGVALUE:
01569                 case SNMP_ERR_WRONGENCODING:
01570                 case SNMP_ERR_WRONGTYPE:
01571                 case SNMP_ERR_WRONGLENGTH:
01572                 case SNMP_ERR_INCONSISTENTVALUE:
01573                     status = SNMP_ERR_BADVALUE;
01574                     asp->status = SNMP_ERR_BADVALUE;
01575                     break;
01576                 case SNMP_ERR_NOACCESS:
01577                 case SNMP_ERR_NOTWRITABLE:
01578                 case SNMP_ERR_NOCREATION:
01579                 case SNMP_ERR_INCONSISTENTNAME:
01580                 case SNMP_ERR_AUTHORIZATIONERROR:
01581                     status = SNMP_ERR_NOSUCHNAME;
01582                     asp->status = SNMP_ERR_NOSUCHNAME;
01583                     break;
01584                 case SNMP_ERR_RESOURCEUNAVAILABLE:
01585                 case SNMP_ERR_COMMITFAILED:
01586                 case SNMP_ERR_UNDOFAILED:
01587                     status = SNMP_ERR_GENERR;
01588                     asp->status = SNMP_ERR_GENERR;
01589                     break;
01590             }
01591         }
01592         /*
01593          * Similarly we may need to "dumb down" v2 exception
01594          *  types to throw an error for a v1 query.
01595          *  See RFC2576 - section 4.1.2.3
01596          */
01597         if ((asp->pdu->command != SNMP_MSG_SET) &&
01598             (asp->pdu->version == SNMP_VERSION_1)) {
01599             for (var_ptr = asp->pdu->variables, i = 1;
01600                  var_ptr != NULL; var_ptr = var_ptr->next_variable, i++) {
01601                 switch (var_ptr->type) {
01602                     case SNMP_NOSUCHOBJECT:
01603                     case SNMP_NOSUCHINSTANCE:
01604                     case SNMP_ENDOFMIBVIEW:
01605                     case ASN_COUNTER64:
01606                         status = SNMP_ERR_NOSUCHNAME;
01607                         asp->status = SNMP_ERR_NOSUCHNAME;
01608                         asp->index = i;
01609                         break;
01610                 }
01611             }
01612         }
01613 #endif /* snmpv1 support */
01614     } 
01616     /*
01617      * Update the snmp error-count statistics
01618      *   XXX - should we include the V2 errors in this or not?
01619      */
01620 #define INCLUDE_V2ERRORS_IN_V1STATS
01621 
01622     switch (status) {
01623 #ifdef INCLUDE_V2ERRORS_IN_V1STATS
01624     case SNMP_ERR_WRONGVALUE:
01625     case SNMP_ERR_WRONGENCODING:
01626     case SNMP_ERR_WRONGTYPE:
01627     case SNMP_ERR_WRONGLENGTH:
01628     case SNMP_ERR_INCONSISTENTVALUE:
01629 #endif
01630     case SNMP_ERR_BADVALUE:
01631         snmp_increment_statistic(STAT_SNMPOUTBADVALUES);
01632         break;
01633 #ifdef INCLUDE_V2ERRORS_IN_V1STATS
01634     case SNMP_ERR_NOACCESS:
01635     case SNMP_ERR_NOTWRITABLE:
01636     case SNMP_ERR_NOCREATION:
01637     case SNMP_ERR_INCONSISTENTNAME:
01638     case SNMP_ERR_AUTHORIZATIONERROR:
01639 #endif
01640     case SNMP_ERR_NOSUCHNAME:
01641         snmp_increment_statistic(STAT_SNMPOUTNOSUCHNAMES);
01642         break;
01643 #ifdef INCLUDE_V2ERRORS_IN_V1STATS
01644     case SNMP_ERR_RESOURCEUNAVAILABLE:
01645     case SNMP_ERR_COMMITFAILED:
01646     case SNMP_ERR_UNDOFAILED:
01647 #endif
01648     case SNMP_ERR_GENERR:
01649         snmp_increment_statistic(STAT_SNMPOUTGENERRS);
01650         break;
01651 
01652     case SNMP_ERR_TOOBIG:
01653         snmp_increment_statistic(STAT_SNMPOUTTOOBIGS);
01654         break;
01655     }
01656 
01657     if ((status == SNMP_ERR_NOERROR) && (asp->pdu)) {
01658         snmp_increment_statistic_by((asp->pdu->command == SNMP_MSG_SET ?
01659                                      STAT_SNMPINTOTALSETVARS :
01660                                      STAT_SNMPINTOTALREQVARS),
01661                                     count_varbinds(asp->pdu->variables));
01662     } else {
01663         /*
01664          * Use a copy of the original request
01665          *   to report failures.
01666          */
01667         snmp_free_pdu(asp->pdu);
01668         asp->pdu = asp->orig_pdu;
01669         asp->orig_pdu = NULL;
01670     }
01671     if (asp->pdu) {
01672         asp->pdu->command = SNMP_MSG_RESPONSE;
01673         asp->pdu->errstat = asp->status;
01674         asp->pdu->errindex = asp->index;
01675         if (!snmp_send(asp->session, asp->pdu)) {
01676             netsnmp_variable_list *var_ptr;
01677             snmp_perror("send response");
01678             for (var_ptr = asp->pdu->variables; var_ptr != NULL;
01679                      var_ptr = var_ptr->next_variable) {
01680                 size_t  c_oidlen = 256, c_outlen = 0;
01681                 u_char *c_oid = (u_char *) malloc(c_oidlen);
01682 
01683                 if (c_oid) {
01684                     if (!sprint_realloc_objid (&c_oid, &c_oidlen, &c_outlen, 1,
01685                                                var_ptr->name,
01686                                                var_ptr->name_length)) {
01687                         snmp_log(LOG_ERR, "    -- %s [TRUNCATED]\n", c_oid);
01688                     } else {
01689                         snmp_log(LOG_ERR, "    -- %s\n", c_oid);
01690                     }
01691                     SNMP_FREE(c_oid);
01692                 }
01693             }
01694             snmp_free_pdu(asp->pdu);
01695             asp->pdu = NULL;
01696         }
01697         snmp_increment_statistic(STAT_SNMPOUTPKTS);
01698         snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES);
01699         asp->pdu = NULL; /* yyy-rks: redundant, no? */
01700         netsnmp_remove_and_free_agent_snmp_session(asp);
01701     }
01702     return 1;
01703 }
01704 
01705 void
01706 dump_sess_list(void)
01707 {
01708     netsnmp_agent_session *a;
01709 
01710     DEBUGMSGTL(("snmp_agent", "DUMP agent_sess_list -> "));
01711     for (a = agent_session_list; a != NULL; a = a->next) {
01712         DEBUGMSG(("snmp_agent", "%08p[session %08p] -> ", a, a->session));
01713     }
01714     DEBUGMSG(("snmp_agent", "[NIL]\n"));
01715 }
01716 
01717 void
01718 netsnmp_remove_and_free_agent_snmp_session(netsnmp_agent_session *asp)
01719 {
01720     netsnmp_agent_session *a, **prevNext = &agent_session_list;
01721 
01722     DEBUGMSGTL(("snmp_agent", "REMOVE session == %08p\n", asp));
01723 
01724     for (a = agent_session_list; a != NULL; a = *prevNext) {
01725         if (a == asp) {
01726             *prevNext = a->next;
01727             a->next = NULL;
01728             free_agent_snmp_session(a);
01729             asp = NULL;
01730             break;
01731         } else {
01732             prevNext = &(a->next);
01733         }
01734     }
01735 
01736     if (a == NULL && asp != NULL) {
01737         /*
01738          * We coulnd't find it on the list, so free it anyway.  
01739          */
01740         free_agent_snmp_session(asp);
01741     }
01742 }
01743 
01744 void
01745 netsnmp_free_agent_snmp_session_by_session(netsnmp_session * sess,
01746                                            void (*free_request)
01747                                            (netsnmp_request_list *))
01748 {
01749     netsnmp_agent_session *a, *next, **prevNext = &agent_session_list;
01750 
01751     DEBUGMSGTL(("snmp_agent", "REMOVE session == %08p\n", sess));
01752 
01753     for (a = agent_session_list; a != NULL; a = next) {
01754         if (a->session == sess) {
01755             *prevNext = a->next;
01756             next = a->next;
01757             free_agent_snmp_session(a);
01758         } else {
01759             prevNext = &(a->next);
01760             next = a->next;
01761         }
01762     }
01763 }
01764 
01766 int
01767 handle_snmp_packet(int op, netsnmp_session * session, int reqid,
01768                    netsnmp_pdu *pdu, void *magic)
01769 {
01770     netsnmp_agent_session *asp;
01771     int             status, access_ret, rc;
01772 
01773     /*
01774      * We only support receiving here.  
01775      */
01776     if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
01777         return 1;
01778     }
01779 
01780     /*
01781      * RESPONSE messages won't get this far, but TRAP-like messages
01782      * might.  
01783      */
01784     if (pdu->command == SNMP_MSG_TRAP || pdu->command == SNMP_MSG_INFORM ||
01785         pdu->command == SNMP_MSG_TRAP2) {
01786         DEBUGMSGTL(("snmp_agent", "received trap-like PDU (%02x)\n",
01787                     pdu->command));
01788         pdu->command = SNMP_MSG_TRAP2;
01789         snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS);
01790         return 1;
01791     }
01792 
01793     /*
01794      * send snmpv3 authfail trap.
01795      */
01796     if (pdu->version  == SNMP_VERSION_3 && 
01797         session->s_snmp_errno == SNMPERR_USM_AUTHENTICATIONFAILURE) {
01798            send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
01799            return 1;
01800     } 
01801         
01802     if (magic == NULL) {
01803         asp = init_agent_snmp_session(session, pdu);
01804         status = SNMP_ERR_NOERROR;
01805     } else {
01806         asp = (netsnmp_agent_session *) magic;
01807         status = asp->status;
01808     }
01809 
01810     if ((access_ret = check_access(asp->pdu)) != 0) {
01811         if (access_ret == VACM_NOSUCHCONTEXT) {
01812             /*
01813              * rfc3413 section 3.2, step 5 says that we increment the
01814              * counter but don't return a response of any kind 
01815              */
01816 
01817             /*
01818              * we currently don't support unavailable contexts, as
01819              * there is no reason to that I currently know of 
01820              */
01821             snmp_increment_statistic(STAT_SNMPUNKNOWNCONTEXTS);
01822 
01823             /*
01824              * drop the request 
01825              */
01826             netsnmp_remove_and_free_agent_snmp_session(asp);
01827             return 0;
01828         } else {
01829             /*
01830              * access control setup is incorrect 
01831              */
01832             send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
01833 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
01834 #if defined(NETSNMP_DISABLE_SNMPV1)
01835             if (asp->pdu->version != SNMP_VERSION_2c) {
01836 #else
01837 #if defined(NETSNMP_DISABLE_SNMPV2C)
01838             if (asp->pdu->version != SNMP_VERSION_1) {
01839 #else
01840             if (asp->pdu->version != SNMP_VERSION_1
01841                 && asp->pdu->version != SNMP_VERSION_2c) {
01842 #endif
01843 #endif
01844                 asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR;
01845                 asp->pdu->command = SNMP_MSG_RESPONSE;
01846                 snmp_increment_statistic(STAT_SNMPOUTPKTS);
01847                 if (!snmp_send(asp->session, asp->pdu))
01848                     snmp_free_pdu(asp->pdu);
01849                 asp->pdu = NULL;
01850                 netsnmp_remove_and_free_agent_snmp_session(asp);
01851                 return 1;
01852             } else {
01853 #endif /* support for community based SNMP */
01854                 /*
01855                  * drop the request 
01856                  */
01857                 netsnmp_remove_and_free_agent_snmp_session(asp);
01858                 return 0;
01859 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
01860             }
01861 #endif /* support for community based SNMP */
01862         }
01863     }
01864 
01865     rc = netsnmp_handle_request(asp, status);
01866 
01867     /*
01868      * done 
01869      */
01870     DEBUGMSGTL(("snmp_agent", "end of handle_snmp_packet, asp = %08p\n",
01871                 asp));
01872     return rc;
01873 }
01874 
01875 netsnmp_request_info *
01876 netsnmp_add_varbind_to_cache(netsnmp_agent_session *asp, int vbcount,
01877                              netsnmp_variable_list * varbind_ptr,
01878                              netsnmp_subtree *tp)
01879 {
01880     netsnmp_request_info *request = NULL;
01881     int             cacheid;
01882 
01883     DEBUGMSGTL(("snmp_agent", "add_vb_to_cache(%8p, %d, ", asp, vbcount));
01884     DEBUGMSGOID(("snmp_agent", varbind_ptr->name,
01885                  varbind_ptr->name_length));
01886     DEBUGMSG(("snmp_agent", ", %8p)\n", tp));
01887 
01888     if (tp &&
01889         (asp->pdu->command == SNMP_MSG_GETNEXT ||
01890          asp->pdu->command == SNMP_MSG_GETBULK)) {
01891         int result;
01892         int prefix_len;
01893 
01894         prefix_len = netsnmp_oid_find_prefix(tp->start_a,
01895                                              tp->start_len,
01896                                              tp->end_a, tp->end_len);
01897         if (prefix_len < 1) {
01898             result = VACM_NOTINVIEW; /* ack...  bad bad thing happened */
01899         } else {
01900             result =
01901                 netsnmp_acm_check_subtree(asp->pdu, tp->start_a, prefix_len);
01902         }
01903 
01904         while (result == VACM_NOTINVIEW) {
01905             /* the entire subtree is not in view. Skip it. */
01913             tp = tp->next;
01914             if (tp) {
01915                 prefix_len = netsnmp_oid_find_prefix(tp->start_a,
01916                                                      tp->start_len,
01917                                                      tp->end_a,
01918                                                      tp->end_len);
01919                 if (prefix_len < 1) {
01920                     /* ack...  bad bad thing happened */
01921                     result = VACM_NOTINVIEW;
01922                 } else {
01923                     result =
01924                         netsnmp_acm_check_subtree(asp->pdu,
01925                                                   tp->start_a, prefix_len);
01926                 }
01927             }
01928             else
01929                 break;
01930         }
01931     }
01932     if (tp == NULL) {
01933         /*
01934          * no appropriate registration found 
01935          */
01936         /*
01937          * make up the response ourselves 
01938          */
01939         switch (asp->pdu->command) {
01940         case SNMP_MSG_GETNEXT:
01941         case SNMP_MSG_GETBULK:
01942             varbind_ptr->type = SNMP_ENDOFMIBVIEW;
01943             break;
01944 
01945         case SNMP_MSG_SET:
01946         case SNMP_MSG_GET:
01947             varbind_ptr->type = SNMP_NOSUCHOBJECT;
01948             break;
01949 
01950         default:
01951             return NULL;        /* shouldn't get here */
01952         }
01953     } else {
01954         DEBUGMSGTL(("snmp_agent", "tp->start "));
01955         DEBUGMSGOID(("snmp_agent", tp->start_a, tp->start_len));
01956         DEBUGMSG(("snmp_agent", ", tp->end "));
01957         DEBUGMSGOID(("snmp_agent", tp->end_a, tp->end_len));
01958         DEBUGMSG(("snmp_agent", ", \n"));
01959 
01960         /*
01961          * malloc the request structure 
01962          */
01963         request = &(asp->requests[vbcount - 1]);
01964         request->index = vbcount;
01965         request->delegated = 0;
01966         request->processed = 0;
01967         request->status = 0;
01968         request->subtree = tp;
01969         request->agent_req_info = asp->reqinfo;
01970         if (request->parent_data) {
01971             netsnmp_free_request_data_sets(request);
01972         }
01973         DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n",
01974                     asp, asp->reqinfo));
01975 
01976         /*
01977          * for non-SET modes, set the type to NULL 
01978          */
01979         if (!MODE_IS_SET(asp->pdu->command)) {
01980         DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n",
01981                     asp, asp->reqinfo));
01982             if (varbind_ptr->type == ASN_PRIV_INCL_RANGE) {
01983                 DEBUGMSGTL(("snmp_agent", "varbind %d is inclusive\n",
01984                             request->index));
01985                 request->inclusive = 1;
01986             }
01987             varbind_ptr->type = ASN_NULL;
01988         }
01989 
01990         /*
01991          * place them in a cache 
01992          */
01993         if (tp->global_cacheid) {
01994             /*
01995              * we need to merge all marked subtrees together 
01996              */
01997             if (asp->cache_store && -1 !=
01998                 (cacheid = netsnmp_get_local_cachid(asp->cache_store,
01999                                                     tp->global_cacheid))) {
02000             } else {
02001                 cacheid = ++(asp->treecache_num);
02002                 netsnmp_get_or_add_local_cachid(&asp->cache_store,
02003                                                 tp->global_cacheid,
02004                                                 cacheid);
02005                 goto mallocslot;        /* XXX: ick */
02006             }
02007         } else if (tp->cacheid > -1 && tp->cacheid <= asp->treecache_num &&
02008                    asp->treecache[tp->cacheid].subtree == tp) {
02009             /*
02010              * we have already added a request to this tree
02011              * pointer before 
02012              */
02013             cacheid = tp->cacheid;
02014         } else {
02015             cacheid = ++(asp->treecache_num);
02016           mallocslot:
02017             /*
02018              * new slot needed 
02019              */
02020             if (asp->treecache_num >= asp->treecache_len) {
02021                 /*
02022                  * exapand cache array 
02023                  */
02024                 /*
02025                  * WWW: non-linear expansion needed (with cap) 
02026                  */
02027 #define CACHE_GROW_SIZE 16
02028                 asp->treecache_len =
02029                     (asp->treecache_len + CACHE_GROW_SIZE);
02030                 asp->treecache =
02031                     realloc(asp->treecache,
02032                             sizeof(netsnmp_tree_cache) *
02033                             asp->treecache_len);
02034                 if (asp->treecache == NULL)
02035                     return NULL;
02036                 memset(&(asp->treecache[cacheid]), 0x00,
02037                        sizeof(netsnmp_tree_cache) * (CACHE_GROW_SIZE));
02038             }
02039             asp->treecache[cacheid].subtree = tp;
02040             asp->treecache[cacheid].requests_begin = request;
02041             tp->cacheid = cacheid;
02042         }
02043 
02044         /*
02045          * if this is a search type, get the ending range oid as well 
02046          */
02047         if (asp->pdu->command == SNMP_MSG_GETNEXT ||
02048             asp->pdu->command == SNMP_MSG_GETBULK) {
02049             request->range_end = tp->end_a;
02050             request->range_end_len = tp->end_len;
02051         } else {
02052             request->range_end = NULL;
02053             request->range_end_len = 0;
02054         }
02055 
02056         /*
02057          * link into chain 
02058          */
02059         if (asp->treecache[cacheid].requests_end)
02060             asp->treecache[cacheid].requests_end->next = request;
02061         request->next = NULL;
02062         request->prev = asp->treecache[cacheid].requests_end;
02063         asp->treecache[cacheid].requests_end = request;
02064 
02065         /*
02066          * add the given request to the list of requests they need
02067          * to handle results for 
02068          */
02069         request->requestvb = request->requestvb_start = varbind_ptr;
02070     }
02071     return request;
02072 }
02073 
02074 /*
02075  * check the ACM(s) for the results on each of the varbinds.
02076  * If ACM disallows it, replace the value with type
02077  * 
02078  * Returns number of varbinds with ACM errors
02079  */
02080 int
02081 check_acm(netsnmp_agent_session *asp, u_char type)
02082 {
02083     int             view;
02084     int             i, j, k;
02085     netsnmp_request_info *request;
02086     int             ret = 0;
02087     netsnmp_variable_list *vb, *vb2, *vbc;
02088     int             earliest = 0;
02089 
02090     for (i = 0; i <= asp->treecache_num; i++) {
02091         for (request = asp->treecache[i].requests_begin;
02092              request; request = request->next) {
02093             /*
02094              * for each request, run it through in_a_view() 
02095              */
02096             earliest = 0;
02097             for(j = request->repeat, vb = request->requestvb_start;
02098                 vb && j > -1;
02099                 j--, vb = vb->next_variable) {
02100                 if (vb->type != ASN_NULL &&
02101                     vb->type != ASN_PRIV_RETRY) { /* not yet processed */
02102                     view =
02103                         in_a_view(vb->name, &vb->name_length,
02104                                   asp->pdu, vb->type);
02105 
02106                     /*
02107                      * if a ACM error occurs, mark it as type passed in 
02108                      */
02109                     if (view != VACM_SUCCESS) {
02110                         ret++;
02111                         if (request->repeat < request->orig_repeat) {
02112                             /* basically this means a GETBULK */
02113                             request->repeat++;
02114                             if (!earliest) {
02115                                 request->requestvb = vb;
02116                                 earliest = 1;
02117                             }
02118 
02119                             /* ugh.  if a whole now exists, we need to
02120                                move the contents up the chain and fill
02121                                in at the end else we won't end up
02122                                lexographically sorted properly */
02123                             if (j > -1 && vb->next_variable &&
02124                                 vb->next_variable->type != ASN_NULL &&
02125                                 vb->next_variable->type != ASN_PRIV_RETRY) {
02126                                 for(k = j, vbc = vb, vb2 = vb->next_variable;
02127                                     k > -2 && vbc && vb2;
02128                                     k--, vbc = vb2, vb2 = vb2->next_variable) {
02129                                     /* clone next into the current */
02130                                     snmp_clone_var(vb2, vbc);
02131                                     vbc->next_variable = vb2;
02132                                 }
02133                             }
02134                         }
02135                         snmp_set_var_typed_value(vb, type, NULL, 0);
02136                     }
02137                 }
02138             }
02139         }
02140     }
02141     return ret;
02142 }
02143 
02144 
02145 int
02146 netsnmp_create_subtree_cache(netsnmp_agent_session *asp)
02147 {
02148     netsnmp_subtree *tp;
02149     netsnmp_variable_list *varbind_ptr, *vbsave, *vbptr, **prevNext;
02150     int             view;
02151     int             vbcount = 0;
02152     int             bulkcount = 0, bulkrep = 0;
02153     int             i = 0, n = 0, r = 0;
02154     netsnmp_request_info *request;
02155 
02156     if (asp->treecache == NULL && asp->treecache_len == 0) {
02157         asp->treecache_len = SNMP_MAX(1 + asp->vbcount / 4, 16);
02158         asp->treecache =
02159             calloc(asp->treecache_len, sizeof(netsnmp_tree_cache));
02160         if (asp->treecache == NULL)
02161             return SNMP_ERR_GENERR;
02162     }
02163     asp->treecache_num = -1;
02164 
02165     if (asp->pdu->command == SNMP_MSG_GETBULK) {
02166         /*
02167          * getbulk prep 
02168          */
02169         int             count = count_varbinds(asp->pdu->variables);
02170         if (asp->pdu->errstat < 0) {
02171             asp->pdu->errstat = 0;
02172         }
02173         if (asp->pdu->errindex < 0) {
02174             asp->pdu->errindex = 0;
02175         }
02176 
02177         if (asp->pdu->errstat < count) {
02178             n = asp->pdu->errstat;
02179         } else {
02180             n = count;
02181         }
02182         if ((r = count - n) <= 0) {
02183             r = 0;
02184             asp->bulkcache = NULL;
02185         } else {
02186             int numresponses;
02187             int           maxbulk =
02188                 netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
02189                                    NETSNMP_DS_AGENT_MAX_GETBULKREPEATS);
02190             int maxresponses =
02191                 netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
02192                                    NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES);
02193 
02194             if (maxresponses == 0)
02195                 maxresponses = 100;   /* more than reasonable default */
02196 
02197             if (maxbulk == 0)
02198                 maxbulk = -1;
02199 
02200             /* limit getbulk number of repeats to a configured size */
02201             if (asp->pdu->errindex > maxbulk && maxbulk != -1) {
02202                 asp->pdu->errindex = maxbulk;
02203             }
02204 
02205             numresponses = asp->pdu->errindex * r;
02206 
02207             /* limit getbulk number of getbulk responses to a configured size */
02208             if (maxresponses != -1 && numresponses > maxresponses) {
02209                 /* attempt to truncate this */
02210                 asp->pdu->errindex = maxresponses/r;
02211                 numresponses = asp->pdu->errindex * r;
02212                 DEBUGMSGTL(("snmp_agent", "truncating number of getbulk repeats to %d\n", asp->pdu->errindex));
02213             }
02214 
02215             asp->bulkcache =
02216                 (netsnmp_variable_list **) malloc(numresponses *
02217                                                   sizeof(struct
02218                                                          varbind_list *));
02219             if (!asp->bulkcache) {
02220                 DEBUGMSGTL(("snmp_agent", "Bulkcache malloc failed\n"));
02221                 return SNMP_ERR_GENERR;
02222             }
02223         }
02224         DEBUGMSGTL(("snmp_agent", "GETBULK N = %d, M = %d, R = %d\n",
02225                     n, asp->pdu->errindex, r));
02226     }
02227 
02228     /*
02229      * collect varbinds into their registered trees 
02230      */
02231     prevNext = &(asp->pdu->variables);
02232     for (varbind_ptr = asp->pdu->variables; varbind_ptr;
02233          varbind_ptr = vbsave) {
02234 
02235         /*
02236          * getbulk mess with this pointer, so save it 
02237          */
02238         vbsave = varbind_ptr->next_variable;
02239 
02240         if (asp->pdu->command == SNMP_MSG_GETBULK) {
02241             if (n > 0) {
02242                 n--;
02243             } else {
02244                 /*
02245                  * repeate request varbinds on GETBULK.  These will
02246                  * have to be properly rearranged later though as
02247                  * responses are supposed to actually be interlaced
02248                  * with each other.  This is done with the asp->bulkcache. 
02249                  */
02250                 bulkrep = asp->pdu->errindex - 1;
02251                 if (asp->pdu->errindex > 0) {
02252                     vbptr = varbind_ptr;
02253                     asp->bulkcache[bulkcount++] = vbptr;
02254 
02255                     for (i = 1; i < asp->pdu->errindex; i++) {
02256                         vbptr->next_variable =
02257                             SNMP_MALLOC_STRUCT(variable_list);
02258                         /*
02259                          * don't clone the oid as it's got to be
02260                          * overwritten anyway 
02261                          */
02262                         if (!vbptr->next_variable) {
02263                             /*
02264                              * XXXWWW: ack!!! 
02265                              */
02266                             DEBUGMSGTL(("snmp_agent", "NextVar malloc failed\n"));
02267                         } else {
02268                             vbptr = vbptr->next_variable;
02269                             vbptr->name_length = 0;
02270                             vbptr->type = ASN_NULL;
02271                             asp->bulkcache[bulkcount++] = vbptr;
02272                         }
02273                     }
02274                     vbptr->next_variable = vbsave;
02275                 } else {
02276                     /*
02277                      * 0 repeats requested for this varbind, so take it off
02278                      * the list.  
02279                      */
02280                     vbptr = varbind_ptr;
02281                     *prevNext = vbptr->next_variable;
02282                     vbptr->next_variable = NULL;
02283                     snmp_free_varbind(vbptr);
02284                     asp->vbcount--;
02285                     continue;
02286                 }
02287             }
02288         }
02289 
02290         /*
02291          * count the varbinds 
02292          */
02293         ++vbcount;
02294 
02295         /*
02296          * find the owning tree 
02297          */
02298         tp = netsnmp_subtree_find(varbind_ptr->name, varbind_ptr->name_length,
02299                                   NULL, asp->pdu->contextName);
02300 
02301         /*
02302          * check access control 
02303          */
02304         switch (asp->pdu->command) {
02305         case SNMP_MSG_GET:
02306             view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
02307                              asp->pdu, varbind_ptr->type);
02308             if (view != VACM_SUCCESS)
02309                 snmp_set_var_typed_value(varbind_ptr, SNMP_NOSUCHOBJECT,
02310                                          NULL, 0);
02311             break;
02312 
02313         case SNMP_MSG_SET:
02314             view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
02315                              asp->pdu, varbind_ptr->type);
02316             if (view != VACM_SUCCESS)
02317                 return SNMP_ERR_NOACCESS;
02318             break;
02319 
02320         case SNMP_MSG_GETNEXT:
02321         case SNMP_MSG_GETBULK:
02322         default:
02323             view = VACM_SUCCESS;
02324             /*
02325              * XXXWWW: check VACM here to see if "tp" is even worthwhile 
02326              */
02327         }
02328         if (view == VACM_SUCCESS) {
02329             request = netsnmp_add_varbind_to_cache(asp, vbcount, varbind_ptr,
02330                                                    tp);
02331             if (request && asp->pdu->command == SNMP_MSG_GETBULK) {
02332                 request->repeat = request->orig_repeat = bulkrep;
02333             }
02334         }
02335 
02336         prevNext = &(varbind_ptr->next_variable);
02337     }
02338 
02339     return SNMPERR_SUCCESS;
02340 }
02341 
02342 /*
02343  * this function is only applicable in getnext like contexts 
02344  */
02345 int
02346 netsnmp_reassign_requests(netsnmp_agent_session *asp)
02347 {
02348     /*
02349      * assume all the requests have been filled or rejected by the
02350      * subtrees, so reassign the rejected ones to the next subtree in
02351      * the chain 
02352      */
02353 
02354     int             i;
02355 
02356     /*
02357      * get old info 
02358      */
02359     netsnmp_tree_cache *old_treecache = asp->treecache;
02360 
02361     /*
02362      * malloc new space 
02363      */
02364     asp->treecache =
02365         (netsnmp_tree_cache *) calloc(asp->treecache_len,
02366                                       sizeof(netsnmp_tree_cache));
02367     asp->treecache_num = -1;
02368     if (asp->cache_store) {
02369         netsnmp_free_cachemap(asp->cache_store);
02370         asp->cache_store = NULL;
02371     }
02372 
02373     for (i = 0; i < asp->vbcount; i++) {
02374         if (asp->requests[i].requestvb == NULL) {
02375             /*
02376              * Occurs when there's a mixture of still active
02377              *   and "endOfMibView" repetitions
02378              */
02379             continue;
02380         }
02381         if (asp->requests[i].requestvb->type == ASN_NULL) {
02382             if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index,
02383                                               asp->requests[i].requestvb,
02384                                               asp->requests[i].subtree->next)) {
02385                 if (old_treecache != NULL) {
02386                     SNMP_FREE(old_treecache);
02387                     old_treecache = NULL;
02388                 }
02389             }
02390         } else if (asp->requests[i].requestvb->type == ASN_PRIV_RETRY) {
02391             /*
02392              * re-add the same subtree 
02393              */
02394             asp->requests[i].requestvb->type = ASN_NULL;
02395             if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index,
02396                                               asp->requests[i].requestvb,
02397                                               asp->requests[i].subtree)) {
02398                 if (old_treecache != NULL) {
02399                     SNMP_FREE(old_treecache);
02400                     old_treecache = NULL;
02401                 }
02402             }
02403         }
02404     }
02405 
02406     if (old_treecache != NULL) {
02407         SNMP_FREE(old_treecache);
02408     }
02409     return SNMP_ERR_NOERROR;
02410 }
02411 
02412 void
02413 netsnmp_delete_request_infos(netsnmp_request_info *reqlist)
02414 {
02415     while (reqlist) {
02416         netsnmp_free_request_data_sets(reqlist);
02417         reqlist = reqlist->next;
02418     }
02419 }
02420 
02421 void
02422 netsnmp_delete_subtree_cache(netsnmp_agent_session *asp)
02423 {
02424     while (asp->treecache_num >= 0) {
02425         /*
02426          * don't delete subtrees 
02427          */
02428         netsnmp_delete_request_infos(asp->treecache[asp->treecache_num].
02429                                      requests_begin);
02430         asp->treecache_num--;
02431     }
02432 }
02433 
02434 /*
02435  * check all requests for errors
02436  *
02437  * @Note:
02438  * This function is a little different from the others in that
02439  * it does not use any linked lists, instead using the original
02440  * asp requests array. This is of particular importance for
02441  * cases where the linked lists are unreliable. One known instance
02442  * of this scenario occurs when the row_merge helper is used, which
02443  * may temporarily disrupts linked lists during its (and its childrens)
02444  * handling of requests.
02445  */
02446 int
02447 netsnmp_check_all_requests_error(netsnmp_agent_session *asp,
02448                                  int look_for_specific)
02449 {
02450     int i;
02451 
02452     /*
02453      * find any errors marked in the requests 
02454      */
02455     for( i = 0; i < asp->vbcount; ++i ) {
02456         if ((SNMP_ERR_NOERROR != asp->requests[i].status) &&
02457             (!look_for_specific ||
02458              asp->requests[i].status == look_for_specific))
02459             return asp->requests[i].status;
02460     }
02461 
02462     return SNMP_ERR_NOERROR;
02463 }
02464 
02465 int
02466 netsnmp_check_requests_error(netsnmp_request_info *requests)
02467 {
02468     /*
02469      * find any errors marked in the requests 
02470      */
02471     for (;requests;requests = requests->next) {
02472         if (requests->status != SNMP_ERR_NOERROR)
02473             return requests->status;
02474     }
02475     return SNMP_ERR_NOERROR;
02476 }
02477 
02478 int
02479 netsnmp_check_requests_status(netsnmp_agent_session *asp,
02480                               netsnmp_request_info *requests,
02481                               int look_for_specific)
02482 {
02483     /*
02484      * find any errors marked in the requests 
02485      */
02486     while (requests) {
02487         if(requests->agent_req_info != asp->reqinfo) {
02488             DEBUGMSGTL(("verbose:asp",
02489                         "**reqinfo %p doesn't match cached reqinfo %p\n",
02490                         asp->reqinfo, requests->agent_req_info));
02491         }
02492         if (requests->status != SNMP_ERR_NOERROR &&
02493             (!look_for_specific || requests->status == look_for_specific)
02494             && (look_for_specific || asp->index == 0
02495                 || requests->index < asp->index)) {
02496             asp->index = requests->index;
02497             asp->status = requests->status;
02498         }
02499         requests = requests->next;
02500     }
02501     return asp->status;
02502 }
02503 
02504 int
02505 netsnmp_check_all_requests_status(netsnmp_agent_session *asp,
02506                                   int look_for_specific)
02507 {
02508     int             i;
02509     for (i = 0; i <= asp->treecache_num; i++) {
02510         netsnmp_check_requests_status(asp,
02511                                       asp->treecache[i].requests_begin,
02512                                       look_for_specific);
02513     }
02514     return asp->status;
02515 }
02516 
02517 int
02518 handle_var_requests(netsnmp_agent_session *asp)
02519 {
02520     int             i, retstatus = SNMP_ERR_NOERROR,
02521         status = SNMP_ERR_NOERROR, final_status = SNMP_ERR_NOERROR;
02522     netsnmp_handler_registration *reginfo;
02523 
02524     asp->reqinfo->asp = asp;
02525     asp->reqinfo->mode = asp->mode;
02526 
02527     /*
02528      * now, have the subtrees in the cache go search for their results 
02529      */
02530     for (i = 0; i <= asp->treecache_num; i++) {
02531         /*
02532          * don't call handlers w/null reginfo.
02533          * - when is this? sub agent disconnected while request processing?
02534          * - should this case encompass more of this subroutine?
02535          *   - does check_request_status make send if handlers weren't called?
02536          */
02537         if(NULL != asp->treecache[i].subtree->reginfo) {
02538             reginfo = asp->treecache[i].subtree->reginfo;
02539             status = netsnmp_call_handlers(reginfo, asp->reqinfo,
02540                                            asp->treecache[i].requests_begin);
02541         }
02542         else
02543             status = SNMP_ERR_GENERR;
02544 
02545         /*
02546          * find any errors marked in the requests.  For later parts of
02547          * SET processing, only check for new errors specific to that
02548          * set processing directive (which must superceed the previous
02549          * errors).
02550          */
02551         switch (asp->mode) {
02552         case MODE_SET_COMMIT:
02553             retstatus = netsnmp_check_requests_status(asp,
02554                                                       asp->treecache[i].
02555                                                       requests_begin,
02556                                                       SNMP_ERR_COMMITFAILED);
02557             break;
02558 
02559         case MODE_SET_UNDO:
02560             retstatus = netsnmp_check_requests_status(asp,
02561                                                       asp->treecache[i].
02562                                                       requests_begin,
02563                                                       SNMP_ERR_UNDOFAILED);
02564             break;
02565 
02566         default:
02567             retstatus = netsnmp_check_requests_status(asp,
02568                                                       asp->treecache[i].
02569                                                       requests_begin, 0);
02570             break;
02571         }
02572 
02573         /*
02574          * always take lowest varbind if possible 
02575          */
02576         if (retstatus != SNMP_ERR_NOERROR) {
02577             status = retstatus;
02578         }
02579 
02580         /*
02581          * other things we know less about (no index) 
02582          */
02583         /*
02584          * WWW: drop support for this? 
02585          */
02586         if (final_status == SNMP_ERR_NOERROR && status != SNMP_ERR_NOERROR) {
02587             /*
02588              * we can't break here, since some processing needs to be
02589              * done for all requests anyway (IE, SET handling for UNDO
02590              * needs to be called regardless of previous status
02591              * results.
02592              * WWW:  This should be predictable though and
02593              * breaking should be possible in some cases (eg GET,
02594              * GETNEXT, ...) 
02595              */
02596             final_status = status;
02597         }
02598     }
02599 
02600     return final_status;
02601 }
02602 
02603 void
02604 netsnmp_check_delegated_requests(void)
02605 {
02606     netsnmp_agent_session *asp, *prev_asp = NULL, *next_asp = NULL;
02607 
02608     for (asp = agent_delegated_list; asp; asp = next_asp) {
02609         next_asp = asp->next;   /* save in case we clean up asp */
02610         if (!netsnmp_check_for_delegated(asp)) {
02611 
02612             /*
02613              * we're done with this one, remove from queue 
02614              */
02615             if (prev_asp != NULL)
02616                 prev_asp->next = asp->next;
02617             else
02618                 agent_delegated_list = asp->next;
02619             asp->next = NULL;
02620 
02621             /*
02622              * check request status
02623              */
02624             netsnmp_check_all_requests_status(asp, 0);
02625             
02626             /*
02627              * continue processing or finish up 
02628              */
02629             check_delayed_request(asp);
02630 
02631             /*
02632              * if head was removed, don't drop it if it
02633              * was it re-queued
02634              */
02635             if ((prev_asp == NULL) && (agent_delegated_list == asp)) {
02636                 prev_asp = asp;
02637             }
02638         } else {
02639 
02640             /*
02641              * asp is still on the queue
02642              */
02643             prev_asp = asp;
02644         }
02645     }
02646 }
02647 
02648 /*
02649  * loop through our sessions known delegated sessions and check to see
02650  * if they've completed yet. If there are no more delegated sessions,
02651  * check for and process any queued requests
02652  */
02653 void
02654 netsnmp_check_outstanding_agent_requests(void)
02655 {
02656     netsnmp_agent_session *asp;
02657 
02658     /*
02659      * deal with delegated requests
02660      */
02661     netsnmp_check_delegated_requests();
02662 
02663     /*
02664      * if we are processing a set and there are more delegated
02665      * requests, keep waiting before getting to queued requests.
02666      */
02667     if (netsnmp_processing_set && (NULL != agent_delegated_list))
02668         return;
02669 
02670     while (netsnmp_agent_queued_list) {
02671 
02672         /*
02673          * if we are processing a set, the first item better be
02674          * the set being (or waiting to be) processed.
02675          */
02676         netsnmp_assert((!netsnmp_processing_set) ||
02677                        (netsnmp_processing_set == netsnmp_agent_queued_list));
02678 
02679         /*
02680          * if the top request is a set, don't pop it
02681          * off if there are delegated requests
02682          */
02683         if ((netsnmp_agent_queued_list->pdu->command == SNMP_MSG_SET) &&
02684             (agent_delegated_list)) {
02685 
02686             netsnmp_assert(netsnmp_processing_set == NULL);
02687 
02688             netsnmp_processing_set = netsnmp_agent_queued_list;
02689             DEBUGMSGTL(("snmp_agent", "SET request remains queued while "
02690                         "delegated requests finish, asp = %08p\n",
02691                         agent_delegated_list));
02692             break;
02693         }
02694 
02695         /*
02696          * pop the first request and process it
02697          */
02698         asp = netsnmp_agent_queued_list;
02699         netsnmp_agent_queued_list = asp->next;
02700         DEBUGMSGTL(("snmp_agent",
02701                     "processing queued request, asp = %08p\n", asp));
02702 
02703         netsnmp_handle_request(asp, asp->status);
02704 
02705         /*
02706          * if we hit a set, stop
02707          */
02708         if (NULL != netsnmp_processing_set)
02709             break;
02710     }
02711 }
02712 
02718 int
02719 netsnmp_check_transaction_id(int transaction_id)
02720 {
02721     netsnmp_agent_session *asp, *prev_asp = NULL;
02722 
02723     for (asp = agent_delegated_list; asp; prev_asp = asp, asp = asp->next) {
02724         if (asp->pdu->transid == transaction_id)
02725             return SNMPERR_SUCCESS;
02726     }
02727     return SNMPERR_GENERR;
02728 }
02729 
02730 
02731 /*
02732  * check_delayed_request(asp)
02733  *
02734  * Called to rexamine a set of requests and continue processing them
02735  * once all the previous (delayed) requests have been handled one way
02736  * or another.
02737  */
02738 
02739 int
02740 check_delayed_request(netsnmp_agent_session *asp)
02741 {
02742     int             status = SNMP_ERR_NOERROR;
02743 
02744     DEBUGMSGTL(("snmp_agent", "processing delegated request, asp = %08p\n",
02745                 asp));
02746 
02747     switch (asp->mode) {
02748     case SNMP_MSG_GETBULK:
02749     case SNMP_MSG_GETNEXT:
02750         netsnmp_check_all_requests_status(asp, 0);
02751         if (asp->flags & SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS) {
02752             DEBUGMSGTL(("snmp_agent","canceling next walk for asp %p\n", asp));
02753             break;
02754         }
02755         handle_getnext_loop(asp);
02756         if (netsnmp_check_for_delegated(asp) &&
02757             netsnmp_check_transaction_id(asp->pdu->transid) !=
02758             SNMPERR_SUCCESS) {
02759             /*
02760              * add to delegated request chain 
02761              */
02762             if (!netsnmp_check_delegated_chain_for(asp)) {
02763                 asp->next = agent_delegated_list;
02764                 agent_delegated_list = asp;
02765             }
02766         }
02767         break;
02768 
02769     case MODE_SET_COMMIT:
02770         netsnmp_check_all_requests_status(asp, SNMP_ERR_COMMITFAILED);
02771         goto settop;
02772 
02773     case MODE_SET_UNDO:
02774         netsnmp_check_all_requests_status(asp, SNMP_ERR_UNDOFAILED);
02775         goto settop;
02776 
02777     case MODE_SET_BEGIN:
02778     case MODE_SET_RESERVE1:
02779     case MODE_SET_RESERVE2:
02780     case MODE_SET_ACTION:
02781     case MODE_SET_FREE:
02782       settop:
02783         /* If we should do only one pass, this mean we */
02784         /* should not reenter this function */
02785         if ((asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) {
02786             /* We should have finished the processing after the first */
02787             /* handle_set_loop, so just wrap up */
02788             break;
02789         }
02790         handle_set_loop(asp);
02791         if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) {
02792 
02793             if (netsnmp_check_for_delegated_and_add(asp)) {
02794                 /*
02795                  * add to delegated request chain 
02796                  */
02797                 if (!asp->status)
02798                     asp->status = status;
02799             }
02800 
02801             return SNMP_ERR_NOERROR;
02802         }
02803         break;
02804 
02805     default:
02806         break;
02807     }
02808 
02809     /*
02810      * if we don't have anything outstanding (delegated), wrap up 
02811      */
02812     if (!netsnmp_check_for_delegated(asp))
02813         return netsnmp_wrap_up_request(asp, status);
02814 
02815     return 1;
02816 }
02817 
02819 int
02820 check_getnext_results(netsnmp_agent_session *asp)
02821 {
02822     /*
02823      * get old info 
02824      */
02825     netsnmp_tree_cache *old_treecache = asp->treecache;
02826     int             old_treecache_num = asp->treecache_num;
02827     int             count = 0;
02828     int             i, special = 0;
02829     netsnmp_request_info *request;
02830 
02831     if (asp->mode == SNMP_MSG_GET) {
02832         /*
02833          * Special case for doing INCLUSIVE getNext operations in
02834          * AgentX subagents.  
02835          */
02836         DEBUGMSGTL(("snmp_agent",
02837                     "asp->mode == SNMP_MSG_GET in ch_getnext\n"));
02838         asp->mode = asp->oldmode;
02839         special = 1;
02840     }
02841 
02842     for (i = 0; i <= old_treecache_num; i++) {
02843         for (request = old_treecache[i].requests_begin; request;
02844              request = request->next) {
02845 
02846             /*
02847              * If we have just done the special case AgentX GET, then any
02848              * requests which were not INCLUSIVE will now have a wrong
02849              * response, so junk them and retry from the same place (except
02850              * that this time the handler will be called in "inexact"
02851              * mode).  
02852              */
02853 
02854             if (special) {
02855                 if (!request->inclusive) {
02856                     DEBUGMSGTL(("snmp_agent",
02857                                 "request %d wasn't inclusive\n",
02858                                 request->index));
02859                     snmp_set_var_typed_value(request->requestvb,
02860                                              ASN_PRIV_RETRY, NULL, 0);
02861                 } else if (request->requestvb->type == ASN_NULL ||
02862                            request->requestvb->type == SNMP_NOSUCHINSTANCE ||
02863                            request->requestvb->type == SNMP_NOSUCHOBJECT) {
02864                     /*
02865                      * it was inclusive, but no results.  Still retry this
02866                      * search. 
02867                      */
02868                     snmp_set_var_typed_value(request->requestvb,
02869                                              ASN_PRIV_RETRY, NULL, 0);
02870                 }
02871             }
02872 
02873             /*
02874              * out of range? 
02875              */
02876             if (snmp_oid_compare(request->requestvb->name,
02877                                  request->requestvb->name_length,
02878                                  request->range_end,
02879                                  request->range_end_len) >= 0) {
02880                 /*
02881                  * ack, it's beyond the accepted end of range. 
02882                  */
02883                 /*
02884                  * fix it by setting the oid to the end of range oid instead 
02885                  */
02886                 DEBUGMSGTL(("check_getnext_results",
02887                             "request response %d out of range\n",
02888                             request->index));
02889                 /*
02890                  * I'm not sure why inclusive is set unconditionally here (see
02891                  * comments for revision 1.161), but it causes a problem for
02892                  * GETBULK over an overridden variable. The bulk-to-next
02893                  * handler re-uses the same request for multiple varbinds,
02894                  * and once inclusive was set, it was never cleared. So, a
02895                  * hack. Instead of setting it to 1, set it to 2, so bulk-to
02896                  * next can clear it later. As of the time of this hack, all
02897                  * checks of this var are boolean checks (not == 1), so this
02898                  * should be safe. Cross your fingers.
02899                  */
02900                 request->inclusive = 2;
02901                 /*
02902                  * XXX: should set this to the original OID? 
02903                  */
02904                 snmp_set_var_objid(request->requestvb,
02905                                    request->range_end,
02906                                    request->range_end_len);
02907                 snmp_set_var_typed_value(request->requestvb, ASN_NULL,
02908                                          NULL, 0);
02909             }
02910 
02911             /*
02912              * mark any existent requests with illegal results as NULL 
02913              */
02914             if (request->requestvb->type == SNMP_ENDOFMIBVIEW) {
02915                 /*
02916                  * illegal response from a subagent.  Change it back to NULL 
02917                  *  xxx-rks: err, how do we know this is a subagent?
02918                  */
02919                 request->requestvb->type = ASN_NULL;
02920                 request->inclusive = 1;
02921             }
02922 
02923             if (request->requestvb->type == ASN_NULL ||
02924                 request->requestvb->type == ASN_PRIV_RETRY ||
02925                 (asp->reqinfo->mode == MODE_GETBULK
02926                  && request->repeat > 0))
02927                 count++;
02928         }
02929     }
02930     return count;
02931 }
02932 
02936 int
02937 handle_getnext_loop(netsnmp_agent_session *asp)
02938 {
02939     int             status;
02940     netsnmp_variable_list *var_ptr;
02941 
02942     /*
02943      * loop 
02944      */
02945     while (netsnmp_running) {
02946 
02947         /*
02948          * bail for now if anything is delegated. 
02949          */
02950         if (netsnmp_check_for_delegated(asp)) {
02951             return SNMP_ERR_NOERROR;
02952         }
02953 
02954         /*
02955          * check vacm against results 
02956          */
02957         check_acm(asp, ASN_PRIV_RETRY);
02958 
02959         /*
02960          * need to keep going we're not done yet. 
02961          */
02962         if (!check_getnext_results(asp))
02963             /*
02964              * nothing left, quit now 
02965              */
02966             break;
02967 
02968         /*
02969          * never had a request (empty pdu), quit now 
02970          */
02971         /*
02972          * XXXWWW: huh?  this would be too late, no?  shouldn't we
02973          * catch this earlier? 
02974          */
02975         /*
02976          * if (count == 0)
02977          * break; 
02978          */
02979 
02980         DEBUGIF("results") {
02981             DEBUGMSGTL(("results",
02982                         "getnext results, before next pass:\n"));
02983             for (var_ptr = asp->pdu->variables; var_ptr;
02984                  var_ptr = var_ptr->next_variable) {
02985                 DEBUGMSGTL(("results", "\t"));
02986                 DEBUGMSGVAR(("results", var_ptr));
02987                 DEBUGMSG(("results", "\n"));
02988             }
02989         }
02990 
02991         netsnmp_reassign_requests(asp);
02992         status = handle_var_requests(asp);
02993         if (status != SNMP_ERR_NOERROR) {
02994             return status;      /* should never really happen */
02995         }
02996     }
02997     return SNMP_ERR_NOERROR;
02998 }
02999 
03000 int
03001 handle_set(netsnmp_agent_session *asp)
03002 {
03003     int             status;
03004     /*
03005      * SETS require 3-4 passes through the var_op_list.
03006      * The first two
03007      * passes verify that all types, lengths, and values are valid
03008      * and may reserve resources and the third does the set and a
03009      * fourth executes any actions.  Then the identical GET RESPONSE
03010      * packet is returned.
03011      * If either of the first two passes returns an error, another
03012      * pass is made so that any reserved resources can be freed.
03013      * If the third pass returns an error, another pass is
03014      * made so that
03015      * any changes can be reversed.
03016      * If the fourth pass (or any of the error handling passes)
03017      * return an error, we'd rather not know about it!
03018      */
03019     if (!(asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) {
03020         switch (asp->mode) {
03021         case MODE_SET_BEGIN:
03022             snmp_increment_statistic(STAT_SNMPINSETREQUESTS);
03023             asp->rw = WRITE;    /* WWW: still needed? */
03024             asp->mode = MODE_SET_RESERVE1;
03025             asp->status = SNMP_ERR_NOERROR;
03026             break;
03027 
03028         case MODE_SET_RESERVE1:
03029 
03030             if (asp->status != SNMP_ERR_NOERROR)
03031                 asp->mode = MODE_SET_FREE;
03032             else
03033                 asp->mode = MODE_SET_RESERVE2;
03034             break;
03035 
03036         case MODE_SET_RESERVE2:
03037             if (asp->status != SNMP_ERR_NOERROR)
03038                 asp->mode = MODE_SET_FREE;
03039             else
03040                 asp->mode = MODE_SET_ACTION;
03041             break;
03042 
03043         case MODE_SET_ACTION:
03044             if (asp->status != SNMP_ERR_NOERROR)
03045                 asp->mode = MODE_SET_UNDO;
03046             else
03047                 asp->mode = MODE_SET_COMMIT;
03048             break;
03049 
03050         case MODE_SET_COMMIT:
03051             if (asp->status != SNMP_ERR_NOERROR) {
03052                 asp->mode = FINISHED_FAILURE;
03053             } else {
03054                 asp->mode = FINISHED_SUCCESS;
03055             }
03056             break;
03057 
03058         case MODE_SET_UNDO:
03059             asp->mode = FINISHED_FAILURE;
03060             break;
03061 
03062         case MODE_SET_FREE:
03063             asp->mode = FINISHED_FAILURE;
03064             break;
03065         }
03066     }
03067 
03068     if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) {
03069         DEBUGMSGTL(("agent_set", "doing set mode = %d (%s)\n", asp->mode,
03070                     se_find_label_in_slist("agent_mode", asp->mode)));
03071         status = handle_var_requests(asp);
03072         DEBUGMSGTL(("agent_set", "did set mode = %d, status = %d\n",
03073                     asp->mode, status));
03074         if ((status != SNMP_ERR_NOERROR && asp->status == SNMP_ERR_NOERROR) ||
03075             status == SNMP_ERR_COMMITFAILED || 
03076             status == SNMP_ERR_UNDOFAILED) {
03077             asp->status = status;
03078         }
03079     }
03080     return asp->status;
03081 }
03082 
03083 int
03084 handle_set_loop(netsnmp_agent_session *asp)
03085 {
03086     while (asp->mode != FINISHED_FAILURE && asp->mode != FINISHED_SUCCESS) {
03087         handle_set(asp);
03088         if (netsnmp_check_for_delegated(asp)) {
03089             return SNMP_ERR_NOERROR;
03090         }
03091         if (asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY) {
03092             return asp->status;
03093         }
03094     }
03095     return asp->status;
03096 }
03097 
03098 int
03099 netsnmp_handle_request(netsnmp_agent_session *asp, int status)
03100 {
03101     /*
03102      * if this isn't a delegated request trying to finish,
03103      * processing of a set request should not start until all
03104      * delegated requests have completed, and no other new requests
03105      * should be processed until the set request completes.
03106      */
03107     if ((0 == netsnmp_check_delegated_chain_for(asp)) &&
03108         (asp != netsnmp_processing_set)) {
03109         /*
03110          * if we are processing a set and this is not a delegated
03111          * request, queue the request
03112          */
03113         if (netsnmp_processing_set) {
03114             netsnmp_add_queued(asp);
03115             DEBUGMSGTL(("snmp_agent",
03116                         "request queued while processing set, "
03117                         "asp = %08p\n", asp));
03118             return 1;
03119         }
03120 
03121         /*
03122          * check for set request
03123          */
03124         if (asp->pdu->command == SNMP_MSG_SET) {
03125             netsnmp_processing_set = asp;
03126 
03127             /*
03128              * if there are delegated requests, we must wait for them
03129              * to finish.
03130              */
03131             if (agent_delegated_list) {
03132                 DEBUGMSGTL(("snmp_agent", "SET request queued while "
03133                             "delegated requests finish, asp = %08p\n",
03134                             asp));
03135                 netsnmp_add_queued(asp);
03136                 return 1;
03137             }
03138         }
03139     }
03140 
03141     /*
03142      * process the request 
03143      */
03144     status = handle_pdu(asp);
03145 
03146     /*
03147      * print the results in appropriate debugging mode 
03148      */
03149     DEBUGIF("results") {
03150         netsnmp_variable_list *var_ptr;
03151         DEBUGMSGTL(("results", "request results (status = %d):\n",
03152                     status));
03153         for (var_ptr = asp->pdu->variables; var_ptr;
03154              var_ptr = var_ptr->next_variable) {
03155             DEBUGMSGTL(("results", "\t"));
03156             DEBUGMSGVAR(("results", var_ptr));
03157             DEBUGMSG(("results", "\n"));
03158         }
03159     }
03160 
03161     /*
03162      * check for uncompleted requests 
03163      */
03164     if (netsnmp_check_for_delegated_and_add(asp)) {
03165         /*
03166          * add to delegated request chain 
03167          */
03168         asp->status = status;
03169     } else {
03170         /*
03171          * if we don't have anything outstanding (delegated), wrap up
03172          */
03173         return netsnmp_wrap_up_request(asp, status);
03174     }
03175 
03176     return 1;
03177 }
03178 
03230 int
03231 handle_pdu(netsnmp_agent_session *asp)
03232 {
03233     int             status, inclusives = 0;
03234     netsnmp_variable_list *v = NULL;
03235 
03236     /*
03237      * for illegal requests, mark all nodes as ASN_NULL 
03238      */
03239     switch (asp->pdu->command) {
03240 
03241     case SNMP_MSG_INTERNAL_SET_RESERVE2:
03242     case SNMP_MSG_INTERNAL_SET_ACTION:
03243     case SNMP_MSG_INTERNAL_SET_COMMIT:
03244     case SNMP_MSG_INTERNAL_SET_FREE:
03245     case SNMP_MSG_INTERNAL_SET_UNDO:
03246         status = get_set_cache(asp);
03247         if (status != SNMP_ERR_NOERROR)
03248             return status;
03249         break;
03250 
03251     case SNMP_MSG_GET:
03252     case SNMP_MSG_GETNEXT:
03253     case SNMP_MSG_GETBULK:
03254         for (v = asp->pdu->variables; v != NULL; v = v->next_variable) {
03255             if (v->type == ASN_PRIV_INCL_RANGE) {
03256                 /*
03257                  * Leave the type for now (it gets set to
03258                  * ASN_NULL in netsnmp_add_varbind_to_cache,
03259                  * called by create_subnetsnmp_tree_cache below).
03260                  * If we set it to ASN_NULL now, we wouldn't be
03261                  * able to distinguish INCLUSIVE search
03262                  * ranges.  
03263                  */
03264                 inclusives++;
03265             } else {
03266                 snmp_set_var_typed_value(v, ASN_NULL, NULL, 0);
03267             }
03268         }
03269         /*
03270          * fall through 
03271          */
03272 
03273     case SNMP_MSG_INTERNAL_SET_BEGIN:
03274     case SNMP_MSG_INTERNAL_SET_RESERVE1:
03275     default:
03276         asp->vbcount = count_varbinds(asp->pdu->variables);
03277         if (asp->vbcount) /* efence doesn't like 0 size allocs */
03278             asp->requests = (netsnmp_request_info *)
03279                 calloc(asp->vbcount, sizeof(netsnmp_request_info));
03280         /*
03281          * collect varbinds 
03282          */
03283         status = netsnmp_create_subtree_cache(asp);
03284         if (status != SNMP_ERR_NOERROR)
03285             return status;
03286     }
03287 
03288     asp->mode = asp->pdu->command;
03289     switch (asp->mode) {
03290     case SNMP_MSG_GET:
03291         /*
03292          * increment the message type counter 
03293          */
03294         snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
03295 
03296         /*
03297          * check vacm ahead of time 
03298          */
03299         check_acm(asp, SNMP_NOSUCHOBJECT);
03300 
03301         /*
03302          * get the results 
03303          */
03304         status = handle_var_requests(asp);
03305 
03306         /*
03307          * Deal with unhandled results -> noSuchInstance (rather
03308          * than noSuchObject -- in that case, the type will
03309          * already have been set to noSuchObject when we realised
03310          * we couldn't find an appropriate tree).  
03311          */
03312         if (status == SNMP_ERR_NOERROR)
03313             snmp_replace_var_types(asp->pdu->variables, ASN_NULL,
03314                                    SNMP_NOSUCHINSTANCE);
03315         break;
03316 
03317     case SNMP_MSG_GETNEXT:
03318         snmp_increment_statistic(STAT_SNMPINGETNEXTS);
03319         /*
03320          * fall through 
03321          */
03322 
03323     case SNMP_MSG_GETBULK:     /* note: there is no getbulk stat */
03324         /*
03325          * loop through our mib tree till we find an
03326          * appropriate response to return to the caller. 
03327          */
03328 
03329         if (inclusives) {
03330             /*
03331              * This is a special case for AgentX INCLUSIVE getNext
03332              * requests where a result lexi-equal to the request is okay
03333              * but if such a result does not exist, we still want the
03334              * lexi-next one.  So basically we do a GET first, and if any
03335              * of the INCLUSIVE requests are satisfied, we use that
03336              * value.  Then, unsatisfied INCLUSIVE requests, and
03337              * non-INCLUSIVE requests get done as normal.  
03338              */
03339 
03340             DEBUGMSGTL(("snmp_agent", "inclusive range(s) in getNext\n"));
03341             asp->oldmode = asp->mode;
03342             asp->mode = SNMP_MSG_GET;
03343         }
03344 
03345         /*
03346          * first pass 
03347          */
03348         status = handle_var_requests(asp);
03349         if (status != SNMP_ERR_NOERROR) {
03350             if (!inclusives)
03351                 return status;  /* should never really happen */
03352             else
03353                 asp->status = SNMP_ERR_NOERROR;
03354         }
03355 
03356         /*
03357          * loop through our mib tree till we find an
03358          * appropriate response to return to the caller. 
03359          */
03360 
03361         status = handle_getnext_loop(asp);
03362         break;
03363 
03364     case SNMP_MSG_SET:
03365 #ifdef NETSNMP_DISABLE_SET_SUPPORT
03366         return SNMP_ERR_NOTWRITABLE;
03367 #else
03368         /*
03369          * check access permissions first 
03370          */
03371         if (check_acm(asp, SNMP_NOSUCHOBJECT))
03372             return SNMP_ERR_NOTWRITABLE;
03373 
03374         asp->mode = MODE_SET_BEGIN;
03375         status = handle_set_loop(asp);
03376 #endif
03377         break;
03378 
03379     case SNMP_MSG_INTERNAL_SET_BEGIN:
03380     case SNMP_MSG_INTERNAL_SET_RESERVE1:
03381     case SNMP_MSG_INTERNAL_SET_RESERVE2:
03382     case SNMP_MSG_INTERNAL_SET_ACTION:
03383     case SNMP_MSG_INTERNAL_SET_COMMIT:
03384     case SNMP_MSG_INTERNAL_SET_FREE:
03385     case SNMP_MSG_INTERNAL_SET_UNDO:
03386         asp->pdu->flags |= UCD_MSG_FLAG_ONE_PASS_ONLY;
03387         status = handle_set_loop(asp);
03388         /*
03389          * asp related cache is saved in cleanup 
03390          */
03391         break;
03392 
03393     case SNMP_MSG_RESPONSE:
03394         snmp_increment_statistic(STAT_SNMPINGETRESPONSES);
03395         return SNMP_ERR_NOERROR;
03396 
03397     case SNMP_MSG_TRAP:
03398     case SNMP_MSG_TRAP2:
03399         snmp_increment_statistic(STAT_SNMPINTRAPS);
03400         return SNMP_ERR_NOERROR;
03401 
03402     default:
03403         /*
03404          * WWW: are reports counted somewhere ? 
03405          */
03406         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03407         return SNMPERR_GENERR;  /* shouldn't get here */
03408         /*
03409          * WWW 
03410          */
03411     }
03412     return status;
03413 }
03414 
03418 NETSNMP_STATIC_INLINE int
03419 _request_set_error(netsnmp_request_info *request, int mode, int error_value)
03420 {
03421     if (!request)
03422         return SNMPERR_NO_VARS;
03423 
03424     request->processed = 1;
03425     request->delegated = REQUEST_IS_NOT_DELEGATED;
03426 
03427     switch (error_value) {
03428     case SNMP_NOSUCHOBJECT:
03429     case SNMP_NOSUCHINSTANCE:
03430     case SNMP_ENDOFMIBVIEW:
03431         /*
03432          * these are exceptions that should be put in the varbind
03433          * in the case of a GET but should be translated for a SET
03434          * into a real error status code and put in the request 
03435          */
03436         switch (mode) {
03437         case MODE_GET:
03438         case MODE_GETNEXT:
03439         case MODE_GETBULK:
03440             request->requestvb->type = error_value;
03441             return SNMPERR_SUCCESS;
03442 
03443             /*
03444              * These are technically illegal to set by the
03445              * client APIs for these modes.  But accepting
03446              * them here allows the 'sparse_table' helper to
03447              * provide some common table handling processing
03448              *
03449             snmp_log(LOG_ERR, "Illegal error_value %d for mode %d ignored\n",
03450                      error_value, mode);
03451             return SNMPERR_VALUE;
03452              */
03453 
03454         default:
03455             request->status = SNMP_ERR_NOSUCHNAME;      /* WWW: correct? */
03456             return SNMPERR_SUCCESS;
03457         }
03458         break;                  /* never get here */
03459 
03460     default:
03461         if (error_value < 0) {
03462             /*
03463              * illegal local error code.  translate to generr 
03464              */
03465             /*
03466              * WWW: full translation map? 
03467              */
03468             snmp_log(LOG_ERR, "Illegal error_value %d translated to %d\n",
03469                      error_value, SNMP_ERR_GENERR);
03470             request->status = SNMP_ERR_GENERR;
03471         } else {
03472             /*
03473              * WWW: translations and mode checking? 
03474              */
03475             request->status = error_value;
03476         }
03477         return SNMPERR_SUCCESS;
03478     }
03479     return SNMPERR_SUCCESS;
03480 }
03481 
03486 int
03487 netsnmp_request_set_error(netsnmp_request_info *request, int error_value)
03488 {
03489     if (!request || !request->agent_req_info)
03490         return SNMPERR_NO_VARS;
03491 
03492     return _request_set_error(request, request->agent_req_info->mode,
03493                               error_value);
03494 }
03495 
03501 int
03502 netsnmp_request_set_error_idx(netsnmp_request_info *request,
03503                               int error_value, int idx)
03504 {
03505     int i;
03506     netsnmp_request_info *req = request;
03507 
03508     if (!request || !request->agent_req_info)
03509         return SNMPERR_NO_VARS;
03510 
03511     /*
03512      * Skip to the indicated varbind
03513      */
03514     for ( i=2; i<idx; i++) {
03515         req = req->next;
03516         if (!req)
03517             return SNMPERR_NO_VARS;
03518     }
03519     
03520     return _request_set_error(req, request->agent_req_info->mode,
03521                               error_value);
03522 }
03523 
03529 NETSNMP_INLINE int
03530 netsnmp_request_set_error_all( netsnmp_request_info *requests, int error)
03531 {
03532     int mode, rc, result = SNMPERR_SUCCESS;
03533 
03534     if((NULL == requests) || (NULL == requests->agent_req_info))
03535         return SNMPERR_NO_VARS;
03536     
03537     mode = requests->agent_req_info->mode; /* every req has same mode */
03538     
03539     for(; requests ; requests = requests->next) {
03540 
03542         netsnmp_assert(NULL != requests->agent_req_info);
03543         netsnmp_assert(mode == requests->agent_req_info->mode);
03544 
03545         /*
03546          * set error for this request. Log any errors, save the last
03547          * to return to the user.
03548          */
03549         if((rc = _request_set_error(requests, mode, error))) {
03550             snmp_log(LOG_WARNING,"got %d while setting request error\n", rc);
03551             result = rc;
03552         }
03553     }
03554     return result;
03555 }
03556 
03557 extern struct timeval starttime;
03558 
03559                 /*
03560                  * Return the value of 'sysUpTime' at the given marker 
03561                  */
03562 u_long
03563 netsnmp_marker_uptime(marker_t pm)
03564 {
03565     u_long          res;
03566     marker_t        start = (marker_t) & starttime;
03567 
03568     res = uatime_hdiff(start, pm);
03569     return res;                 /* atime_diff works in msec, not csec */
03570 }
03571 
03572                         /*
03573                          * struct timeval equivalents of these 
03574                          */
03575 u_long
03576 netsnmp_timeval_uptime(struct timeval * tv)
03577 {
03578     return netsnmp_marker_uptime((marker_t) tv);
03579 }
03580 
03581                 /*
03582                  * Return the current value of 'sysUpTime' 
03583                  */
03584 u_long
03585 netsnmp_get_agent_uptime(void)
03586 {
03587     struct timeval  now;
03588     gettimeofday(&now, NULL);
03589 
03590     return netsnmp_timeval_uptime(&now);
03591 }
03592 
03593 
03594 
03595 NETSNMP_INLINE void
03596 netsnmp_agent_add_list_data(netsnmp_agent_request_info *ari,
03597                             netsnmp_data_list *node)
03598 {
03599     if (ari) {
03600         if (ari->agent_data) {
03601             netsnmp_add_list_data(&ari->agent_data, node);
03602         } else {
03603             ari->agent_data = node;
03604         }
03605     }
03606 }
03607 
03608 NETSNMP_INLINE int
03609 netsnmp_agent_remove_list_data(netsnmp_agent_request_info *ari,
03610                                const char * name)
03611 {
03612     if ((NULL == ari) || (NULL == ari->agent_data))
03613         return 1;
03614 
03615     return netsnmp_remove_list_node(&ari->agent_data, name);
03616 }
03617 
03618 NETSNMP_INLINE void    *
03619 netsnmp_agent_get_list_data(netsnmp_agent_request_info *ari,
03620                             const char *name)
03621 {
03622     if (ari) {
03623         return netsnmp_get_list_data(ari->agent_data, name);
03624     }
03625     return NULL;
03626 }
03627 
03628 NETSNMP_INLINE void
03629 netsnmp_free_agent_data_set(netsnmp_agent_request_info *ari)
03630 {
03631     if (ari) {
03632         netsnmp_free_list_data(ari->agent_data);
03633     }
03634 }
03635 
03636 NETSNMP_INLINE void
03637 netsnmp_free_agent_data_sets(netsnmp_agent_request_info *ari)
03638 {
03639     if (ari) {
03640         netsnmp_free_all_list_data(ari->agent_data);
03641     }
03642 }
03643 
03644 NETSNMP_INLINE void
03645 netsnmp_free_agent_request_info(netsnmp_agent_request_info *ari)
03646 {
03647     if (ari) {
03648         if (ari->agent_data) {
03649             netsnmp_free_all_list_data(ari->agent_data);
03650         }
03651         SNMP_FREE(ari);
03652     }
03653 }
03654 
03655 /*************************************************************************
03656  *
03657  * deprecated functions
03658  *
03659  */
03660 
03668 int
03669 netsnmp_set_request_error(netsnmp_agent_request_info *reqinfo,
03670                           netsnmp_request_info *request, int error_value)
03671 {
03672     if (!request || !reqinfo)
03673         return error_value;
03674 
03675     _request_set_error(request, reqinfo->mode, error_value);
03676     
03677     return error_value;
03678 }
03679 
03687 int
03688 netsnmp_set_mode_request_error(int mode, netsnmp_request_info *request,
03689                                int error_value)
03690 {
03691     _request_set_error(request, mode, error_value);
03692     
03693     return error_value;
03694 }
03695 
03703 int
03704 netsnmp_set_all_requests_error(netsnmp_agent_request_info *reqinfo,
03705                                netsnmp_request_info *requests,
03706                                int error_value)
03707 {
03708     netsnmp_request_set_error_all(requests, error_value);
03709     return error_value;
03710 }