]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/snmp/agent/v2_0/src/agent_registry.c
Initial revision
[karo-tx-redboot.git] / packages / net / snmp / agent / v2_0 / src / agent_registry.c
1 //==========================================================================
2 //
3 //      ./agent/current/src/agent_registry.c
4 //
5 //
6 //==========================================================================
7 //####ECOSGPLCOPYRIGHTBEGIN####
8 // -------------------------------------------
9 // This file is part of eCos, the Embedded Configurable Operating System.
10 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
11 //
12 // eCos is free software; you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 2 or (at your option) any later version.
15 //
16 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 // for more details.
20 //
21 // You should have received a copy of the GNU General Public License along
22 // with eCos; if not, write to the Free Software Foundation, Inc.,
23 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 //
25 // As a special exception, if other files instantiate templates or use macros
26 // or inline functions from this file, or you compile this file and link it
27 // with other works to produce a work based on this file, this file does not
28 // by itself cause the resulting work to be covered by the GNU General Public
29 // License. However the source code for this file must still be made available
30 // in accordance with section (3) of the GNU General Public License.
31 //
32 // This exception does not invalidate any other reasons why a work based on
33 // this file might be covered by the GNU General Public License.
34 //
35 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
36 // at http://sources.redhat.com/ecos/ecos-license/
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //####UCDSNMPCOPYRIGHTBEGIN####
40 //
41 // -------------------------------------------
42 //
43 // Portions of this software may have been derived from the UCD-SNMP
44 // project,  <http://ucd-snmp.ucdavis.edu/>  from the University of
45 // California at Davis, which was originally based on the Carnegie Mellon
46 // University SNMP implementation.  Portions of this software are therefore
47 // covered by the appropriate copyright disclaimers included herein.
48 //
49 // The release used was version 4.1.2 of May 2000.  "ucd-snmp-4.1.2"
50 // -------------------------------------------
51 //
52 //####UCDSNMPCOPYRIGHTEND####
53 //==========================================================================
54 //#####DESCRIPTIONBEGIN####
55 //
56 // Author(s):    hmt
57 // Contributors: hmt
58 // Date:         2000-05-30
59 // Purpose:      Port of UCD-SNMP distribution to eCos.
60 // Description:  
61 //              
62 //
63 //####DESCRIPTIONEND####
64 //
65 //==========================================================================
66 /********************************************************************
67        Copyright 1989, 1991, 1992 by Carnegie Mellon University
68
69                           Derivative Work -
70 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
71
72                          All Rights Reserved
73
74 Permission to use, copy, modify and distribute this software and its
75 documentation for any purpose and without fee is hereby granted,
76 provided that the above copyright notice appears in all copies and
77 that both that copyright notice and this permission notice appear in
78 supporting documentation, and that the name of CMU and The Regents of
79 the University of California not be used in advertising or publicity
80 pertaining to distribution of the software without specific written
81 permission.
82
83 CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
84 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
85 WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL CMU OR
86 THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
87 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
88 FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
89 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
90 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
91 *********************************************************************/
92 /*
93  * agent_registry.c
94  *
95  * Maintain a registry of MIB subtrees, together
96  *   with related information regarding mibmodule, sessions, etc
97  */
98
99 #define IN_SNMP_VARS_C
100
101 #include <config.h>
102 #if HAVE_STRING_H
103 #include <string.h>
104 #endif
105 #if HAVE_STDLIB_H
106 #include <stdlib.h>
107 #endif
108 #include <sys/types.h>
109 #include <stdio.h>
110 #if HAVE_FCNTL_H
111 #include <fcntl.h>
112 #endif
113 #if HAVE_WINSOCK_H
114 #include <winsock.h>
115 #endif
116 #if TIME_WITH_SYS_TIME
117 # ifdef WIN32
118 #  include <sys/timeb.h>
119 # else
120 #  include <sys/time.h>
121 # endif
122 # include <time.h>
123 #else
124 # if HAVE_SYS_TIME_H
125 #  include <sys/time.h>
126 # else
127 #  include <time.h>
128 # endif
129 #endif
130
131 #if HAVE_DMALLOC_H
132 #include <dmalloc.h>
133 #endif
134
135 #include "mibincl.h"
136 #include "snmp_client.h"
137 #include "default_store.h"
138 #include "ds_agent.h"
139 #include "callback.h"
140 #include "agent_callbacks.h"
141 #include "agent_registry.h"
142 #include "snmp_alarm.h"
143
144 #include "snmpd.h"
145 #include "mibgroup/struct.h"
146 #include "mib_module_includes.h"
147
148 #ifdef USING_AGENTX_SUBAGENT_MODULE
149 #include "agentx/subagent.h"
150 #include "agentx/client.h"
151 #endif
152
153
154 struct snmp_index {
155     struct variable_list        varbind;        /* or pointer to var_list ? */
156     struct snmp_session         *session;       /* NULL implies unused  ? */
157     struct snmp_index           *next_oid;
158     struct snmp_index           *prev_oid;
159     struct snmp_index           *next_idx;
160 } *snmp_index_head = NULL; 
161 struct subtree *subtrees;
162
163 int tree_compare(const struct subtree *ap, const struct subtree *bp)
164 {
165   return snmp_oid_compare(ap->name,ap->namelen,bp->name,bp->namelen);
166 }
167
168
169
170         /*
171          *  Split the subtree into two at the specified point,
172          *    returning the new (second) subtree
173          */
174 struct subtree *
175 split_subtree(struct subtree *current, oid name[], int name_len )
176 {
177     struct subtree *new_sub, *ptr;
178     int i;
179     char *cp;
180
181     if ( snmp_oid_compare(name, name_len,
182                           current->end, current->end_len) > 0 )
183         return NULL;    /* Split comes after the end of this subtree */
184
185     new_sub = (struct subtree *)malloc(sizeof(struct subtree));
186     if ( new_sub == NULL )
187         return NULL;
188     memcpy(new_sub, current, sizeof(struct subtree));
189
190         /* Set up the point of division */
191     memcpy(current->end,   name, name_len*sizeof(oid));
192     memcpy(new_sub->start, name, name_len*sizeof(oid));
193     current->end_len   = name_len;
194     new_sub->start_len = name_len;
195
196         /*
197          * Split the variables between the two new subtrees
198          */
199     i = current->variables_len;
200     current->variables_len = 0;
201
202     for ( ; i > 0 ; i-- ) {
203                 /* Note that the variable "name" field omits
204                    the prefix common to the whole registration,
205                    hence the strange comparison here */
206         if ( snmp_oid_compare( new_sub->variables[0].name,
207                                new_sub->variables[0].namelen,
208                                name     + current->namelen, 
209                                name_len - current->namelen ) >= 0 )
210             break;      /* All following variables belong to the second subtree */
211
212         current->variables_len++;
213         new_sub->variables_len--;
214         cp = (char *)new_sub->variables;
215         new_sub->variables = (struct variable *)(cp + new_sub->variables_width);
216     }
217
218         /* Delegated trees should retain their variables regardless */
219     if ( current->variables_len > 0 &&
220                 IS_DELEGATED((u_char)current->variables[0].type)) {
221         new_sub->variables_len = 1;
222         new_sub->variables     = current->variables;
223     }
224
225         /* Propogate this split down through any children */
226     if ( current->children )
227         new_sub->children = split_subtree(current->children, name, name_len);
228
229         /* Retain the correct linking of the list */
230     for ( ptr = current ; ptr != NULL ; ptr=ptr->children )
231           ptr->next = new_sub;
232     for ( ptr = new_sub ; ptr != NULL ; ptr=ptr->children )
233           ptr->prev = current;
234     for ( ptr = new_sub->next ; ptr != NULL ; ptr=ptr->children )
235           ptr->prev = new_sub;
236
237     return new_sub;
238 }
239
240 int
241 load_subtree( struct subtree *new_sub )
242 {
243     struct subtree *tree1, *tree2, *new2;
244     struct subtree *prev, *next;
245     int res;
246
247     if ( new_sub == NULL )
248         return MIB_REGISTERED_OK;       /* Degenerate case */
249
250                 /*
251                  * Find the subtree that contains the start of 
252                  *  the new subtree (if any)...
253                  */
254     tree1 = find_subtree( new_sub->start, new_sub->start_len, NULL );
255                 /*
256                  * ...and the subtree that follows the new one
257                  *      (NULL implies this is the final region covered)
258                  */  
259     if ( tree1 == NULL )
260         tree2 = find_subtree_next( new_sub->start, new_sub->start_len, NULL );
261     else
262         tree2 = tree1->next;
263
264
265         /*
266          * Handle new subtrees that start in virgin territory.
267          */
268     if ( tree1 == NULL ) {
269         new2 = NULL;
270                 /* Is there any overlap with later subtrees ? */
271         if ( tree2 && snmp_oid_compare( new_sub->end, new_sub->end_len,
272                                         tree2->start, tree2->start_len ) > 0 )
273             new2 = split_subtree( new_sub, tree2->start, tree2->start_len );
274
275                 /*
276                  * Link the new subtree (less any overlapping region)
277                  *  with the list of existing registrations
278                  */
279         if ( tree2 ) {
280             new_sub->prev = tree2->prev;
281             tree2->prev       = new_sub;
282         }
283         else
284             new_sub->prev = find_subtree_previous( new_sub->start, new_sub->start_len, NULL );
285
286         if ( new_sub->prev )
287             new_sub->prev->next = new_sub;
288         else
289             subtrees = new_sub;
290
291         new_sub->next     = tree2;
292
293                 /*
294                  * If there was any overlap,
295                  *  recurse to merge in the overlapping region
296                  *  (including anything that may follow the overlap)
297                  */
298         if ( new2 )
299             return load_subtree( new2 );
300     }
301
302     else {
303         /*
304          *  If the new subtree starts *within* an existing registration
305          *    (rather than at the same point as it), then split the
306          *    existing subtree at this point.
307          */
308         if ( snmp_oid_compare( new_sub->start, new_sub->start_len, 
309                                tree1->start,   tree1->start_len) != 0 )
310             tree1 = split_subtree( tree1, new_sub->start, new_sub->start_len);
311             if ( tree1 == NULL )
312                 return MIB_REGISTRATION_FAILED;
313
314         /*  Now consider the end of this existing subtree:
315          *      If it matches the new subtree precisely,
316          *        simply merge the new one into the list of children
317          *      If it includes the whole of the new subtree,
318          *        split it at the appropriate point, and merge again
319          *
320          *      If the new subtree extends beyond this existing region,
321          *        split it, and recurse to merge the two parts.
322          */
323
324          switch ( snmp_oid_compare( new_sub->end, new_sub->end_len, 
325                                     tree1->end,   tree1->end_len))  {
326
327                 case -1:        /* Existing subtree contains new one */
328                         (void) split_subtree( tree1,
329                                         new_sub->end, new_sub->end_len);
330                         /* Fall Through */
331
332                 case  0:        /* The two trees match precisely */
333                         /*
334                          * Note: This is the only point where the original
335                          *       registration OID ("name") is used
336                          */
337                         prev = NULL;
338                         next = tree1;
339                         while ( next && next->namelen > new_sub->namelen ) {
340                                 prev = next;
341                                 next = next->children;
342                         }
343                         while ( next && next->namelen == new_sub->namelen &&
344                                         next->priority < new_sub->priority ) {
345                                 prev = next;
346                                 next = next->children;
347                         }
348                         if ( next &&    next->namelen  == new_sub->namelen &&
349                                         next->priority == new_sub->priority )
350                            return MIB_DUPLICATE_REGISTRATION;
351
352                         if ( prev ) {
353                             new_sub->children = next;
354                             prev->children    = new_sub;
355                             new_sub->prev = prev->prev;
356                             new_sub->next = prev->next;
357                         }
358                         else {
359                             new_sub->children = next;
360                             new_sub->prev = next->prev;
361                             new_sub->next = next->next;
362
363                             for ( next = new_sub->next ;
364                                   next != NULL ;
365                                   next = next->children )
366                                         next->prev = new_sub;
367
368                             for ( prev = new_sub->prev ;
369                                   prev != NULL ;
370                                   prev = prev->children )
371                                         prev->next = new_sub;
372                         }
373                         break;
374
375                 case  1:        /* New subtree contains the existing one */
376                         new2 = split_subtree( new_sub,
377                                         tree1->end, tree1->end_len);
378                         res = load_subtree( new_sub );
379                         if ( res != MIB_REGISTERED_OK )
380                             return res;
381                         return load_subtree( new2 );
382
383          }
384
385     }
386     return 0;
387 }
388
389
390 int
391 register_mib_range(const char *moduleName,
392              struct variable *var,
393              size_t varsize,
394              size_t numvars,
395              oid *mibloc,
396              size_t mibloclen,
397              int priority,
398              int range_subid,
399              oid range_ubound,
400              struct snmp_session *ss)
401 {
402   struct subtree *subtree, *sub2;
403   int res, i;
404   struct register_parameters reg_parms;
405   
406   subtree = (struct subtree *) malloc(sizeof(struct subtree));
407   if ( subtree == NULL )
408     return MIB_REGISTRATION_FAILED;
409   memset(subtree, 0, sizeof(struct subtree));
410
411   DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
412   DEBUGMSGOID(("register_mib", mibloc, mibloclen));
413   DEBUGMSG(("register_mib","\n"));
414     
415         /*
416          * Create the new subtree node being registered
417          */
418   memcpy(subtree->name, mibloc, mibloclen*sizeof(oid));
419   subtree->namelen = (u_char) mibloclen;
420   memcpy(subtree->start, mibloc, mibloclen*sizeof(oid));
421   subtree->start_len = (u_char) mibloclen;
422   memcpy(subtree->end, mibloc, mibloclen*sizeof(oid));
423   subtree->end[ mibloclen-1 ]++;        /* XXX - or use 'variables' info ? */
424   subtree->end_len = (u_char) mibloclen;
425   memcpy(subtree->label, moduleName, strlen(moduleName)+1);
426   if ( var ) {
427     subtree->variables = (struct variable *) malloc(varsize*numvars);
428     memcpy(subtree->variables, var, numvars*varsize);
429     subtree->variables_len = numvars;
430     subtree->variables_width = varsize;
431   }
432   subtree->priority = priority;
433   subtree->session = ss;
434   res = load_subtree(subtree);
435
436         /*
437          * If registering a range,
438          *   use the first subtree as a template
439          *   for the rest of the range
440          */
441   if (( res == MIB_REGISTERED_OK ) && ( range_subid != 0 )) {
442     for ( i = mibloc[range_subid-1] +1 ; i < (int)range_ubound ; i++ ) {
443         sub2 = (struct subtree *) malloc(sizeof(struct subtree));
444         if ( sub2 == NULL ) {
445             unregister_mib_range( mibloc, mibloclen, priority,
446                                   range_subid, range_ubound);
447             return MIB_REGISTRATION_FAILED;
448         }
449         memcpy( sub2, subtree, sizeof(struct subtree));
450         sub2->start[range_subid-1] = i;
451         sub2->end[  range_subid-1] = i;         /* XXX - ???? */
452         res = load_subtree(sub2);
453         if ( res != MIB_REGISTERED_OK ) {
454             unregister_mib_range( mibloc, mibloclen, priority,
455                                   range_subid, range_ubound);
456             return MIB_REGISTRATION_FAILED;
457         }
458     }
459   }
460
461
462   reg_parms.name = mibloc;
463   reg_parms.namelen = mibloclen;
464   reg_parms.priority = priority;
465   reg_parms.range_subid  = range_subid;
466   reg_parms.range_ubound = range_ubound;
467   snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_REGISTER_OID,
468                       &reg_parms);
469
470   return res;
471 }
472
473 int
474 register_mib_priority(const char *moduleName,
475              struct variable *var,
476              size_t varsize,
477              size_t numvars,
478              oid *mibloc,
479              size_t mibloclen,
480              int priority)
481 {
482   return register_mib_range( moduleName, var, varsize, numvars,
483                                 mibloc, mibloclen, priority, 0, 0, NULL );
484 }
485
486 int
487 register_mib(const char *moduleName,
488              struct variable *var,
489              size_t varsize,
490              size_t numvars,
491              oid *mibloc,
492              size_t mibloclen)
493 {
494   return register_mib_priority( moduleName, var, varsize, numvars,
495                                 mibloc, mibloclen, DEFAULT_MIB_PRIORITY );
496 }
497
498
499 void
500 unload_subtree( struct subtree *sub, struct subtree *prev)
501 {
502     struct subtree *ptr;
503
504     if ( prev != NULL ) {       /* non-leading entries are easy */
505         prev->children = sub->children;
506         return;
507     }
508                         /* otherwise, we need to amend our neighbours as well */
509
510     if ( sub->children == NULL) {       /* just remove this node completely */
511         for (ptr = sub->prev ; ptr ; ptr=ptr->children )
512             ptr->next = sub->next;
513         for (ptr = sub->next ; ptr ; ptr=ptr->children )
514             ptr->prev = sub->prev;
515         return;
516     }
517     else {
518         for (ptr = sub->prev ; ptr ; ptr=ptr->children )
519             ptr->next = sub->children;
520         for (ptr = sub->next ; ptr ; ptr=ptr->children )
521             ptr->prev = sub->children;
522         return;
523     }
524 }
525
526 int
527 unregister_mib_range( oid *name, size_t len, int priority,
528                         int range_subid, oid range_ubound)
529 {
530   struct subtree *list, *myptr;
531   struct subtree *prev, *child;             /* loop through children */
532   struct register_parameters reg_parms;
533
534   list = find_subtree( name, len, subtrees );
535   if ( list == NULL )
536         return MIB_NO_SUCH_REGISTRATION;
537
538   for ( child=list, prev=NULL;  child != NULL;
539                                 prev=child, child=child->children ) {
540       if (( snmp_oid_compare( child->name, child->namelen, name, len) == 0 )
541           && ( child->priority == priority ))
542                 break;  /* found it */
543   }
544   if ( child == NULL )
545         return MIB_NO_SUCH_REGISTRATION;
546
547   unload_subtree( child, prev );
548   myptr = child;        /* remember this for later */
549
550                 /*
551                  *  Now handle any occurances in the following subtrees,
552                  *      as a result of splitting this range.  Due to the
553                  *      nature of the way such splits work, the first
554                  *      subtree 'slice' that doesn't refer to the given
555                  *      name marks the end of the original region.
556                  *
557                  *  This should also serve to register ranges.
558                  */
559
560   for ( list = myptr->next ; list != NULL ; list=list->next ) {
561         for ( child=list, prev=NULL;  child != NULL;
562                                       prev=child, child=child->children ) {
563             if (( snmp_oid_compare( child->name, child->namelen,
564                                                         name, len) == 0 )
565                 && ( child->priority == priority )) {
566
567                     unload_subtree( child, prev );
568                     free_subtree( child );
569                     break;
570             }
571         }
572         if ( child == NULL )    /* Didn't find the given name */
573             break;
574   }
575   free_subtree( myptr );
576   
577   reg_parms.name = name;
578   reg_parms.namelen = len;
579   reg_parms.priority = priority;
580   reg_parms.range_subid  = range_subid;
581   reg_parms.range_ubound = range_ubound;
582   snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_UNREGISTER_OID,
583                       &reg_parms);
584
585   return MIB_UNREGISTERED_OK;
586 }
587
588 int
589 unregister_mib_priority(oid *name, size_t len, int priority)
590 {
591   return unregister_mib_range( name, len, priority, 0, 0 );
592 }
593
594 int
595 unregister_mib(oid *name,
596                size_t len)
597 {
598   return unregister_mib_priority( name, len, DEFAULT_MIB_PRIORITY );
599 }
600
601 void
602 unregister_mibs_by_session (struct snmp_session *ss)
603 {
604   struct subtree *list, *list2;
605   struct subtree *child, *prev, *next_child;
606
607   for( list = subtrees; list != NULL; list = list2) {
608     list2 = list->next;
609     for ( child=list, prev=NULL;  child != NULL; child=next_child ) {
610
611       next_child = child->children;
612       if (( (ss->flags & SNMP_FLAGS_SUBSESSION) && child->session == ss ) ||
613           (!(ss->flags & SNMP_FLAGS_SUBSESSION) &&
614                                       child->session->subsession == ss )) {
615               unload_subtree( child, prev );
616               free_subtree( child );
617       }
618       else
619           prev = child;
620     }
621   }
622 }
623
624
625 struct subtree *
626 free_subtree(struct subtree *st)
627 {
628   struct subtree *ret = NULL;
629   if ((snmp_oid_compare(st->name, st->namelen, st->start, st->start_len) == 0)
630        && (st->variables != NULL))
631     free(st->variables);
632   if (st->next != NULL)
633     ret = st->next;
634   free(st);
635   return ret;
636 }
637
638 /* in_a_view: determines if a given snmp_pdu is allowed to see a
639    given name/namelen OID pointer
640    name         IN - name of var, OUT - name matched
641    nameLen      IN -number of sub-ids in name, OUT - subid-is in matched name
642    pi           IN - relevant auth info re PDU 
643    cvp          IN - relevant auth info re mib module
644 */
645
646 int
647 in_a_view(oid             *name,      /* IN - name of var, OUT - name matched */
648           size_t          *namelen,   /* IN -number of sub-ids in name*/
649           struct snmp_pdu *pdu,       /* IN - relevant auth info re PDU */
650           int              type)      /* IN - variable type being checked */
651 {
652
653   struct view_parameters view_parms;
654   view_parms.pdu = pdu;
655   view_parms.name = name;
656   if (namelen)
657       view_parms.namelen = *namelen;
658   else
659       view_parms.namelen = 0;
660   view_parms.errorcode = 0;
661
662   if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW)
663     return 0;           /* Enable bypassing of view-based access control */
664
665   /* check for v1 and counter64s, since snmpv1 doesn't support it */
666   if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64)
667     return 5;
668   switch (pdu->version) {
669   case SNMP_VERSION_1:
670   case SNMP_VERSION_2c:
671 #ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
672   case SNMP_VERSION_3:
673 #endif
674     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_ACM_CHECK,
675                         &view_parms);
676     return view_parms.errorcode;
677   }
678   return 1;
679 }
680
681 /* in_a_view: determines if a given snmp_pdu is ever going to be allowed to do
682    anynthing or if it's not going to ever be authenticated. */
683 int
684 check_access(struct snmp_pdu *pdu)      /* IN - pdu being checked */
685 {
686   struct view_parameters view_parms;
687   view_parms.pdu = pdu;
688   view_parms.name = 0;
689   view_parms.namelen = 0;
690   view_parms.errorcode = 0;
691
692   if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW)
693     return 0;           /* Enable bypassing of view-based access control */
694
695   switch (pdu->version) {
696   case SNMP_VERSION_1:
697   case SNMP_VERSION_2c:
698 #ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
699   case SNMP_VERSION_3:
700 #endif
701     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
702                         SNMPD_CALLBACK_ACM_CHECK_INITIAL,
703                         &view_parms);
704     return view_parms.errorcode;
705   }
706   return 1;
707 }
708
709 /* lexicographical compare two object identifiers.
710  * Returns -1 if name1 < name2,
711  *          0 if name1 = name2, or name1 matches name2 for length of name2
712  *          1 if name1 > name2
713  *
714  * Note: snmp_oid_compare checks len2 before last return.
715  */
716 int
717 compare_tree(const oid *in_name1,
718              size_t len1, 
719              const oid *in_name2, 
720              size_t len2)
721 {
722     register int len, res;
723     register const oid * name1 = in_name1;
724     register const oid * name2 = in_name2;
725
726     /* len = minimum of len1 and len2 */
727     if (len1 < len2)
728         len = len1;
729     else
730         len = len2;
731     /* find first non-matching OID */
732     while(len-- > 0){
733         res = *(name1++) - *(name2++);
734         if (res < 0)
735             return -1;
736         if (res > 0)
737             return 1;
738     }
739     /* both OIDs equal up to length of shorter OID */
740     if (len1 < len2)
741         return -1;
742
743     /* name1 matches name2 for length of name2, or they are equal */
744     return 0;
745 }
746
747 struct subtree *find_subtree_previous(oid *name,
748                              size_t len,
749                              struct subtree *subtree)
750 {
751   struct subtree *myptr, *previous = NULL;
752
753   if ( subtree )
754         myptr = subtree;
755   else
756         myptr = subtrees;       /* look through everything */
757
758   for( ; myptr != NULL; previous = myptr, myptr = myptr->next) {
759     if (snmp_oid_compare(name, len, myptr->start, myptr->start_len) < 0)
760       return previous;
761   }
762   return previous;
763 }
764
765 struct subtree *find_subtree_next(oid *name, 
766                                   size_t len,
767                                   struct subtree *subtree)
768 {
769   struct subtree *myptr = NULL;
770
771   myptr = find_subtree_previous(name, len, subtree);
772   if ( myptr != NULL ) {
773      myptr = myptr->next;
774      while ( myptr && (myptr->variables == NULL || myptr->variables_len == 0) )
775          myptr = myptr->next;
776      return myptr;
777   }
778   else if (subtree && snmp_oid_compare(name, len, subtree->start, subtree->start_len) < 0)
779      return subtree;
780   else
781      return NULL;
782 }
783
784 struct subtree *find_subtree(oid *name,
785                              size_t len,
786                              struct subtree *subtree)
787 {
788   struct subtree *myptr;
789
790   myptr = find_subtree_previous(name, len, subtree);
791   if (myptr && snmp_oid_compare(name, len, myptr->end, myptr->end_len) < 0)
792         return myptr;
793
794   return NULL;
795 }
796
797 struct snmp_session *get_session_for_oid( oid *name, size_t len)
798 {
799    struct subtree *myptr;
800
801    myptr = find_subtree_previous(name, len, subtrees);
802    while ( myptr && myptr->variables == NULL )
803         myptr = myptr->next;
804
805    if ( myptr == NULL )
806         return NULL;
807    else
808         return myptr->session;
809 }
810
811
812
813 static struct subtree root_subtrees[] = {
814    { { 0 }, 1 },        /* ccitt */
815    { { 1 }, 1 },        /*  iso  */
816    { { 2 }, 1 }         /* joint-ccitt-iso */
817 };
818
819
820 void setup_tree (void)
821 {
822 #ifdef USING_AGENTX_SUBAGENT_MODULE
823   int role;
824
825   role = ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_ROLE);
826   ds_set_boolean(DS_APPLICATION_ID, DS_AGENT_ROLE, MASTER_AGENT);
827 #endif
828
829   register_mib("", NULL, 0, 0,
830         root_subtrees[0].name,  root_subtrees[0].namelen);
831   register_mib("", NULL, 0, 0,
832         root_subtrees[1].name,  root_subtrees[1].namelen);
833   register_mib("", NULL, 0, 0,
834         root_subtrees[2].name,  root_subtrees[2].namelen);
835
836   /* Support for 'static' subtrees (subtrees_old) has now been dropped */
837
838   /* No longer necessary to sort the mib tree - this is inherent in
839      the construction of the subtree structure */
840
841 #ifdef USING_AGENTX_SUBAGENT_MODULE
842   ds_set_boolean(DS_APPLICATION_ID, DS_AGENT_ROLE, role);
843 #endif
844 }
845
846         /*
847          * Initial support for index allocation
848          */
849 extern struct snmp_session *main_session;
850
851 char *
852 register_string_index( oid *name, size_t name_len, char *cp )
853 {
854     struct variable_list varbind, *res;
855     
856     memset( &varbind, 0, sizeof(struct variable_list));
857     varbind.type = ASN_OCTET_STR;
858     snmp_set_var_objid( &varbind, name, name_len );
859     if ( cp != ANY_STRING_INDEX ) {
860         snmp_set_var_value( &varbind, (u_char *)cp, strlen(cp) );
861         res = register_index( &varbind, ALLOCATE_THIS_INDEX, main_session );
862     }
863     else
864         res = register_index( &varbind, ALLOCATE_ANY_INDEX, main_session );
865
866     if ( res == NULL )
867         return NULL;
868     else
869         return (char *)res->val.string;
870 }
871
872 int
873 register_int_index( oid *name, size_t name_len, int val )
874 {
875     struct variable_list varbind, *res;
876     
877     memset( &varbind, 0, sizeof(struct variable_list));
878     varbind.type = ASN_INTEGER;
879     snmp_set_var_objid( &varbind, name, name_len );
880     varbind.val.string = varbind.buf;
881     if ( val != ANY_INTEGER_INDEX ) {
882         varbind.val_len = sizeof(long);
883         *varbind.val.integer = val;
884         res = register_index( &varbind, ALLOCATE_THIS_INDEX, main_session );
885     }
886     else
887         res = register_index( &varbind, ALLOCATE_ANY_INDEX, main_session );
888
889     if ( res == NULL )
890         return -1;
891     else
892         return *res->val.integer;
893 }
894
895 struct variable_list *
896 register_oid_index( oid *name, size_t name_len,
897                     oid *value, size_t value_len )
898 {
899     struct variable_list varbind;
900     
901     memset( &varbind, 0, sizeof(struct variable_list));
902     varbind.type = ASN_OBJECT_ID;
903     snmp_set_var_objid( &varbind, name, name_len );
904     if ( value != ANY_OID_INDEX ) {
905         snmp_set_var_value( &varbind, (u_char*)value, value_len*sizeof(oid) );
906         return( register_index( &varbind, ALLOCATE_THIS_INDEX, main_session ));
907     }
908     else
909         return( register_index( &varbind, ALLOCATE_ANY_INDEX, main_session ));
910 }
911
912 struct variable_list*
913 register_index(struct variable_list *varbind, int flags, struct snmp_session *ss )
914 {
915     struct snmp_index *new_index, *idxptr, *idxptr2;
916     struct snmp_index *prev_oid_ptr, *prev_idx_ptr;
917     int res, res2, i;
918
919 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING)
920     if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_ROLE) == SUB_AGENT )
921         return( agentx_register_index( ss, varbind, flags ));
922 #endif
923                 /* Look for the requested OID entry */
924     prev_oid_ptr = NULL;
925     prev_idx_ptr = NULL;
926     res  = 1;
927     res2 = 1;
928     for( idxptr = snmp_index_head ; idxptr != NULL;
929                          prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) {
930         if ((res = snmp_oid_compare(varbind->name, varbind->name_length,
931                                         idxptr->varbind.name,
932                                         idxptr->varbind.name_length)) <= 0 )
933                 break;
934     }
935
936                 /*  Found the OID - now look at the registered indices */
937     if ( res == 0 && idxptr ) {
938         if ( varbind->type != idxptr->varbind.type )
939             return NULL;                /* wrong type */
940
941                         /*
942                          * If we've been asked for an arbitrary new value,
943                          *      then find the end of the list.
944                          * If we've been asked for any arbitrary value,
945                          *      then look for an unused entry, and use that.
946                          *      If there aren't any, continue as for new.
947                          * Otherwise, locate the given value in the (sorted)
948                          *      list of already allocated values
949                          */
950         if ( flags & ALLOCATE_ANY_INDEX ) {
951             for(idxptr2 = idxptr ; idxptr2 != NULL;
952                  prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
953                 if ( flags == ALLOCATE_ANY_INDEX && idxptr2->session == NULL ) {
954                     idxptr2->session = ss ;
955                     return &idxptr2->varbind;
956                 }
957             }
958         }
959         else {
960             for(idxptr2 = idxptr ; idxptr2 != NULL;
961                  prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
962                 switch ( varbind->type ) {
963                     case ASN_INTEGER:
964                         res2 = (*varbind->val.integer - *idxptr2->varbind.val.integer);
965                         break;
966                     case ASN_OCTET_STR:
967                         i = SNMP_MIN(varbind->val_len, idxptr2->varbind.val_len);
968                         res2 = memcmp(varbind->val.string, idxptr2->varbind.val.string, i);
969                         break;
970                     case ASN_OBJECT_ID:
971                         res2 = snmp_oid_compare(varbind->val.objid, varbind->val_len/sizeof(oid),
972                                         idxptr2->varbind.val.objid,
973                                         idxptr2->varbind.val_len/sizeof(oid));
974                         break;
975                     default:
976                         return NULL;            /* wrong type */
977                 }
978                 if ( res2 <= 0 )
979                     break;
980             }
981             if ( res2 == 0 )
982                 return NULL;                    /* duplicate value */
983         }
984     }
985
986                 /*
987                  * OK - we've now located where the new entry needs to
988                  *      be fitted into the index registry tree          
989                  * To recap:
990                  *      'prev_oid_ptr' points to the head of the OID index
991                  *          list prior to this one.  If this is null, then
992                  *          it means that this is the first OID in the list.
993                  *      'idxptr' points either to the head of this OID list,
994                  *          or the next OID (if this is a new OID request)
995                  *          These can be distinguished by the value of 'res'.
996                  *
997                  *      'prev_idx_ptr' points to the index entry that sorts
998                  *          immediately prior to the requested value (if any).
999                  *          If an arbitrary value is required, then this will
1000                  *          point to the last allocated index.
1001                  *          If this pointer is null, then either this is a new
1002                  *          OID request, or the requested value is the first
1003                  *          in the list.
1004                  *      'idxptr2' points to the next sorted index (if any)
1005                  *          but is not actually needed any more.
1006                  *
1007                  *  Clear?  Good!
1008                  *      I hope you've been paying attention.
1009                  *          There'll be a test later :-)
1010                  */
1011
1012                 /*
1013                  *      We proceed by creating the new entry
1014                  *         (by copying the entry provided)
1015                  */
1016         new_index = (struct snmp_index *)malloc( sizeof( struct snmp_index ));
1017         if (new_index == NULL)
1018             return NULL;
1019         if (snmp_clone_var( varbind, &new_index->varbind ) != 0 ) {
1020             free( new_index );
1021             return NULL;
1022         }
1023         new_index->session = ss;
1024
1025         if ( varbind->type == ASN_OCTET_STR && flags == ALLOCATE_THIS_INDEX )
1026             new_index->varbind.val.string[new_index->varbind.val_len] = 0;
1027
1028                 /*
1029                  * If we've been given a value, then we can use that, but
1030                  *    otherwise, we need to create a new value for this entry.
1031                  * Note that ANY_INDEX and NEW_INDEX are both covered by this
1032                  *   test (since NEW_INDEX & ANY_INDEX = ANY_INDEX, remember?)
1033                  */
1034         if ( flags & ALLOCATE_ANY_INDEX ) {
1035             if ( prev_idx_ptr ) {
1036                 if ( snmp_clone_var( &prev_idx_ptr->varbind, &new_index->varbind ) != 0 ) {
1037                     free( new_index );
1038                     return NULL;
1039                 }
1040             }
1041             else
1042                 new_index->varbind.val.string = new_index->varbind.buf;
1043
1044             switch ( varbind->type ) {
1045                 case ASN_INTEGER:
1046                     if ( prev_idx_ptr ) {
1047                         (*new_index->varbind.val.integer)++; 
1048                     }
1049                     else
1050                         *(new_index->varbind.val.integer) = 1;
1051                     new_index->varbind.val_len = sizeof(long);
1052                     break;
1053                 case ASN_OCTET_STR:
1054                     if ( prev_idx_ptr ) {
1055                         i =  new_index->varbind.val_len-1;
1056                         while ( new_index->varbind.buf[ i ] == 'z' ) {
1057                             new_index->varbind.buf[ i ] = 'a';
1058                             i--;
1059                             if ( i < 0 ) {
1060                                 i =  new_index->varbind.val_len;
1061                                 new_index->varbind.buf[ i ] = 'a';
1062                                 new_index->varbind.buf[ i+1 ] = 0;
1063                             }
1064                         }
1065                         new_index->varbind.buf[ i ]++;
1066                     }
1067                     else
1068                         strcpy((char *)new_index->varbind.buf, "aaaa");
1069                     new_index->varbind.val_len = strlen((char *)new_index->varbind.buf);
1070                     break;
1071                 case ASN_OBJECT_ID:
1072                     if ( prev_idx_ptr ) {
1073                         i =  prev_idx_ptr->varbind.val_len/sizeof(oid) -1;
1074                         while ( new_index->varbind.val.objid[ i ] == 255 ) {
1075                             new_index->varbind.val.objid[ i ] = 1;
1076                             i--;
1077                             if ( i == 0 && new_index->varbind.val.objid[0] == 2 ) {
1078                                 new_index->varbind.val.objid[ 0 ] = 1;
1079                                 i =  new_index->varbind.val_len/sizeof(oid);
1080                                 new_index->varbind.val.objid[ i ] = 0;
1081                                 new_index->varbind.val_len += sizeof(oid);
1082                             }
1083                         }
1084                         new_index->varbind.val.objid[ i ]++;
1085                     }
1086                     else {
1087                         /* If the requested OID name is small enough,
1088                          *   append another OID (1) and use this as the
1089                          *   default starting value for new indexes.
1090                          */
1091                         if ( (varbind->name_length+1) * sizeof(oid) <= 40 ) {
1092                             for ( i = 0 ; i < (int)varbind->name_length ; i++ )
1093                                 new_index->varbind.val.objid[i] = varbind->name[i];
1094                             new_index->varbind.val.objid[varbind->name_length] = 1;
1095                             new_index->varbind.val_len =
1096                                         (varbind->name_length+1) * sizeof(oid);
1097                         }
1098                         else {
1099                             /* Otherwise use '.1.1.1.1...' */
1100                             i = 40/sizeof(oid);
1101                             if ( i > 4 )
1102                                 i = 4;
1103                             new_index->varbind.val_len = i * (sizeof(oid));
1104                             for (i-- ; i>=0 ; i-- )
1105                                 new_index->varbind.val.objid[i] = 1;
1106                         }
1107                     }
1108                     break;
1109                 default:
1110                     free( new_index );
1111                     return NULL;        /* Index type not supported */
1112             }
1113         }
1114
1115                 /*
1116                  * Right - we've set up the new entry.
1117                  * All that remains is to link it into the tree.
1118                  * There are a number of possible cases here,
1119                  *   so watch carefully.
1120                  */
1121         if ( prev_idx_ptr ) {
1122             new_index->next_idx = prev_idx_ptr->next_idx;
1123             new_index->next_oid = prev_idx_ptr->next_oid;
1124             prev_idx_ptr->next_idx = new_index;
1125         }
1126         else {
1127             if ( res == 0 && idxptr ) {
1128                 new_index->next_idx = idxptr;
1129                 new_index->next_oid = idxptr->next_oid;
1130             }
1131             else {
1132                 new_index->next_idx = NULL;
1133                 new_index->next_oid = idxptr;
1134             }
1135
1136             if ( prev_oid_ptr ) {
1137                 while ( prev_oid_ptr ) {
1138                     prev_oid_ptr->next_oid = new_index;
1139                     prev_oid_ptr = prev_oid_ptr->next_idx;
1140                 }
1141             }
1142             else
1143                 snmp_index_head = new_index;
1144         }
1145     return &new_index->varbind;
1146 }
1147
1148         /*
1149          * Release an allocated index,
1150          *   to allow it to be used elsewhere
1151          */
1152 int
1153 release_index(struct variable_list *varbind)
1154 {
1155     return( unregister_index( varbind, TRUE, NULL ));
1156 }
1157
1158         /*
1159          * Completely remove an allocated index,
1160          *   due to errors in the registration process.
1161          */
1162 int
1163 remove_index(struct variable_list *varbind, struct snmp_session *ss)
1164 {
1165     return( unregister_index( varbind, FALSE, ss ));
1166 }
1167
1168 void
1169 unregister_index_by_session(struct snmp_session *ss)
1170 {
1171     struct snmp_index *idxptr, *idxptr2;
1172     for(idxptr = snmp_index_head ; idxptr != NULL; idxptr = idxptr->next_oid)
1173         for(idxptr2 = idxptr ; idxptr2 != NULL; idxptr2 = idxptr2->next_idx)
1174             if ( idxptr2->session == ss )
1175                 idxptr2->session = NULL;
1176 }
1177
1178
1179 int
1180 unregister_index(struct variable_list *varbind, int remember, struct snmp_session *ss)
1181 {
1182     struct snmp_index *idxptr, *idxptr2;
1183     struct snmp_index *prev_oid_ptr, *prev_idx_ptr;
1184     int res, res2, i;
1185
1186 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING)
1187     if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_ROLE) == SUB_AGENT )
1188         return( agentx_unregister_index( ss, varbind ));
1189 #endif
1190                 /* Look for the requested OID entry */
1191     prev_oid_ptr = NULL;
1192     prev_idx_ptr = NULL;
1193     res  = 1;
1194     res2 = 1;
1195     for( idxptr = snmp_index_head ; idxptr != NULL;
1196                          prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) {
1197         if ((res = snmp_oid_compare(varbind->name, varbind->name_length,
1198                                         idxptr->varbind.name,
1199                                         idxptr->varbind.name_length)) <= 0 )
1200                 break;
1201     }
1202
1203     if ( res != 0 )
1204         return INDEX_ERR_NOT_ALLOCATED;
1205     if ( varbind->type != idxptr->varbind.type )
1206         return INDEX_ERR_WRONG_TYPE;
1207
1208     for(idxptr2 = idxptr ; idxptr2 != NULL;
1209                 prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
1210         i = SNMP_MIN(varbind->val_len, idxptr2->varbind.val_len);
1211         res2 = memcmp(varbind->val.string, idxptr2->varbind.val.string, i);
1212         if ( res2 <= 0 )
1213             break;
1214     }
1215     if ( res2 != 0 )
1216         return INDEX_ERR_NOT_ALLOCATED;
1217     if ( ss != idxptr2->session )
1218         return INDEX_ERR_WRONG_SESSION;
1219
1220                 /*
1221                  *  If this is a "normal" index unregistration,
1222                  *      mark the index entry as unused, but leave
1223                  *      it in situ.  This allows differentiation
1224                  *      between ANY_INDEX and NEW_INDEX
1225                  */
1226     if ( remember ) {
1227         idxptr2->session = NULL;        /* Unused index */
1228         return SNMP_ERR_NOERROR;
1229     }
1230                 /*
1231                  *  If this is a failed attempt to register a
1232                  *      number of indexes, the successful ones
1233                  *      must be removed completely.
1234                  */
1235     if ( prev_idx_ptr ) {
1236         prev_idx_ptr->next_idx = idxptr2->next_idx;
1237     }
1238     else if ( prev_oid_ptr ) {
1239         if ( idxptr2->next_idx )        /* Use p_idx_ptr as a temp variable */
1240             prev_idx_ptr = idxptr2->next_idx;
1241         else
1242             prev_idx_ptr = idxptr2->next_oid;
1243         while ( prev_oid_ptr ) {
1244             prev_oid_ptr->next_oid = prev_idx_ptr;
1245             prev_oid_ptr = prev_oid_ptr->next_idx;
1246         }
1247     }
1248     else {
1249         if ( idxptr2->next_idx )
1250             snmp_index_head = idxptr2->next_idx;
1251         else
1252             snmp_index_head = idxptr2->next_oid;
1253     }
1254     snmp_free_var( (struct variable_list *)idxptr2 );
1255     return SNMP_ERR_NOERROR;
1256 }
1257
1258
1259 void dump_registry( void )
1260 {
1261     struct subtree *myptr, *myptr2;
1262     struct snmp_index *idxptr, *idxptr2;
1263     char start_oid[SPRINT_MAX_LEN];
1264     char end_oid[SPRINT_MAX_LEN];
1265
1266     for( myptr = subtrees ; myptr != NULL; myptr = myptr->next) {
1267         sprint_objid(start_oid, myptr->start, myptr->start_len);
1268         sprint_objid(end_oid, myptr->end, myptr->end_len);
1269         printf("%c %s - %s %c\n",
1270                 ( myptr->variables ? ' ' : '(' ),
1271                   start_oid, end_oid,
1272                 ( myptr->variables ? ' ' : ')' ));
1273         for( myptr2 = myptr ; myptr2 != NULL; myptr2 = myptr2->children) {
1274             if ( myptr2->label && myptr2->label[0] )
1275                 printf("\t%s\n", myptr2->label);
1276         }
1277     }
1278
1279     if ( snmp_index_head )
1280         printf("\nIndex Allocations:\n");
1281     for( idxptr = snmp_index_head ; idxptr != NULL; idxptr = idxptr->next_oid) {
1282         sprint_objid(start_oid, idxptr->varbind.name, idxptr->varbind.name_length);
1283         printf("%s indexes:\n", start_oid);
1284         for( idxptr2 = idxptr ; idxptr2 != NULL; idxptr2 = idxptr2->next_idx) {
1285             switch( idxptr2->varbind.type ) {
1286                 case ASN_INTEGER:
1287                     printf("    %c %ld %c\n",
1288                         ( idxptr2->session ? ' ' : '(' ),
1289                           *idxptr2->varbind.val.integer,
1290                         ( idxptr2->session ? ' ' : ')' ));
1291                     break;
1292                 case ASN_OCTET_STR:
1293                     printf("    %c %s %c\n",
1294                         ( idxptr2->session ? ' ' : '(' ),
1295                           idxptr2->varbind.val.string,
1296                         ( idxptr2->session ? ' ' : ')' ));
1297                     break;
1298                 case ASN_OBJECT_ID:
1299                     sprint_objid(end_oid, idxptr2->varbind.val.objid,
1300                                 idxptr2->varbind.val_len/sizeof(oid));
1301                     printf("    %c %s %c\n",
1302                         ( idxptr2->session ? ' ' : '(' ),
1303                           end_oid,
1304                         ( idxptr2->session ? ' ' : ')' ));
1305                     break;
1306                 default:
1307                     printf("unsupported type (%d)\n",
1308                                 idxptr2->varbind.type);
1309             }
1310         }
1311     }
1312 }
1313
1314 #ifdef TESTING
1315 struct variable_list varbind;
1316 struct snmp_session main_sess, *main_session=&main_sess;
1317
1318 void
1319 test_string_register( int n, char *cp )
1320 {
1321     varbind.name[4] = n;
1322     if (register_string_index(varbind.name, varbind.name_length, cp) == NULL)
1323         printf("allocating %s failed\n", cp);
1324 }
1325
1326 void
1327 test_int_register( int n, int val )
1328 {
1329     varbind.name[4] = n;
1330     if (register_int_index( varbind.name, varbind.name_length, val ) == -1 )
1331         printf("allocating %d/%d failed\n", n, val);
1332 }
1333
1334 void
1335 test_oid_register( int n, int subid )
1336 {
1337     struct variable_list *res;
1338
1339     varbind.name[4] = n;
1340     if ( subid != -1 ) {
1341         varbind.val.objid[5] = subid;
1342         res = register_oid_index(varbind.name, varbind.name_length,
1343                     varbind.val.objid,
1344                     varbind.val_len/sizeof(oid) );
1345     }
1346     else
1347         res = register_oid_index(varbind.name, varbind.name_length, NULL, 0);
1348
1349     if (res == NULL )
1350         printf("allocating %d/%d failed\n", n, subid);
1351 }
1352
1353 void
1354 main( int argc, char argv[] )
1355 {
1356     oid name[] = { 1, 2, 3, 4, 0 };
1357     int i;
1358     
1359     memset( &varbind, 0, sizeof(struct variable_list));
1360     snmp_set_var_objid( &varbind, name, 5 );
1361     varbind.type = ASN_OCTET_STR;
1362                 /*
1363                  * Test index structure linking:
1364                  *      a) sorted by OID
1365                  */
1366     test_string_register( 20, "empty OID" );
1367     test_string_register( 10, "first OID" );
1368     test_string_register( 40, "last OID" );
1369     test_string_register( 30, "middle OID" );
1370
1371                 /*
1372                  *      b) sorted by index value
1373                  */
1374     test_string_register( 25, "eee: empty IDX" );
1375     test_string_register( 25, "aaa: first IDX" );
1376     test_string_register( 25, "zzz: last IDX" );
1377     test_string_register( 25, "mmm: middle IDX" );
1378     printf("This next one should fail....\n");
1379     test_string_register( 25, "eee: empty IDX" );       /* duplicate */
1380     printf("done\n");
1381
1382                 /*
1383                  *      c) test initial index linking
1384                  */
1385     test_string_register( 5, "eee: empty initial IDX" );
1386     test_string_register( 5, "aaa: replace initial IDX" );
1387
1388                 /*
1389                  *      Did it all work?
1390                  */
1391     dump_registry();
1392     unregister_index_by_session( main_session );
1393                 /*
1394                  *  Now test index allocation
1395                  *      a) integer values
1396                  */
1397     test_int_register( 110, -1 );       /* empty */
1398     test_int_register( 110, -1 );       /* append */
1399     test_int_register( 110, 10 );       /* append exact */
1400     printf("This next one should fail....\n");
1401     test_int_register( 110, 10 );       /* exact duplicate */
1402     printf("done\n");
1403     test_int_register( 110, -1 );       /* append */
1404     test_int_register( 110,  5 );       /* insert exact */
1405
1406                 /*
1407                  *      b) string values
1408                  */
1409     test_string_register( 120, NULL );          /* empty */
1410     test_string_register( 120, NULL );          /* append */
1411     test_string_register( 120, "aaaz" );
1412     test_string_register( 120, NULL );          /* minor rollover */
1413     test_string_register( 120, "zzzz" );
1414     test_string_register( 120, NULL );          /* major rollover */
1415
1416                 /*
1417                  *      c) OID values
1418                  */
1419     
1420     test_oid_register( 130, -1 );       /* empty */
1421     test_oid_register( 130, -1 );       /* append */
1422
1423     varbind.val_len = varbind.name_length*sizeof(oid);
1424     memcpy( varbind.buf, varbind.name, varbind.val_len);
1425     varbind.val.objid = (oid*) varbind.buf;
1426     varbind.val_len += sizeof(oid);
1427
1428     test_oid_register( 130, 255 );      /* append exact */
1429     test_oid_register( 130, -1 );       /* minor rollover */
1430     test_oid_register( 130, 100 );      /* insert exact */
1431     printf("This next one should fail....\n");
1432     test_oid_register( 130, 100 );      /* exact duplicate */
1433     printf("done\n");
1434
1435     varbind.val.objid = (oid*)varbind.buf;
1436     for ( i=0; i<6; i++ )
1437         varbind.val.objid[i]=255;
1438     varbind.val.objid[0]=1;
1439     test_oid_register( 130, 255 );      /* set up rollover  */
1440     test_oid_register( 130, -1 );       /* medium rollover */
1441
1442     for ( i=0; i<6; i++ )
1443         varbind.val.objid[i]=255;
1444     varbind.val.objid[0]=2;
1445     test_oid_register( 130, 255 );      /* set up rollover  */
1446     test_oid_register( 130, -1 );       /* major rollover */
1447
1448                 /*
1449                  *      Did it all work?
1450                  */
1451     dump_registry();
1452
1453                 /*
1454                  *      Test the various "invalid" requests
1455                  *      (unsupported types, mis-matched types, etc)
1456                  */
1457     printf("The rest of these should fail....\n");
1458     test_oid_register( 110, -1 );
1459     test_oid_register( 110, 100 );
1460     test_oid_register( 120, -1 );
1461     test_oid_register( 120, 100 );
1462     test_string_register( 110, NULL );
1463     test_string_register( 110, "aaaa" );
1464     test_string_register( 130, NULL );
1465     test_string_register( 130, "aaaa" );
1466     test_int_register( 120, -1 );
1467     test_int_register( 120,  1 );
1468     test_int_register( 130, -1 );
1469     test_int_register( 130,  1 );
1470     printf("done - this dump should be the same as before\n");
1471     dump_registry();
1472 }
1473 #endif