4 * Maintain a registry of MIB subtrees, together
5 * with related information regarding mibmodule, sessions, etc
10 #include <net-snmp/net-snmp-config.h>
18 #include <sys/types.h>
24 #if TIME_WITH_SYS_TIME
26 # include <sys/timeb.h>
28 # include <sys/time.h>
33 # include <sys/time.h>
39 #include <netinet/in.h>
46 #include <net-snmp/net-snmp-includes.h>
47 #include <net-snmp/agent/net-snmp-agent-includes.h>
48 #include <net-snmp/agent/agent_callbacks.h>
51 #include "mibgroup/struct.h"
52 #include <net-snmp/agent/old_api.h>
53 #include <net-snmp/agent/null.h>
54 #include <net-snmp/agent/table.h>
55 #include <net-snmp/agent/table_iterator.h>
56 #include <net-snmp/agent/agent_registry.h>
57 #include "mib_module_includes.h"
59 #ifdef USING_AGENTX_SUBAGENT_MODULE
60 #include "agentx/subagent.h"
61 #include "agentx/client.h"
64 static void register_mib_detach_node(netsnmp_subtree *s);
65 static NETSNMP_INLINE void invalidate_lookup_cache(const char *context);
66 void netsnmp_set_lookup_cache_size(int newsize);
67 int netsnmp_get_lookup_cache_size(void);
69 subtree_context_cache *context_subtrees = NULL;
72 netsnmp_subtree_free(netsnmp_subtree *a)
75 if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen,
76 a->start_a, a->start_len) == 0) {
80 SNMP_FREE(a->start_a);
82 SNMP_FREE(a->label_a);
83 netsnmp_handler_registration_free(a->reginfo);
89 netsnmp_subtree_deepcopy(netsnmp_subtree *a)
91 netsnmp_subtree *b = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
94 memcpy(b, a, sizeof(netsnmp_subtree));
95 b->name_a = snmp_duplicate_objid(a->name_a, a->namelen);
96 b->start_a = snmp_duplicate_objid(a->start_a, a->start_len);
97 b->end_a = snmp_duplicate_objid(a->end_a, a->end_len);
98 b->label_a = strdup(a->label_a);
100 if (b->name_a == NULL || b->start_a == NULL ||
101 b->end_a == NULL || b->label_a == NULL) {
102 netsnmp_subtree_free(b);
106 if (a->variables != NULL) {
107 b->variables = (struct variable *)malloc(a->variables_len *
109 if (b->variables != NULL) {
110 memcpy(b->variables, a->variables,a->variables_len*a->variables_width);
112 netsnmp_subtree_free(b);
117 if (a->reginfo != NULL) {
118 b->reginfo = netsnmp_handler_registration_dup(a->reginfo);
119 if (b->reginfo == NULL) {
120 netsnmp_subtree_free(b);
128 subtree_context_cache *
129 get_top_context_cache(void)
131 return context_subtrees;
135 netsnmp_subtree_find_first(const char *context_name)
137 subtree_context_cache *ptr;
143 DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n",
145 for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
146 if (ptr->context_name != NULL &&
147 strcmp(ptr->context_name, context_name) == 0) {
148 DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name));
149 return ptr->first_subtree;
152 DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n",
158 add_subtree(netsnmp_subtree *new_tree, const char *context_name)
160 subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache);
169 DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n",
171 ptr->next = context_subtrees;
172 ptr->first_subtree = new_tree;
173 ptr->context_name = strdup(context_name);
174 context_subtrees = ptr;
175 return ptr->first_subtree;
179 netsnmp_subtree_replace_first(netsnmp_subtree *new_tree,
180 const char *context_name)
182 subtree_context_cache *ptr;
186 for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
187 if (ptr->context_name != NULL &&
188 strcmp(ptr->context_name, context_name) == 0) {
189 ptr->first_subtree = new_tree;
190 return ptr->first_subtree;
193 return add_subtree(new_tree, context_name);
199 netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp)
201 return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen);
205 netsnmp_subtree_join(netsnmp_subtree *root)
207 netsnmp_subtree *s, *tmp, *c, *d;
209 while (root != NULL) {
211 while (s != NULL && root->reginfo == s->reginfo) {
213 DEBUGMSGTL(("subtree", "root start "));
214 DEBUGMSGOID(("subtree", root->start_a, root->start_len));
215 DEBUGMSG(("subtree", " (original end "));
216 DEBUGMSGOID(("subtree", root->end_a, root->end_len));
217 DEBUGMSG(("subtree", ")\n"));
218 DEBUGMSGTL(("subtree", " JOINING to "));
219 DEBUGMSGOID(("subtree", s->start_a, s->start_len));
221 SNMP_FREE(root->end_a);
222 root->end_a = s->end_a;
223 root->end_len = s->end_len;
226 for (c = root; c != NULL; c = c->children) {
229 for (c = s; c != NULL; c = c->children) {
232 DEBUGMSG(("subtree", " so new end "));
233 DEBUGMSGOID(("subtree", root->end_a, root->end_len));
234 DEBUGMSG(("subtree", "\n"));
236 * Probably need to free children too?
238 for (c = s->children; c != NULL; c = d) {
240 netsnmp_subtree_free(c);
242 netsnmp_subtree_free(s);
251 * Split the subtree into two at the specified point,
252 * returning the new (second) subtree
255 netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len)
257 struct variable *vp = NULL;
258 netsnmp_subtree *new_sub, *ptr;
259 int i = 0, rc = 0, rc2 = 0;
260 size_t common_len = 0;
264 if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) {
265 /* Split comes after the end of this subtree */
269 new_sub = netsnmp_subtree_deepcopy(current);
270 if (new_sub == NULL) {
274 /* Set up the point of division. */
275 tmp_a = snmp_duplicate_objid(name, name_len);
277 netsnmp_subtree_free(new_sub);
280 tmp_b = snmp_duplicate_objid(name, name_len);
282 netsnmp_subtree_free(new_sub);
287 if (current->end_a != NULL) {
288 free(current->end_a);
290 current->end_a = tmp_a;
291 current->end_len = name_len;
292 if (new_sub->start_a != NULL) {
293 free(new_sub->start_a);
295 new_sub->start_a = tmp_b;
296 new_sub->start_len = name_len;
298 /* Split the variables between the two new subtrees. */
299 i = current->variables_len;
300 current->variables_len = 0;
302 for (vp = current->variables; i > 0; i--) {
303 /* Note that the variable "name" field omits the prefix common to the
304 whole registration, hence the strange comparison here. */
306 rc = snmp_oid_compare(vp->name, vp->namelen,
307 name + current->namelen,
308 name_len - current->namelen);
310 if (name_len - current->namelen > vp->namelen) {
311 common_len = vp->namelen;
313 common_len = name_len - current->namelen;
316 rc2 = snmp_oid_compare(vp->name, common_len,
317 name + current->namelen, common_len);
320 break; /* All following variables belong to the second subtree */
323 current->variables_len++;
325 new_sub->variables_len--;
326 cp = (char *) new_sub->variables;
327 new_sub->variables = (struct variable *)(cp +
328 new_sub->variables_width);
330 vp = (struct variable *) ((char *) vp + current->variables_width);
333 /* Delegated trees should retain their variables regardless */
334 if (current->variables_len > 0 &&
335 IS_DELEGATED((u_char) current->variables[0].type)) {
336 new_sub->variables_len = 1;
337 new_sub->variables = current->variables;
340 /* Propogate this split down through any children */
341 if (current->children) {
342 new_sub->children = netsnmp_subtree_split(current->children,
346 /* Retain the correct linking of the list */
347 for (ptr = current; ptr != NULL; ptr = ptr->children) {
350 for (ptr = new_sub; ptr != NULL; ptr = ptr->children) {
353 for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) {
361 netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name)
363 netsnmp_subtree *tree1, *tree2, *new2;
364 netsnmp_subtree *prev, *next;
367 if (new_sub == NULL) {
368 return MIB_REGISTERED_OK; /* Degenerate case */
370 /* Find the subtree that contains the start of the new subtree (if
373 tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len,
376 /* ... and the subtree that follows the new one (NULL implies this is the
377 final region covered). */
380 tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len,
386 /* Handle new subtrees that start in virgin territory. */
390 /* Is there any overlap with later subtrees? */
391 if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len,
392 tree2->start_a, tree2->start_len) > 0) {
393 new2 = netsnmp_subtree_split(new_sub,
394 tree2->start_a, tree2->start_len);
397 /* Link the new subtree (less any overlapping region) with the list of
398 existing registrations. */
401 new_sub->prev = tree2->prev;
402 tree2->prev = new_sub;
404 new_sub->prev = netsnmp_subtree_find_prev(new_sub->start_a,
405 new_sub->start_len, NULL, context_name);
407 new_sub->prev->next = new_sub;
409 netsnmp_subtree_replace_first(new_sub, context_name);
412 new_sub->next = tree2;
414 /* If there was any overlap, recurse to merge in the overlapping
415 region (including anything that may follow the overlap). */
417 return netsnmp_subtree_load(new2, context_name);
421 /* If the new subtree starts *within* an existing registration
422 (rather than at the same point as it), then split the existing
423 subtree at this point. */
424 if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len,
425 tree1->start_a, tree1->start_len) != 0) {
426 tree1 = netsnmp_subtree_split(tree1, new_sub->start_a,
431 return MIB_REGISTRATION_FAILED;
434 /* Now consider the end of this existing subtree:
436 If it matches the new subtree precisely,
437 simply merge the new one into the list of children
439 If it includes the whole of the new subtree,
440 split it at the appropriate point, and merge again
442 If the new subtree extends beyond this existing region,
443 split it, and recurse to merge the two parts. */
445 rc = snmp_oid_compare(new_sub->end_a, new_sub->end_len,
446 tree1->end_a, tree1->end_len);
450 /* Existing subtree contains new one. */
451 netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len);
455 /* The two trees match precisely. */
457 /* Note: This is the only point where the original registration
458 OID ("name") is used. */
463 while (next && next->namelen > new_sub->namelen) {
465 next = next->children;
468 while (next && next->namelen == new_sub->namelen &&
469 next->priority < new_sub->priority ) {
471 next = next->children;
474 if (next && (next->namelen == new_sub->namelen) &&
475 (next->priority == new_sub->priority)) {
476 return MIB_DUPLICATE_REGISTRATION;
480 prev->children = new_sub;
481 new_sub->children = next;
482 new_sub->prev = prev->prev;
483 new_sub->next = prev->next;
485 new_sub->children = next;
486 new_sub->prev = next->prev;
487 new_sub->next = next->next;
489 for (next = new_sub->next; next != NULL;next = next->children){
490 next->prev = new_sub;
493 for (prev = new_sub->prev; prev != NULL;prev = prev->children){
494 prev->next = new_sub;
500 /* New subtree contains the existing one. */
501 new2 = netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len);
502 res = netsnmp_subtree_load(new_sub, context_name);
503 if (res != MIB_REGISTERED_OK) {
504 netsnmp_subtree_free(new2);
507 return netsnmp_subtree_load(new2, context_name);
514 netsnmp_register_mib(const char *moduleName,
515 struct variable *var,
523 netsnmp_session * ss,
527 netsnmp_handler_registration *reginfo,
528 int perform_callback)
530 netsnmp_subtree *subtree, *sub2;
532 struct register_parameters reg_parms;
533 int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
535 subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
536 if (subtree == NULL) {
537 return MIB_REGISTRATION_FAILED;
540 DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
541 DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid,
543 DEBUGMSG(("register_mib", "\n"));
545 /* Create the new subtree node being registered. */
547 subtree->name_a = snmp_duplicate_objid(mibloc, mibloclen);
548 subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen);
549 subtree->end_a = snmp_duplicate_objid(mibloc, mibloclen);
550 subtree->label_a = strdup(moduleName);
551 if (subtree->name_a == NULL || subtree->start_a == NULL ||
552 subtree->end_a == NULL || subtree->label_a == NULL) {
553 netsnmp_subtree_free(subtree);
554 return MIB_REGISTRATION_FAILED;
556 subtree->namelen = (u_char)mibloclen;
557 subtree->start_len = (u_char)mibloclen;
558 subtree->end_len = (u_char)mibloclen;
559 subtree->end_a[mibloclen - 1]++;
562 subtree->variables = (struct variable *)malloc(varsize*numvars);
563 if (subtree->variables == NULL) {
564 netsnmp_subtree_free(subtree);
565 return MIB_REGISTRATION_FAILED;
567 memcpy(subtree->variables, var, numvars*varsize);
568 subtree->variables_len = numvars;
569 subtree->variables_width = varsize;
571 subtree->priority = priority;
572 subtree->timeout = timeout;
573 subtree->range_subid = range_subid;
574 subtree->range_ubound = range_ubound;
575 subtree->session = ss;
576 subtree->reginfo = reginfo;
577 subtree->flags = (u_char)flags; /* used to identify instance oids */
578 subtree->flags |= SUBTREE_ATTACHED;
579 subtree->global_cacheid = reginfo->global_cacheid;
581 netsnmp_set_lookup_cache_size(0);
582 res = netsnmp_subtree_load(subtree, context);
584 /* If registering a range, use the first subtree as a template for the
585 rest of the range. */
587 if (res == MIB_REGISTERED_OK && range_subid != 0) {
588 for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) {
589 sub2 = netsnmp_subtree_deepcopy(subtree);
592 unregister_mib_context(mibloc, mibloclen, priority,
593 range_subid, range_ubound, context);
594 netsnmp_set_lookup_cache_size(old_lookup_cache_val);
595 invalidate_lookup_cache(context);
596 return MIB_REGISTRATION_FAILED;
599 sub2->name_a[range_subid - 1] = i;
600 sub2->start_a[range_subid - 1] = i;
601 sub2->end_a[range_subid - 1] = i; /* XXX - ???? */
602 res = netsnmp_subtree_load(sub2, context);
603 sub2->flags |= SUBTREE_ATTACHED;
604 if (res != MIB_REGISTERED_OK) {
605 unregister_mib_context(mibloc, mibloclen, priority,
606 range_subid, range_ubound, context);
607 netsnmp_subtree_free(sub2);
608 netsnmp_set_lookup_cache_size(old_lookup_cache_val);
609 invalidate_lookup_cache(context);
613 } else if (res == MIB_DUPLICATE_REGISTRATION ||
614 res == MIB_REGISTRATION_FAILED) {
615 netsnmp_subtree_free(subtree);
619 * mark the MIB as detached, if there's no master agent present as of now
621 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
622 NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
623 extern struct snmp_session *main_session;
624 if (main_session == NULL) {
625 register_mib_detach_node(subtree);
629 if (perform_callback) {
630 reg_parms.name = mibloc;
631 reg_parms.namelen = mibloclen;
632 reg_parms.priority = priority;
633 reg_parms.range_subid = range_subid;
634 reg_parms.range_ubound = range_ubound;
635 reg_parms.timeout = timeout;
636 reg_parms.flags = (u_char) flags;
639 * Should this really be called if the registration hasn't actually
643 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
644 SNMPD_CALLBACK_REGISTER_OID, ®_parms);
647 netsnmp_set_lookup_cache_size(old_lookup_cache_val);
648 invalidate_lookup_cache(context);
653 * Reattach a particular node.
657 register_mib_reattach_node(netsnmp_subtree *s)
659 if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) {
660 struct register_parameters reg_parms;
662 * only do registrations that are not the top level nodes
665 * XXX: do this better
667 reg_parms.name = s->name_a;
668 reg_parms.namelen = s->namelen;
669 reg_parms.priority = s->priority;
670 reg_parms.range_subid = s->range_subid;
671 reg_parms.range_ubound = s->range_ubound;
672 reg_parms.timeout = s->timeout;
673 reg_parms.flags = s->flags;
674 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
675 SNMPD_CALLBACK_REGISTER_OID, ®_parms);
676 s->flags |= SUBTREE_ATTACHED;
681 * Call callbacks to reattach all our nodes.
685 register_mib_reattach(void)
687 netsnmp_subtree *s, *t;
688 subtree_context_cache *ptr;
690 for (ptr = context_subtrees; ptr; ptr = ptr->next) {
691 for (s = ptr->first_subtree; s != NULL; s = s->next) {
692 register_mib_reattach_node(s);
693 for (t = s->children; t != NULL; t = t->children) {
694 register_mib_reattach_node(t);
701 * Mark a node as detached.
705 register_mib_detach_node(netsnmp_subtree *s)
708 s->flags = s->flags & ~SUBTREE_ATTACHED;
713 * Mark all our registered OIDs as detached. This is only really
714 * useful for subagent protocols, when a connection is lost or
719 register_mib_detach(void)
721 netsnmp_subtree *s, *t;
722 subtree_context_cache *ptr;
723 for (ptr = context_subtrees; ptr; ptr = ptr->next) {
724 for (s = ptr->first_subtree; s != NULL; s = s->next) {
725 register_mib_detach_node(s);
726 for (t = s->children; t != NULL; t = t->children) {
727 register_mib_detach_node(t);
734 register_mib_context(const char *moduleName,
735 struct variable *var,
743 netsnmp_session * ss,
744 const char *context, int timeout, int flags)
746 return netsnmp_register_old_api(moduleName, var, varsize, numvars,
747 mibloc, mibloclen, priority,
748 range_subid, range_ubound, ss, context,
753 register_mib_range(const char *moduleName,
754 struct variable *var,
760 int range_subid, oid range_ubound, netsnmp_session * ss)
762 return register_mib_context(moduleName, var, varsize, numvars,
763 mibloc, mibloclen, priority,
764 range_subid, range_ubound, ss, "", -1, 0);
768 register_mib_priority(const char *moduleName,
769 struct variable *var,
772 oid * mibloc, size_t mibloclen, int priority)
774 return register_mib_range(moduleName, var, varsize, numvars,
775 mibloc, mibloclen, priority, 0, 0, NULL);
779 register_mib(const char *moduleName,
780 struct variable *var,
782 size_t numvars, oid * mibloc, size_t mibloclen)
784 return register_mib_priority(moduleName, var, varsize, numvars,
785 mibloc, mibloclen, DEFAULT_MIB_PRIORITY);
789 netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev)
791 netsnmp_subtree *ptr;
793 DEBUGMSGTL(("register_mib", "unload("));
795 DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len));
797 DEBUGMSG(("register_mib", "[NIL]"));
799 DEBUGMSG(("register_mib", ", "));
801 DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len));
803 DEBUGMSG(("register_mib", "[NIL]"));
805 DEBUGMSG(("register_mib", ")\n"));
807 if (prev != NULL) { /* non-leading entries are easy */
808 prev->children = sub->children;
812 * otherwise, we need to amend our neighbours as well
815 if (sub->children == NULL) { /* just remove this node completely */
816 for (ptr = sub->prev; ptr; ptr = ptr->children)
817 ptr->next = sub->next;
818 for (ptr = sub->next; ptr; ptr = ptr->children)
819 ptr->prev = sub->prev;
822 for (ptr = sub->prev; ptr; ptr = ptr->children)
823 ptr->next = sub->children;
824 for (ptr = sub->next; ptr; ptr = ptr->children)
825 ptr->prev = sub->children;
831 unregister_mib_context(oid * name, size_t len, int priority,
832 int range_subid, oid range_ubound,
835 netsnmp_subtree *list, *myptr;
836 netsnmp_subtree *prev, *child; /* loop through children */
837 struct register_parameters reg_parms;
838 int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
839 netsnmp_set_lookup_cache_size(0);
841 DEBUGMSGTL(("register_mib", "unregistering "));
842 DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound));
843 DEBUGMSG(("register_mib", "\n"));
845 list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context),
848 return MIB_NO_SUCH_REGISTRATION;
851 for (child = list, prev = NULL; child != NULL;
852 prev = child, child = child->children) {
853 if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 &&
854 child->priority == priority) {
855 break; /* found it */
860 return MIB_NO_SUCH_REGISTRATION;
863 netsnmp_subtree_unload(child, prev);
864 myptr = child; /* remember this for later */
867 * Now handle any occurances in the following subtrees,
868 * as a result of splitting this range. Due to the
869 * nature of the way such splits work, the first
870 * subtree 'slice' that doesn't refer to the given
871 * name marks the end of the original region.
873 * This should also serve to register ranges.
876 for (list = myptr->next; list != NULL; list = list->next) {
877 for (child = list, prev = NULL; child != NULL;
878 prev = child, child = child->children) {
879 if ((netsnmp_oid_equals(child->name_a, child->namelen,
881 (child->priority == priority)) {
882 netsnmp_subtree_unload(child, prev);
883 netsnmp_subtree_free(child);
887 if (child == NULL) /* Didn't find the given name */
890 netsnmp_subtree_free(myptr);
892 reg_parms.name = name;
893 reg_parms.namelen = len;
894 reg_parms.priority = priority;
895 reg_parms.range_subid = range_subid;
896 reg_parms.range_ubound = range_ubound;
897 reg_parms.flags = 0x00; /* this is okay I think */
898 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
899 SNMPD_CALLBACK_UNREGISTER_OID, ®_parms);
901 netsnmp_set_lookup_cache_size(old_lookup_cache_val);
902 invalidate_lookup_cache(context);
903 return MIB_UNREGISTERED_OK;
907 netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority,
908 int var_subid, oid range_ubound,
911 netsnmp_subtree *list, *myptr;
912 netsnmp_subtree *prev, *child; /* loop through children */
913 struct register_parameters reg_parms;
914 oid range_lbound = name[var_subid - 1];
916 DEBUGMSGTL(("register_mib", "unregistering "));
917 DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound));
918 DEBUGMSG(("register_mib", "\n"));
920 for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) {
921 list = netsnmp_subtree_find(name, len,
922 netsnmp_subtree_find_first(context), context);
928 for (child = list, prev = NULL; child != NULL;
929 prev = child, child = child->children) {
931 if (netsnmp_oid_equals(child->name_a, child->namelen,
933 (child->priority == priority)) {
934 break; /* found it */
942 netsnmp_subtree_unload(child, prev);
943 myptr = child; /* remember this for later */
945 for (list = myptr->next; list != NULL; list = list->next) {
946 for (child = list, prev = NULL; child != NULL;
947 prev = child, child = child->children) {
949 if (netsnmp_oid_equals(child->name_a, child->namelen,
951 (child->priority == priority)) {
952 netsnmp_subtree_unload(child, prev);
953 netsnmp_subtree_free(child);
957 if (child == NULL) { /* Didn't find the given name */
961 netsnmp_subtree_free(myptr);
964 name[var_subid - 1] = range_lbound;
965 reg_parms.name = name;
966 reg_parms.namelen = len;
967 reg_parms.priority = priority;
968 reg_parms.range_subid = var_subid;
969 reg_parms.range_ubound = range_ubound;
970 reg_parms.flags = 0x00; /* this is okay I think */
971 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
972 SNMPD_CALLBACK_UNREGISTER_OID, ®_parms);
978 unregister_mib_range(oid * name, size_t len, int priority,
979 int range_subid, oid range_ubound)
981 return unregister_mib_context(name, len, priority, range_subid,
986 unregister_mib_priority(oid * name, size_t len, int priority)
988 return unregister_mib_range(name, len, priority, 0, 0);
992 unregister_mib(oid * name, size_t len)
994 return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY);
998 unregister_mibs_by_session(netsnmp_session * ss)
1000 netsnmp_subtree *list, *list2;
1001 netsnmp_subtree *child, *prev, *next_child;
1002 struct register_parameters rp;
1003 subtree_context_cache *contextptr;
1005 DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n",
1006 ss, ss->contextName ? ss->contextName : "[NIL]"));
1008 for (contextptr = get_top_context_cache(); contextptr != NULL;
1009 contextptr = contextptr->next) {
1010 for (list = contextptr->first_subtree; list != NULL; list = list2) {
1013 for (child = list, prev = NULL; child != NULL; child = next_child){
1014 next_child = child->children;
1016 if (((ss->flags & SNMP_FLAGS_SUBSESSION) &&
1017 child->session == ss) ||
1018 (!(ss->flags & SNMP_FLAGS_SUBSESSION) && child->session &&
1019 child->session->subsession == ss)) {
1021 rp.name = child->name_a;
1022 child->name_a = NULL;
1023 rp.namelen = child->namelen;
1024 rp.priority = child->priority;
1025 rp.range_subid = child->range_subid;
1026 rp.range_ubound = child->range_ubound;
1027 rp.timeout = child->timeout;
1028 rp.flags = child->flags;
1030 if (child->reginfo != NULL) {
1032 * Don't let's free the session pointer just yet!
1034 child->reginfo->handler->myvoid = NULL;
1035 netsnmp_handler_registration_free(child->reginfo);
1036 child->reginfo = NULL;
1039 netsnmp_subtree_unload(child, prev);
1040 netsnmp_subtree_free(child);
1042 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1043 SNMPD_CALLBACK_UNREGISTER_OID, &rp);
1050 netsnmp_subtree_join(contextptr->first_subtree);
1055 * in_a_view: determines if a given snmp_pdu is allowed to see a
1056 * given name/namelen OID pointer
1057 * name IN - name of var, OUT - name matched
1058 * nameLen IN -number of sub-ids in name, OUT - subid-is in matched name
1059 * pi IN - relevant auth info re PDU
1060 * cvp IN - relevant auth info re mib module
1064 in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type)
1066 struct view_parameters view_parms;
1068 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
1069 /* Enable bypassing of view-based access control */
1070 return VACM_SUCCESS;
1074 * check for v1 and counter64s, since snmpv1 doesn't support it
1076 if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) {
1077 return VACM_NOTINVIEW;
1080 view_parms.pdu = pdu;
1081 view_parms.name = name;
1082 if (namelen != NULL) {
1083 view_parms.namelen = *namelen;
1085 view_parms.namelen = 0;
1087 view_parms.errorcode = 0;
1088 view_parms.check_subtree = 0;
1090 switch (pdu->version) {
1091 case SNMP_VERSION_1:
1092 case SNMP_VERSION_2c:
1093 case SNMP_VERSION_3:
1094 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1095 SNMPD_CALLBACK_ACM_CHECK, &view_parms);
1096 return view_parms.errorcode;
1098 return VACM_NOSECNAME;
1102 * check_acces: determines if a given snmp_pdu is ever going to be
1103 * allowed to do anynthing or if it's not going to ever be
1107 check_access(netsnmp_pdu *pdu)
1108 { /* IN - pdu being checked */
1109 struct view_parameters view_parms;
1110 view_parms.pdu = pdu;
1111 view_parms.name = 0;
1112 view_parms.namelen = 0;
1113 view_parms.errorcode = 0;
1114 view_parms.check_subtree = 0;
1116 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
1117 /* Enable bypassing of view-based access control */
1121 switch (pdu->version) {
1122 case SNMP_VERSION_1:
1123 case SNMP_VERSION_2c:
1124 case SNMP_VERSION_3:
1125 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1126 SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms);
1127 return view_parms.errorcode;
1132 /** checks to see if everything within a
1133 * given subtree is either: in view, not in view, or possibly both.
1134 * If the entire subtree is not-in-view we can use this information to
1135 * skip calling the sub-handlers entirely.
1136 * @returns 0 if entire subtree is accessible, 5 if not and 7 if
1137 * portions are both. 1 on error (illegal pdu version).
1140 netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen)
1141 { /* IN - pdu being checked */
1142 struct view_parameters view_parms;
1143 view_parms.pdu = pdu;
1144 view_parms.name = name;
1145 view_parms.namelen = namelen;
1146 view_parms.errorcode = 0;
1147 view_parms.check_subtree = 1;
1149 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
1150 /* Enable bypassing of view-based access control */
1154 switch (pdu->version) {
1155 case SNMP_VERSION_1:
1156 case SNMP_VERSION_2c:
1157 case SNMP_VERSION_3:
1158 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1159 SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms);
1160 return view_parms.errorcode;
1165 #define SUBTREE_DEFAULT_CACHE_SIZE 8
1166 #define SUBTREE_MAX_CACHE_SIZE 32
1167 int lookup_cache_size = 0; /*enabled later after registrations are loaded */
1169 typedef struct lookup_cache_s {
1170 netsnmp_subtree *next;
1171 netsnmp_subtree *previous;
1174 typedef struct lookup_cache_context_s {
1176 struct lookup_cache_context_s *next;
1179 lookup_cache cache[SUBTREE_MAX_CACHE_SIZE];
1180 } lookup_cache_context;
1182 static lookup_cache_context *thecontextcache = NULL;
1184 /** set the lookup cache size for optimized agent registration performance.
1185 * @param newsize set to the maximum size of a cache for a given
1186 * context. Set to 0 to completely disable caching, or to -1 to set
1187 * to the default cache size (8), or to a number of your chosing. The
1188 * rough guide is that it should be equal to the maximum number of
1189 * simultanious managers you expect to talk to the agent (M) times 80%
1190 * (or so, he says randomly) the average number (N) of varbinds you
1191 * expect to receive in a given request for a manager. ie, M times N.
1192 * Bigger does NOT necessarily mean better. Certainly 16 should be an
1193 * upper limit. 32 is the hard coded limit.
1196 netsnmp_set_lookup_cache_size(int newsize) {
1198 lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE;
1199 else if (newsize < SUBTREE_MAX_CACHE_SIZE)
1200 lookup_cache_size = newsize;
1202 lookup_cache_size = SUBTREE_MAX_CACHE_SIZE;
1205 /** retrieves the current value of the lookup cache size
1206 * @return the current lookup cache size
1209 netsnmp_get_lookup_cache_size(void) {
1210 return lookup_cache_size;
1213 static NETSNMP_INLINE lookup_cache_context *
1214 get_context_lookup_cache(const char *context) {
1215 lookup_cache_context *ptr;
1219 for(ptr = thecontextcache; ptr; ptr = ptr->next) {
1220 if (strcmp(ptr->context, context) == 0)
1224 if (netsnmp_subtree_find_first(context)) {
1225 ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context);
1226 ptr->next = thecontextcache;
1227 ptr->context = strdup(context);
1228 thecontextcache = ptr;
1236 static NETSNMP_INLINE void
1237 lookup_cache_add(const char *context,
1238 netsnmp_subtree *next, netsnmp_subtree *previous) {
1239 lookup_cache_context *cptr;
1241 if ((cptr = get_context_lookup_cache(context)) == NULL)
1244 if (cptr->thecachecount < lookup_cache_size)
1245 cptr->thecachecount++;
1247 cptr->cache[cptr->currentpos].next = next;
1248 cptr->cache[cptr->currentpos].previous = previous;
1250 if (++cptr->currentpos >= lookup_cache_size)
1251 cptr->currentpos = 0;
1254 static NETSNMP_INLINE void
1255 lookup_cache_replace(lookup_cache *ptr,
1256 netsnmp_subtree *next, netsnmp_subtree *previous) {
1259 ptr->previous = previous;
1262 static NETSNMP_INLINE lookup_cache *
1263 lookup_cache_find(const char *context, oid *name, size_t name_len,
1265 lookup_cache_context *cptr;
1266 lookup_cache *ret = NULL;
1270 if ((cptr = get_context_lookup_cache(context)) == NULL)
1273 for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) {
1274 if (cptr->cache[i].previous->start_a)
1275 cmp = snmp_oid_compare(name, name_len,
1276 cptr->cache[i].previous->start_a,
1277 cptr->cache[i].previous->start_len);
1282 ret = &(cptr->cache[i]);
1288 static NETSNMP_INLINE void
1289 invalidate_lookup_cache(const char *context) {
1290 lookup_cache_context *cptr;
1291 if ((cptr = get_context_lookup_cache(context)) != NULL) {
1292 cptr->thecachecount = 0;
1293 cptr->currentpos = 0;
1298 netsnmp_subtree_find_prev(oid *name, size_t len, netsnmp_subtree *subtree,
1299 const char *context_name)
1301 lookup_cache *lookup_cache = NULL;
1302 netsnmp_subtree *myptr = NULL, *previous = NULL;
1308 /* look through everything */
1309 if (lookup_cache_size) {
1310 lookup_cache = lookup_cache_find(context_name, name, len, &cmp);
1312 myptr = lookup_cache->next;
1313 previous = lookup_cache->previous;
1316 myptr = netsnmp_subtree_find_first(context_name);
1318 myptr = netsnmp_subtree_find_first(context_name);
1322 for (; myptr != NULL; previous = myptr, myptr = myptr->next) {
1323 if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) {
1324 if (lookup_cache_size && previous && cmp) {
1326 lookup_cache_replace(lookup_cache, myptr, previous);
1328 lookup_cache_add(context_name, myptr, previous);
1338 netsnmp_subtree_find_next(oid *name, size_t len,
1339 netsnmp_subtree *subtree, const char *context_name)
1341 netsnmp_subtree *myptr = NULL;
1343 myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
1345 if (myptr != NULL) {
1346 myptr = myptr->next;
1347 while (myptr != NULL && (myptr->variables == NULL ||
1348 myptr->variables_len == 0)) {
1349 myptr = myptr->next;
1352 } else if (subtree != NULL && snmp_oid_compare(name, len,
1353 subtree->start_a, subtree->start_len) < 0) {
1361 netsnmp_subtree_find(oid *name, size_t len, netsnmp_subtree *subtree,
1362 const char *context_name)
1364 netsnmp_subtree *myptr;
1366 myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
1367 if (myptr && myptr->end_a &&
1368 snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) {
1376 get_session_for_oid(oid *name, size_t len, const char *context_name)
1378 netsnmp_subtree *myptr;
1380 myptr = netsnmp_subtree_find_prev(name, len,
1381 netsnmp_subtree_find_first(context_name),
1384 while (myptr && myptr->variables == NULL) {
1385 myptr = myptr->next;
1388 if (myptr == NULL) {
1391 return myptr->session;
1398 oid ccitt[1] = { 0 };
1400 oid joint_ccitt_iso[1] = { 2 };
1402 #ifdef USING_AGENTX_SUBAGENT_MODULE
1403 int role = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1404 NETSNMP_DS_AGENT_ROLE);
1406 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE,
1410 netsnmp_register_null(ccitt, 1);
1411 netsnmp_register_null(iso, 1);
1412 netsnmp_register_null(joint_ccitt_iso, 1);
1414 #ifdef USING_AGENTX_SUBAGENT_MODULE
1415 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE,
1420 #ifdef BRCM_SNMP_DEBUG
1421 extern void dump_idx_registry(void);
1425 struct variable *vp = NULL;
1426 netsnmp_subtree *myptr, *myptr2;
1427 u_char *s = NULL, *e = NULL, *v = NULL;
1428 size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0;
1431 if ((s = (u_char *) calloc(sl, 1)) != NULL &&
1432 (e = (u_char *) calloc(sl, 1)) != NULL &&
1433 (v = (u_char *) calloc(sl, 1)) != NULL) {
1435 subtree_context_cache *ptr;
1436 for (ptr = context_subtrees; ptr; ptr = ptr->next) {
1437 printf("Subtrees for Context: %s\n", ptr->context_name);
1438 for (myptr = ptr->first_subtree; myptr != NULL;
1439 myptr = myptr->next) {
1440 sl_o = el_o = vl_o = 0;
1442 if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
1444 myptr->start_len)) {
1447 if (!sprint_realloc_objid(&e, &el, &el_o, 1,
1453 if (myptr->variables) {
1454 printf("%02x ( %s - %s ) [", myptr->flags, s, e);
1455 for (i = 0, vp = myptr->variables;
1456 i < myptr->variables_len; i++) {
1458 if (!sprint_realloc_objid
1459 (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) {
1463 vp = (struct variable *) ((char *) vp +
1464 myptr->variables_width);
1468 printf("%02x %s - %s \n", myptr->flags, s, e);
1470 for (myptr2 = myptr; myptr2 != NULL;
1471 myptr2 = myptr2->children) {
1472 if (myptr2->label_a && myptr2->label_a[0]) {
1473 if (strcmp(myptr2->label_a, "old_api") == 0) {
1474 struct variable *vp =
1475 myptr2->reginfo->handler->myvoid;
1477 sprint_realloc_objid(&s, &sl, &sl_o, 1,
1478 vp->name, vp->namelen);
1479 printf("\t%s[%s] %p var %s\n", myptr2->label_a,
1480 myptr2->reginfo->handlerName ? myptr2->
1481 reginfo->handlerName : "no-name",
1482 myptr2->reginfo, s);
1484 printf("\t%s %s %p\n", myptr2->label_a,
1485 myptr2->reginfo->handlerName ? myptr2->
1487 handlerName : "no-handler-name",
1506 dump_idx_registry();
1510 int external_readfd[NUM_EXTERNAL_FDS], external_readfdlen = 0;
1511 int external_writefd[NUM_EXTERNAL_FDS], external_writefdlen = 0;
1512 int external_exceptfd[NUM_EXTERNAL_FDS], external_exceptfdlen = 0;
1513 void (*external_readfdfunc[NUM_EXTERNAL_FDS]) (int, void *);
1514 void (*external_writefdfunc[NUM_EXTERNAL_FDS]) (int, void *);
1515 void (*external_exceptfdfunc[NUM_EXTERNAL_FDS]) (int, void *);
1516 void *external_readfd_data[NUM_EXTERNAL_FDS];
1517 void *external_writefd_data[NUM_EXTERNAL_FDS];
1518 void *external_exceptfd_data[NUM_EXTERNAL_FDS];
1521 register_readfd(int fd, void (*func) (int, void *), void *data)
1523 if (external_readfdlen < NUM_EXTERNAL_FDS) {
1524 external_readfd[external_readfdlen] = fd;
1525 external_readfdfunc[external_readfdlen] = func;
1526 external_readfd_data[external_readfdlen] = data;
1527 external_readfdlen++;
1528 DEBUGMSGTL(("register_readfd", "registered fd %d\n", fd));
1529 return FD_REGISTERED_OK;
1531 snmp_log(LOG_CRIT, "register_readfd: too many file descriptors\n");
1532 return FD_REGISTRATION_FAILED;
1537 register_writefd(int fd, void (*func) (int, void *), void *data)
1539 if (external_writefdlen < NUM_EXTERNAL_FDS) {
1540 external_writefd[external_writefdlen] = fd;
1541 external_writefdfunc[external_writefdlen] = func;
1542 external_writefd_data[external_writefdlen] = data;
1543 external_writefdlen++;
1544 DEBUGMSGTL(("register_writefd", "registered fd %d\n", fd));
1545 return FD_REGISTERED_OK;
1548 "register_writefd: too many file descriptors\n");
1549 return FD_REGISTRATION_FAILED;
1554 register_exceptfd(int fd, void (*func) (int, void *), void *data)
1556 if (external_exceptfdlen < NUM_EXTERNAL_FDS) {
1557 external_exceptfd[external_exceptfdlen] = fd;
1558 external_exceptfdfunc[external_exceptfdlen] = func;
1559 external_exceptfd_data[external_exceptfdlen] = data;
1560 external_exceptfdlen++;
1561 DEBUGMSGTL(("register_exceptfd", "registered fd %d\n", fd));
1562 return FD_REGISTERED_OK;
1565 "register_exceptfd: too many file descriptors\n");
1566 return FD_REGISTRATION_FAILED;
1571 unregister_readfd(int fd)
1575 for (i = 0; i < external_readfdlen; i++) {
1576 if (external_readfd[i] == fd) {
1577 external_readfdlen--;
1578 for (j = i; j < external_readfdlen; j++) {
1579 external_readfd[j] = external_readfd[j + 1];
1580 external_readfdfunc[j] = external_readfdfunc[j + 1];
1581 external_readfd_data[j] = external_readfd_data[j + 1];
1583 DEBUGMSGTL(("unregister_readfd", "unregistered fd %d\n", fd));
1584 return FD_UNREGISTERED_OK;
1587 return FD_NO_SUCH_REGISTRATION;
1591 unregister_writefd(int fd)
1595 for (i = 0; i < external_writefdlen; i++) {
1596 if (external_writefd[i] == fd) {
1597 external_writefdlen--;
1598 for (j = i; j < external_writefdlen; j++) {
1599 external_writefd[j] = external_writefd[j + 1];
1600 external_writefdfunc[j] = external_writefdfunc[j + 1];
1601 external_writefd_data[j] = external_writefd_data[j + 1];
1603 DEBUGMSGTL(("unregister_writefd", "unregistered fd %d\n", fd));
1604 return FD_UNREGISTERED_OK;
1607 return FD_NO_SUCH_REGISTRATION;
1611 unregister_exceptfd(int fd)
1615 for (i = 0; i < external_exceptfdlen; i++) {
1616 if (external_exceptfd[i] == fd) {
1617 external_exceptfdlen--;
1618 for (j = i; j < external_exceptfdlen; j++) {
1619 external_exceptfd[j] = external_exceptfd[j + 1];
1620 external_exceptfdfunc[j] = external_exceptfdfunc[j + 1];
1621 external_exceptfd_data[j] = external_exceptfd_data[j + 1];
1623 DEBUGMSGTL(("unregister_exceptfd", "unregistered fd %d\n",
1625 return FD_UNREGISTERED_OK;
1628 return FD_NO_SUCH_REGISTRATION;
1631 int external_signal_scheduled[NUM_EXTERNAL_SIGS];
1632 void (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int);
1637 * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines
1638 * below for every single that might be handled by register_signal().
1642 agent_SIGCHLD_handler(int sig)
1644 external_signal_scheduled[SIGCHLD]++;
1645 #ifndef HAVE_SIGACTION
1647 * signal() sucks. It *might* have SysV semantics, which means that
1648 * * a signal handler is reset once it gets called. Ensure that it
1651 signal(SIGCHLD, agent_SIGCHLD_handler);
1656 register_signal(int sig, void (*func) (int))
1660 #if defined(SIGCHLD)
1662 #ifdef HAVE_SIGACTION
1664 static struct sigaction act;
1665 act.sa_handler = agent_SIGCHLD_handler;
1666 sigemptyset(&act.sa_mask);
1668 sigaction(SIGCHLD, &act, NULL);
1671 signal(SIGCHLD, agent_SIGCHLD_handler);
1677 "register_signal: signal %d cannot be handled\n", sig);
1678 return SIG_REGISTRATION_FAILED;
1681 external_signal_handler[sig] = func;
1682 external_signal_scheduled[sig] = 0;
1684 DEBUGMSGTL(("register_signal", "registered signal %d\n", sig));
1685 return SIG_REGISTERED_OK;
1689 unregister_signal(int sig)
1691 signal(sig, SIG_DFL);
1692 DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig));
1693 return SIG_UNREGISTERED_OK;