net-snmp 5.7
table_tdata.c
00001 #include <net-snmp/net-snmp-config.h>
00002 #include <net-snmp/net-snmp-features.h>
00003 
00004 #include <net-snmp/net-snmp-includes.h>
00005 #include <net-snmp/agent/net-snmp-agent-includes.h>
00006 
00007 #include <net-snmp/agent/table_tdata.h>
00008 
00009 #if HAVE_STRING_H
00010 #include <string.h>
00011 #else
00012 #include <strings.h>
00013 #endif
00014 
00015 #include <net-snmp/agent/table.h>
00016 #include <net-snmp/agent/table_container.h>
00017 #include <net-snmp/agent/read_only.h>
00018 
00019 #if HAVE_DMALLOC_H
00020 #include <dmalloc.h>
00021 #endif
00022 
00023 netsnmp_feature_provide(table_tdata)
00024 netsnmp_feature_child_of(table_tdata_all, mib_helpers)
00025 netsnmp_feature_child_of(table_tdata, table_tdata_all)
00026 netsnmp_feature_child_of(table_tdata_delete_table, table_tdata_all)
00027 netsnmp_feature_child_of(table_tdata_extract_table, table_tdata_all)
00028 netsnmp_feature_child_of(table_tdata_remove_row, table_tdata_all)
00029 netsnmp_feature_child_of(table_tdata_insert_row, table_tdata_all)
00030 
00031 #ifdef NETSNMP_FEATURE_REQUIRE_TABLE_TDATA
00032 netsnmp_feature_require(table_container_row_insert)
00033 #ifdef NETSNMP_FEATURE_REQUIRE_TABLE_TDATA_REMOVE_ROW
00034 netsnmp_feature_require(table_container_row_remove)
00035 #endif /* NETSNMP_FEATURE_REQUIRE_TABLE_TDATA_REMOVE_ROW */
00036 #endif /* NETSNMP_FEATURE_REQUIRE_TABLE_TDATA */
00037 
00038 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA
00039 
00056 /* ==================================
00057  *
00058  * TData API: Table maintenance
00059  *
00060  * ================================== */
00061 
00062 /*
00063  * generates the index portion of an table oid from a varlist.
00064  */
00065 void
00066 _netsnmp_tdata_generate_index_oid(netsnmp_tdata_row *row)
00067 {
00068     build_oid(&row->oid_index.oids, &row->oid_index.len, NULL, 0, row->indexes);
00069 }
00070 
00072 netsnmp_tdata *
00073 netsnmp_tdata_create_table(const char *name, long flags)
00074 {
00075     netsnmp_tdata *table = SNMP_MALLOC_TYPEDEF(netsnmp_tdata);
00076     if ( !table )
00077         return NULL;
00078 
00079     table->flags = flags;
00080     if (name)
00081         table->name = strdup(name);
00082 
00083     if (!(table->flags & TDATA_FLAG_NO_CONTAINER)) {
00084         table->container = netsnmp_container_find( name );
00085         if (!table->container)
00086             table->container = netsnmp_container_find( "table_container" );
00087         if (table->container)
00088             table->container->container_name = strdup(name);
00089     }
00090     return table;
00091 }
00092 
00093 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_DELETE_TABLE
00094 
00095 void
00096 netsnmp_tdata_delete_table(netsnmp_tdata *table)
00097 {
00098     if (!table)
00099        return;
00100 
00101     if (table->name)
00102        free(table->name);
00103     if (table->container)
00104        CONTAINER_FREE(table->container);
00105     
00106     SNMP_FREE(table);
00107     return;
00108 }
00109 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_DELETE_TABLE */
00110 
00112 netsnmp_tdata_row *
00113 netsnmp_tdata_create_row(void)
00114 {
00115     netsnmp_tdata_row *row = SNMP_MALLOC_TYPEDEF(netsnmp_tdata_row);
00116     return row;
00117 }
00118 
00120 netsnmp_feature_child_of(tdata_clone_row, table_tdata_all)
00121 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_CLONE_ROW
00122 netsnmp_tdata_row *
00123 netsnmp_tdata_clone_row(netsnmp_tdata_row *row)
00124 {
00125     netsnmp_tdata_row *newrow = NULL;
00126     if (!row)
00127         return NULL;
00128 
00129     memdup((u_char **) & newrow, (u_char *) row,
00130            sizeof(netsnmp_tdata_row));
00131     if (!newrow)
00132         return NULL;
00133 
00134     if (row->indexes) {
00135         newrow->indexes = snmp_clone_varbind(newrow->indexes);
00136         if (!newrow->indexes) {
00137             SNMP_FREE(newrow);
00138             return NULL;
00139         }
00140     }
00141 
00142     if (row->oid_index.oids) {
00143         newrow->oid_index.oids =
00144             snmp_duplicate_objid(row->oid_index.oids, row->oid_index.len);
00145         if (!newrow->oid_index.oids) {
00146             if (newrow->indexes)
00147                 snmp_free_varbind(newrow->indexes);
00148             SNMP_FREE(newrow);
00149             return NULL;
00150         }
00151     }
00152 
00153     return newrow;
00154 }
00155 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_CLONE_ROW */
00156 
00159 netsnmp_feature_child_of(tdata_copy_row, table_tdata_all)
00160 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_COPY_ROW
00161 int
00162 netsnmp_tdata_copy_row(netsnmp_tdata_row *dst_row, netsnmp_tdata_row *src_row)
00163 {
00164      if ( !src_row || !dst_row )
00165          return -1;
00166 
00167     memcpy((u_char *) dst_row, (u_char *) src_row,
00168            sizeof(netsnmp_tdata_row));
00169     if (src_row->indexes) {
00170         dst_row->indexes = snmp_clone_varbind(src_row->indexes);
00171         if (!dst_row->indexes)
00172             return -1;
00173     }
00174 
00175     if (src_row->oid_index.oids) {
00176         dst_row->oid_index.oids = snmp_duplicate_objid(src_row->oid_index.oids,
00177                                                        src_row->oid_index.len);
00178         if (!dst_row->oid_index.oids)
00179             return -1;
00180     }
00181 
00182     return 0;
00183 }
00184 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_COPY_ROW */
00185 
00189 void           *
00190 netsnmp_tdata_delete_row(netsnmp_tdata_row *row)
00191 {
00192     void           *data;
00193 
00194     if (!row)
00195         return NULL;
00196 
00197     /*
00198      * free the memory we can 
00199      */
00200     if (row->indexes)
00201         snmp_free_varbind(row->indexes);
00202     SNMP_FREE(row->oid_index.oids);
00203     data = row->data;
00204     free(row);
00205 
00206     /*
00207      * return the void * pointer 
00208      */
00209     return data;
00210 }
00211 
00218 int
00219 netsnmp_tdata_add_row(netsnmp_tdata     *table,
00220                       netsnmp_tdata_row *row)
00221 {
00222     if (!row || !table)
00223         return SNMPERR_GENERR;
00224 
00225     if (row->indexes)
00226         _netsnmp_tdata_generate_index_oid(row);
00227 
00228     if (!row->oid_index.oids) {
00229         snmp_log(LOG_ERR,
00230                  "illegal data attempted to be added to table %s (no index)\n",
00231                  table->name);
00232         return SNMPERR_GENERR;
00233     }
00234 
00235     /*
00236      * The individual index values probably won't be needed,
00237      *    so this memory can be released.
00238      * Note that this is purely internal to the helper.
00239      * The calling application can set this flag as
00240      *    a hint to the helper that these values aren't
00241      *    required, but it's up to the helper as to
00242      *    whether it takes any notice or not!
00243      */
00244     if (table->flags & TDATA_FLAG_NO_STORE_INDEXES) {
00245         snmp_free_varbind(row->indexes);
00246         row->indexes = NULL;
00247     }
00248 
00249     /*
00250      * add this row to the stored table
00251      */
00252     if (CONTAINER_INSERT( table->container, row ) != 0)
00253         return SNMPERR_GENERR;
00254 
00255     DEBUGMSGTL(("tdata_add_row", "added row (%p)\n", row));
00256 
00257     return SNMPERR_SUCCESS;
00258 }
00259 
00261 netsnmp_feature_child_of(tdata_replace_row, table_tdata_all)
00262 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_REPLACE_ROW
00263 void
00264 netsnmp_tdata_replace_row(netsnmp_tdata *table,
00265                                netsnmp_tdata_row *origrow,
00266                                netsnmp_tdata_row *newrow)
00267 {
00268     netsnmp_tdata_remove_row(table, origrow);
00269     netsnmp_tdata_add_row(table, newrow);
00270 }
00271 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_REPLACE_ROW */
00272 
00279 netsnmp_tdata_row *
00280 netsnmp_tdata_remove_row(netsnmp_tdata *table,
00281                               netsnmp_tdata_row *row)
00282 {
00283     if (!row || !table)
00284         return NULL;
00285 
00286     CONTAINER_REMOVE( table->container, row );
00287     return row;
00288 }
00289 
00297 void           *
00298 netsnmp_tdata_remove_and_delete_row(netsnmp_tdata     *table,
00299                                     netsnmp_tdata_row *row)
00300 {
00301     if (!row || !table)
00302         return NULL;
00303 
00304     /*
00305      * remove it from the list 
00306      */
00307     netsnmp_tdata_remove_row(table, row);
00308     return netsnmp_tdata_delete_row(row);
00309 }
00310 
00311 
00312 /* ==================================
00313  *
00314  * TData API: MIB maintenance
00315  *
00316  * ================================== */
00317 
00318 Netsnmp_Node_Handler _netsnmp_tdata_helper_handler;
00319 
00321 netsnmp_mib_handler *
00322 netsnmp_get_tdata_handler(netsnmp_tdata *table)
00323 {
00324     netsnmp_mib_handler *ret = NULL;
00325 
00326     if (!table) {
00327         snmp_log(LOG_INFO,
00328                  "netsnmp_get_tdata_handler(NULL) called\n");
00329         return NULL;
00330     }
00331 
00332     ret = netsnmp_create_handler(TABLE_TDATA_NAME,
00333                                _netsnmp_tdata_helper_handler);
00334     if (ret) {
00335         ret->flags |= MIB_HANDLER_AUTO_NEXT;
00336         ret->myvoid = (void *) table;
00337     }
00338     return ret;
00339 }
00340 
00341 /*
00342  * The helper handler that takes care of passing a specific row of
00343  * data down to the lower handler(s).  The table_container helper
00344  * has already taken care of identifying the appropriate row of the
00345  * table (and converting GETNEXT requests into an equivalent GET request)
00346  * So all we need to do here is make sure that the row is accessible
00347  * using tdata-style retrieval techniques as well.
00348  */
00349 int
00350 _netsnmp_tdata_helper_handler(netsnmp_mib_handler *handler,
00351                                   netsnmp_handler_registration *reginfo,
00352                                   netsnmp_agent_request_info *reqinfo,
00353                                   netsnmp_request_info *requests)
00354 {
00355     netsnmp_tdata *table = (netsnmp_tdata *) handler->myvoid;
00356     netsnmp_request_info       *request;
00357     netsnmp_table_request_info *table_info;
00358     netsnmp_tdata_row          *row;
00359     int                         need_processing = 1;
00360 
00361     switch ( reqinfo->mode ) {
00362     case MODE_GET:
00363         need_processing = 0; /* only need processing if some vars found */
00366 #ifndef NETSNMP_NO_WRITE_SUPPORT
00367     case MODE_SET_RESERVE1:
00368 #endif /* NETSNMP_NO_WRITE_SUPPORT */
00369 
00370         for (request = requests; request; request = request->next) {
00371             if (request->processed)
00372                 continue;
00373     
00374             table_info = netsnmp_extract_table_info(request);
00375             if (!table_info) {
00376                 netsnmp_assert(table_info); /* yes, this will always hit */
00377                 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
00378                 continue;           /* eek */
00379             }
00380             row = (netsnmp_tdata_row*)netsnmp_container_table_row_extract( request );
00381             if (!row && (reqinfo->mode == MODE_GET)) {
00382                 netsnmp_assert(row); /* yes, this will always hit */
00383                 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
00384                 continue;           /* eek */
00385             }
00386             ++need_processing;
00387             netsnmp_request_add_list_data(request,
00388                                       netsnmp_create_data_list(
00389                                           TABLE_TDATA_TABLE, table, NULL));
00390             netsnmp_request_add_list_data(request,
00391                                       netsnmp_create_data_list(
00392                                           TABLE_TDATA_ROW,   row,   NULL));
00393         }
00395         if (!need_processing)
00396             handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
00397     }
00398 
00399     /* next handler called automatically - 'AUTO_NEXT' */
00400     return SNMP_ERR_NOERROR;
00401 }
00402 
00403 
00405 int
00406 netsnmp_tdata_register(netsnmp_handler_registration    *reginfo,
00407                        netsnmp_tdata                   *table,
00408                        netsnmp_table_registration_info *table_info)
00409 {
00410     netsnmp_inject_handler(reginfo, netsnmp_get_tdata_handler(table));
00411     return netsnmp_container_table_register(reginfo, table_info,
00412                   table->container, TABLE_CONTAINER_KEY_NETSNMP_INDEX);
00413 }
00414 
00415 netsnmp_feature_child_of(tdata_unregister, table_tdata_all)
00416 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_UNREGISTER
00417 int
00418 netsnmp_tdata_unregister(netsnmp_handler_registration    *reginfo)
00419 {
00420     /* free table; */
00421     return netsnmp_container_table_unregister(reginfo);
00422 }
00423 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_UNREGISTER */
00424 
00425 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_EXTRACT_TABLE
00426 
00427 netsnmp_tdata *
00428 netsnmp_tdata_extract_table(netsnmp_request_info *request)
00429 {
00430     return (netsnmp_tdata *) netsnmp_request_get_list_data(request,
00431                                                            TABLE_TDATA_TABLE);
00432 }
00433 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_EXTRACT_TABLE */
00434 
00436 netsnmp_feature_child_of(tdata_extract_container, table_tdata_all)
00437 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_EXTRACT_CONTAINER
00438 netsnmp_container *
00439 netsnmp_tdata_extract_container(netsnmp_request_info *request)
00440 {
00441     netsnmp_tdata *tdata = (netsnmp_tdata*)
00442         netsnmp_request_get_list_data(request, TABLE_TDATA_TABLE);
00443     return ( tdata ? tdata->container : NULL );
00444 }
00445 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_EXTRACT_CONTAINER */
00446 
00448 netsnmp_tdata_row *
00449 netsnmp_tdata_extract_row(netsnmp_request_info *request)
00450 {
00451     return (netsnmp_tdata_row *) netsnmp_container_table_row_extract(request);
00452 }
00453 
00456 void           *
00457 netsnmp_tdata_extract_entry(netsnmp_request_info *request)
00458 {
00459     netsnmp_tdata_row *row =
00460         (netsnmp_tdata_row *) netsnmp_tdata_extract_row(request);
00461     if (row)
00462         return row->data;
00463     else
00464         return NULL;
00465 }
00466 
00467 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_INSERT_ROW
00468 
00469 NETSNMP_INLINE void
00470 netsnmp_insert_tdata_row(netsnmp_request_info *request,
00471                          netsnmp_tdata_row *row)
00472 {
00473     netsnmp_container_table_row_insert(request, (netsnmp_index *)row);
00474 }
00475 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_INSERT_ROW */
00476 
00477 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_REMOVE_ROW
00478 
00479 NETSNMP_INLINE void
00480 netsnmp_remove_tdata_row(netsnmp_request_info *request,
00481                          netsnmp_tdata_row *row)
00482 {
00483     netsnmp_container_table_row_remove(request, (netsnmp_index *)row);
00484 }
00485 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_REMOVE_ROW */
00486 
00487 
00488 /* ==================================
00489  *
00490  * Generic API: Row operations
00491  *
00492  * ================================== */
00493 
00495 void *
00496 netsnmp_tdata_row_entry( netsnmp_tdata_row *row )
00497 {
00498     if (row)
00499         return row->data;
00500     else
00501         return NULL;
00502 }
00503 
00505 netsnmp_tdata_row *
00506 netsnmp_tdata_row_first(netsnmp_tdata *table)
00507 {
00508     return (netsnmp_tdata_row *)CONTAINER_FIRST( table->container );
00509 }
00510 
00512 netsnmp_tdata_row *
00513 netsnmp_tdata_row_get(  netsnmp_tdata     *table,
00514                         netsnmp_tdata_row *row)
00515 {
00516     return (netsnmp_tdata_row*)CONTAINER_FIND( table->container, row );
00517 }
00518 
00520 netsnmp_tdata_row *
00521 netsnmp_tdata_row_next( netsnmp_tdata      *table,
00522                         netsnmp_tdata_row  *row)
00523 {
00524     return (netsnmp_tdata_row *)CONTAINER_NEXT( table->container, row  );
00525 }
00526 
00528 netsnmp_tdata_row *
00529 netsnmp_tdata_row_get_byidx(netsnmp_tdata         *table,
00530                             netsnmp_variable_list *indexes)
00531 {
00532     oid             searchfor[      MAX_OID_LEN];
00533     size_t          searchfor_len = MAX_OID_LEN;
00534 
00535     build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
00536                       indexes);
00537     return netsnmp_tdata_row_get_byoid(table, searchfor, searchfor_len);
00538 }
00539 
00541 netsnmp_tdata_row *
00542 netsnmp_tdata_row_get_byoid(netsnmp_tdata *table,
00543                             oid * searchfor, size_t searchfor_len)
00544 {
00545     netsnmp_index index;
00546     if (!table)
00547         return NULL;
00548 
00549     index.oids = searchfor;
00550     index.len  = searchfor_len;
00551     return (netsnmp_tdata_row*)CONTAINER_FIND( table->container, &index );
00552 }
00553 
00556 netsnmp_tdata_row *
00557 netsnmp_tdata_row_next_byidx(netsnmp_tdata         *table,
00558                              netsnmp_variable_list *indexes)
00559 {
00560     oid             searchfor[      MAX_OID_LEN];
00561     size_t          searchfor_len = MAX_OID_LEN;
00562 
00563     build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
00564                       indexes);
00565     return netsnmp_tdata_row_next_byoid(table, searchfor, searchfor_len);
00566 }
00567 
00570 netsnmp_tdata_row *
00571 netsnmp_tdata_row_next_byoid(netsnmp_tdata *table,
00572                              oid * searchfor, size_t searchfor_len)
00573 {
00574     netsnmp_index index;
00575     if (!table)
00576         return NULL;
00577 
00578     index.oids = searchfor;
00579     index.len  = searchfor_len;
00580     return (netsnmp_tdata_row*)CONTAINER_NEXT( table->container, &index );
00581 }
00582 
00583 netsnmp_feature_child_of(tdata_row_count, table_tdata_all)
00584 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_ROW_COUNT
00585 int
00586 netsnmp_tdata_row_count(netsnmp_tdata *table)
00587 {
00588     if (!table)
00589         return 0;
00590     return CONTAINER_SIZE( table->container );
00591 }
00592 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_ROW_COUNT */
00593 
00594 /* ==================================
00595  *
00596  * Generic API: Index operations on a 'tdata' table
00597  *
00598  * ================================== */
00599 
00600 
00602 netsnmp_feature_child_of(tdata_compare_idx, table_tdata_all)
00603 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_COMPARE_IDX
00604 int
00605 netsnmp_tdata_compare_idx(netsnmp_tdata_row     *row,
00606                           netsnmp_variable_list *indexes)
00607 {
00608     oid             searchfor[      MAX_OID_LEN];
00609     size_t          searchfor_len = MAX_OID_LEN;
00610 
00611     build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
00612                       indexes);
00613     return netsnmp_tdata_compare_oid(row, searchfor, searchfor_len);
00614 }
00615 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_COMPARE_IDX */
00616 
00618 int
00619 netsnmp_tdata_compare_oid(netsnmp_tdata_row     *row,
00620                           oid * compareto, size_t compareto_len)
00621 {
00622     netsnmp_index *index = (netsnmp_index *)row;
00623     return snmp_oid_compare( index->oids, index->len,
00624                              compareto,   compareto_len);
00625 }
00626 
00627 int
00628 netsnmp_tdata_compare_subtree_idx(netsnmp_tdata_row     *row,
00629                                   netsnmp_variable_list *indexes)
00630 {
00631     oid             searchfor[      MAX_OID_LEN];
00632     size_t          searchfor_len = MAX_OID_LEN;
00633 
00634     build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
00635                       indexes);
00636     return netsnmp_tdata_compare_subtree_oid(row, searchfor, searchfor_len);
00637 }
00638 
00639 int
00640 netsnmp_tdata_compare_subtree_oid(netsnmp_tdata_row     *row,
00641                                   oid * compareto, size_t compareto_len)
00642 {
00643     netsnmp_index *index = (netsnmp_index *)row;
00644     return snmp_oidtree_compare( index->oids, index->len,
00645                                  compareto,   compareto_len);
00646 }
00647 #else /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA */
00648 netsnmp_feature_unused(table_tdata);
00649 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA */
00650 
00651