Logo
Home page Net-SNMP

Archive Search:

Require all words?

Site Search:
Google
Main Page | Modules | Data Structures | File List | Data Fields | Related Pages | Examples

agent_registry.c

00001 /*
00002  * agent_registry.c
00003  */
00004 /* Portions of this file are subject to the following copyright(s).  See
00005  * the Net-SNMP's COPYING file for more details and other copyrights
00006  * that may apply:
00007  */
00008 /*
00009  * Portions of this file are copyrighted by:
00010  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00011  * Use is subject to license terms specified in the COPYING file
00012  * distributed with the Net-SNMP package.
00013  */
00020 #define IN_SNMP_VARS_C
00021 
00022 #include <net-snmp/net-snmp-config.h>
00023 #include <signal.h>
00024 #if HAVE_STRING_H
00025 #include <string.h>
00026 #endif
00027 #if HAVE_STDLIB_H
00028 #include <stdlib.h>
00029 #endif
00030 #include <sys/types.h>
00031 #include <stdio.h>
00032 #include <fcntl.h>
00033 #if HAVE_WINSOCK_H
00034 #include <winsock.h>
00035 #endif
00036 #if TIME_WITH_SYS_TIME
00037 # ifdef WIN32
00038 #  include <sys/timeb.h>
00039 # else
00040 #  include <sys/time.h>
00041 # endif
00042 # include <time.h>
00043 #else
00044 # if HAVE_SYS_TIME_H
00045 #  include <sys/time.h>
00046 # else
00047 #  include <time.h>
00048 # endif
00049 #endif
00050 #if HAVE_NETINET_IN_H
00051 #include <netinet/in.h>
00052 #endif
00053 
00054 #include <net-snmp/net-snmp-includes.h>
00055 #include <net-snmp/agent/net-snmp-agent-includes.h>
00056 #include <net-snmp/agent/agent_callbacks.h>
00057 
00058 #include "snmpd.h"
00059 #include "mibgroup/struct.h"
00060 #include <net-snmp/agent/old_api.h>
00061 #include <net-snmp/agent/null.h>
00062 #include <net-snmp/agent/table.h>
00063 #include <net-snmp/agent/table_iterator.h>
00064 #include <net-snmp/agent/agent_registry.h>
00065 #include "mib_module_includes.h"
00066 
00067 #ifdef USING_AGENTX_SUBAGENT_MODULE
00068 #include "agentx/subagent.h"
00069 #include "agentx/client.h"
00070 #endif
00071 
00072 static void register_mib_detach_node(netsnmp_subtree *s);
00073 NETSNMP_STATIC_INLINE void invalidate_lookup_cache(const char *context);
00074 void netsnmp_set_lookup_cache_size(int newsize);
00075 int netsnmp_get_lookup_cache_size(void);
00076 
00077 subtree_context_cache *context_subtrees = NULL;
00078 
00079 void
00080 netsnmp_subtree_free(netsnmp_subtree *a)
00081 {
00082   if (a != NULL) {
00083     if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen, 
00084                                              a->start_a, a->start_len) == 0) {
00085       SNMP_FREE(a->variables);
00086     }
00087     SNMP_FREE(a->name_a);
00088     SNMP_FREE(a->start_a);
00089     SNMP_FREE(a->end_a);
00090     SNMP_FREE(a->label_a);
00091     netsnmp_handler_registration_free(a->reginfo);
00092     SNMP_FREE(a);
00093   }
00094 }
00095 
00096 netsnmp_subtree *
00097 netsnmp_subtree_deepcopy(netsnmp_subtree *a)
00098 {
00099   netsnmp_subtree *b = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
00100 
00101   if (b != NULL) {
00102     memcpy(b, a, sizeof(netsnmp_subtree));
00103     b->name_a  = snmp_duplicate_objid(a->name_a,  a->namelen);
00104     b->start_a = snmp_duplicate_objid(a->start_a, a->start_len);
00105     b->end_a   = snmp_duplicate_objid(a->end_a,   a->end_len);
00106     b->label_a = strdup(a->label_a);
00107     
00108     if (b->name_a == NULL || b->start_a == NULL || 
00109         b->end_a  == NULL || b->label_a == NULL) {
00110       netsnmp_subtree_free(b);
00111       return NULL;
00112     }
00113 
00114     if (a->variables != NULL) {
00115       b->variables = (struct variable *)malloc(a->variables_len * 
00116                                                a->variables_width);
00117       if (b->variables != NULL) {
00118         memcpy(b->variables, a->variables,a->variables_len*a->variables_width);
00119       } else {
00120         netsnmp_subtree_free(b);
00121         return NULL;
00122       }
00123     }
00124 
00125     if (a->reginfo != NULL) {
00126       b->reginfo = netsnmp_handler_registration_dup(a->reginfo);
00127       if (b->reginfo == NULL) {
00128         netsnmp_subtree_free(b);
00129         return NULL;
00130       }
00131     }
00132   }
00133   return b;
00134 }
00135 
00136 subtree_context_cache *
00137 get_top_context_cache(void)
00138 {
00139     return context_subtrees;
00140 }
00141 
00142 netsnmp_subtree *
00143 netsnmp_subtree_find_first(const char *context_name)
00144 {
00145     subtree_context_cache *ptr;
00146 
00147     if (!context_name) {
00148         context_name = "";
00149     }
00150 
00151     DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", 
00152                 context_name));
00153     for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
00154         if (ptr->context_name != NULL && 
00155             strcmp(ptr->context_name, context_name) == 0) {
00156             DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name));
00157             return ptr->first_subtree;
00158         }
00159     }
00160     DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", 
00161                 context_name));
00162     return NULL;
00163 }
00164 
00165 netsnmp_subtree *
00166 add_subtree(netsnmp_subtree *new_tree, const char *context_name)
00167 {
00168     subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache);
00169     
00170     if (!context_name) {
00171         context_name = "";
00172     }
00173 
00174     if (!ptr) {
00175         return NULL;
00176     }
00177     
00178     DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n",      
00179                 context_name));
00180 
00181     ptr->next = context_subtrees;
00182     ptr->first_subtree = new_tree;
00183     ptr->context_name = strdup(context_name);
00184     context_subtrees = ptr;
00185 
00186     return ptr->first_subtree;
00187 }
00188 
00189 netsnmp_subtree *
00190 netsnmp_subtree_replace_first(netsnmp_subtree *new_tree, 
00191                               const char *context_name)
00192 {
00193     subtree_context_cache *ptr;
00194     if (!context_name) {
00195         context_name = "";
00196     }
00197     for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
00198         if (ptr->context_name != NULL &&
00199             strcmp(ptr->context_name, context_name) == 0) {
00200             ptr->first_subtree = new_tree;
00201             return ptr->first_subtree;
00202         }
00203     }
00204     return add_subtree(new_tree, context_name);
00205 }
00206 
00207 NETSNMP_INLINE void
00208 netsnmp_subtree_change_next(netsnmp_subtree *ptr, netsnmp_subtree *thenext)
00209 {
00210     ptr->next = thenext;
00211     if (thenext)
00212         netsnmp_oid_compare_ll(ptr->start_a,
00213                                ptr->start_len,
00214                                thenext->start_a,
00215                                thenext->start_len,
00216                                &thenext->oid_off);
00217 }
00218 
00219 NETSNMP_INLINE void
00220 netsnmp_subtree_change_prev(netsnmp_subtree *ptr, netsnmp_subtree *theprev)
00221 {
00222     ptr->prev = theprev;
00223     if (theprev)
00224         netsnmp_oid_compare_ll(theprev->start_a,
00225                                theprev->start_len,
00226                                ptr->start_a,
00227                                ptr->start_len,
00228                                &ptr->oid_off);
00229 }
00230 
00231 int
00232 netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp)
00233 {
00234     return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen);
00235 }
00236 
00237 void
00238 netsnmp_subtree_join(netsnmp_subtree *root)
00239 {
00240     netsnmp_subtree *s, *tmp, *c, *d;
00241 
00242     while (root != NULL) {
00243         s = root->next;
00244         while (s != NULL && root->reginfo == s->reginfo) {
00245             tmp = s->next;
00246             DEBUGMSGTL(("subtree", "root start "));
00247             DEBUGMSGOID(("subtree", root->start_a, root->start_len));
00248             DEBUGMSG(("subtree", " (original end "));
00249             DEBUGMSGOID(("subtree", root->end_a, root->end_len));
00250             DEBUGMSG(("subtree", ")\n"));
00251             DEBUGMSGTL(("subtree", "  JOINING to "));
00252             DEBUGMSGOID(("subtree", s->start_a, s->start_len));
00253 
00254             SNMP_FREE(root->end_a);
00255             root->end_a   = s->end_a;
00256             root->end_len = s->end_len;
00257             s->end_a      = NULL;
00258 
00259             for (c = root; c != NULL; c = c->children) {
00260                 netsnmp_subtree_change_next(c, s->next);
00261             }
00262             for (c = s; c != NULL; c = c->children) {
00263                 netsnmp_subtree_change_prev(c, root);
00264             }
00265             DEBUGMSG(("subtree", " so new end "));
00266             DEBUGMSGOID(("subtree", root->end_a, root->end_len));
00267             DEBUGMSG(("subtree", "\n"));
00268             /*
00269              * Probably need to free children too?  
00270              */
00271             for (c = s->children; c != NULL; c = d) {
00272                 d = c->children;
00273                 netsnmp_subtree_free(c);
00274             }
00275             netsnmp_subtree_free(s);
00276             s = tmp;
00277         }
00278         root = root->next;
00279     }
00280 }
00281 
00282 
00283         /*
00284          *  Split the subtree into two at the specified point,
00285          *    returning the new (second) subtree
00286          */
00287 netsnmp_subtree *
00288 netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len)
00289 {
00290     struct variable *vp = NULL;
00291     netsnmp_subtree *new_sub, *ptr;
00292     int i = 0, rc = 0, rc2 = 0;
00293     size_t common_len = 0;
00294     char *cp;
00295     oid *tmp_a, *tmp_b;
00296 
00297     if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) {
00298         /* Split comes after the end of this subtree */
00299         return NULL;
00300     }
00301 
00302     new_sub = netsnmp_subtree_deepcopy(current);
00303     if (new_sub == NULL) {
00304         return NULL;
00305     }
00306 
00307     /*  Set up the point of division.  */
00308     tmp_a = snmp_duplicate_objid(name, name_len);
00309     if (tmp_a == NULL) {
00310         netsnmp_subtree_free(new_sub);
00311         return NULL;
00312     }
00313     tmp_b = snmp_duplicate_objid(name, name_len);
00314     if (tmp_b == NULL) {
00315         netsnmp_subtree_free(new_sub);
00316         SNMP_FREE(tmp_a);
00317         return NULL;
00318     }
00319 
00320     if (current->end_a != NULL) {
00321         SNMP_FREE(current->end_a);
00322     }
00323     current->end_a = tmp_a;
00324     current->end_len = name_len;
00325     if (new_sub->start_a != NULL) {
00326         SNMP_FREE(new_sub->start_a);
00327     }
00328     new_sub->start_a = tmp_b;
00329     new_sub->start_len = name_len;
00330 
00331     /*  Split the variables between the two new subtrees.  */
00332     i = current->variables_len;
00333     current->variables_len = 0;
00334 
00335     for (vp = current->variables; i > 0; i--) {
00336         /*  Note that the variable "name" field omits the prefix common to the
00337             whole registration, hence the strange comparison here.  */
00338 
00339         rc = snmp_oid_compare(vp->name, vp->namelen,
00340                               name     + current->namelen, 
00341                               name_len - current->namelen);
00342 
00343         if (name_len - current->namelen > vp->namelen) {
00344             common_len = vp->namelen;
00345         } else {
00346             common_len = name_len - current->namelen;
00347         }
00348 
00349         rc2 = snmp_oid_compare(vp->name, common_len,
00350                                name + current->namelen, common_len);
00351 
00352         if (rc >= 0) {
00353             break;  /* All following variables belong to the second subtree */
00354         }
00355 
00356         current->variables_len++;
00357         if (rc2 < 0) {
00358             new_sub->variables_len--;
00359             cp = (char *) new_sub->variables;
00360             new_sub->variables = (struct variable *)(cp + 
00361                                                      new_sub->variables_width);
00362         }
00363         vp = (struct variable *) ((char *) vp + current->variables_width);
00364     }
00365 
00366     /* Delegated trees should retain their variables regardless */
00367     if (current->variables_len > 0 &&
00368         IS_DELEGATED((u_char) current->variables[0].type)) {
00369         new_sub->variables_len = 1;
00370         new_sub->variables = current->variables;
00371     }
00372 
00373     /* Propogate this split down through any children */
00374     if (current->children) {
00375         new_sub->children = netsnmp_subtree_split(current->children, 
00376                                                   name, name_len);
00377     }
00378 
00379     /* Retain the correct linking of the list */
00380     for (ptr = current; ptr != NULL; ptr = ptr->children) {
00381         netsnmp_subtree_change_next(ptr, new_sub);
00382     }
00383     for (ptr = new_sub; ptr != NULL; ptr = ptr->children) {
00384         netsnmp_subtree_change_prev(ptr, current);
00385     }
00386     for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) {
00387         netsnmp_subtree_change_prev(ptr, new_sub);
00388     }
00389 
00390     return new_sub;
00391 }
00392 
00393 int
00394 netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name)
00395 {
00396     netsnmp_subtree *tree1, *tree2, *new2;
00397     netsnmp_subtree *prev, *next;
00398     int             res, rc = 0;
00399 
00400     if (new_sub == NULL) {
00401         return MIB_REGISTERED_OK;       /* Degenerate case */
00402     }
00403 
00404     if (!netsnmp_subtree_find_first(context_name)) {
00405         static int inloop = 0;
00406         if (!inloop) {
00407             oid ccitt[1]           = { 0 };
00408             oid iso[1]             = { 1 };
00409             oid joint_ccitt_iso[1] = { 2 };
00410             inloop = 1;
00411             netsnmp_register_null_context(snmp_duplicate_objid(ccitt, 1), 1,
00412                                           context_name);
00413             netsnmp_register_null_context(snmp_duplicate_objid(iso, 1), 1,
00414                                           context_name);
00415             netsnmp_register_null_context(snmp_duplicate_objid(joint_ccitt_iso, 1),
00416                                           1, context_name);
00417             inloop = 0;
00418         }
00419     }
00420 
00421     /*  Find the subtree that contains the start of the new subtree (if
00422         any)...*/
00423 
00424     tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, 
00425                                  NULL, context_name);
00426 
00427     /*  ... and the subtree that follows the new one (NULL implies this is the
00428         final region covered).  */
00429 
00430     if (tree1 == NULL) {
00431         tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len,
00432                                           NULL, context_name);
00433     } else {
00434         tree2 = tree1->next;
00435     }
00436 
00437     /*  Handle new subtrees that start in virgin territory.  */
00438 
00439     if (tree1 == NULL) {
00440         new2 = NULL;
00441         /*  Is there any overlap with later subtrees?  */
00442         if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len,
00443                                       tree2->start_a, tree2->start_len) > 0) {
00444             new2 = netsnmp_subtree_split(new_sub, 
00445                                          tree2->start_a, tree2->start_len);
00446         }
00447 
00448         /*  Link the new subtree (less any overlapping region) with the list of
00449             existing registrations.  */
00450 
00451         if (tree2) {
00452             netsnmp_subtree_change_prev(new_sub, tree2->prev);
00453             netsnmp_subtree_change_prev(tree2, new_sub);
00454         } else {
00455             netsnmp_subtree_change_prev(new_sub,
00456                                         netsnmp_subtree_find_prev(new_sub->start_a,
00457                                                                   new_sub->start_len, NULL, context_name));
00458 
00459             if (new_sub->prev) {
00460                 netsnmp_subtree_change_next(new_sub->prev, new_sub);
00461             } else {
00462                 netsnmp_subtree_replace_first(new_sub, context_name);
00463             }
00464 
00465             netsnmp_subtree_change_next(new_sub, tree2);
00466 
00467             /* If there was any overlap, recurse to merge in the overlapping
00468                region (including anything that may follow the overlap).  */
00469             if (new2) {
00470                 return netsnmp_subtree_load(new2, context_name);
00471             }
00472         }
00473     } else {
00474         /*  If the new subtree starts *within* an existing registration
00475             (rather than at the same point as it), then split the existing
00476             subtree at this point.  */
00477 
00478         if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len, 
00479                              tree1->start_a,   tree1->start_len) != 0) {
00480             tree1 = netsnmp_subtree_split(tree1, new_sub->start_a, 
00481                                           new_sub->start_len);
00482         }
00483 
00484         if (tree1 == NULL) {
00485             return MIB_REGISTRATION_FAILED;
00486         }
00487 
00488         /*  Now consider the end of this existing subtree:
00489             
00490             If it matches the new subtree precisely,
00491                     simply merge the new one into the list of children
00492 
00493             If it includes the whole of the new subtree,
00494                     split it at the appropriate point, and merge again
00495      
00496             If the new subtree extends beyond this existing region,
00497                     split it, and recurse to merge the two parts.  */
00498 
00499         rc = snmp_oid_compare(new_sub->end_a, new_sub->end_len, 
00500                               tree1->end_a, tree1->end_len);
00501 
00502         switch (rc) {
00503 
00504         case -1:
00505             /*  Existing subtree contains new one.  */
00506             netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len);
00507             /* Fall Through */
00508 
00509         case  0:
00510             /*  The two trees match precisely.  */
00511 
00512             /*  Note: This is the only point where the original registration
00513                 OID ("name") is used.  */
00514 
00515             prev = NULL;
00516             next = tree1;
00517         
00518             while (next && next->namelen > new_sub->namelen) {
00519                 prev = next;
00520                 next = next->children;
00521             }
00522 
00523             while (next && next->namelen == new_sub->namelen &&
00524                    next->priority < new_sub->priority ) {
00525                 prev = next;
00526                 next = next->children;
00527             }
00528         
00529             if (next && (next->namelen  == new_sub->namelen) &&
00530                 (next->priority == new_sub->priority)) {
00531                 netsnmp_assert("registration" != "duplicate");
00532                 return MIB_DUPLICATE_REGISTRATION;
00533             }
00534 
00535             if (prev) {
00536                 prev->children    = new_sub;
00537                 new_sub->children = next;
00538                 netsnmp_subtree_change_prev(new_sub, prev->prev);
00539                 netsnmp_subtree_change_next(new_sub, prev->next);
00540             } else {
00541                 new_sub->children = next;
00542                 netsnmp_subtree_change_prev(new_sub, next->prev);
00543                 netsnmp_subtree_change_next(new_sub, next->next);
00544         
00545                 for (next = new_sub->next; next != NULL;next = next->children){
00546                     netsnmp_subtree_change_prev(next, new_sub);
00547                 }
00548 
00549                 for (prev = new_sub->prev; prev != NULL;prev = prev->children){
00550                     netsnmp_subtree_change_next(prev, new_sub);
00551                 }
00552             }
00553             break;
00554 
00555         case  1:
00556             /*  New subtree contains the existing one.  */
00557             new2 = netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len);
00558             res = netsnmp_subtree_load(new_sub, context_name);
00559             if (res != MIB_REGISTERED_OK) {
00560                 netsnmp_subtree_free(new2);
00561                 return res;
00562             }
00563             return netsnmp_subtree_load(new2, context_name);
00564         }
00565     }
00566     return 0;
00567 }
00568 
00569 /*
00570  * Note: reginfo will be freed on failures
00571  */
00572 int
00573 netsnmp_register_mib(const char *moduleName,
00574                      struct variable *var,
00575                      size_t varsize,
00576                      size_t numvars,
00577                      oid * mibloc,
00578                      size_t mibloclen,
00579                      int priority,
00580                      int range_subid,
00581                      oid range_ubound,
00582                      netsnmp_session * ss,
00583                      const char *context,
00584                      int timeout,
00585                      int flags,
00586                      netsnmp_handler_registration *reginfo,
00587                      int perform_callback)
00588 {
00589     netsnmp_subtree *subtree, *sub2;
00590     int             res, i;
00591     struct register_parameters reg_parms;
00592     int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
00593 
00594     if (moduleName == NULL ||
00595         mibloc     == NULL) {
00596         /* Shouldn't happen ??? */
00597         netsnmp_handler_registration_free(reginfo);
00598         return MIB_REGISTRATION_FAILED;
00599     }
00600     subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
00601     if (subtree == NULL) {
00602         netsnmp_handler_registration_free(reginfo);
00603         return MIB_REGISTRATION_FAILED;
00604     }
00605 
00606     DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
00607     DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid,
00608                       range_ubound));
00609     DEBUGMSG(("register_mib", " with context \"%s\"\n", context));
00610 
00611     /*
00612      * verify that the passed context is equal to the context
00613      * in the reginfo.
00614      * (which begs the question, why do we have both? It appears that the
00615      *  reginfo item didn't appear til 5.2)
00616      */
00617     if( ((NULL == context) && (NULL != reginfo->contextName)) ||
00618         ((NULL != context) && (NULL == reginfo->contextName)) ||
00619         ( ((NULL != context) && (NULL != reginfo->contextName)) &&
00620           (0 != strcmp(context, reginfo->contextName))) ) {
00621         snmp_log(LOG_WARNING,"context passed during registration does not "
00622                  "equal the reginfo contextName! ('%s' != '%s')\n",
00623                  context, reginfo->contextName);
00624         netsnmp_assert("register context" == "reginfo->contextName");
00625     }
00626 
00627     /*  Create the new subtree node being registered.  */
00628 
00629     subtree->reginfo = reginfo;
00630     subtree->name_a  = snmp_duplicate_objid(mibloc, mibloclen);
00631     subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen);
00632     subtree->end_a   = snmp_duplicate_objid(mibloc, mibloclen);
00633     subtree->label_a = strdup(moduleName);
00634     if (subtree->name_a == NULL || subtree->start_a == NULL || 
00635         subtree->end_a  == NULL || subtree->label_a == NULL) {
00636         netsnmp_subtree_free(subtree); /* also frees reginfo */
00637         return MIB_REGISTRATION_FAILED;
00638     }
00639     subtree->namelen   = (u_char)mibloclen;
00640     subtree->start_len = (u_char)mibloclen;
00641     subtree->end_len   = (u_char)mibloclen;
00642     subtree->end_a[mibloclen - 1]++;
00643 
00644     if (var != NULL) {
00645         subtree->variables = (struct variable *)malloc(varsize*numvars);
00646         if (subtree->variables == NULL) {
00647             netsnmp_subtree_free(subtree); /* also frees reginfo */
00648             return MIB_REGISTRATION_FAILED;
00649         }
00650         memcpy(subtree->variables, var, numvars*varsize);
00651         subtree->variables_len = numvars;
00652         subtree->variables_width = varsize;
00653     }
00654     subtree->priority = priority;
00655     subtree->timeout = timeout;
00656     subtree->range_subid = range_subid;
00657     subtree->range_ubound = range_ubound;
00658     subtree->session = ss;
00659     subtree->flags = (u_char)flags;    /*  used to identify instance oids  */
00660     subtree->flags |= SUBTREE_ATTACHED;
00661     subtree->global_cacheid = reginfo->global_cacheid;
00662 
00663     netsnmp_set_lookup_cache_size(0);
00664     res = netsnmp_subtree_load(subtree, context);
00665 
00666     /*  If registering a range, use the first subtree as a template for the
00667         rest of the range.  */
00668 
00669     if (res == MIB_REGISTERED_OK && range_subid != 0) {
00670         for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) {
00671             sub2 = netsnmp_subtree_deepcopy(subtree);
00672 
00673             if (sub2 == NULL) {
00674                 unregister_mib_context(mibloc, mibloclen, priority,
00675                                        range_subid, range_ubound, context);
00676                 netsnmp_set_lookup_cache_size(old_lookup_cache_val);
00677                 invalidate_lookup_cache(context);
00678                 return MIB_REGISTRATION_FAILED;
00679             }
00680 
00681             sub2->name_a[range_subid - 1]  = i;
00682             sub2->start_a[range_subid - 1] = i;
00683             sub2->end_a[range_subid - 1]   = i;     /* XXX - ???? */
00684             if (range_subid == (int)mibloclen)
00685                 ++sub2->end_a[range_subid - 1];
00686             res = netsnmp_subtree_load(sub2, context);
00687             sub2->flags |= SUBTREE_ATTACHED;
00688             if (res != MIB_REGISTERED_OK) {
00689                 unregister_mib_context(mibloc, mibloclen, priority,
00690                                        range_subid, range_ubound, context);
00691                 netsnmp_subtree_free(sub2);
00692                 netsnmp_set_lookup_cache_size(old_lookup_cache_val);
00693                 invalidate_lookup_cache(context);
00694                 return res;
00695             }
00696         }
00697     } else if (res == MIB_DUPLICATE_REGISTRATION ||
00698                res == MIB_REGISTRATION_FAILED) {
00699         netsnmp_set_lookup_cache_size(old_lookup_cache_val);
00700         invalidate_lookup_cache(context);
00701         netsnmp_subtree_free(subtree);
00702         return res;
00703     }
00704 
00705     /*
00706      * mark the MIB as detached, if there's no master agent present as of now 
00707      */
00708     if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
00709                                NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
00710         extern struct snmp_session *main_session;
00711         if (main_session == NULL) {
00712             register_mib_detach_node(subtree);
00713         }
00714     }
00715 
00716     if (res == MIB_REGISTERED_OK && perform_callback) {
00717         memset(&reg_parms, 0x0, sizeof(reg_parms));
00718         reg_parms.name = mibloc;
00719         reg_parms.namelen = mibloclen;
00720         reg_parms.priority = priority;
00721         reg_parms.range_subid = range_subid;
00722         reg_parms.range_ubound = range_ubound;
00723         reg_parms.timeout = timeout;
00724         reg_parms.flags = (u_char) flags;
00725         reg_parms.contextName = context;
00726         snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
00727                             SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
00728     }
00729 
00730     netsnmp_set_lookup_cache_size(old_lookup_cache_val);
00731     invalidate_lookup_cache(context);
00732     return res;
00733 }
00734 
00735 /*
00736  * Reattach a particular node.  
00737  */
00738 
00739 static void
00740 register_mib_reattach_node(netsnmp_subtree *s)
00741 {
00742     if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) {
00743         struct register_parameters reg_parms;
00744         /*
00745          * only do registrations that are not the top level nodes 
00746          */
00747         memset(&reg_parms, 0x0, sizeof(reg_parms));
00748 
00749         /*
00750          * XXX: do this better 
00751          */
00752         reg_parms.name = s->name_a;
00753         reg_parms.namelen = s->namelen;
00754         reg_parms.priority = s->priority;
00755         reg_parms.range_subid = s->range_subid;
00756         reg_parms.range_ubound = s->range_ubound;
00757         reg_parms.timeout = s->timeout;
00758         reg_parms.flags = s->flags;
00759         if ((NULL != s->reginfo) && (NULL != s->reginfo->contextName))
00760             reg_parms.contextName = s->reginfo->contextName;
00761         snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
00762                             SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
00763         s->flags |= SUBTREE_ATTACHED;
00764     }
00765 }
00766 
00767 /*
00768  * Call callbacks to reattach all our nodes.  
00769  */
00770 
00771 void
00772 register_mib_reattach(void)
00773 {
00774     netsnmp_subtree *s, *t;
00775     subtree_context_cache *ptr;
00776 
00777     for (ptr = context_subtrees; ptr; ptr = ptr->next) {
00778         for (s = ptr->first_subtree; s != NULL; s = s->next) {
00779             register_mib_reattach_node(s);
00780             for (t = s->children; t != NULL; t = t->children) {
00781                 register_mib_reattach_node(t);
00782             }
00783         }
00784     }
00785 }
00786 
00787 /*
00788  * Mark a node as detached.  
00789  */
00790 
00791 static void
00792 register_mib_detach_node(netsnmp_subtree *s)
00793 {
00794     if (s != NULL) {
00795         s->flags = s->flags & ~SUBTREE_ATTACHED;
00796     }
00797 }
00798 
00799 /*
00800  * Mark all our registered OIDs as detached.  This is only really
00801  * useful for subagent protocols, when a connection is lost or
00802  * something.  
00803  */
00804 
00805 void
00806 register_mib_detach(void)
00807 {
00808     netsnmp_subtree *s, *t;
00809     subtree_context_cache *ptr;
00810     for (ptr = context_subtrees; ptr; ptr = ptr->next) {
00811         for (s = ptr->first_subtree; s != NULL; s = s->next) {
00812             register_mib_detach_node(s);
00813             for (t = s->children; t != NULL; t = t->children) {
00814                 register_mib_detach_node(t);
00815             }
00816         }
00817     }
00818 }
00819 
00820 int
00821 register_mib_context(const char *moduleName,
00822                      struct variable *var,
00823                      size_t varsize,
00824                      size_t numvars,
00825                      oid * mibloc,
00826                      size_t mibloclen,
00827                      int priority,
00828                      int range_subid,
00829                      oid range_ubound,
00830                      netsnmp_session * ss,
00831                      const char *context, int timeout, int flags)
00832 {
00833     return netsnmp_register_old_api(moduleName, var, varsize, numvars,
00834                                     mibloc, mibloclen, priority,
00835                                     range_subid, range_ubound, ss, context,
00836                                     timeout, flags);
00837 }
00838 
00839 int
00840 register_mib_range(const char *moduleName,
00841                    struct variable *var,
00842                    size_t varsize,
00843                    size_t numvars,
00844                    oid * mibloc,
00845                    size_t mibloclen,
00846                    int priority,
00847                    int range_subid, oid range_ubound, netsnmp_session * ss)
00848 {
00849     return register_mib_context(moduleName, var, varsize, numvars,
00850                                 mibloc, mibloclen, priority,
00851                                 range_subid, range_ubound, ss, "", -1, 0);
00852 }
00853 
00854 int
00855 register_mib_priority(const char *moduleName,
00856                       struct variable *var,
00857                       size_t varsize,
00858                       size_t numvars,
00859                       oid * mibloc, size_t mibloclen, int priority)
00860 {
00861     return register_mib_range(moduleName, var, varsize, numvars,
00862                               mibloc, mibloclen, priority, 0, 0, NULL);
00863 }
00864 
00865 int
00866 register_mib(const char *moduleName,
00867              struct variable *var,
00868              size_t varsize,
00869              size_t numvars, oid * mibloc, size_t mibloclen)
00870 {
00871     return register_mib_priority(moduleName, var, varsize, numvars,
00872                                  mibloc, mibloclen, DEFAULT_MIB_PRIORITY);
00873 }
00874 
00875 void
00876 netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context)
00877 {
00878     netsnmp_subtree *ptr;
00879 
00880     DEBUGMSGTL(("register_mib", "unload("));
00881     if (sub != NULL) {
00882         DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len));
00883     } else {
00884         DEBUGMSG(("register_mib", "[NIL]"));
00885     }
00886     DEBUGMSG(("register_mib", ", "));
00887     if (prev != NULL) {
00888         DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len));
00889     } else {
00890         DEBUGMSG(("register_mib", "[NIL]"));
00891     }
00892     DEBUGMSG(("register_mib", ")\n"));
00893 
00894     if (prev != NULL) {         /* non-leading entries are easy */
00895         prev->children = sub->children;
00896         invalidate_lookup_cache(context);
00897         return;
00898     }
00899     /*
00900      * otherwise, we need to amend our neighbours as well 
00901      */
00902 
00903     if (sub->children == NULL) {        /* just remove this node completely */
00904         for (ptr = sub->prev; ptr; ptr = ptr->children) {
00905             netsnmp_subtree_change_next(ptr, sub->next);
00906         }
00907         for (ptr = sub->next; ptr; ptr = ptr->children) {
00908             netsnmp_subtree_change_prev(ptr, sub->prev);
00909         }
00910 
00911         if (sub->prev == NULL) {
00912             netsnmp_subtree_replace_first(sub->next, context);
00913         }
00914 
00915     } else {
00916         for (ptr = sub->prev; ptr; ptr = ptr->children)
00917             netsnmp_subtree_change_next(ptr, sub->children);
00918         for (ptr = sub->next; ptr; ptr = ptr->children)
00919             netsnmp_subtree_change_prev(ptr, sub->children);
00920 
00921         if (sub->prev == NULL) {
00922             netsnmp_subtree_replace_first(sub->children, context);
00923         }
00924     }
00925     invalidate_lookup_cache(context);
00926 }
00927 
00957 int
00958 unregister_mib_context(oid * name, size_t len, int priority,
00959                        int range_subid, oid range_ubound,
00960                        const char *context)
00961 {
00962     netsnmp_subtree *list, *myptr;
00963     netsnmp_subtree *prev, *child, *next; /* loop through children */
00964     struct register_parameters reg_parms;
00965     int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
00966     netsnmp_set_lookup_cache_size(0);
00967 
00968     DEBUGMSGTL(("register_mib", "unregistering "));
00969     DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound));
00970     DEBUGMSG(("register_mib", "\n"));
00971 
00972     list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context),
00973                                 context);
00974     if (list == NULL) {
00975         return MIB_NO_SUCH_REGISTRATION;
00976     }
00977 
00978     for (child = list, prev = NULL; child != NULL;
00979          prev = child, child = child->children) {
00980         if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 &&
00981             child->priority == priority) {
00982             break;              /* found it */
00983         }
00984     }
00985 
00986     if (child == NULL) {
00987         return MIB_NO_SUCH_REGISTRATION;
00988     }
00989 
00990     netsnmp_subtree_unload(child, prev, context);
00991     myptr = child;              /* remember this for later */
00992 
00993     /*
00994      *  Now handle any occurances in the following subtrees,
00995      *      as a result of splitting this range.  Due to the
00996      *      nature of the way such splits work, the first
00997      *      subtree 'slice' that doesn't refer to the given
00998      *      name marks the end of the original region.
00999      *
01000      *  This should also serve to register ranges.
01001      */
01002 
01003     for (list = myptr->next; list != NULL; list = next) {
01004         next = list->next; /* list gets freed sometimes; cache next */
01005         for (child = list, prev = NULL; child != NULL;
01006              prev = child, child = child->children) {
01007             if ((netsnmp_oid_equals(child->name_a, child->namelen,
01008                                   name, len) == 0) &&
01009                 (child->priority == priority)) {
01010                 netsnmp_subtree_unload(child, prev, context);
01011                 netsnmp_subtree_free(child);
01012                 break;
01013             }
01014         }
01015         if (child == NULL)      /* Didn't find the given name */
01016             break;
01017     }
01018     netsnmp_subtree_free(myptr);
01019 
01020     memset(&reg_parms, 0x0, sizeof(reg_parms));
01021     reg_parms.name = name;
01022     reg_parms.namelen = len;
01023     reg_parms.priority = priority;
01024     reg_parms.range_subid = range_subid;
01025     reg_parms.range_ubound = range_ubound;
01026     reg_parms.flags = 0x00;     /*  this is okay I think  */
01027     reg_parms.contextName = context;
01028     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
01029                         SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
01030 
01031     netsnmp_set_lookup_cache_size(old_lookup_cache_val);
01032     invalidate_lookup_cache(context);
01033     return MIB_UNREGISTERED_OK;
01034 }
01035 
01036 int
01037 netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority,
01038                                  int var_subid, oid range_ubound,
01039                                  const char *context)
01040 {
01041     netsnmp_subtree *list, *myptr;
01042     netsnmp_subtree *prev, *child;       /* loop through children */
01043     struct register_parameters reg_parms;
01044     oid             range_lbound = name[var_subid - 1];
01045 
01046     DEBUGMSGTL(("register_mib", "unregistering "));
01047     DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound));
01048     DEBUGMSG(("register_mib", "\n"));
01049 
01050     for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) {
01051         list = netsnmp_subtree_find(name, len, 
01052                                 netsnmp_subtree_find_first(context), context);
01053 
01054         if (list == NULL) {
01055             continue;
01056         }
01057 
01058         for (child = list, prev = NULL; child != NULL;
01059              prev = child, child = child->children) {
01060 
01061             if (netsnmp_oid_equals(child->name_a, child->namelen, 
01062                                  name, len) == 0 && 
01063                 (child->priority == priority)) {
01064                 break;          /* found it */
01065             }
01066         }
01067 
01068         if (child == NULL) {
01069             continue;
01070         }
01071 
01072         netsnmp_subtree_unload(child, prev, context);
01073         myptr = child;          /* remember this for later */
01074 
01075         for (list = myptr->next; list != NULL; list = list->next) {
01076             for (child = list, prev = NULL; child != NULL;
01077                  prev = child, child = child->children) {
01078 
01079                 if (netsnmp_oid_equals(child->name_a, child->namelen, 
01080                                       name, len) == 0 &&
01081                     (child->priority == priority)) {
01082                     netsnmp_subtree_unload(child, prev, context);
01083                     netsnmp_subtree_free(child);
01084                     break;
01085                 }
01086             }
01087             if (child == NULL) {        /* Didn't find the given name */
01088                 break;
01089             }
01090         }
01091         netsnmp_subtree_free(myptr);
01092     }
01093 
01094     name[var_subid - 1] = range_lbound;
01095     memset(&reg_parms, 0x0, sizeof(reg_parms));
01096     reg_parms.name = name;
01097     reg_parms.namelen = len;
01098     reg_parms.priority = priority;
01099     reg_parms.range_subid = var_subid;
01100     reg_parms.range_ubound = range_ubound;
01101     reg_parms.flags = 0x00;     /*  this is okay I think  */
01102     reg_parms.contextName = context;
01103     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
01104                         SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
01105 
01106     return 0;
01107 }
01108 
01109 int
01110 unregister_mib_range(oid * name, size_t len, int priority,
01111                      int range_subid, oid range_ubound)
01112 {
01113     return unregister_mib_context(name, len, priority, range_subid,
01114                                   range_ubound, "");
01115 }
01116 
01117 int
01118 unregister_mib_priority(oid * name, size_t len, int priority)
01119 {
01120     return unregister_mib_range(name, len, priority, 0, 0);
01121 }
01122 
01123 int
01124 unregister_mib(oid * name, size_t len)
01125 {
01126     return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY);
01127 }
01128 
01129 void
01130 unregister_mibs_by_session(netsnmp_session * ss)
01131 {
01132     netsnmp_subtree *list, *list2;
01133     netsnmp_subtree *child, *prev, *next_child;
01134     struct register_parameters rp;
01135     subtree_context_cache *contextptr;
01136 
01137     DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n",
01138                 ss, (ss && ss->contextName) ? ss->contextName : "[NIL]"));
01139 
01140     for (contextptr = get_top_context_cache(); contextptr != NULL;
01141          contextptr = contextptr->next) {
01142         for (list = contextptr->first_subtree; list != NULL; list = list2) {
01143             list2 = list->next;
01144 
01145             for (child = list, prev = NULL; child != NULL; child = next_child){
01146                 next_child = child->children;
01147 
01148                 if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) &&
01149                      child->session == ss) ||
01150                     (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session &&
01151                      child->session->subsession == ss)) {
01152 
01153                     memset(&rp,0x0,sizeof(rp));
01154                     rp.name = child->name_a;
01155                     child->name_a = NULL;
01156                     rp.namelen = child->namelen;
01157                     rp.priority = child->priority;
01158                     rp.range_subid = child->range_subid;
01159                     rp.range_ubound = child->range_ubound;
01160                     rp.timeout = child->timeout;
01161                     rp.flags = child->flags;
01162                     if ((NULL != child->reginfo) &&
01163                         (NULL != child->reginfo->contextName))
01164                         rp.contextName = child->reginfo->contextName;
01165 
01166                     if (child->reginfo != NULL) {
01167                         /*
01168                          * Don't let's free the session pointer just yet!  
01169                          */
01170                         child->reginfo->handler->myvoid = NULL;
01171                         netsnmp_handler_registration_free(child->reginfo);
01172                         child->reginfo = NULL;
01173                     }
01174 
01175                     netsnmp_subtree_unload(child, prev, contextptr->context_name);
01176                     netsnmp_subtree_free(child);
01177 
01178                     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
01179                                         SNMPD_CALLBACK_UNREGISTER_OID, &rp);
01180                     SNMP_FREE(rp.name);
01181                 } else {
01182                     prev = child;
01183                 }
01184             }
01185         }
01186         netsnmp_subtree_join(contextptr->first_subtree);
01187     }
01188 }
01189 
01190 /*
01191  * in_a_view: determines if a given snmp_pdu is allowed to see a
01192  * given name/namelen OID pointer
01193  * name         IN - name of var, OUT - name matched
01194  * nameLen      IN -number of sub-ids in name, OUT - subid-is in matched name
01195  * pi           IN - relevant auth info re PDU 
01196  * cvp          IN - relevant auth info re mib module
01197  */
01198 
01199 int
01200 in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type)
01201 {
01202     struct view_parameters view_parms;
01203 
01204     if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
01205         /* Enable bypassing of view-based access control */
01206         return VACM_SUCCESS;
01207     }
01208 
01209     /*
01210      * check for v1 and counter64s, since snmpv1 doesn't support it 
01211      */
01212 #ifndef DISABLE_SNMPV1
01213     if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) {
01214         return VACM_NOTINVIEW;
01215     }
01216 #endif
01217 
01218     view_parms.pdu = pdu;
01219     view_parms.name = name;
01220     if (namelen != NULL) {
01221         view_parms.namelen = *namelen;
01222     } else {
01223         view_parms.namelen = 0;
01224     }
01225     view_parms.errorcode = 0;
01226     view_parms.check_subtree = 0;
01227 
01228     switch (pdu->version) {
01229 #ifndef DISABLE_SNMPV1
01230     case SNMP_VERSION_1:
01231 #endif
01232 #ifndef DISABLE_SNMPV2C
01233     case SNMP_VERSION_2c:
01234 #endif
01235     case SNMP_VERSION_3:
01236         snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
01237                             SNMPD_CALLBACK_ACM_CHECK, &view_parms);
01238         return view_parms.errorcode;
01239     }
01240     return VACM_NOSECNAME;
01241 }
01242 
01243 /*
01244  * check_acces: determines if a given snmp_pdu is ever going to be
01245  * allowed to do anynthing or if it's not going to ever be
01246  * authenticated.
01247  */
01248 int
01249 check_access(netsnmp_pdu *pdu)
01250 {                               /* IN - pdu being checked */
01251     struct view_parameters view_parms;
01252     view_parms.pdu = pdu;
01253     view_parms.name = 0;
01254     view_parms.namelen = 0;
01255     view_parms.errorcode = 0;
01256     view_parms.check_subtree = 0;
01257 
01258     if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
01259         /* Enable bypassing of view-based access control */
01260         return 0;
01261     }
01262 
01263     switch (pdu->version) {
01264 #ifndef DISABLE_SNMPV1
01265     case SNMP_VERSION_1:
01266 #endif
01267 #ifndef DISABLE_SNMPV2C
01268     case SNMP_VERSION_2c:
01269 #endif
01270     case SNMP_VERSION_3:
01271         snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
01272                             SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms);
01273         return view_parms.errorcode;
01274     }
01275     return 1;
01276 }
01277 
01285 int
01286 netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen)
01287 {                               /* IN - pdu being checked */
01288     struct view_parameters view_parms;
01289     view_parms.pdu = pdu;
01290     view_parms.name = name;
01291     view_parms.namelen = namelen;
01292     view_parms.errorcode = 0;
01293     view_parms.check_subtree = 1;
01294 
01295     if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
01296         /* Enable bypassing of view-based access control */
01297         return 0;
01298     }
01299 
01300     switch (pdu->version) {
01301 #ifndef DISABLE_SNMPV1
01302     case SNMP_VERSION_1:
01303 #endif
01304 #ifndef DISABLE_SNMPV2C
01305     case SNMP_VERSION_2c:
01306 #endif
01307     case SNMP_VERSION_3:
01308         snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
01309                             SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms);
01310         return view_parms.errorcode;
01311     }
01312     return 1;
01313 }
01314 
01315 #define SUBTREE_DEFAULT_CACHE_SIZE 8
01316 #define SUBTREE_MAX_CACHE_SIZE     32
01317 int lookup_cache_size = 0; /*enabled later after registrations are loaded */
01318 
01319 typedef struct lookup_cache_s {
01320    netsnmp_subtree *next;
01321    netsnmp_subtree *previous;
01322 } lookup_cache;
01323 
01324 typedef struct lookup_cache_context_s {
01325    char *context;
01326    struct lookup_cache_context_s *next;
01327    int thecachecount;
01328    int currentpos;
01329    lookup_cache cache[SUBTREE_MAX_CACHE_SIZE];
01330 } lookup_cache_context;
01331 
01332 static lookup_cache_context *thecontextcache = NULL;
01333 
01345 void
01346 netsnmp_set_lookup_cache_size(int newsize) {
01347     if (newsize < 0)
01348         lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE;
01349     else if (newsize < SUBTREE_MAX_CACHE_SIZE)
01350         lookup_cache_size = newsize;
01351     else
01352         lookup_cache_size = SUBTREE_MAX_CACHE_SIZE;
01353 }
01354 
01358 int
01359 netsnmp_get_lookup_cache_size(void) {
01360     return lookup_cache_size;
01361 }
01362 
01363 NETSNMP_STATIC_INLINE lookup_cache_context *
01364 get_context_lookup_cache(const char *context) {
01365     lookup_cache_context *ptr;
01366     if (!context)
01367         context = "";
01368 
01369     for(ptr = thecontextcache; ptr; ptr = ptr->next) {
01370         if (strcmp(ptr->context, context) == 0)
01371             break;
01372     }
01373     if (!ptr) {
01374         if (netsnmp_subtree_find_first(context)) {
01375             ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context);
01376             ptr->next = thecontextcache;
01377             ptr->context = strdup(context);
01378             thecontextcache = ptr;
01379         } else {
01380             return NULL;
01381         }
01382     }
01383     return ptr;
01384 }
01385 
01386 NETSNMP_STATIC_INLINE void
01387 lookup_cache_add(const char *context,
01388                  netsnmp_subtree *next, netsnmp_subtree *previous) {
01389     lookup_cache_context *cptr;
01390 
01391     if ((cptr = get_context_lookup_cache(context)) == NULL)
01392         return;
01393     
01394     if (cptr->thecachecount < lookup_cache_size)
01395         cptr->thecachecount++;
01396 
01397     cptr->cache[cptr->currentpos].next = next;
01398     cptr->cache[cptr->currentpos].previous = previous;
01399 
01400     if (++cptr->currentpos >= lookup_cache_size)
01401         cptr->currentpos = 0;
01402 }
01403 
01404 NETSNMP_STATIC_INLINE void
01405 lookup_cache_replace(lookup_cache *ptr,
01406                      netsnmp_subtree *next, netsnmp_subtree *previous) {
01407 
01408     ptr->next = next;
01409     ptr->previous = previous;
01410 }
01411 
01412 NETSNMP_STATIC_INLINE lookup_cache *
01413 lookup_cache_find(const char *context, oid *name, size_t name_len,
01414                   int *retcmp) {
01415     lookup_cache_context *cptr;
01416     lookup_cache *ret = NULL;
01417     int cmp;
01418     int i;
01419 
01420     if ((cptr = get_context_lookup_cache(context)) == NULL)
01421         return NULL;
01422 
01423     for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) {
01424         if (cptr->cache[i].previous->start_a)
01425             cmp = snmp_oid_compare(name, name_len,
01426                                    cptr->cache[i].previous->start_a,
01427                                    cptr->cache[i].previous->start_len);
01428         else
01429             cmp = 1;
01430         if (cmp >= 0) {
01431             *retcmp = cmp;
01432             ret = &(cptr->cache[i]);
01433         }
01434     }
01435     return ret;
01436 }
01437 
01438 NETSNMP_STATIC_INLINE void
01439 invalidate_lookup_cache(const char *context) {
01440     lookup_cache_context *cptr;
01441     if ((cptr = get_context_lookup_cache(context)) != NULL) {
01442         cptr->thecachecount = 0;
01443         cptr->currentpos = 0;
01444     }
01445 }
01446 
01447 netsnmp_subtree *
01448 netsnmp_subtree_find_prev(oid *name, size_t len, netsnmp_subtree *subtree,
01449                           const char *context_name)
01450 {
01451     lookup_cache *lookup_cache = NULL;
01452     netsnmp_subtree *myptr = NULL, *previous = NULL;
01453     int cmp = 1;
01454     int ll_off = 0;
01455 
01456     if (subtree) {
01457         myptr = subtree;
01458     } else {
01459         /* look through everything */
01460         if (lookup_cache_size) {
01461             lookup_cache = lookup_cache_find(context_name, name, len, &cmp);
01462             if (lookup_cache) {
01463                 myptr = lookup_cache->next;
01464                 previous = lookup_cache->previous;
01465             }
01466             if (!myptr)
01467                 myptr = netsnmp_subtree_find_first(context_name);
01468         } else {
01469             myptr = netsnmp_subtree_find_first(context_name);
01470         }
01471     }
01472 
01473     /*
01474      * this optimization causes a segfault on sf cf alpha-linux1.
01475      * ifdef out until someone figures out why and fixes it. xxx-rks 20051117
01476      */
01477 #ifndef __alpha
01478 #define WTEST_OPTIMIZATION 1
01479 #endif
01480 #ifdef WTEST_OPTIMIZATION
01481     DEBUGMSGTL(("wtest","oid in: "));
01482     DEBUGMSGOID(("wtest", name, len));
01483     DEBUGMSG(("wtest","\n"));
01484 #endif
01485     for (; myptr != NULL; previous = myptr, myptr = myptr->next) {
01486 #ifdef WTEST_OPTIMIZATION
01487         /* Compare the incoming oid with the linked list.  If we have
01488            results of previous compares, its faster to make sure the
01489            length we differed in the last check is greater than the
01490            length between this pointer and the last then we don't need
01491            to actually perform a comparison */
01492         DEBUGMSGTL(("wtest","oid cmp: "));
01493         DEBUGMSGOID(("wtest", myptr->start_a, myptr->start_len));
01494         DEBUGMSG(("wtest","  --- off = %d, in off = %d test = %d\n",
01495                   myptr->oid_off, ll_off,
01496                   !(ll_off && myptr->oid_off &&
01497                     myptr->oid_off > ll_off)));
01498         if (!(ll_off && myptr->oid_off && myptr->oid_off > ll_off) &&
01499             netsnmp_oid_compare_ll(name, len,
01500                                    myptr->start_a, myptr->start_len,
01501                                    &ll_off) < 0) {
01502 #else
01503         if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) {
01504 #endif
01505             if (lookup_cache_size && previous && cmp) {
01506                 if (lookup_cache) {
01507                     lookup_cache_replace(lookup_cache, myptr, previous);
01508                 } else {
01509                     lookup_cache_add(context_name, myptr, previous);
01510                 }
01511             }
01512             return previous;
01513         }
01514     }
01515     return previous;
01516 }
01517 
01518 netsnmp_subtree *
01519 netsnmp_subtree_find_next(oid *name, size_t len,
01520                           netsnmp_subtree *subtree, const char *context_name)
01521 {
01522     netsnmp_subtree *myptr = NULL;
01523 
01524     myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
01525 
01526     if (myptr != NULL) {
01527         myptr = myptr->next;
01528         while (myptr != NULL && (myptr->variables == NULL || 
01529                                  myptr->variables_len == 0)) {
01530             myptr = myptr->next;
01531         }
01532         return myptr;
01533     } else if (subtree != NULL && snmp_oid_compare(name, len, 
01534                                    subtree->start_a, subtree->start_len) < 0) {
01535         return subtree;
01536     } else {
01537         return NULL;
01538     }
01539 }
01540 
01541 netsnmp_subtree *
01542 netsnmp_subtree_find(oid *name, size_t len, netsnmp_subtree *subtree, 
01543                      const char *context_name)
01544 {
01545     netsnmp_subtree *myptr;
01546 
01547     myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
01548     if (myptr && myptr->end_a &&
01549         snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) {
01550         return myptr;
01551     }
01552 
01553     return NULL;
01554 }
01555 
01556 netsnmp_session *
01557 get_session_for_oid(oid *name, size_t len, const char *context_name)
01558 {
01559     netsnmp_subtree *myptr;
01560 
01561     myptr = netsnmp_subtree_find_prev(name, len, 
01562                                       netsnmp_subtree_find_first(context_name),
01563                                       context_name);
01564 
01565     while (myptr && myptr->variables == NULL) {
01566         myptr = myptr->next;
01567     }
01568 
01569     if (myptr == NULL) {
01570         return NULL;
01571     } else {
01572         return myptr->session;
01573     }
01574 }
01575 
01576 void
01577 setup_tree(void)
01578 {
01579     oid ccitt[1]           = { 0 };
01580     oid iso[1]             = { 1 };
01581     oid joint_ccitt_iso[1] = { 2 };
01582 
01583 #ifdef USING_AGENTX_SUBAGENT_MODULE
01584     int role =  netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
01585                                        NETSNMP_DS_AGENT_ROLE);
01586 
01587     netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
01588                            MASTER_AGENT);
01589 #endif
01590 
01591     /* 
01592      * we need to have the oid's in the heap, that we can *free* it for every case, 
01593      * thats the purpose of the duplicate_objid's
01594      */
01595     netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1);
01596     netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1);
01597     netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1);
01598 
01599 #ifdef USING_AGENTX_SUBAGENT_MODULE
01600     netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
01601                            role);
01602 #endif
01603 }
01604 
01605 int 
01606 remove_tree_entry (oid *name, size_t len) {
01607 
01608     netsnmp_subtree *sub = NULL;
01609 
01610     if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) {
01611         return MIB_NO_SUCH_REGISTRATION;
01612     }
01613 
01614     return unregister_mib_context(name, len, sub->priority,
01615                                   sub->range_subid, sub->range_ubound, "");
01616 
01617 }
01618 
01619 
01620 void
01621 shutdown_tree(void) {
01622     oid ccitt[1]           = { 0 };
01623     oid iso[1]             = { 1 };
01624     oid joint_ccitt_iso[1] = { 2 };
01625 
01626     DEBUGMSGTL(("agent_registry", "shut down tree\n"));
01627 
01628     remove_tree_entry(joint_ccitt_iso, 1);
01629     remove_tree_entry(iso, 1);
01630     remove_tree_entry(ccitt, 1);
01631 
01632 }
01633 
01634 void
01635 clear_subtree (netsnmp_subtree *sub) {
01636 
01637     netsnmp_subtree *nxt;
01638     
01639     if (sub == NULL)
01640         return;
01641 
01642     for(nxt = sub; nxt;) {
01643         if (nxt->children != NULL) {
01644             clear_subtree(nxt->children);
01645         }
01646         sub = nxt;
01647         nxt = nxt->next;
01648         netsnmp_subtree_free(sub);
01649     }
01650 
01651 }
01652 
01653 void
01654 clear_lookup_cache(void) {
01655 
01656     lookup_cache_context *ptr = NULL, *next = NULL;
01657 
01658     ptr = thecontextcache;
01659     while (ptr) {
01660         next = ptr->next;
01661         SNMP_FREE(ptr->context);
01662         SNMP_FREE(ptr);
01663         ptr = next;
01664     }
01665     thecontextcache = NULL; /* !!! */
01666 }
01667 
01668 void
01669 clear_context(void) {
01670 
01671     subtree_context_cache *ptr = NULL, *next = NULL;
01672 
01673     DEBUGMSGTL(("agent_registry", "clear context\n"));
01674 
01675     ptr = get_top_context_cache(); 
01676     while (ptr) {
01677         next = ptr->next;
01678 
01679         if (ptr->first_subtree) {
01680             clear_subtree(ptr->first_subtree);
01681         }
01682 
01683         SNMP_FREE(ptr->context_name);
01684         SNMP_FREE(ptr);
01685 
01686         ptr = next;
01687     }
01688     context_subtrees = NULL; /* !!! */
01689     clear_lookup_cache();
01690 }
01691 
01692 extern void     dump_idx_registry(void);
01693 void
01694 dump_registry(void)
01695 {
01696     struct variable *vp = NULL;
01697     netsnmp_subtree *myptr, *myptr2;
01698     u_char *s = NULL, *e = NULL, *v = NULL;
01699     size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0;
01700     int i = 0;
01701 
01702     if ((s = (u_char *) calloc(sl, 1)) != NULL &&
01703         (e = (u_char *) calloc(sl, 1)) != NULL &&
01704         (v = (u_char *) calloc(sl, 1)) != NULL) {
01705 
01706         subtree_context_cache *ptr;
01707         for (ptr = context_subtrees; ptr; ptr = ptr->next) {
01708             printf("Subtrees for Context: %s\n", ptr->context_name);
01709             for (myptr = ptr->first_subtree; myptr != NULL;
01710                  myptr = myptr->next) {
01711                 sl_o = el_o = vl_o = 0;
01712 
01713                 if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
01714                                           myptr->start_a,
01715                                           myptr->start_len)) {
01716                     break;
01717                 }
01718                 if (!sprint_realloc_objid(&e, &el, &el_o, 1,
01719                                           myptr->end_a,
01720                                           myptr->end_len)) {
01721                     break;
01722                 }
01723 
01724                 if (myptr->variables) {
01725                     printf("%02x ( %s - %s ) [", myptr->flags, s, e);
01726                     for (i = 0, vp = myptr->variables;
01727                          i < myptr->variables_len; i++) {
01728                         vl_o = 0;
01729                         if (!sprint_realloc_objid
01730                             (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) {
01731                             break;
01732                         }
01733                         printf("%s, ", v);
01734                         vp = (struct variable *) ((char *) vp +
01735                                                   myptr->variables_width);
01736                     }
01737                     printf("]\n");
01738                 } else {
01739                     printf("%02x   %s - %s  \n", myptr->flags, s, e);
01740                 }
01741                 for (myptr2 = myptr; myptr2 != NULL;
01742                      myptr2 = myptr2->children) {
01743                     if (myptr2->label_a && myptr2->label_a[0]) {
01744                         if (strcmp(myptr2->label_a, "old_api") == 0) {
01745                             struct variable *vp =
01746                                 myptr2->reginfo->handler->myvoid;
01747 
01748                             sprint_realloc_objid(&s, &sl, &sl_o, 1,
01749                                                  vp->name, vp->namelen);
01750                             printf("\t%s[%s] %p var %s\n", myptr2->label_a,
01751                                    myptr2->reginfo->handlerName ? myptr2->
01752                                    reginfo->handlerName : "no-name",
01753                                    myptr2->reginfo, s);
01754                         } else {
01755                             printf("\t%s %s %p\n", myptr2->label_a,
01756                                    myptr2->reginfo->handlerName ? myptr2->
01757                                    reginfo->
01758                                    handlerName : "no-handler-name",
01759                                    myptr2->reginfo);
01760                         }
01761                     }
01762                 }
01763             }
01764         }
01765     }
01766 
01767     if (s != NULL) {
01768         SNMP_FREE(s);
01769     }
01770     if (e != NULL) {
01771         SNMP_FREE(e);
01772     }
01773     if (v != NULL) {
01774         SNMP_FREE(v);
01775     }
01776 
01777     dump_idx_registry();
01778 }
01779 
01780 int             external_signal_scheduled[NUM_EXTERNAL_SIGS];
01781 void            (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int);
01782 
01783 #ifndef WIN32
01784 
01785 /*
01786  * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines
01787  *       below for every single that might be handled by register_signal().
01788  */
01789 
01790 RETSIGTYPE
01791 agent_SIGCHLD_handler(int sig)
01792 {
01793     external_signal_scheduled[SIGCHLD]++;
01794 #ifndef HAVE_SIGACTION
01795     /*
01796      * signal() sucks. It *might* have SysV semantics, which means that
01797      * * a signal handler is reset once it gets called. Ensure that it
01798      * * remains active.
01799      */
01800     signal(SIGCHLD, agent_SIGCHLD_handler);
01801 #endif
01802 }
01803 
01804 int
01805 register_signal(int sig, void (*func) (int))
01806 {
01807 
01808     switch (sig) {
01809 #if defined(SIGCHLD)
01810     case SIGCHLD:
01811 #ifdef HAVE_SIGACTION
01812         {
01813             static struct sigaction act;
01814             act.sa_handler = agent_SIGCHLD_handler;
01815             sigemptyset(&act.sa_mask);
01816             act.sa_flags = 0;
01817             sigaction(SIGCHLD, &act, NULL);
01818         }
01819 #else
01820         signal(SIGCHLD, agent_SIGCHLD_handler);
01821 #endif
01822         break;
01823 #endif
01824     default:
01825         snmp_log(LOG_CRIT,
01826                  "register_signal: signal %d cannot be handled\n", sig);
01827         return SIG_REGISTRATION_FAILED;
01828     }
01829 
01830     external_signal_handler[sig] = func;
01831     external_signal_scheduled[sig] = 0;
01832 
01833     DEBUGMSGTL(("register_signal", "registered signal %d\n", sig));
01834     return SIG_REGISTERED_OK;
01835 }
01836 
01837 int
01838 unregister_signal(int sig)
01839 {
01840     signal(sig, SIG_DFL);
01841     DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig));
01842     return SIG_UNREGISTERED_OK;
01843 }
01844 
01845 #endif                          /* !WIN32 */
01846 

Generated on Fri Dec 30 13:47:43 2005 for net-snmp by  doxygen 1.3.9.1

Valid CSS!


Last modified: Thursday, 01-Mar-2007 16:20:12 PST
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.