and added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / agent_registry.c
1 /*
2  * agent_registry.c
3  *
4  * Maintain a registry of MIB subtrees, together
5  *   with related information regarding mibmodule, sessions, etc
6  */
7
8 #define IN_SNMP_VARS_C
9
10 #include <net-snmp/net-snmp-config.h>
11 #include <signal.h>
12 #if HAVE_STRING_H
13 #include <string.h>
14 #endif
15 #if HAVE_STDLIB_H
16 #include <stdlib.h>
17 #endif
18 #include <sys/types.h>
19 #include <stdio.h>
20 #include <fcntl.h>
21 #if HAVE_WINSOCK_H
22 #include <winsock.h>
23 #endif
24 #if TIME_WITH_SYS_TIME
25 # ifdef WIN32
26 #  include <sys/timeb.h>
27 # else
28 #  include <sys/time.h>
29 # endif
30 # include <time.h>
31 #else
32 # if HAVE_SYS_TIME_H
33 #  include <sys/time.h>
34 # else
35 #  include <time.h>
36 # endif
37 #endif
38 #if HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
41
42 #if HAVE_DMALLOC_H
43 #include <dmalloc.h>
44 #endif
45
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>
49
50 #include "snmpd.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"
58
59 #ifdef USING_AGENTX_SUBAGENT_MODULE
60 #include "agentx/subagent.h"
61 #include "agentx/client.h"
62 #endif
63
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);
68
69 subtree_context_cache *context_subtrees = NULL;
70
71 void
72 netsnmp_subtree_free(netsnmp_subtree *a)
73 {
74   if (a != NULL) {
75     if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen, 
76                                              a->start_a, a->start_len) == 0) {
77       free(a->variables);
78     }
79     SNMP_FREE(a->name_a);
80     SNMP_FREE(a->start_a);
81     SNMP_FREE(a->end_a);
82     SNMP_FREE(a->label_a);
83     netsnmp_handler_registration_free(a->reginfo);
84     free(a);
85   }
86 }
87
88 netsnmp_subtree *
89 netsnmp_subtree_deepcopy(netsnmp_subtree *a)
90 {
91   netsnmp_subtree *b = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
92
93   if (b != NULL) {
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);
99     
100     if (b->name_a == NULL || b->start_a == NULL || 
101         b->end_a  == NULL || b->label_a == NULL) {
102       netsnmp_subtree_free(b);
103       return NULL;
104     }
105
106     if (a->variables != NULL) {
107       b->variables = (struct variable *)malloc(a->variables_len * 
108                                                a->variables_width);
109       if (b->variables != NULL) {
110         memcpy(b->variables, a->variables,a->variables_len*a->variables_width);
111       } else {
112         netsnmp_subtree_free(b);
113         return NULL;
114       }
115     }
116
117     if (a->reginfo != NULL) {
118       b->reginfo = netsnmp_handler_registration_dup(a->reginfo);
119       if (b->reginfo == NULL) {
120         netsnmp_subtree_free(b);
121         return NULL;
122       }
123     }
124   }
125   return b;
126 }
127
128 subtree_context_cache *
129 get_top_context_cache(void)
130 {
131     return context_subtrees;
132 }
133
134 netsnmp_subtree *
135 netsnmp_subtree_find_first(const char *context_name)
136 {
137     subtree_context_cache *ptr;
138
139     if (!context_name) {
140         context_name = "";
141     }
142
143     DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", 
144                 context_name));
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;
150         }
151     }
152     DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", 
153                 context_name));
154     return NULL;
155 }
156
157 netsnmp_subtree *
158 add_subtree(netsnmp_subtree *new_tree, const char *context_name)
159 {
160     subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache);
161     if (!context_name) {
162         context_name = "";
163     }
164
165     if (!ptr) {
166         return NULL;
167     }
168
169     DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n",      
170                 context_name));
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;
176 }
177
178 netsnmp_subtree *
179 netsnmp_subtree_replace_first(netsnmp_subtree *new_tree, 
180                               const char *context_name)
181 {
182     subtree_context_cache *ptr;
183     if (!context_name) {
184         context_name = "";
185     }
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;
191         }
192     }
193     return add_subtree(new_tree, context_name);
194 }
195
196
197
198 int
199 netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp)
200 {
201     return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen);
202 }
203
204 void
205 netsnmp_subtree_join(netsnmp_subtree *root)
206 {
207     netsnmp_subtree *s, *tmp, *c, *d;
208
209     while (root != NULL) {
210         s = root->next;
211         while (s != NULL && root->reginfo == s->reginfo) {
212             tmp = s->next;
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));
220
221             SNMP_FREE(root->end_a);
222             root->end_a   = s->end_a;
223             root->end_len = s->end_len;
224             s->end_a      = NULL;
225
226             for (c = root; c != NULL; c = c->children) {
227                 c->next = s->next;
228             }
229             for (c = s; c != NULL; c = c->children) {
230                 c->prev = root;
231             }
232             DEBUGMSG(("subtree", " so new end "));
233             DEBUGMSGOID(("subtree", root->end_a, root->end_len));
234             DEBUGMSG(("subtree", "\n"));
235             /*
236              * Probably need to free children too?  
237              */
238             for (c = s->children; c != NULL; c = d) {
239                 d = c->children;
240                 netsnmp_subtree_free(c);
241             }
242             netsnmp_subtree_free(s);
243             s = tmp;
244         }
245         root = root->next;
246     }
247 }
248
249
250         /*
251          *  Split the subtree into two at the specified point,
252          *    returning the new (second) subtree
253          */
254 netsnmp_subtree *
255 netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len)
256 {
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;
261     char *cp;
262     oid *tmp_a, *tmp_b;
263
264     if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) {
265         /* Split comes after the end of this subtree */
266         return NULL;
267     }
268
269     new_sub = netsnmp_subtree_deepcopy(current);
270     if (new_sub == NULL) {
271         return NULL;
272     }
273
274     /*  Set up the point of division.  */
275     tmp_a = snmp_duplicate_objid(name, name_len);
276     if (tmp_a == NULL) {
277         netsnmp_subtree_free(new_sub);
278         return NULL;
279     }
280     tmp_b = snmp_duplicate_objid(name, name_len);
281     if (tmp_b == NULL) {
282         netsnmp_subtree_free(new_sub);
283         free(tmp_a);
284         return NULL;
285     }
286
287     if (current->end_a != NULL) {
288         free(current->end_a);
289     }
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);
294     }
295     new_sub->start_a = tmp_b;
296     new_sub->start_len = name_len;
297
298     /*  Split the variables between the two new subtrees.  */
299     i = current->variables_len;
300     current->variables_len = 0;
301
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.  */
305
306         rc = snmp_oid_compare(vp->name, vp->namelen,
307                               name     + current->namelen, 
308                               name_len - current->namelen);
309
310         if (name_len - current->namelen > vp->namelen) {
311             common_len = vp->namelen;
312         } else {
313             common_len = name_len - current->namelen;
314         }
315
316         rc2 = snmp_oid_compare(vp->name, common_len,
317                                name + current->namelen, common_len);
318
319         if (rc >= 0) {
320             break;  /* All following variables belong to the second subtree */
321         }
322
323         current->variables_len++;
324         if (rc2 < 0) {
325             new_sub->variables_len--;
326             cp = (char *) new_sub->variables;
327             new_sub->variables = (struct variable *)(cp + 
328                                                      new_sub->variables_width);
329         }
330         vp = (struct variable *) ((char *) vp + current->variables_width);
331     }
332
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;
338     }
339
340     /* Propogate this split down through any children */
341     if (current->children) {
342         new_sub->children = netsnmp_subtree_split(current->children, 
343                                                   name, name_len);
344     }
345
346     /* Retain the correct linking of the list */
347     for (ptr = current; ptr != NULL; ptr = ptr->children) {
348       ptr->next = new_sub;
349     }
350     for (ptr = new_sub; ptr != NULL; ptr = ptr->children) {
351       ptr->prev = current;
352     }
353     for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) {
354       ptr->prev = new_sub;
355     }
356
357     return new_sub;
358 }
359
360 int
361 netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name)
362 {
363     netsnmp_subtree *tree1, *tree2, *new2;
364     netsnmp_subtree *prev, *next;
365     int             res, rc = 0;
366
367     if (new_sub == NULL) {
368         return MIB_REGISTERED_OK;       /* Degenerate case */
369     }
370     /*  Find the subtree that contains the start of the new subtree (if
371         any)...*/
372
373     tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, 
374                                  NULL, context_name);
375
376     /*  ... and the subtree that follows the new one (NULL implies this is the
377         final region covered).  */
378
379     if (tree1 == NULL) {
380         tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len,
381                                           NULL, context_name);
382     } else {
383         tree2 = tree1->next;
384     }
385
386     /*  Handle new subtrees that start in virgin territory.  */
387
388     if (tree1 == NULL) {
389         new2 = NULL;
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);
395         }
396
397         /*  Link the new subtree (less any overlapping region) with the list of
398             existing registrations.  */
399
400         if (tree2) {
401             new_sub->prev = tree2->prev;
402             tree2->prev   = new_sub;
403         } else {
404             new_sub->prev = netsnmp_subtree_find_prev(new_sub->start_a,
405                                       new_sub->start_len, NULL, context_name);
406             if (new_sub->prev) {
407                 new_sub->prev->next = new_sub;
408             } else {
409                 netsnmp_subtree_replace_first(new_sub, context_name);
410             }
411
412             new_sub->next = tree2;
413
414             /* If there was any overlap, recurse to merge in the overlapping
415                region (including anything that may follow the overlap).  */
416             if (new2) {
417                 return netsnmp_subtree_load(new2, context_name);
418             }
419         }
420     } else {
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, 
427                                           new_sub->start_len);
428         }
429
430         if (tree1 == NULL) {
431             return MIB_REGISTRATION_FAILED;
432         }
433
434         /*  Now consider the end of this existing subtree:
435             
436             If it matches the new subtree precisely,
437                     simply merge the new one into the list of children
438
439             If it includes the whole of the new subtree,
440                     split it at the appropriate point, and merge again
441      
442             If the new subtree extends beyond this existing region,
443                     split it, and recurse to merge the two parts.  */
444
445         rc = snmp_oid_compare(new_sub->end_a, new_sub->end_len, 
446                               tree1->end_a, tree1->end_len);
447         switch (rc) {
448
449         case -1:
450             /*  Existing subtree contains new one.  */
451             netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len);
452             /* Fall Through */
453
454         case  0:
455             /*  The two trees match precisely.  */
456
457             /*  Note: This is the only point where the original registration
458                 OID ("name") is used.  */
459
460             prev = NULL;
461             next = tree1;
462         
463             while (next && next->namelen > new_sub->namelen) {
464                 prev = next;
465                 next = next->children;
466             }
467
468             while (next && next->namelen == new_sub->namelen &&
469                    next->priority < new_sub->priority ) {
470                 prev = next;
471                 next = next->children;
472             }
473         
474             if (next && (next->namelen  == new_sub->namelen) &&
475                 (next->priority == new_sub->priority)) {
476                 return MIB_DUPLICATE_REGISTRATION;
477             }
478
479             if (prev) {
480                 prev->children    = new_sub;
481                 new_sub->children = next;
482                 new_sub->prev = prev->prev;
483                 new_sub->next = prev->next;
484             } else {
485                 new_sub->children = next;
486                 new_sub->prev = next->prev;
487                 new_sub->next = next->next;
488         
489                 for (next = new_sub->next; next != NULL;next = next->children){
490                     next->prev = new_sub;
491                 }
492
493                 for (prev = new_sub->prev; prev != NULL;prev = prev->children){
494                     prev->next = new_sub;
495                 }
496             }
497             break;
498
499         case  1:
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);
505                 return res;
506             }
507             return netsnmp_subtree_load(new2, context_name);
508         }
509     }
510     return 0;
511 }
512
513 int
514 netsnmp_register_mib(const char *moduleName,
515                      struct variable *var,
516                      size_t varsize,
517                      size_t numvars,
518                      oid * mibloc,
519                      size_t mibloclen,
520                      int priority,
521                      int range_subid,
522                      oid range_ubound,
523                      netsnmp_session * ss,
524                      const char *context,
525                      int timeout,
526                      int flags,
527                      netsnmp_handler_registration *reginfo,
528                      int perform_callback)
529 {
530     netsnmp_subtree *subtree, *sub2;
531     int             res, i;
532     struct register_parameters reg_parms;
533     int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
534
535     subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
536     if (subtree == NULL) {
537         return MIB_REGISTRATION_FAILED;
538     }
539
540     DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
541     DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid,
542                       range_ubound));
543     DEBUGMSG(("register_mib", "\n"));
544
545     /*  Create the new subtree node being registered.  */
546
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;
555     }
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]++;
560
561     if (var != NULL) {
562         subtree->variables = (struct variable *)malloc(varsize*numvars);
563         if (subtree->variables == NULL) {
564             netsnmp_subtree_free(subtree);
565             return MIB_REGISTRATION_FAILED;
566         }
567         memcpy(subtree->variables, var, numvars*varsize);
568         subtree->variables_len = numvars;
569         subtree->variables_width = varsize;
570     }
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;
580
581     netsnmp_set_lookup_cache_size(0);
582     res = netsnmp_subtree_load(subtree, context);
583
584     /*  If registering a range, use the first subtree as a template for the
585         rest of the range.  */
586
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);
590
591             if (sub2 == NULL) {
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;
597             }
598
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);
610                 return res;
611             }
612         }
613     } else if (res == MIB_DUPLICATE_REGISTRATION ||
614                res == MIB_REGISTRATION_FAILED) {
615         netsnmp_subtree_free(subtree);
616     }
617
618     /*
619      * mark the MIB as detached, if there's no master agent present as of now 
620      */
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);
626         }
627     }
628
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;
637
638         /*
639          * Should this really be called if the registration hasn't actually 
640          * succeeded?  
641          */
642
643         snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
644                             SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
645     }
646
647     netsnmp_set_lookup_cache_size(old_lookup_cache_val);
648     invalidate_lookup_cache(context);
649     return res;
650 }
651
652 /*
653  * Reattach a particular node.  
654  */
655
656 static void
657 register_mib_reattach_node(netsnmp_subtree *s)
658 {
659     if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) {
660         struct register_parameters reg_parms;
661         /*
662          * only do registrations that are not the top level nodes 
663          */
664         /*
665          * XXX: do this better 
666          */
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, &reg_parms);
676         s->flags |= SUBTREE_ATTACHED;
677     }
678 }
679
680 /*
681  * Call callbacks to reattach all our nodes.  
682  */
683
684 void
685 register_mib_reattach(void)
686 {
687     netsnmp_subtree *s, *t;
688     subtree_context_cache *ptr;
689
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);
695             }
696         }
697     }
698 }
699
700 /*
701  * Mark a node as detached.  
702  */
703
704 static void
705 register_mib_detach_node(netsnmp_subtree *s)
706 {
707     if (s != NULL) {
708         s->flags = s->flags & ~SUBTREE_ATTACHED;
709     }
710 }
711
712 /*
713  * Mark all our registered OIDs as detached.  This is only really
714  * useful for subagent protocols, when a connection is lost or
715  * something.  
716  */
717
718 void
719 register_mib_detach(void)
720 {
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);
728             }
729         }
730     }
731 }
732
733 int
734 register_mib_context(const char *moduleName,
735                      struct variable *var,
736                      size_t varsize,
737                      size_t numvars,
738                      oid * mibloc,
739                      size_t mibloclen,
740                      int priority,
741                      int range_subid,
742                      oid range_ubound,
743                      netsnmp_session * ss,
744                      const char *context, int timeout, int flags)
745 {
746     return netsnmp_register_old_api(moduleName, var, varsize, numvars,
747                                     mibloc, mibloclen, priority,
748                                     range_subid, range_ubound, ss, context,
749                                     timeout, flags);
750 }
751
752 int
753 register_mib_range(const char *moduleName,
754                    struct variable *var,
755                    size_t varsize,
756                    size_t numvars,
757                    oid * mibloc,
758                    size_t mibloclen,
759                    int priority,
760                    int range_subid, oid range_ubound, netsnmp_session * ss)
761 {
762     return register_mib_context(moduleName, var, varsize, numvars,
763                                 mibloc, mibloclen, priority,
764                                 range_subid, range_ubound, ss, "", -1, 0);
765 }
766
767 int
768 register_mib_priority(const char *moduleName,
769                       struct variable *var,
770                       size_t varsize,
771                       size_t numvars,
772                       oid * mibloc, size_t mibloclen, int priority)
773 {
774     return register_mib_range(moduleName, var, varsize, numvars,
775                               mibloc, mibloclen, priority, 0, 0, NULL);
776 }
777
778 int
779 register_mib(const char *moduleName,
780              struct variable *var,
781              size_t varsize,
782              size_t numvars, oid * mibloc, size_t mibloclen)
783 {
784     return register_mib_priority(moduleName, var, varsize, numvars,
785                                  mibloc, mibloclen, DEFAULT_MIB_PRIORITY);
786 }
787
788 void
789 netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev)
790 {
791     netsnmp_subtree *ptr;
792
793     DEBUGMSGTL(("register_mib", "unload("));
794     if (sub != NULL) {
795         DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len));
796     } else {
797         DEBUGMSG(("register_mib", "[NIL]"));
798     }
799     DEBUGMSG(("register_mib", ", "));
800     if (prev != NULL) {
801         DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len));
802     } else {
803         DEBUGMSG(("register_mib", "[NIL]"));
804     }
805     DEBUGMSG(("register_mib", ")\n"));
806
807     if (prev != NULL) {         /* non-leading entries are easy */
808         prev->children = sub->children;
809         return;
810     }
811     /*
812      * otherwise, we need to amend our neighbours as well 
813      */
814
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;
820         return;
821     } else {
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;
826         return;
827     }
828 }
829
830 int
831 unregister_mib_context(oid * name, size_t len, int priority,
832                        int range_subid, oid range_ubound,
833                        const char *context)
834 {
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);
840
841     DEBUGMSGTL(("register_mib", "unregistering "));
842     DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound));
843     DEBUGMSG(("register_mib", "\n"));
844
845     list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context),
846                                 context);
847     if (list == NULL) {
848         return MIB_NO_SUCH_REGISTRATION;
849     }
850
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 */
856         }
857     }
858
859     if (child == NULL) {
860         return MIB_NO_SUCH_REGISTRATION;
861     }
862
863     netsnmp_subtree_unload(child, prev);
864     myptr = child;              /* remember this for later */
865
866     /*
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.
872      *
873      *  This should also serve to register ranges.
874      */
875
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,
880                                   name, len) == 0) &&
881                 (child->priority == priority)) {
882                 netsnmp_subtree_unload(child, prev);
883                 netsnmp_subtree_free(child);
884                 break;
885             }
886         }
887         if (child == NULL)      /* Didn't find the given name */
888             break;
889     }
890     netsnmp_subtree_free(myptr);
891
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, &reg_parms);
900
901     netsnmp_set_lookup_cache_size(old_lookup_cache_val);
902     invalidate_lookup_cache(context);
903     return MIB_UNREGISTERED_OK;
904 }
905
906 int
907 netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority,
908                                  int var_subid, oid range_ubound,
909                                  const char *context)
910 {
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];
915
916     DEBUGMSGTL(("register_mib", "unregistering "));
917     DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound));
918     DEBUGMSG(("register_mib", "\n"));
919
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);
923
924         if (list == NULL) {
925             continue;
926         }
927
928         for (child = list, prev = NULL; child != NULL;
929              prev = child, child = child->children) {
930
931             if (netsnmp_oid_equals(child->name_a, child->namelen, 
932                                  name, len) == 0 && 
933                 (child->priority == priority)) {
934                 break;          /* found it */
935             }
936         }
937
938         if (child == NULL) {
939             continue;
940         }
941
942         netsnmp_subtree_unload(child, prev);
943         myptr = child;          /* remember this for later */
944
945         for (list = myptr->next; list != NULL; list = list->next) {
946             for (child = list, prev = NULL; child != NULL;
947                  prev = child, child = child->children) {
948
949                 if (netsnmp_oid_equals(child->name_a, child->namelen, 
950                                       name, len) == 0 &&
951                     (child->priority == priority)) {
952                     netsnmp_subtree_unload(child, prev);
953                     netsnmp_subtree_free(child);
954                     break;
955                 }
956             }
957             if (child == NULL) {        /* Didn't find the given name */
958                 break;
959             }
960         }
961         netsnmp_subtree_free(myptr);
962     }
963
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, &reg_parms);
973
974     return 0;
975 }
976
977 int
978 unregister_mib_range(oid * name, size_t len, int priority,
979                      int range_subid, oid range_ubound)
980 {
981     return unregister_mib_context(name, len, priority, range_subid,
982                                   range_ubound, "");
983 }
984
985 int
986 unregister_mib_priority(oid * name, size_t len, int priority)
987 {
988     return unregister_mib_range(name, len, priority, 0, 0);
989 }
990
991 int
992 unregister_mib(oid * name, size_t len)
993 {
994     return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY);
995 }
996
997 void
998 unregister_mibs_by_session(netsnmp_session * ss)
999 {
1000     netsnmp_subtree *list, *list2;
1001     netsnmp_subtree *child, *prev, *next_child;
1002     struct register_parameters rp;
1003     subtree_context_cache *contextptr;
1004
1005     DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n",
1006                 ss, ss->contextName ? ss->contextName : "[NIL]"));
1007
1008     for (contextptr = get_top_context_cache(); contextptr != NULL;
1009          contextptr = contextptr->next) {
1010         for (list = contextptr->first_subtree; list != NULL; list = list2) {
1011             list2 = list->next;
1012
1013             for (child = list, prev = NULL; child != NULL; child = next_child){
1014                 next_child = child->children;
1015
1016                 if (((ss->flags & SNMP_FLAGS_SUBSESSION) &&
1017                      child->session == ss) ||
1018                     (!(ss->flags & SNMP_FLAGS_SUBSESSION) && child->session &&
1019                      child->session->subsession == ss)) {
1020
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;
1029
1030                     if (child->reginfo != NULL) {
1031                         /*
1032                          * Don't let's free the session pointer just yet!  
1033                          */
1034                         child->reginfo->handler->myvoid = NULL;
1035                         netsnmp_handler_registration_free(child->reginfo);
1036                         child->reginfo = NULL;
1037                     }
1038
1039                     netsnmp_subtree_unload(child, prev);
1040                     netsnmp_subtree_free(child);
1041
1042                     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1043                                         SNMPD_CALLBACK_UNREGISTER_OID, &rp);
1044                     SNMP_FREE(rp.name);
1045                 } else {
1046                     prev = child;
1047                 }
1048             }
1049         }
1050         netsnmp_subtree_join(contextptr->first_subtree);
1051     }
1052 }
1053
1054 /*
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
1061  */
1062
1063 int
1064 in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type)
1065 {
1066     struct view_parameters view_parms;
1067
1068     if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
1069         /* Enable bypassing of view-based access control */
1070         return VACM_SUCCESS;
1071     }
1072
1073     /*
1074      * check for v1 and counter64s, since snmpv1 doesn't support it 
1075      */
1076     if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) {
1077         return VACM_NOTINVIEW;
1078     }
1079
1080     view_parms.pdu = pdu;
1081     view_parms.name = name;
1082     if (namelen != NULL) {
1083         view_parms.namelen = *namelen;
1084     } else {
1085         view_parms.namelen = 0;
1086     }
1087     view_parms.errorcode = 0;
1088     view_parms.check_subtree = 0;
1089
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;
1097     }
1098     return VACM_NOSECNAME;
1099 }
1100
1101 /*
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
1104  * authenticated.
1105  */
1106 int
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;
1115
1116     if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
1117         /* Enable bypassing of view-based access control */
1118         return 0;
1119     }
1120
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;
1128     }
1129     return 1;
1130 }
1131
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).
1138  */
1139 int
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;
1148
1149     if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
1150         /* Enable bypassing of view-based access control */
1151         return 0;
1152     }
1153
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;
1161     }
1162     return 1;
1163 }
1164
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 */
1168
1169 typedef struct lookup_cache_s {
1170    netsnmp_subtree *next;
1171    netsnmp_subtree *previous;
1172 } lookup_cache;
1173
1174 typedef struct lookup_cache_context_s {
1175    char *context;
1176    struct lookup_cache_context_s *next;
1177    int thecachecount;
1178    int currentpos;
1179    lookup_cache cache[SUBTREE_MAX_CACHE_SIZE];
1180 } lookup_cache_context;
1181
1182 static lookup_cache_context *thecontextcache = NULL;
1183
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.
1194  */
1195 void
1196 netsnmp_set_lookup_cache_size(int newsize) {
1197     if (newsize < 0)
1198         lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE;
1199     else if (newsize < SUBTREE_MAX_CACHE_SIZE)
1200         lookup_cache_size = newsize;
1201     else
1202         lookup_cache_size = SUBTREE_MAX_CACHE_SIZE;
1203 }
1204
1205 /** retrieves the current value of the lookup cache size
1206  *  @return the current lookup cache size
1207  */
1208 int
1209 netsnmp_get_lookup_cache_size(void) {
1210     return lookup_cache_size;
1211 }
1212
1213 static NETSNMP_INLINE lookup_cache_context *
1214 get_context_lookup_cache(const char *context) {
1215     lookup_cache_context *ptr;
1216     if (!context)
1217         context = "";
1218
1219     for(ptr = thecontextcache; ptr; ptr = ptr->next) {
1220         if (strcmp(ptr->context, context) == 0)
1221             break;
1222     }
1223     if (!ptr) {
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;
1229         } else {
1230             return NULL;
1231         }
1232     }
1233     return ptr;
1234 }
1235
1236 static NETSNMP_INLINE void
1237 lookup_cache_add(const char *context,
1238                  netsnmp_subtree *next, netsnmp_subtree *previous) {
1239     lookup_cache_context *cptr;
1240
1241     if ((cptr = get_context_lookup_cache(context)) == NULL)
1242         return;
1243     
1244     if (cptr->thecachecount < lookup_cache_size)
1245         cptr->thecachecount++;
1246
1247     cptr->cache[cptr->currentpos].next = next;
1248     cptr->cache[cptr->currentpos].previous = previous;
1249
1250     if (++cptr->currentpos >= lookup_cache_size)
1251         cptr->currentpos = 0;
1252 }
1253
1254 static NETSNMP_INLINE void
1255 lookup_cache_replace(lookup_cache *ptr,
1256                      netsnmp_subtree *next, netsnmp_subtree *previous) {
1257
1258     ptr->next = next;
1259     ptr->previous = previous;
1260 }
1261
1262 static NETSNMP_INLINE lookup_cache *
1263 lookup_cache_find(const char *context, oid *name, size_t name_len,
1264                   int *retcmp) {
1265     lookup_cache_context *cptr;
1266     lookup_cache *ret = NULL;
1267     int cmp;
1268     int i;
1269
1270     if ((cptr = get_context_lookup_cache(context)) == NULL)
1271         return NULL;
1272
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);
1278         else
1279             cmp = 1;
1280         if (cmp >= 0) {
1281             *retcmp = cmp;
1282             ret = &(cptr->cache[i]);
1283         }
1284     }
1285     return ret;
1286 }
1287
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;
1294     }
1295 }
1296
1297 netsnmp_subtree *
1298 netsnmp_subtree_find_prev(oid *name, size_t len, netsnmp_subtree *subtree,
1299                           const char *context_name)
1300 {
1301     lookup_cache *lookup_cache = NULL;
1302     netsnmp_subtree *myptr = NULL, *previous = NULL;
1303     int cmp = 1;
1304
1305     if (subtree) {
1306         myptr = subtree;
1307     } else {
1308         /* look through everything */
1309         if (lookup_cache_size) {
1310             lookup_cache = lookup_cache_find(context_name, name, len, &cmp);
1311             if (lookup_cache) {
1312                 myptr = lookup_cache->next;
1313                 previous = lookup_cache->previous;
1314             }
1315             if (!myptr)
1316                 myptr = netsnmp_subtree_find_first(context_name);
1317         } else {
1318             myptr = netsnmp_subtree_find_first(context_name);
1319         }
1320     }
1321
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) {
1325                 if (lookup_cache) {
1326                     lookup_cache_replace(lookup_cache, myptr, previous);
1327                 } else {
1328                     lookup_cache_add(context_name, myptr, previous);
1329                 }
1330             }
1331             return previous;
1332         }
1333     }
1334     return previous;
1335 }
1336
1337 netsnmp_subtree *
1338 netsnmp_subtree_find_next(oid *name, size_t len,
1339                           netsnmp_subtree *subtree, const char *context_name)
1340 {
1341     netsnmp_subtree *myptr = NULL;
1342
1343     myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
1344
1345     if (myptr != NULL) {
1346         myptr = myptr->next;
1347         while (myptr != NULL && (myptr->variables == NULL || 
1348                                  myptr->variables_len == 0)) {
1349             myptr = myptr->next;
1350         }
1351         return myptr;
1352     } else if (subtree != NULL && snmp_oid_compare(name, len, 
1353                                    subtree->start_a, subtree->start_len) < 0) {
1354         return subtree;
1355     } else {
1356         return NULL;
1357     }
1358 }
1359
1360 netsnmp_subtree *
1361 netsnmp_subtree_find(oid *name, size_t len, netsnmp_subtree *subtree, 
1362                      const char *context_name)
1363 {
1364     netsnmp_subtree *myptr;
1365
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) {
1369         return myptr;
1370     }
1371
1372     return NULL;
1373 }
1374
1375 netsnmp_session *
1376 get_session_for_oid(oid *name, size_t len, const char *context_name)
1377 {
1378     netsnmp_subtree *myptr;
1379
1380     myptr = netsnmp_subtree_find_prev(name, len, 
1381                                       netsnmp_subtree_find_first(context_name),
1382                                       context_name);
1383
1384     while (myptr && myptr->variables == NULL) {
1385         myptr = myptr->next;
1386     }
1387
1388     if (myptr == NULL) {
1389         return NULL;
1390     } else {
1391         return myptr->session;
1392     }
1393 }
1394
1395 void
1396 setup_tree(void)
1397 {
1398     oid ccitt[1]           = { 0 };
1399     oid iso[1]             = { 1 };
1400     oid joint_ccitt_iso[1] = { 2 };
1401
1402 #ifdef USING_AGENTX_SUBAGENT_MODULE
1403     int role =  netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
1404                                        NETSNMP_DS_AGENT_ROLE);
1405
1406     netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
1407                            MASTER_AGENT);
1408 #endif
1409
1410     netsnmp_register_null(ccitt, 1);
1411     netsnmp_register_null(iso, 1);
1412     netsnmp_register_null(joint_ccitt_iso, 1);
1413
1414 #ifdef USING_AGENTX_SUBAGENT_MODULE
1415     netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
1416                            role);
1417 #endif
1418 }
1419
1420 #ifdef BRCM_SNMP_DEBUG
1421 extern void     dump_idx_registry(void);
1422 void
1423 dump_registry(void)
1424 {
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;
1429     int i = 0;
1430
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) {
1434
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;
1441
1442                 if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
1443                                           myptr->start_a,
1444                                           myptr->start_len)) {
1445                     break;
1446                 }
1447                 if (!sprint_realloc_objid(&e, &el, &el_o, 1,
1448                                           myptr->end_a,
1449                                           myptr->end_len)) {
1450                     break;
1451                 }
1452
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++) {
1457                         vl_o = 0;
1458                         if (!sprint_realloc_objid
1459                             (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) {
1460                             break;
1461                         }
1462                         printf("%s, ", v);
1463                         vp = (struct variable *) ((char *) vp +
1464                                                   myptr->variables_width);
1465                     }
1466                     printf("]\n");
1467                 } else {
1468                     printf("%02x   %s - %s  \n", myptr->flags, s, e);
1469                 }
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;
1476
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);
1483                         } else {
1484                             printf("\t%s %s %p\n", myptr2->label_a,
1485                                    myptr2->reginfo->handlerName ? myptr2->
1486                                    reginfo->
1487                                    handlerName : "no-handler-name",
1488                                    myptr2->reginfo);
1489                         }
1490                     }
1491                 }
1492             }
1493         }
1494     }
1495
1496     if (s != NULL) {
1497         free(s);
1498     }
1499     if (e != NULL) {
1500         free(e);
1501     }
1502     if (v != NULL) {
1503         free(v);
1504     }
1505
1506     dump_idx_registry();
1507 }
1508 #endif
1509
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];
1519
1520 int
1521 register_readfd(int fd, void (*func) (int, void *), void *data)
1522 {
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;
1530     } else {
1531         snmp_log(LOG_CRIT, "register_readfd: too many file descriptors\n");
1532         return FD_REGISTRATION_FAILED;
1533     }
1534 }
1535
1536 int
1537 register_writefd(int fd, void (*func) (int, void *), void *data)
1538 {
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;
1546     } else {
1547         snmp_log(LOG_CRIT,
1548                  "register_writefd: too many file descriptors\n");
1549         return FD_REGISTRATION_FAILED;
1550     }
1551 }
1552
1553 int
1554 register_exceptfd(int fd, void (*func) (int, void *), void *data)
1555 {
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;
1563     } else {
1564         snmp_log(LOG_CRIT,
1565                  "register_exceptfd: too many file descriptors\n");
1566         return FD_REGISTRATION_FAILED;
1567     }
1568 }
1569
1570 int
1571 unregister_readfd(int fd)
1572 {
1573     int             i, j;
1574
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];
1582             }
1583             DEBUGMSGTL(("unregister_readfd", "unregistered fd %d\n", fd));
1584             return FD_UNREGISTERED_OK;
1585         }
1586     }
1587     return FD_NO_SUCH_REGISTRATION;
1588 }
1589
1590 int
1591 unregister_writefd(int fd)
1592 {
1593     int             i, j;
1594
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];
1602             }
1603             DEBUGMSGTL(("unregister_writefd", "unregistered fd %d\n", fd));
1604             return FD_UNREGISTERED_OK;
1605         }
1606     }
1607     return FD_NO_SUCH_REGISTRATION;
1608 }
1609
1610 int
1611 unregister_exceptfd(int fd)
1612 {
1613     int             i, j;
1614
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];
1622             }
1623             DEBUGMSGTL(("unregister_exceptfd", "unregistered fd %d\n",
1624                         fd));
1625             return FD_UNREGISTERED_OK;
1626         }
1627     }
1628     return FD_NO_SUCH_REGISTRATION;
1629 }
1630
1631 int             external_signal_scheduled[NUM_EXTERNAL_SIGS];
1632 void            (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int);
1633
1634 #ifndef WIN32
1635
1636 /*
1637  * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines
1638  *       below for every single that might be handled by register_signal().
1639  */
1640
1641 RETSIGTYPE
1642 agent_SIGCHLD_handler(int sig)
1643 {
1644     external_signal_scheduled[SIGCHLD]++;
1645 #ifndef HAVE_SIGACTION
1646     /*
1647      * signal() sucks. It *might* have SysV semantics, which means that
1648      * * a signal handler is reset once it gets called. Ensure that it
1649      * * remains active.
1650      */
1651     signal(SIGCHLD, agent_SIGCHLD_handler);
1652 #endif
1653 }
1654
1655 int
1656 register_signal(int sig, void (*func) (int))
1657 {
1658
1659     switch (sig) {
1660 #if defined(SIGCHLD)
1661     case SIGCHLD:
1662 #ifdef HAVE_SIGACTION
1663         {
1664             static struct sigaction act;
1665             act.sa_handler = agent_SIGCHLD_handler;
1666             sigemptyset(&act.sa_mask);
1667             act.sa_flags = 0;
1668             sigaction(SIGCHLD, &act, NULL);
1669         }
1670 #else
1671         signal(SIGCHLD, agent_SIGCHLD_handler);
1672 #endif
1673         break;
1674 #endif
1675     default:
1676         snmp_log(LOG_CRIT,
1677                  "register_signal: signal %d cannot be handled\n", sig);
1678         return SIG_REGISTRATION_FAILED;
1679     }
1680
1681     external_signal_handler[sig] = func;
1682     external_signal_scheduled[sig] = 0;
1683
1684     DEBUGMSGTL(("register_signal", "registered signal %d\n", sig));
1685     return SIG_REGISTERED_OK;
1686 }
1687
1688 int
1689 unregister_signal(int sig)
1690 {
1691     signal(sig, SIG_DFL);
1692     DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig));
1693     return SIG_UNREGISTERED_OK;
1694 }
1695
1696 #endif                          /* !WIN32 */