net-snmp 5.7
agent_index.c
00001 /*
00002  * agent_index.c
00003  *
00004  * Maintain a registry of index allocations
00005  *      (Primarily required for AgentX support,
00006  *       but it could be more widely useable).
00007  */
00008 
00009 
00010 #include <net-snmp/net-snmp-config.h>
00011 #include <net-snmp/net-snmp-features.h>
00012 #include <signal.h>
00013 #if HAVE_STRING_H
00014 #include <string.h>
00015 #endif
00016 #if HAVE_STDLIB_H
00017 #include <stdlib.h>
00018 #endif
00019 #include <sys/types.h>
00020 #include <stdio.h>
00021 #include <fcntl.h>
00022 #if TIME_WITH_SYS_TIME
00023 # include <sys/time.h>
00024 # include <time.h>
00025 #else
00026 # if HAVE_SYS_TIME_H
00027 #  include <sys/time.h>
00028 # else
00029 #  include <time.h>
00030 # endif
00031 #endif
00032 #if HAVE_NETINET_IN_H
00033 #include <netinet/in.h>
00034 #endif
00035 
00036 #include <net-snmp/net-snmp-includes.h>
00037 #include <net-snmp/agent/net-snmp-agent-includes.h>
00038 #include <net-snmp/agent/agent_callbacks.h>
00039 #include <net-snmp/agent/agent_index.h>
00040 
00041 #include "snmpd.h"
00042 #include "mibgroup/struct.h"
00043 #include <net-snmp/agent/table.h>
00044 #include <net-snmp/agent/table_iterator.h>
00045 #include "mib_module_includes.h"
00046 
00047 #ifdef USING_AGENTX_SUBAGENT_MODULE
00048 #include "agentx/subagent.h"
00049 #include "agentx/client.h"
00050 #endif
00051 
00052 netsnmp_feature_child_of(agent_index_all, libnetsnmpagent)
00053 
00054 netsnmp_feature_child_of(remove_index, agent_index_all)
00055 
00056         /*
00057          * Initial support for index allocation
00058          */
00059 
00060 struct snmp_index {
00061     netsnmp_variable_list *varbind;     /* or pointer to var_list ? */
00062     int             allocated;
00063     netsnmp_session *session;
00064     struct snmp_index *next_oid;
00065     struct snmp_index *prev_oid;
00066     struct snmp_index *next_idx;
00067 }              *snmp_index_head = NULL;
00068 
00069 extern netsnmp_session *main_session;
00070 
00071 /*
00072  * The caller is responsible for free()ing the memory returned by
00073  * this function.  
00074  */
00075 
00076 char           *
00077 register_string_index(oid * name, size_t name_len, char *cp)
00078 {
00079     netsnmp_variable_list varbind, *res;
00080 
00081     memset(&varbind, 0, sizeof(netsnmp_variable_list));
00082     varbind.type = ASN_OCTET_STR;
00083     snmp_set_var_objid(&varbind, name, name_len);
00084     if (cp != ANY_STRING_INDEX) {
00085         snmp_set_var_value(&varbind, (u_char *) cp, strlen(cp));
00086         res = register_index(&varbind, ALLOCATE_THIS_INDEX, main_session);
00087     } else {
00088         res = register_index(&varbind, ALLOCATE_ANY_INDEX, main_session);
00089     }
00090 
00091     if (res == NULL) {
00092         return NULL;
00093     } else {
00094         char *rv = (char *)malloc(res->val_len + 1);
00095         if (rv) {
00096             memcpy(rv, res->val.string, res->val_len);
00097             rv[res->val_len] = 0;
00098         }
00099         free(res);
00100         return rv;
00101     }
00102 }
00103 
00104 int
00105 register_int_index(oid * name, size_t name_len, int val)
00106 {
00107     netsnmp_variable_list varbind, *res;
00108 
00109     memset(&varbind, 0, sizeof(netsnmp_variable_list));
00110     varbind.type = ASN_INTEGER;
00111     snmp_set_var_objid(&varbind, name, name_len);
00112     varbind.val.string = varbind.buf;
00113     if (val != ANY_INTEGER_INDEX) {
00114         varbind.val_len = sizeof(long);
00115         *varbind.val.integer = val;
00116         res = register_index(&varbind, ALLOCATE_THIS_INDEX, main_session);
00117     } else {
00118         res = register_index(&varbind, ALLOCATE_ANY_INDEX, main_session);
00119     }
00120 
00121     if (res == NULL) {
00122         return -1;
00123     } else {
00124         int             rv = *(res->val.integer);
00125         free(res);
00126         return rv;
00127     }
00128 }
00129 
00130 /*
00131  * The caller is responsible for free()ing the memory returned by
00132  * this function.  
00133  */
00134 
00135 netsnmp_variable_list *
00136 register_oid_index(oid * name, size_t name_len,
00137                    oid * value, size_t value_len)
00138 {
00139     netsnmp_variable_list varbind;
00140 
00141     memset(&varbind, 0, sizeof(netsnmp_variable_list));
00142     varbind.type = ASN_OBJECT_ID;
00143     snmp_set_var_objid(&varbind, name, name_len);
00144     if (value != ANY_OID_INDEX) {
00145         snmp_set_var_value(&varbind, (u_char *) value,
00146                            value_len * sizeof(oid));
00147         return register_index(&varbind, ALLOCATE_THIS_INDEX, main_session);
00148     } else {
00149         return register_index(&varbind, ALLOCATE_ANY_INDEX, main_session);
00150     }
00151 }
00152 
00153 /*
00154  * The caller is responsible for free()ing the memory returned by
00155  * this function.  
00156  */
00157 
00158 netsnmp_variable_list *
00159 register_index(netsnmp_variable_list * varbind, int flags,
00160                netsnmp_session * ss)
00161 {
00162     netsnmp_variable_list *rv = NULL;
00163     struct snmp_index *new_index, *idxptr, *idxptr2;
00164     struct snmp_index *prev_oid_ptr, *prev_idx_ptr;
00165     int             res, res2, i;
00166 
00167     DEBUGMSGTL(("register_index", "register "));
00168     DEBUGMSGVAR(("register_index", varbind));
00169     DEBUGMSG(("register_index", "for session %8p\n", ss));
00170 
00171 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING)
00172     if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
00173                                NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) {
00174         return (agentx_register_index(ss, varbind, flags));
00175     }
00176 #endif
00177     /*
00178      * Look for the requested OID entry 
00179      */
00180     prev_oid_ptr = NULL;
00181     prev_idx_ptr = NULL;
00182     res = 1;
00183     res2 = 1;
00184     for (idxptr = snmp_index_head; idxptr != NULL;
00185          prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) {
00186         if ((res = snmp_oid_compare(varbind->name, varbind->name_length,
00187                                     idxptr->varbind->name,
00188                                     idxptr->varbind->name_length)) <= 0)
00189             break;
00190     }
00191 
00192     /*
00193      * Found the OID - now look at the registered indices 
00194      */
00195     if (res == 0 && idxptr) {
00196         if (varbind->type != idxptr->varbind->type)
00197             return NULL;        /* wrong type */
00198 
00199         /*
00200          * If we've been asked for an arbitrary new value,
00201          *      then find the end of the list.
00202          * If we've been asked for any arbitrary value,
00203          *      then look for an unused entry, and use that.
00204          *      If there aren't any, continue as for new.
00205          * Otherwise, locate the given value in the (sorted)
00206          *      list of already allocated values
00207          */
00208         if (flags & ALLOCATE_ANY_INDEX) {
00209             for (idxptr2 = idxptr; idxptr2 != NULL;
00210                  prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
00211 
00212                 if (flags == ALLOCATE_ANY_INDEX && !(idxptr2->allocated)) {
00213                     if ((rv =
00214                          snmp_clone_varbind(idxptr2->varbind)) != NULL) {
00215                         idxptr2->session = ss;
00216                         idxptr2->allocated = 1;
00217                     }
00218                     return rv;
00219                 }
00220             }
00221         } else {
00222             for (idxptr2 = idxptr; idxptr2 != NULL;
00223                  prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
00224                 switch (varbind->type) {
00225                 case ASN_INTEGER:
00226                     res2 =
00227                         (*varbind->val.integer -
00228                          *idxptr2->varbind->val.integer);
00229                     break;
00230                 case ASN_OCTET_STR:
00231                     i = SNMP_MIN(varbind->val_len,
00232                                  idxptr2->varbind->val_len);
00233                     res2 =
00234                         memcmp(varbind->val.string,
00235                                idxptr2->varbind->val.string, i);
00236                     break;
00237                 case ASN_OBJECT_ID:
00238                     res2 =
00239                         snmp_oid_compare(varbind->val.objid,
00240                                          varbind->val_len / sizeof(oid),
00241                                          idxptr2->varbind->val.objid,
00242                                          idxptr2->varbind->val_len /
00243                                          sizeof(oid));
00244                     break;
00245                 default:
00246                     return NULL;        /* wrong type */
00247                 }
00248                 if (res2 <= 0)
00249                     break;
00250             }
00251             if (res2 == 0) {
00252                 if (idxptr2->allocated) {
00253                     /*
00254                      * No good: the index is in use.  
00255                      */
00256                     return NULL;
00257                 } else {
00258                     /*
00259                      * Okay, it's unallocated, we can just claim ownership
00260                      * here.  
00261                      */
00262                     if ((rv =
00263                          snmp_clone_varbind(idxptr2->varbind)) != NULL) {
00264                         idxptr2->session = ss;
00265                         idxptr2->allocated = 1;
00266                     }
00267                     return rv;
00268                 }
00269             }
00270         }
00271     }
00272 
00273     /*
00274      * OK - we've now located where the new entry needs to
00275      *      be fitted into the index registry tree          
00276      * To recap:
00277      *      'prev_oid_ptr' points to the head of the OID index
00278      *          list prior to this one.  If this is null, then
00279      *          it means that this is the first OID in the list.
00280      *      'idxptr' points either to the head of this OID list,
00281      *          or the next OID (if this is a new OID request)
00282      *          These can be distinguished by the value of 'res'.
00283      *
00284      *      'prev_idx_ptr' points to the index entry that sorts
00285      *          immediately prior to the requested value (if any).
00286      *          If an arbitrary value is required, then this will
00287      *          point to the last allocated index.
00288      *          If this pointer is null, then either this is a new
00289      *          OID request, or the requested value is the first
00290      *          in the list.
00291      *      'idxptr2' points to the next sorted index (if any)
00292      *          but is not actually needed any more.
00293      *
00294      *  Clear?  Good!
00295      *      I hope you've been paying attention.
00296      *          There'll be a test later :-)
00297      */
00298 
00299     /*
00300      *      We proceed by creating the new entry
00301      *         (by copying the entry provided)
00302      */
00303     new_index = (struct snmp_index *) calloc(1, sizeof(struct snmp_index));
00304     if (new_index == NULL)
00305         return NULL;
00306 
00307     if (NULL == snmp_varlist_add_variable(&new_index->varbind,
00308                                           varbind->name,
00309                                           varbind->name_length,
00310                                           varbind->type,
00311                                           varbind->val.string,
00312                                           varbind->val_len)) {
00313         /*
00314          * if (snmp_clone_var( varbind, new_index->varbind ) != 0 ) 
00315          */
00316         free(new_index);
00317         return NULL;
00318     }
00319     new_index->session = ss;
00320     new_index->allocated = 1;
00321 
00322     if (varbind->type == ASN_OCTET_STR && flags == ALLOCATE_THIS_INDEX)
00323         new_index->varbind->val.string[new_index->varbind->val_len] = 0;
00324 
00325     /*
00326      * If we've been given a value, then we can use that, but
00327      *    otherwise, we need to create a new value for this entry.
00328      * Note that ANY_INDEX and NEW_INDEX are both covered by this
00329      *   test (since NEW_INDEX & ANY_INDEX = ANY_INDEX, remember?)
00330      */
00331     if (flags & ALLOCATE_ANY_INDEX) {
00332         if (prev_idx_ptr) {
00333             if (snmp_clone_var(prev_idx_ptr->varbind, new_index->varbind)
00334                 != 0) {
00335                 free(new_index);
00336                 return NULL;
00337             }
00338         } else
00339             new_index->varbind->val.string = new_index->varbind->buf;
00340 
00341         switch (varbind->type) {
00342         case ASN_INTEGER:
00343             if (prev_idx_ptr) {
00344                 (*new_index->varbind->val.integer)++;
00345             } else
00346                 *(new_index->varbind->val.integer) = 1;
00347             new_index->varbind->val_len = sizeof(long);
00348             break;
00349         case ASN_OCTET_STR:
00350             if (prev_idx_ptr) {
00351                 i = new_index->varbind->val_len - 1;
00352                 while (new_index->varbind->buf[i] == 'z') {
00353                     new_index->varbind->buf[i] = 'a';
00354                     i--;
00355                     if (i < 0) {
00356                         i = new_index->varbind->val_len;
00357                         new_index->varbind->buf[i] = 'a';
00358                         new_index->varbind->buf[i + 1] = 0;
00359                     }
00360                 }
00361                 new_index->varbind->buf[i]++;
00362             } else
00363                 strcpy((char *) new_index->varbind->buf, "aaaa");
00364             new_index->varbind->val_len =
00365                 strlen((char *) new_index->varbind->buf);
00366             break;
00367         case ASN_OBJECT_ID:
00368             if (prev_idx_ptr) {
00369                 i = prev_idx_ptr->varbind->val_len / sizeof(oid) - 1;
00370                 while (new_index->varbind->val.objid[i] == 255) {
00371                     new_index->varbind->val.objid[i] = 1;
00372                     i--;
00373                     if (i == 0 && new_index->varbind->val.objid[0] == 2) {
00374                         new_index->varbind->val.objid[0] = 1;
00375                         i = new_index->varbind->val_len / sizeof(oid);
00376                         new_index->varbind->val.objid[i] = 0;
00377                         new_index->varbind->val_len += sizeof(oid);
00378                     }
00379                 }
00380                 new_index->varbind->val.objid[i]++;
00381             } else {
00382                 /*
00383                  * If the requested OID name is small enough,
00384                  * *   append another OID (1) and use this as the
00385                  * *   default starting value for new indexes.
00386                  */
00387                 if ((varbind->name_length + 1) * sizeof(oid) <= 40) {
00388                     for (i = 0; i < (int) varbind->name_length; i++)
00389                         new_index->varbind->val.objid[i] =
00390                             varbind->name[i];
00391                     new_index->varbind->val.objid[varbind->name_length] =
00392                         1;
00393                     new_index->varbind->val_len =
00394                         (varbind->name_length + 1) * sizeof(oid);
00395                 } else {
00396                     /*
00397                      * Otherwise use '.1.1.1.1...' 
00398                      */
00399                     i = 40 / sizeof(oid);
00400                     if (i > 4)
00401                         i = 4;
00402                     new_index->varbind->val_len = i * (sizeof(oid));
00403                     for (i--; i >= 0; i--)
00404                         new_index->varbind->val.objid[i] = 1;
00405                 }
00406             }
00407             break;
00408         default:
00409             snmp_free_var(new_index->varbind);
00410             free(new_index);
00411             return NULL;        /* Index type not supported */
00412         }
00413     }
00414 
00415     /*
00416      * Try to duplicate the new varbind for return.  
00417      */
00418 
00419     if ((rv = snmp_clone_varbind(new_index->varbind)) == NULL) {
00420         snmp_free_var(new_index->varbind);
00421         free(new_index);
00422         return NULL;
00423     }
00424 
00425     /*
00426      * Right - we've set up the new entry.
00427      * All that remains is to link it into the tree.
00428      * There are a number of possible cases here,
00429      *   so watch carefully.
00430      */
00431     if (prev_idx_ptr) {
00432         new_index->next_idx = prev_idx_ptr->next_idx;
00433         new_index->next_oid = prev_idx_ptr->next_oid;
00434         prev_idx_ptr->next_idx = new_index;
00435     } else {
00436         if (res == 0 && idxptr) {
00437             new_index->next_idx = idxptr;
00438             new_index->next_oid = idxptr->next_oid;
00439         } else {
00440             new_index->next_idx = NULL;
00441             new_index->next_oid = idxptr;
00442         }
00443 
00444         if (prev_oid_ptr) {
00445             while (prev_oid_ptr) {
00446                 prev_oid_ptr->next_oid = new_index;
00447                 prev_oid_ptr = prev_oid_ptr->next_idx;
00448             }
00449         } else
00450             snmp_index_head = new_index;
00451     }
00452     return rv;
00453 }
00454 
00455         /*
00456          * Release an allocated index,
00457          *   to allow it to be used elsewhere
00458          */
00459 netsnmp_feature_child_of(release_index,netsnmp_unused)
00460 #ifndef NETSNMP_FEATURE_REMOVE_RELEASE_INDEX
00461 int
00462 release_index(netsnmp_variable_list * varbind)
00463 {
00464     return (unregister_index(varbind, TRUE, NULL));
00465 }
00466 #endif /* NETSNMP_FEATURE_REMOVE_RELEASE_INDEX */
00467 
00468 #ifndef NETSNMP_FEATURE_REMOVE_REMOVE_INDEX
00469         /*
00470          * Completely remove an allocated index,
00471          *   due to errors in the registration process.
00472          */
00473 int
00474 remove_index(netsnmp_variable_list * varbind, netsnmp_session * ss)
00475 {
00476     return (unregister_index(varbind, FALSE, ss));
00477 }
00478 #endif /* NETSNMP_FEATURE_REMOVE_REMOVE_INDEX */
00479 
00480 void
00481 unregister_index_by_session(netsnmp_session * ss)
00482 {
00483     struct snmp_index *idxptr, *idxptr2;
00484     for (idxptr = snmp_index_head; idxptr != NULL;
00485          idxptr = idxptr->next_oid)
00486         for (idxptr2 = idxptr; idxptr2 != NULL;
00487              idxptr2 = idxptr2->next_idx)
00488             if (idxptr2->session == ss) {
00489                 idxptr2->allocated = 0;
00490                 idxptr2->session = NULL;
00491             }
00492 }
00493 
00494 
00495 int
00496 unregister_index(netsnmp_variable_list * varbind, int remember,
00497                  netsnmp_session * ss)
00498 {
00499     struct snmp_index *idxptr, *idxptr2;
00500     struct snmp_index *prev_oid_ptr, *prev_idx_ptr;
00501     int             res, res2, i;
00502 
00503 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING)
00504     if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
00505                                NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) {
00506         return (agentx_unregister_index(ss, varbind));
00507     }
00508 #endif
00509     /*
00510      * Look for the requested OID entry 
00511      */
00512     prev_oid_ptr = NULL;
00513     prev_idx_ptr = NULL;
00514     res = 1;
00515     res2 = 1;
00516     for (idxptr = snmp_index_head; idxptr != NULL;
00517          prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) {
00518         if ((res = snmp_oid_compare(varbind->name, varbind->name_length,
00519                                     idxptr->varbind->name,
00520                                     idxptr->varbind->name_length)) <= 0)
00521             break;
00522     }
00523 
00524     if (res != 0)
00525         return INDEX_ERR_NOT_ALLOCATED;
00526     if (varbind->type != idxptr->varbind->type)
00527         return INDEX_ERR_WRONG_TYPE;
00528 
00529     for (idxptr2 = idxptr; idxptr2 != NULL;
00530          prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
00531         i = SNMP_MIN(varbind->val_len, idxptr2->varbind->val_len);
00532         res2 =
00533             memcmp(varbind->val.string, idxptr2->varbind->val.string, i);
00534         if (res2 <= 0)
00535             break;
00536     }
00537     if (res2 != 0 || (res2 == 0 && !idxptr2->allocated)) {
00538         return INDEX_ERR_NOT_ALLOCATED;
00539     }
00540     if (ss != idxptr2->session)
00541         return INDEX_ERR_WRONG_SESSION;
00542 
00543     /*
00544      *  If this is a "normal" index unregistration,
00545      *      mark the index entry as unused, but leave
00546      *      it in situ.  This allows differentiation
00547      *      between ANY_INDEX and NEW_INDEX
00548      */
00549     if (remember) {
00550         idxptr2->allocated = 0; /* Unused index */
00551         idxptr2->session = NULL;
00552         return SNMP_ERR_NOERROR;
00553     }
00554     /*
00555      *  If this is a failed attempt to register a
00556      *      number of indexes, the successful ones
00557      *      must be removed completely.
00558      */
00559     if (prev_idx_ptr) {
00560         prev_idx_ptr->next_idx = idxptr2->next_idx;
00561     } else if (prev_oid_ptr) {
00562         if (idxptr2->next_idx)  /* Use p_idx_ptr as a temp variable */
00563             prev_idx_ptr = idxptr2->next_idx;
00564         else
00565             prev_idx_ptr = idxptr2->next_oid;
00566         while (prev_oid_ptr) {
00567             prev_oid_ptr->next_oid = prev_idx_ptr;
00568             prev_oid_ptr = prev_oid_ptr->next_idx;
00569         }
00570     } else {
00571         if (idxptr2->next_idx)
00572             snmp_index_head = idxptr2->next_idx;
00573         else
00574             snmp_index_head = idxptr2->next_oid;
00575     }
00576     snmp_free_var(idxptr2->varbind);
00577     free(idxptr2);
00578     return SNMP_ERR_NOERROR;
00579 }
00580 
00581 netsnmp_feature_child_of(unregister_indexes,netsnmp_unused)
00582 #ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_INDEXES
00583 int
00584 unregister_string_index(oid * name, size_t name_len, char *cp)
00585 {
00586     netsnmp_variable_list varbind;
00587 
00588     memset(&varbind, 0, sizeof(netsnmp_variable_list));
00589     varbind.type = ASN_OCTET_STR;
00590     snmp_set_var_objid(&varbind, name, name_len);
00591     snmp_set_var_value(&varbind, (u_char *) cp, strlen(cp));
00592     return (unregister_index(&varbind, FALSE, main_session));
00593 }
00594 
00595 int
00596 unregister_int_index(oid * name, size_t name_len, int val)
00597 {
00598     netsnmp_variable_list varbind;
00599 
00600     memset(&varbind, 0, sizeof(netsnmp_variable_list));
00601     varbind.type = ASN_INTEGER;
00602     snmp_set_var_objid(&varbind, name, name_len);
00603     varbind.val.string = varbind.buf;
00604     varbind.val_len = sizeof(long);
00605     *varbind.val.integer = val;
00606     return (unregister_index(&varbind, FALSE, main_session));
00607 }
00608 
00609 int
00610 unregister_oid_index(oid * name, size_t name_len,
00611                      oid * value, size_t value_len)
00612 {
00613     netsnmp_variable_list varbind;
00614 
00615     memset(&varbind, 0, sizeof(netsnmp_variable_list));
00616     varbind.type = ASN_OBJECT_ID;
00617     snmp_set_var_objid(&varbind, name, name_len);
00618     snmp_set_var_value(&varbind, (u_char *) value,
00619                        value_len * sizeof(oid));
00620     return (unregister_index(&varbind, FALSE, main_session));
00621 }
00622 #endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_INDEXES */
00623 
00624 void
00625 dump_idx_registry(void)
00626 {
00627     struct snmp_index *idxptr, *idxptr2;
00628     u_char         *sbuf = NULL, *ebuf = NULL;
00629     size_t          sbuf_len = 0, sout_len = 0, ebuf_len = 0, eout_len = 0;
00630 
00631     if (snmp_index_head != NULL) {
00632         printf("\nIndex Allocations:\n");
00633     }
00634 
00635     for (idxptr = snmp_index_head; idxptr != NULL;
00636          idxptr = idxptr->next_oid) {
00637         sout_len = 0;
00638         if (sprint_realloc_objid(&sbuf, &sbuf_len, &sout_len, 1,
00639                                  idxptr->varbind->name,
00640                                  idxptr->varbind->name_length)) {
00641             printf("%s indexes:\n", sbuf);
00642         } else {
00643             printf("%s [TRUNCATED] indexes:\n", sbuf);
00644         }
00645 
00646         for (idxptr2 = idxptr; idxptr2 != NULL;
00647              idxptr2 = idxptr2->next_idx) {
00648             switch (idxptr2->varbind->type) {
00649             case ASN_INTEGER:
00650                 printf("    %ld for session %8p, allocated %d\n",
00651                        *idxptr2->varbind->val.integer, idxptr2->session,
00652                        idxptr2->allocated);
00653                 break;
00654             case ASN_OCTET_STR:
00655                 printf("    \"%s\" for session %8p, allocated %d\n",
00656                        idxptr2->varbind->val.string, idxptr2->session,
00657                        idxptr2->allocated);
00658                 break;
00659             case ASN_OBJECT_ID:
00660                 eout_len = 0;
00661                 if (sprint_realloc_objid(&ebuf, &ebuf_len, &eout_len, 1,
00662                                          idxptr2->varbind->val.objid,
00663                                          idxptr2->varbind->val_len /
00664                                          sizeof(oid))) {
00665                     printf("    %s for session %8p, allocated %d\n", ebuf,
00666                            idxptr2->session, idxptr2->allocated);
00667                 } else {
00668                     printf
00669                         ("    %s [TRUNCATED] for sess %8p, allocated %d\n",
00670                          ebuf, idxptr2->session, idxptr2->allocated);
00671                 }
00672                 break;
00673             default:
00674                 printf("unsupported type (%d/0x%02x)\n",
00675                        idxptr2->varbind->type, idxptr2->varbind->type);
00676             }
00677         }
00678     }
00679 
00680     if (sbuf != NULL) {
00681         free(sbuf);
00682     }
00683     if (ebuf != NULL) {
00684         free(ebuf);
00685     }
00686 }
00687 
00688 netsnmp_feature_child_of(count_indexes, netsnmp_unused)
00689 #ifndef NETSNMP_FEATURE_REMOVE_UNUSED
00690 unsigned long
00691 count_indexes(oid * name, size_t namelen, int include_unallocated)
00692 {
00693     struct snmp_index *i = NULL, *j = NULL;
00694     unsigned long   n = 0;
00695 
00696     for (i = snmp_index_head; i != NULL; i = i->next_oid) {
00697         if (netsnmp_oid_equals(name, namelen,
00698                              i->varbind->name,
00699                              i->varbind->name_length) == 0) {
00700             for (j = i; j != NULL; j = j->next_idx) {
00701                 if (j->allocated || include_unallocated) {
00702                     n++;
00703                 }
00704             }
00705         }
00706     }
00707     return n;
00708 }
00709 #endif /* NETSNMP_FEATURE_REMOVE_UNUSED */
00710 
00711 #ifdef TESTING
00712 netsnmp_variable_list varbind;
00713 netsnmp_session main_sess, *main_session = &main_sess;
00714 
00715 void
00716 test_string_register(int n, char *cp)
00717 {
00718     varbind->name[4] = n;
00719     if (register_string_index(varbind->name, varbind.name_length, cp) ==
00720         NULL)
00721         printf("allocating %s failed\n", cp);
00722 }
00723 
00724 void
00725 test_int_register(int n, int val)
00726 {
00727     varbind->name[4] = n;
00728     if (register_int_index(varbind->name, varbind.name_length, val) == -1)
00729         printf("allocating %d/%d failed\n", n, val);
00730 }
00731 
00732 void
00733 test_oid_register(int n, int subid)
00734 {
00735     netsnmp_variable_list *res;
00736 
00737     varbind->name[4] = n;
00738     if (subid != -1) {
00739         varbind->val.objid[5] = subid;
00740         res = register_oid_index(varbind->name, varbind.name_length,
00741                                  varbind->val.objid,
00742                                  varbind->val_len / sizeof(oid));
00743     } else
00744         res =
00745             register_oid_index(varbind->name, varbind.name_length, NULL,
00746                                0);
00747 
00748     if (res == NULL)
00749         printf("allocating %d/%d failed\n", n, subid);
00750 }
00751 
00752 void
00753 main(int argc, char argv[])
00754 {
00755     oid             name[] = { 1, 2, 3, 4, 0 };
00756     int             i;
00757 
00758     memset(&varbind, 0, sizeof(netsnmp_variable_list));
00759     snmp_set_var_objid(&varbind, name, 5);
00760     varbind->type = ASN_OCTET_STR;
00761     /*
00762      * Test index structure linking:
00763      *      a) sorted by OID
00764      */
00765     test_string_register(20, "empty OID");
00766     test_string_register(10, "first OID");
00767     test_string_register(40, "last OID");
00768     test_string_register(30, "middle OID");
00769 
00770     /*
00771      *      b) sorted by index value
00772      */
00773     test_string_register(25, "eee: empty IDX");
00774     test_string_register(25, "aaa: first IDX");
00775     test_string_register(25, "zzz: last IDX");
00776     test_string_register(25, "mmm: middle IDX");
00777     printf("This next one should fail....\n");
00778     test_string_register(25, "eee: empty IDX"); /* duplicate */
00779     printf("done\n");
00780 
00781     /*
00782      *      c) test initial index linking
00783      */
00784     test_string_register(5, "eee: empty initial IDX");
00785     test_string_register(5, "aaa: replace initial IDX");
00786 
00787     /*
00788      *      Did it all work?
00789      */
00790     dump_idx_registry();
00791     unregister_index_by_session(main_session);
00792     /*
00793      *  Now test index allocation
00794      *      a) integer values
00795      */
00796     test_int_register(110, -1); /* empty */
00797     test_int_register(110, -1); /* append */
00798     test_int_register(110, 10); /* append exact */
00799     printf("This next one should fail....\n");
00800     test_int_register(110, 10); /* exact duplicate */
00801     printf("done\n");
00802     test_int_register(110, -1); /* append */
00803     test_int_register(110, 5);  /* insert exact */
00804 
00805     /*
00806      *      b) string values
00807      */
00808     test_string_register(120, NULL);    /* empty */
00809     test_string_register(120, NULL);    /* append */
00810     test_string_register(120, "aaaz");
00811     test_string_register(120, NULL);    /* minor rollover */
00812     test_string_register(120, "zzzz");
00813     test_string_register(120, NULL);    /* major rollover */
00814 
00815     /*
00816      *      c) OID values
00817      */
00818 
00819     test_oid_register(130, -1); /* empty */
00820     test_oid_register(130, -1); /* append */
00821 
00822     varbind->val_len = varbind.name_length * sizeof(oid);
00823     memcpy(varbind->buf, varbind.name, varbind.val_len);
00824     varbind->val.objid = (oid *) varbind.buf;
00825     varbind->val_len += sizeof(oid);
00826 
00827     test_oid_register(130, 255);        /* append exact */
00828     test_oid_register(130, -1); /* minor rollover */
00829     test_oid_register(130, 100);        /* insert exact */
00830     printf("This next one should fail....\n");
00831     test_oid_register(130, 100);        /* exact duplicate */
00832     printf("done\n");
00833 
00834     varbind->val.objid = (oid *) varbind.buf;
00835     for (i = 0; i < 6; i++)
00836         varbind->val.objid[i] = 255;
00837     varbind->val.objid[0] = 1;
00838     test_oid_register(130, 255);        /* set up rollover  */
00839     test_oid_register(130, -1); /* medium rollover */
00840 
00841     for (i = 0; i < 6; i++)
00842         varbind->val.objid[i] = 255;
00843     varbind->val.objid[0] = 2;
00844     test_oid_register(130, 255);        /* set up rollover  */
00845     test_oid_register(130, -1); /* major rollover */
00846 
00847     /*
00848      *      Did it all work?
00849      */
00850     dump_idx_registry();
00851 
00852     /*
00853      *      Test the various "invalid" requests
00854      *      (unsupported types, mis-matched types, etc)
00855      */
00856     printf("The rest of these should fail....\n");
00857     test_oid_register(110, -1);
00858     test_oid_register(110, 100);
00859     test_oid_register(120, -1);
00860     test_oid_register(120, 100);
00861     test_string_register(110, NULL);
00862     test_string_register(110, "aaaa");
00863     test_string_register(130, NULL);
00864     test_string_register(130, "aaaa");
00865     test_int_register(120, -1);
00866     test_int_register(120, 1);
00867     test_int_register(130, -1);
00868     test_int_register(130, 1);
00869     printf("done - this dump should be the same as before\n");
00870     dump_idx_registry();
00871 }
00872 #endif