1 //==========================================================================
3 // ./agent/current/src/agent_registry.c
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.
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.
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
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.
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.
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.
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####
41 // -------------------------------------------
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.
49 // The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2"
50 // -------------------------------------------
52 //####UCDSNMPCOPYRIGHTEND####
53 //==========================================================================
54 //#####DESCRIPTIONBEGIN####
59 // Purpose: Port of UCD-SNMP distribution to eCos.
63 //####DESCRIPTIONEND####
65 //==========================================================================
66 /********************************************************************
67 Copyright 1989, 1991, 1992 by Carnegie Mellon University
70 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
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
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 *********************************************************************/
95 * Maintain a registry of MIB subtrees, together
96 * with related information regarding mibmodule, sessions, etc
99 #define IN_SNMP_VARS_C
108 #include <sys/types.h>
116 #if TIME_WITH_SYS_TIME
118 # include <sys/timeb.h>
120 # include <sys/time.h>
125 # include <sys/time.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"
145 #include "mibgroup/struct.h"
146 #include "mib_module_includes.h"
148 #ifdef USING_AGENTX_SUBAGENT_MODULE
149 #include "agentx/subagent.h"
150 #include "agentx/client.h"
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;
163 int tree_compare(const struct subtree *ap, const struct subtree *bp)
165 return snmp_oid_compare(ap->name,ap->namelen,bp->name,bp->namelen);
171 * Split the subtree into two at the specified point,
172 * returning the new (second) subtree
175 split_subtree(struct subtree *current, oid name[], int name_len )
177 struct subtree *new_sub, *ptr;
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 */
185 new_sub = (struct subtree *)malloc(sizeof(struct subtree));
186 if ( new_sub == NULL )
188 memcpy(new_sub, current, sizeof(struct subtree));
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;
197 * Split the variables between the two new subtrees
199 i = current->variables_len;
200 current->variables_len = 0;
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 */
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);
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;
225 /* Propogate this split down through any children */
226 if ( current->children )
227 new_sub->children = split_subtree(current->children, name, name_len);
229 /* Retain the correct linking of the list */
230 for ( ptr = current ; ptr != NULL ; ptr=ptr->children )
232 for ( ptr = new_sub ; ptr != NULL ; ptr=ptr->children )
234 for ( ptr = new_sub->next ; ptr != NULL ; ptr=ptr->children )
241 load_subtree( struct subtree *new_sub )
243 struct subtree *tree1, *tree2, *new2;
244 struct subtree *prev, *next;
247 if ( new_sub == NULL )
248 return MIB_REGISTERED_OK; /* Degenerate case */
251 * Find the subtree that contains the start of
252 * the new subtree (if any)...
254 tree1 = find_subtree( new_sub->start, new_sub->start_len, NULL );
256 * ...and the subtree that follows the new one
257 * (NULL implies this is the final region covered)
260 tree2 = find_subtree_next( new_sub->start, new_sub->start_len, NULL );
266 * Handle new subtrees that start in virgin territory.
268 if ( tree1 == 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 );
276 * Link the new subtree (less any overlapping region)
277 * with the list of existing registrations
280 new_sub->prev = tree2->prev;
281 tree2->prev = new_sub;
284 new_sub->prev = find_subtree_previous( new_sub->start, new_sub->start_len, NULL );
287 new_sub->prev->next = new_sub;
291 new_sub->next = tree2;
294 * If there was any overlap,
295 * recurse to merge in the overlapping region
296 * (including anything that may follow the overlap)
299 return load_subtree( new2 );
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.
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);
312 return MIB_REGISTRATION_FAILED;
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
320 * If the new subtree extends beyond this existing region,
321 * split it, and recurse to merge the two parts.
324 switch ( snmp_oid_compare( new_sub->end, new_sub->end_len,
325 tree1->end, tree1->end_len)) {
327 case -1: /* Existing subtree contains new one */
328 (void) split_subtree( tree1,
329 new_sub->end, new_sub->end_len);
332 case 0: /* The two trees match precisely */
334 * Note: This is the only point where the original
335 * registration OID ("name") is used
339 while ( next && next->namelen > new_sub->namelen ) {
341 next = next->children;
343 while ( next && next->namelen == new_sub->namelen &&
344 next->priority < new_sub->priority ) {
346 next = next->children;
348 if ( next && next->namelen == new_sub->namelen &&
349 next->priority == new_sub->priority )
350 return MIB_DUPLICATE_REGISTRATION;
353 new_sub->children = next;
354 prev->children = new_sub;
355 new_sub->prev = prev->prev;
356 new_sub->next = prev->next;
359 new_sub->children = next;
360 new_sub->prev = next->prev;
361 new_sub->next = next->next;
363 for ( next = new_sub->next ;
365 next = next->children )
366 next->prev = new_sub;
368 for ( prev = new_sub->prev ;
370 prev = prev->children )
371 prev->next = new_sub;
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 )
381 return load_subtree( new2 );
391 register_mib_range(const char *moduleName,
392 struct variable *var,
400 struct snmp_session *ss)
402 struct subtree *subtree, *sub2;
404 struct register_parameters reg_parms;
406 subtree = (struct subtree *) malloc(sizeof(struct subtree));
407 if ( subtree == NULL )
408 return MIB_REGISTRATION_FAILED;
409 memset(subtree, 0, sizeof(struct subtree));
411 DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
412 DEBUGMSGOID(("register_mib", mibloc, mibloclen));
413 DEBUGMSG(("register_mib","\n"));
416 * Create the new subtree node being registered
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);
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;
432 subtree->priority = priority;
433 subtree->session = ss;
434 res = load_subtree(subtree);
437 * If registering a range,
438 * use the first subtree as a template
439 * for the rest of the range
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;
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;
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,
474 register_mib_priority(const char *moduleName,
475 struct variable *var,
482 return register_mib_range( moduleName, var, varsize, numvars,
483 mibloc, mibloclen, priority, 0, 0, NULL );
487 register_mib(const char *moduleName,
488 struct variable *var,
494 return register_mib_priority( moduleName, var, varsize, numvars,
495 mibloc, mibloclen, DEFAULT_MIB_PRIORITY );
500 unload_subtree( struct subtree *sub, struct subtree *prev)
504 if ( prev != NULL ) { /* non-leading entries are easy */
505 prev->children = sub->children;
508 /* otherwise, we need to amend our neighbours as well */
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;
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;
527 unregister_mib_range( oid *name, size_t len, int priority,
528 int range_subid, oid range_ubound)
530 struct subtree *list, *myptr;
531 struct subtree *prev, *child; /* loop through children */
532 struct register_parameters reg_parms;
534 list = find_subtree( name, len, subtrees );
536 return MIB_NO_SUCH_REGISTRATION;
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 */
545 return MIB_NO_SUCH_REGISTRATION;
547 unload_subtree( child, prev );
548 myptr = child; /* remember this for later */
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.
557 * This should also serve to register ranges.
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,
565 && ( child->priority == priority )) {
567 unload_subtree( child, prev );
568 free_subtree( child );
572 if ( child == NULL ) /* Didn't find the given name */
575 free_subtree( myptr );
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,
585 return MIB_UNREGISTERED_OK;
589 unregister_mib_priority(oid *name, size_t len, int priority)
591 return unregister_mib_range( name, len, priority, 0, 0 );
595 unregister_mib(oid *name,
598 return unregister_mib_priority( name, len, DEFAULT_MIB_PRIORITY );
602 unregister_mibs_by_session (struct snmp_session *ss)
604 struct subtree *list, *list2;
605 struct subtree *child, *prev, *next_child;
607 for( list = subtrees; list != NULL; list = list2) {
609 for ( child=list, prev=NULL; child != NULL; child=next_child ) {
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 );
626 free_subtree(struct subtree *st)
628 struct subtree *ret = NULL;
629 if ((snmp_oid_compare(st->name, st->namelen, st->start, st->start_len) == 0)
630 && (st->variables != NULL))
632 if (st->next != NULL)
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
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 */
653 struct view_parameters view_parms;
654 view_parms.pdu = pdu;
655 view_parms.name = name;
657 view_parms.namelen = *namelen;
659 view_parms.namelen = 0;
660 view_parms.errorcode = 0;
662 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW)
663 return 0; /* Enable bypassing of view-based access control */
665 /* check for v1 and counter64s, since snmpv1 doesn't support it */
666 if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64)
668 switch (pdu->version) {
670 case SNMP_VERSION_2c:
671 #ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
674 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_ACM_CHECK,
676 return view_parms.errorcode;
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. */
684 check_access(struct snmp_pdu *pdu) /* IN - pdu being checked */
686 struct view_parameters view_parms;
687 view_parms.pdu = pdu;
689 view_parms.namelen = 0;
690 view_parms.errorcode = 0;
692 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW)
693 return 0; /* Enable bypassing of view-based access control */
695 switch (pdu->version) {
697 case SNMP_VERSION_2c:
698 #ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
701 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
702 SNMPD_CALLBACK_ACM_CHECK_INITIAL,
704 return view_parms.errorcode;
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
714 * Note: snmp_oid_compare checks len2 before last return.
717 compare_tree(const oid *in_name1,
722 register int len, res;
723 register const oid * name1 = in_name1;
724 register const oid * name2 = in_name2;
726 /* len = minimum of len1 and len2 */
731 /* find first non-matching OID */
733 res = *(name1++) - *(name2++);
739 /* both OIDs equal up to length of shorter OID */
743 /* name1 matches name2 for length of name2, or they are equal */
747 struct subtree *find_subtree_previous(oid *name,
749 struct subtree *subtree)
751 struct subtree *myptr, *previous = NULL;
756 myptr = subtrees; /* look through everything */
758 for( ; myptr != NULL; previous = myptr, myptr = myptr->next) {
759 if (snmp_oid_compare(name, len, myptr->start, myptr->start_len) < 0)
765 struct subtree *find_subtree_next(oid *name,
767 struct subtree *subtree)
769 struct subtree *myptr = NULL;
771 myptr = find_subtree_previous(name, len, subtree);
772 if ( myptr != NULL ) {
774 while ( myptr && (myptr->variables == NULL || myptr->variables_len == 0) )
778 else if (subtree && snmp_oid_compare(name, len, subtree->start, subtree->start_len) < 0)
784 struct subtree *find_subtree(oid *name,
786 struct subtree *subtree)
788 struct subtree *myptr;
790 myptr = find_subtree_previous(name, len, subtree);
791 if (myptr && snmp_oid_compare(name, len, myptr->end, myptr->end_len) < 0)
797 struct snmp_session *get_session_for_oid( oid *name, size_t len)
799 struct subtree *myptr;
801 myptr = find_subtree_previous(name, len, subtrees);
802 while ( myptr && myptr->variables == NULL )
808 return myptr->session;
813 static struct subtree root_subtrees[] = {
814 { { 0 }, 1 }, /* ccitt */
815 { { 1 }, 1 }, /* iso */
816 { { 2 }, 1 } /* joint-ccitt-iso */
820 void setup_tree (void)
822 #ifdef USING_AGENTX_SUBAGENT_MODULE
825 role = ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_ROLE);
826 ds_set_boolean(DS_APPLICATION_ID, DS_AGENT_ROLE, MASTER_AGENT);
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);
836 /* Support for 'static' subtrees (subtrees_old) has now been dropped */
838 /* No longer necessary to sort the mib tree - this is inherent in
839 the construction of the subtree structure */
841 #ifdef USING_AGENTX_SUBAGENT_MODULE
842 ds_set_boolean(DS_APPLICATION_ID, DS_AGENT_ROLE, role);
847 * Initial support for index allocation
849 extern struct snmp_session *main_session;
852 register_string_index( oid *name, size_t name_len, char *cp )
854 struct variable_list varbind, *res;
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 );
864 res = register_index( &varbind, ALLOCATE_ANY_INDEX, main_session );
869 return (char *)res->val.string;
873 register_int_index( oid *name, size_t name_len, int val )
875 struct variable_list varbind, *res;
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 );
887 res = register_index( &varbind, ALLOCATE_ANY_INDEX, main_session );
892 return *res->val.integer;
895 struct variable_list *
896 register_oid_index( oid *name, size_t name_len,
897 oid *value, size_t value_len )
899 struct variable_list varbind;
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 ));
909 return( register_index( &varbind, ALLOCATE_ANY_INDEX, main_session ));
912 struct variable_list*
913 register_index(struct variable_list *varbind, int flags, struct snmp_session *ss )
915 struct snmp_index *new_index, *idxptr, *idxptr2;
916 struct snmp_index *prev_oid_ptr, *prev_idx_ptr;
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 ));
923 /* Look for the requested OID entry */
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 )
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 */
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
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;
960 for(idxptr2 = idxptr ; idxptr2 != NULL;
961 prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
962 switch ( varbind->type ) {
964 res2 = (*varbind->val.integer - *idxptr2->varbind.val.integer);
967 i = SNMP_MIN(varbind->val_len, idxptr2->varbind.val_len);
968 res2 = memcmp(varbind->val.string, idxptr2->varbind.val.string, i);
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));
976 return NULL; /* wrong type */
982 return NULL; /* duplicate value */
987 * OK - we've now located where the new entry needs to
988 * be fitted into the index registry tree
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'.
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
1004 * 'idxptr2' points to the next sorted index (if any)
1005 * but is not actually needed any more.
1008 * I hope you've been paying attention.
1009 * There'll be a test later :-)
1013 * We proceed by creating the new entry
1014 * (by copying the entry provided)
1016 new_index = (struct snmp_index *)malloc( sizeof( struct snmp_index ));
1017 if (new_index == NULL)
1019 if (snmp_clone_var( varbind, &new_index->varbind ) != 0 ) {
1023 new_index->session = ss;
1025 if ( varbind->type == ASN_OCTET_STR && flags == ALLOCATE_THIS_INDEX )
1026 new_index->varbind.val.string[new_index->varbind.val_len] = 0;
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?)
1034 if ( flags & ALLOCATE_ANY_INDEX ) {
1035 if ( prev_idx_ptr ) {
1036 if ( snmp_clone_var( &prev_idx_ptr->varbind, &new_index->varbind ) != 0 ) {
1042 new_index->varbind.val.string = new_index->varbind.buf;
1044 switch ( varbind->type ) {
1046 if ( prev_idx_ptr ) {
1047 (*new_index->varbind.val.integer)++;
1050 *(new_index->varbind.val.integer) = 1;
1051 new_index->varbind.val_len = sizeof(long);
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';
1060 i = new_index->varbind.val_len;
1061 new_index->varbind.buf[ i ] = 'a';
1062 new_index->varbind.buf[ i+1 ] = 0;
1065 new_index->varbind.buf[ i ]++;
1068 strcpy((char *)new_index->varbind.buf, "aaaa");
1069 new_index->varbind.val_len = strlen((char *)new_index->varbind.buf);
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;
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);
1084 new_index->varbind.val.objid[ i ]++;
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.
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);
1099 /* Otherwise use '.1.1.1.1...' */
1103 new_index->varbind.val_len = i * (sizeof(oid));
1104 for (i-- ; i>=0 ; i-- )
1105 new_index->varbind.val.objid[i] = 1;
1111 return NULL; /* Index type not supported */
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.
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;
1127 if ( res == 0 && idxptr ) {
1128 new_index->next_idx = idxptr;
1129 new_index->next_oid = idxptr->next_oid;
1132 new_index->next_idx = NULL;
1133 new_index->next_oid = idxptr;
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;
1143 snmp_index_head = new_index;
1145 return &new_index->varbind;
1149 * Release an allocated index,
1150 * to allow it to be used elsewhere
1153 release_index(struct variable_list *varbind)
1155 return( unregister_index( varbind, TRUE, NULL ));
1159 * Completely remove an allocated index,
1160 * due to errors in the registration process.
1163 remove_index(struct variable_list *varbind, struct snmp_session *ss)
1165 return( unregister_index( varbind, FALSE, ss ));
1169 unregister_index_by_session(struct snmp_session *ss)
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;
1180 unregister_index(struct variable_list *varbind, int remember, struct snmp_session *ss)
1182 struct snmp_index *idxptr, *idxptr2;
1183 struct snmp_index *prev_oid_ptr, *prev_idx_ptr;
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 ));
1190 /* Look for the requested OID entry */
1191 prev_oid_ptr = NULL;
1192 prev_idx_ptr = NULL;
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 )
1204 return INDEX_ERR_NOT_ALLOCATED;
1205 if ( varbind->type != idxptr->varbind.type )
1206 return INDEX_ERR_WRONG_TYPE;
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);
1216 return INDEX_ERR_NOT_ALLOCATED;
1217 if ( ss != idxptr2->session )
1218 return INDEX_ERR_WRONG_SESSION;
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
1227 idxptr2->session = NULL; /* Unused index */
1228 return SNMP_ERR_NOERROR;
1231 * If this is a failed attempt to register a
1232 * number of indexes, the successful ones
1233 * must be removed completely.
1235 if ( prev_idx_ptr ) {
1236 prev_idx_ptr->next_idx = idxptr2->next_idx;
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;
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;
1249 if ( idxptr2->next_idx )
1250 snmp_index_head = idxptr2->next_idx;
1252 snmp_index_head = idxptr2->next_oid;
1254 snmp_free_var( (struct variable_list *)idxptr2 );
1255 return SNMP_ERR_NOERROR;
1259 void dump_registry( void )
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];
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 ? ' ' : '(' ),
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);
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 ) {
1287 printf(" %c %ld %c\n",
1288 ( idxptr2->session ? ' ' : '(' ),
1289 *idxptr2->varbind.val.integer,
1290 ( idxptr2->session ? ' ' : ')' ));
1293 printf(" %c %s %c\n",
1294 ( idxptr2->session ? ' ' : '(' ),
1295 idxptr2->varbind.val.string,
1296 ( idxptr2->session ? ' ' : ')' ));
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 ? ' ' : '(' ),
1304 ( idxptr2->session ? ' ' : ')' ));
1307 printf("unsupported type (%d)\n",
1308 idxptr2->varbind.type);
1315 struct variable_list varbind;
1316 struct snmp_session main_sess, *main_session=&main_sess;
1319 test_string_register( int n, char *cp )
1321 varbind.name[4] = n;
1322 if (register_string_index(varbind.name, varbind.name_length, cp) == NULL)
1323 printf("allocating %s failed\n", cp);
1327 test_int_register( int n, int val )
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);
1335 test_oid_register( int n, int subid )
1337 struct variable_list *res;
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,
1344 varbind.val_len/sizeof(oid) );
1347 res = register_oid_index(varbind.name, varbind.name_length, NULL, 0);
1350 printf("allocating %d/%d failed\n", n, subid);
1354 main( int argc, char argv[] )
1356 oid name[] = { 1, 2, 3, 4, 0 };
1359 memset( &varbind, 0, sizeof(struct variable_list));
1360 snmp_set_var_objid( &varbind, name, 5 );
1361 varbind.type = ASN_OCTET_STR;
1363 * Test index structure linking:
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" );
1372 * b) sorted by index value
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 */
1383 * c) test initial index linking
1385 test_string_register( 5, "eee: empty initial IDX" );
1386 test_string_register( 5, "aaa: replace initial IDX" );
1392 unregister_index_by_session( main_session );
1394 * Now test index allocation
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 */
1403 test_int_register( 110, -1 ); /* append */
1404 test_int_register( 110, 5 ); /* insert exact */
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 */
1420 test_oid_register( 130, -1 ); /* empty */
1421 test_oid_register( 130, -1 ); /* append */
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);
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 */
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 */
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 */
1454 * Test the various "invalid" requests
1455 * (unsupported types, mis-matched types, etc)
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");