net-snmp  5.4.1
table_tdata.c
00001 #include <net-snmp/net-snmp-config.h>
00002 
00003 #if HAVE_STRING_H
00004 #include <string.h>
00005 #else
00006 #include <strings.h>
00007 #endif
00008 
00009 #include <net-snmp/net-snmp-includes.h>
00010 #include <net-snmp/agent/net-snmp-agent-includes.h>
00011 
00012 #include <net-snmp/agent/table.h>
00013 #include <net-snmp/agent/table_tdata.h>
00014 #include <net-snmp/agent/table_container.h>
00015 #include <net-snmp/agent/read_only.h>
00016 
00017 #if HAVE_DMALLOC_H
00018 #include <dmalloc.h>
00019 #endif
00020 
00037 /* ==================================
00038  *
00039  * TData API: Table maintenance
00040  *
00041  * ================================== */
00042 
00043 /*
00044  * generates the index portion of an table oid from a varlist.
00045  */
00046 void
00047 _netsnmp_tdata_generate_index_oid(netsnmp_tdata_row *row)
00048 {
00049     build_oid(&row->oid_index.oids, &row->oid_index.len, NULL, 0, row->indexes);
00050 }
00051 
00053 netsnmp_tdata *
00054 netsnmp_tdata_create_table(const char *name, long flags)
00055 {
00056     netsnmp_tdata *table = SNMP_MALLOC_TYPEDEF(netsnmp_tdata);
00057     if ( !table )
00058         return NULL;
00059 
00060     table->flags = flags;
00061     if (name)
00062         table->name = strdup(name);
00063 
00064     if (!(table->flags & TDATA_FLAG_NO_CONTAINER)) {
00065         table->container = netsnmp_container_find( name );
00066         if (!table->container)
00067             table->container = netsnmp_container_find( "table_container" );
00068         if (table->container)
00069             table->container->container_name = strdup(name);
00070     }
00071 
00072     return table;
00073 }
00074 
00076 void
00077 netsnmp_tdata_delete_table(netsnmp_tdata *table)
00078 {
00079     if (!table)
00080        return;
00081 
00082     if (table->name)
00083        free(table->name);
00084     if (table->container)
00085        CONTAINER_FREE(table->container);
00086     
00087     SNMP_FREE(table);
00088     return;
00089 }
00090 
00092 netsnmp_tdata_row *
00093 netsnmp_tdata_create_row(void)
00094 {
00095     netsnmp_tdata_row *row = SNMP_MALLOC_TYPEDEF(netsnmp_tdata_row);
00096     return row;
00097 }
00098 
00100 netsnmp_tdata_row *
00101 netsnmp_tdata_clone_row(netsnmp_tdata_row *row)
00102 {
00103     netsnmp_tdata_row *newrow = NULL;
00104     if (!row)
00105         return NULL;
00106 
00107     memdup((u_char **) & newrow, (u_char *) row,
00108            sizeof(netsnmp_tdata_row));
00109     if (!newrow)
00110         return NULL;
00111 
00112     if (row->indexes) {
00113         newrow->indexes = snmp_clone_varbind(newrow->indexes);
00114         if (!newrow->indexes) {
00115             SNMP_FREE(newrow);
00116             return NULL;
00117         }
00118     }
00119 
00120     if (row->oid_index.oids) {
00121         memdup((u_char **) & newrow->oid_index.oids,
00122                (u_char *) row->oid_index.oids,
00123                row->oid_index.len * sizeof(oid));
00124         if (!newrow->oid_index.oids) {
00125             if (newrow->indexes)
00126                 snmp_free_varbind(newrow->indexes);
00127             SNMP_FREE(newrow);
00128             return NULL;
00129         }
00130     }
00131 
00132     return newrow;
00133 }
00134 
00137 int
00138 netsnmp_tdata_copy_row(netsnmp_tdata_row *dst_row, netsnmp_tdata_row *src_row)
00139 {
00140      if ( !src_row || !dst_row )
00141          return -1;
00142 
00143     memcpy((u_char *) dst_row, (u_char *) src_row,
00144            sizeof(netsnmp_tdata_row));
00145     if (src_row->indexes) {
00146         dst_row->indexes = snmp_clone_varbind(src_row->indexes);
00147         if (!dst_row->indexes)
00148             return -1;
00149     }
00150 
00151     if (src_row->oid_index.oids) {
00152         memdup((u_char **) &dst_row->oid_index.oids,
00153                (u_char  *)  src_row->oid_index.oids,
00154                src_row->oid_index.len * sizeof(oid));
00155         if (!dst_row->oid_index.oids)
00156             return -1;
00157     }
00158 
00159     return 0;
00160 }
00161 
00165 void           *
00166 netsnmp_tdata_delete_row(netsnmp_tdata_row *row)
00167 {
00168     void           *data;
00169 
00170     if (!row)
00171         return NULL;
00172 
00173     /*
00174      * free the memory we can 
00175      */
00176     if (row->indexes)
00177         snmp_free_varbind(row->indexes);
00178     SNMP_FREE(row->oid_index.oids);
00179     data = row->data;
00180     free(row);
00181 
00182     /*
00183      * return the void * pointer 
00184      */
00185     return data;
00186 }
00187 
00194 int
00195 netsnmp_tdata_add_row(netsnmp_tdata     *table,
00196                       netsnmp_tdata_row *row)
00197 {
00198     if (!row || !table)
00199         return SNMPERR_GENERR;
00200 
00201     if (row->indexes)
00202         _netsnmp_tdata_generate_index_oid(row);
00203 
00204     if (!row->oid_index.oids) {
00205         snmp_log(LOG_ERR,
00206                  "illegal data attempted to be added to table %s (no index)\n",
00207                  table->name);
00208         return SNMPERR_GENERR;
00209     }
00210 
00211     /*
00212      * The individual index values probably won't be needed,
00213      *    so this memory can be released.
00214      * Note that this is purely internal to the helper.
00215      * The calling application can set this flag as
00216      *    a hint to the helper that these values aren't
00217      *    required, but it's up to the helper as to
00218      *    whether it takes any notice or not!
00219      */
00220     if (table->flags & TDATA_FLAG_NO_STORE_INDEXES) {
00221         snmp_free_varbind(row->indexes);
00222         row->indexes = NULL;
00223     }
00224 
00225     /*
00226      * add this row to the stored table
00227      */
00228     CONTAINER_INSERT( table->container, row );
00229     DEBUGMSGTL(("tdata_add_row", "added row (%x)\n", row));
00230 
00231     return SNMPERR_SUCCESS;
00232 }
00233 
00235 void
00236 netsnmp_tdata_replace_row(netsnmp_tdata *table,
00237                                netsnmp_tdata_row *origrow,
00238                                netsnmp_tdata_row *newrow)
00239 {
00240     netsnmp_tdata_remove_row(table, origrow);
00241     netsnmp_tdata_add_row(table, newrow);
00242 }
00243 
00250 netsnmp_tdata_row *
00251 netsnmp_tdata_remove_row(netsnmp_tdata *table,
00252                               netsnmp_tdata_row *row)
00253 {
00254     if (!row || !table)
00255         return NULL;
00256 
00257     CONTAINER_REMOVE( table->container, row );
00258     return row;
00259 }
00260 
00268 void           *
00269 netsnmp_tdata_remove_and_delete_row(netsnmp_tdata     *table,
00270                                     netsnmp_tdata_row *row)
00271 {
00272     if (!row || !table)
00273         return NULL;
00274 
00275     /*
00276      * remove it from the list 
00277      */
00278     netsnmp_tdata_remove_row(table, row);
00279     return netsnmp_tdata_delete_row(row);
00280 }
00281 
00282 
00283 /* ==================================
00284  *
00285  * TData API: MIB maintenance
00286  *
00287  * ================================== */
00288 
00289 Netsnmp_Node_Handler _netsnmp_tdata_helper_handler;
00290 
00292 netsnmp_mib_handler *
00293 netsnmp_get_tdata_handler(netsnmp_tdata *table)
00294 {
00295     netsnmp_mib_handler *ret = NULL;
00296 
00297     if (!table) {
00298         snmp_log(LOG_INFO,
00299                  "netsnmp_get_tdata_handler(NULL) called\n");
00300         return NULL;
00301     }
00302 
00303     ret = netsnmp_create_handler(TABLE_TDATA_NAME,
00304                                _netsnmp_tdata_helper_handler);
00305     if (ret) {
00306         ret->flags |= MIB_HANDLER_AUTO_NEXT;
00307         ret->myvoid = (void *) table;
00308     }
00309     return ret;
00310 }
00311 
00312 /*
00313  * The helper handler that takes care of passing a specific row of
00314  * data down to the lower handler(s).  The table_container helper
00315  * has already taken care of identifying the appropriate row of the
00316  * table (and converting GETNEXT requests into an equivalent GET request)
00317  * So all we need to do here is make sure that the row is accessible
00318  * using tdata-style retrieval techniques as well.
00319  */
00320 int
00321 _netsnmp_tdata_helper_handler(netsnmp_mib_handler *handler,
00322                                   netsnmp_handler_registration *reginfo,
00323                                   netsnmp_agent_request_info *reqinfo,
00324                                   netsnmp_request_info *requests)
00325 {
00326     netsnmp_tdata *table = (netsnmp_tdata *) handler->myvoid;
00327     netsnmp_request_info       *request;
00328     netsnmp_table_request_info *table_info;
00329     netsnmp_tdata_row          *row;
00330 
00331     switch ( reqinfo->mode ) {
00332     case MODE_GET:
00333     case MODE_SET_RESERVE1:
00334 
00335         for (request = requests; request; request = request->next) {
00336             if (request->processed)
00337                 continue;
00338     
00339             table_info = netsnmp_extract_table_info(request);
00340             if (!table_info)
00341                 continue;           /* ack */
00342             row = netsnmp_container_table_row_extract( request );
00343 
00344             netsnmp_request_add_list_data(request,
00345                                       netsnmp_create_data_list(
00346                                           TABLE_TDATA_TABLE, table, NULL));
00347             netsnmp_request_add_list_data(request,
00348                                       netsnmp_create_data_list(
00349                                           TABLE_TDATA_ROW,   row,   NULL));
00350         }
00351     }
00352 
00353     /* next handler called automatically - 'AUTO_NEXT' */
00354     return SNMP_ERR_NOERROR;
00355 }
00356 
00357 
00359 int
00360 netsnmp_tdata_register(netsnmp_handler_registration    *reginfo,
00361                        netsnmp_tdata                   *table,
00362                        netsnmp_table_registration_info *table_info)
00363 {
00364     netsnmp_inject_handler(reginfo, netsnmp_get_tdata_handler(table));
00365     return netsnmp_container_table_register(reginfo, table_info,
00366                   table->container, TABLE_CONTAINER_KEY_NETSNMP_INDEX);
00367 }
00368 
00370 netsnmp_tdata *
00371 netsnmp_tdata_extract_table(netsnmp_request_info *request)
00372 {
00373     return (netsnmp_tdata *) netsnmp_request_get_list_data(request,
00374                                                            TABLE_TDATA_TABLE);
00375 }
00376 
00378 netsnmp_container *
00379 netsnmp_tdata_extract_container(netsnmp_request_info *request)
00380 {
00381     netsnmp_tdata *tdata = netsnmp_request_get_list_data(request,
00382                                                          TABLE_TDATA_TABLE);
00383     return ( tdata ? tdata->container : NULL );
00384 }
00385 
00387 netsnmp_tdata_row *
00388 netsnmp_tdata_extract_row(netsnmp_request_info *request)
00389 {
00390     return (netsnmp_tdata_row *) netsnmp_container_table_row_extract(request);
00391 }
00392 
00395 void           *
00396 netsnmp_tdata_extract_entry(netsnmp_request_info *request)
00397 {
00398     netsnmp_tdata_row *row =
00399         (netsnmp_tdata_row *) netsnmp_tdata_extract_row(request);
00400     if (row)
00401         return row->data;
00402     else
00403         return NULL;
00404 }
00405 
00407 NETSNMP_INLINE void
00408 netsnmp_insert_tdata_row(netsnmp_request_info *request,
00409                          netsnmp_tdata_row *row)
00410 {
00411     netsnmp_container_table_row_insert(request, (netsnmp_index *)row);
00412 }
00413 
00414 
00415 /* ==================================
00416  *
00417  * Generic API: Row operations
00418  *
00419  * ================================== */
00420 
00422 void *
00423 netsnmp_tdata_row_entry( netsnmp_tdata_row *row )
00424 {
00425     if (row)
00426         return row->data;
00427     else
00428         return NULL;
00429 }
00430 
00432 netsnmp_tdata_row *
00433 netsnmp_tdata_row_first(netsnmp_tdata *table)
00434 {
00435     return (netsnmp_tdata_row *)CONTAINER_FIRST( table->container );
00436 }
00437 
00439 netsnmp_tdata_row *
00440 netsnmp_tdata_row_get(  netsnmp_tdata     *table,
00441                         netsnmp_tdata_row *row)
00442 {
00443     return CONTAINER_FIND( table->container, row );
00444 }
00445 
00447 netsnmp_tdata_row *
00448 netsnmp_tdata_row_next( netsnmp_tdata      *table,
00449                         netsnmp_tdata_row  *row)
00450 {
00451     return (netsnmp_tdata_row *)CONTAINER_NEXT( table->container, row  );
00452 }
00453 
00455 netsnmp_tdata_row *
00456 netsnmp_tdata_row_get_byidx(netsnmp_tdata         *table,
00457                             netsnmp_variable_list *indexes)
00458 {
00459     oid             searchfor[      MAX_OID_LEN];
00460     size_t          searchfor_len = MAX_OID_LEN;
00461 
00462     build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
00463                       indexes);
00464     return netsnmp_tdata_row_get_byoid(table, searchfor, searchfor_len);
00465 }
00466 
00468 netsnmp_tdata_row *
00469 netsnmp_tdata_row_get_byoid(netsnmp_tdata *table,
00470                             oid * searchfor, size_t searchfor_len)
00471 {
00472     netsnmp_index index;
00473     if (!table)
00474         return NULL;
00475 
00476     index.oids = searchfor;
00477     index.len  = searchfor_len;
00478     return CONTAINER_FIND( table->container, &index );
00479 }
00480 
00483 netsnmp_tdata_row *
00484 netsnmp_tdata_row_next_byidx(netsnmp_tdata         *table,
00485                              netsnmp_variable_list *indexes)
00486 {
00487     oid             searchfor[      MAX_OID_LEN];
00488     size_t          searchfor_len = MAX_OID_LEN;
00489 
00490     build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
00491                       indexes);
00492     return netsnmp_tdata_row_next_byoid(table, searchfor, searchfor_len);
00493 }
00494 
00497 netsnmp_tdata_row *
00498 netsnmp_tdata_row_next_byoid(netsnmp_tdata *table,
00499                              oid * searchfor, size_t searchfor_len)
00500 {
00501     netsnmp_index index;
00502     if (!table)
00503         return NULL;
00504 
00505     index.oids = searchfor;
00506     index.len  = searchfor_len;
00507     return CONTAINER_NEXT( table->container, &index );
00508 }
00509 
00510 int
00511 netsnmp_tdata_row_count(netsnmp_tdata *table)
00512 {
00513     if (!table)
00514         return 0;
00515     return CONTAINER_SIZE( table->container );
00516 }
00517 
00518 /* ==================================
00519  *
00520  * Generic API: Index operations on a 'tdata' table
00521  *
00522  * ================================== */
00523 
00524 
00526 int
00527 netsnmp_tdata_compare_idx(netsnmp_tdata_row     *row,
00528                           netsnmp_variable_list *indexes)
00529 {
00530     oid             searchfor[      MAX_OID_LEN];
00531     size_t          searchfor_len = MAX_OID_LEN;
00532 
00533     build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
00534                       indexes);
00535     return netsnmp_tdata_compare_oid(row, searchfor, searchfor_len);
00536 }
00537 
00539 int
00540 netsnmp_tdata_compare_oid(netsnmp_tdata_row     *row,
00541                           oid * compareto, size_t compareto_len)
00542 {
00543     netsnmp_index *index = (netsnmp_index *)row;
00544     return snmp_oid_compare( index->oids, index->len,
00545                              compareto,   compareto_len);
00546 }
00547 
00548 int
00549 netsnmp_tdata_compare_subtree_idx(netsnmp_tdata_row     *row,
00550                                   netsnmp_variable_list *indexes)
00551 {
00552     oid             searchfor[      MAX_OID_LEN];
00553     size_t          searchfor_len = MAX_OID_LEN;
00554 
00555     build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
00556                       indexes);
00557     return netsnmp_tdata_compare_subtree_oid(row, searchfor, searchfor_len);
00558 }
00559 
00560 int
00561 netsnmp_tdata_compare_subtree_oid(netsnmp_tdata_row     *row,
00562                                   oid * compareto, size_t compareto_len)
00563 {
00564     netsnmp_index *index = (netsnmp_index *)row;
00565     return snmp_oidtree_compare( index->oids, index->len,
00566                                  compareto,   compareto_len);
00567 }
00568