670 lines
20 KiB
C
670 lines
20 KiB
C
/*
|
|
* Portions of this file are subject to the following copyright(s). See
|
|
* the Net-SNMP's COPYING file for more details and other copyrights
|
|
* that may apply:
|
|
*
|
|
* Portions of this file are copyrighted by:
|
|
* Copyright (c) 2016 VMware, Inc. All rights reserved.
|
|
* Use is subject to license terms specified in the COPYING file
|
|
* distributed with the Net-SNMP package.
|
|
*/
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
#include <net-snmp/net-snmp-features.h>
|
|
|
|
#include <net-snmp/net-snmp-includes.h>
|
|
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
|
|
|
#include <net-snmp/agent/table_tdata.h>
|
|
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
|
|
#include <net-snmp/agent/table.h>
|
|
#include <net-snmp/agent/table_container.h>
|
|
#include <net-snmp/agent/read_only.h>
|
|
|
|
#if HAVE_DMALLOC_H
|
|
#include <dmalloc.h>
|
|
#endif
|
|
|
|
netsnmp_feature_child_of(table_tdata_all, mib_helpers)
|
|
netsnmp_feature_child_of(table_tdata, table_tdata_all)
|
|
netsnmp_feature_child_of(table_tdata_delete_table, table_tdata_all)
|
|
netsnmp_feature_child_of(table_tdata_extract_table, table_tdata_all)
|
|
netsnmp_feature_child_of(table_tdata_remove_row, table_tdata_all)
|
|
netsnmp_feature_child_of(table_tdata_insert_row, table_tdata_all)
|
|
|
|
#ifdef NETSNMP_FEATURE_REQUIRE_TABLE_TDATA
|
|
netsnmp_feature_require(table_container_row_insert)
|
|
#ifdef NETSNMP_FEATURE_REQUIRE_TABLE_TDATA_REMOVE_ROW
|
|
netsnmp_feature_require(table_container_row_remove)
|
|
#endif /* NETSNMP_FEATURE_REQUIRE_TABLE_TDATA_REMOVE_ROW */
|
|
#endif /* NETSNMP_FEATURE_REQUIRE_TABLE_TDATA */
|
|
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA
|
|
|
|
/** @defgroup tdata tdata
|
|
* Implement a table with datamatted storage.
|
|
* @ingroup table
|
|
*
|
|
* This helper helps you implement a table where all the rows are
|
|
* expected to be stored within the agent itself and not in some
|
|
* external storage location. It can be used to store a list of
|
|
* rows, where a row consists of the indexes to the table and a
|
|
* generic data pointer. You can then implement a subhandler which
|
|
* is passed the exact row definition and data it must return data
|
|
* for or accept data for. Complex GETNEXT handling is greatly
|
|
* simplified in this case.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/* ==================================
|
|
*
|
|
* TData API: Table maintenance
|
|
*
|
|
* ================================== */
|
|
|
|
/*
|
|
* generates the index portion of an table oid from a varlist.
|
|
*/
|
|
void
|
|
_netsnmp_tdata_generate_index_oid(netsnmp_tdata_row *row)
|
|
{
|
|
build_oid(&row->oid_index.oids, &row->oid_index.len, NULL, 0, row->indexes);
|
|
}
|
|
|
|
/** creates and returns a 'tdata' table data structure */
|
|
netsnmp_tdata *
|
|
netsnmp_tdata_create_table(const char *name, long flags)
|
|
{
|
|
netsnmp_tdata *table = SNMP_MALLOC_TYPEDEF(netsnmp_tdata);
|
|
if ( !table )
|
|
return NULL;
|
|
|
|
table->flags = flags;
|
|
if (name)
|
|
table->name = strdup(name);
|
|
|
|
if (!(table->flags & TDATA_FLAG_NO_CONTAINER)) {
|
|
table->container = netsnmp_container_find( name );
|
|
if (!table->container)
|
|
table->container = netsnmp_container_find( "table_container" );
|
|
if (table->container && name)
|
|
table->container->container_name = strdup(name);
|
|
}
|
|
return table;
|
|
}
|
|
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_DELETE_TABLE
|
|
/** creates and returns a 'tdata' table data structure */
|
|
void
|
|
netsnmp_tdata_delete_table(netsnmp_tdata *table)
|
|
{
|
|
if (!table)
|
|
return;
|
|
|
|
if (table->name)
|
|
free(table->name);
|
|
if (table->container)
|
|
CONTAINER_FREE(table->container);
|
|
|
|
SNMP_FREE(table);
|
|
return;
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_DELETE_TABLE */
|
|
|
|
/** creates and returns a pointer to new row data structure */
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_create_row(void)
|
|
{
|
|
netsnmp_tdata_row *row = SNMP_MALLOC_TYPEDEF(netsnmp_tdata_row);
|
|
return row;
|
|
}
|
|
|
|
/** clones a 'tdata' row. DOES NOT CLONE THE TABLE-SPECIFIC ENTRY DATA. */
|
|
netsnmp_feature_child_of(tdata_clone_row, table_tdata_all)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TDATA_CLONE_ROW
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_clone_row(netsnmp_tdata_row *row)
|
|
{
|
|
netsnmp_tdata_row *newrow = NULL;
|
|
if (!row)
|
|
return NULL;
|
|
|
|
newrow = netsnmp_memdup(row, sizeof(netsnmp_tdata_row));
|
|
if (!newrow)
|
|
return NULL;
|
|
|
|
if (row->indexes) {
|
|
newrow->indexes = snmp_clone_varbind(newrow->indexes);
|
|
if (!newrow->indexes) {
|
|
SNMP_FREE(newrow);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (row->oid_index.oids) {
|
|
newrow->oid_index.oids =
|
|
snmp_duplicate_objid(row->oid_index.oids, row->oid_index.len);
|
|
if (!newrow->oid_index.oids) {
|
|
if (newrow->indexes)
|
|
snmp_free_varbind(newrow->indexes);
|
|
SNMP_FREE(newrow);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return newrow;
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TDATA_CLONE_ROW */
|
|
|
|
/** copy the contents of a 'tdata' row.
|
|
DOES NOT COPY THE TABLE-SPECIFIC ENTRY DATA. */
|
|
netsnmp_feature_child_of(tdata_copy_row, table_tdata_all)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TDATA_COPY_ROW
|
|
int
|
|
netsnmp_tdata_copy_row(netsnmp_tdata_row *dst_row, netsnmp_tdata_row *src_row)
|
|
{
|
|
if ( !src_row || !dst_row )
|
|
return -1;
|
|
|
|
memcpy((u_char *) dst_row, (u_char *) src_row,
|
|
sizeof(netsnmp_tdata_row));
|
|
if (src_row->indexes) {
|
|
dst_row->indexes = snmp_clone_varbind(src_row->indexes);
|
|
if (!dst_row->indexes)
|
|
return -1;
|
|
}
|
|
|
|
if (src_row->oid_index.oids) {
|
|
dst_row->oid_index.oids = snmp_duplicate_objid(src_row->oid_index.oids,
|
|
src_row->oid_index.len);
|
|
if (!dst_row->oid_index.oids)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TDATA_COPY_ROW */
|
|
|
|
/** deletes the memory used by the specified row
|
|
* returns the table-specific entry data
|
|
* (that it doesn't know how to delete) */
|
|
void *
|
|
netsnmp_tdata_delete_row(netsnmp_tdata_row *row)
|
|
{
|
|
void *data;
|
|
|
|
if (!row)
|
|
return NULL;
|
|
|
|
/*
|
|
* free the memory we can
|
|
*/
|
|
if (row->indexes)
|
|
snmp_free_varbind(row->indexes);
|
|
SNMP_FREE(row->oid_index.oids);
|
|
data = row->data;
|
|
free(row);
|
|
|
|
/*
|
|
* return the void * pointer
|
|
*/
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Adds a row to the given table (stored in proper lexographical order).
|
|
*
|
|
* returns SNMPERR_SUCCESS on successful addition.
|
|
* or SNMPERR_GENERR on failure (E.G., indexes already existed)
|
|
*/
|
|
int
|
|
netsnmp_tdata_add_row(netsnmp_tdata *table,
|
|
netsnmp_tdata_row *row)
|
|
{
|
|
if (!row || !table)
|
|
return SNMPERR_GENERR;
|
|
|
|
if (row->indexes)
|
|
_netsnmp_tdata_generate_index_oid(row);
|
|
|
|
if (!row->oid_index.oids) {
|
|
snmp_log(LOG_ERR,
|
|
"illegal data attempted to be added to table %s (no index)\n",
|
|
table->name);
|
|
return SNMPERR_GENERR;
|
|
}
|
|
|
|
/*
|
|
* The individual index values probably won't be needed,
|
|
* so this memory can be released.
|
|
* Note that this is purely internal to the helper.
|
|
* The calling application can set this flag as
|
|
* a hint to the helper that these values aren't
|
|
* required, but it's up to the helper as to
|
|
* whether it takes any notice or not!
|
|
*/
|
|
if (table->flags & TDATA_FLAG_NO_STORE_INDEXES) {
|
|
snmp_free_varbind(row->indexes);
|
|
row->indexes = NULL;
|
|
}
|
|
|
|
/*
|
|
* add this row to the stored table
|
|
*/
|
|
if (CONTAINER_INSERT( table->container, row ) != 0)
|
|
return SNMPERR_GENERR;
|
|
|
|
DEBUGMSGTL(("tdata_add_row", "added row (%p)\n", row));
|
|
|
|
return SNMPERR_SUCCESS;
|
|
}
|
|
|
|
/** swaps out origrow with newrow. This does *not* delete/free anything! */
|
|
netsnmp_feature_child_of(tdata_replace_row, table_tdata_all)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TDATA_REPLACE_ROW
|
|
void
|
|
netsnmp_tdata_replace_row(netsnmp_tdata *table,
|
|
netsnmp_tdata_row *origrow,
|
|
netsnmp_tdata_row *newrow)
|
|
{
|
|
netsnmp_tdata_remove_row(table, origrow);
|
|
netsnmp_tdata_add_row(table, newrow);
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TDATA_REPLACE_ROW */
|
|
|
|
/**
|
|
* removes a row from the given table and returns it (no free's called)
|
|
*
|
|
* returns the row pointer itself on successful removing.
|
|
* or NULL on failure (bad arguments)
|
|
*/
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_remove_row(netsnmp_tdata *table,
|
|
netsnmp_tdata_row *row)
|
|
{
|
|
if (!row || !table)
|
|
return NULL;
|
|
|
|
CONTAINER_REMOVE( table->container, row );
|
|
return row;
|
|
}
|
|
|
|
/**
|
|
* removes and frees a row of the given table and
|
|
* returns the table-specific entry data
|
|
*
|
|
* returns the void * pointer on successful deletion.
|
|
* or NULL on failure (bad arguments)
|
|
*/
|
|
void *
|
|
netsnmp_tdata_remove_and_delete_row(netsnmp_tdata *table,
|
|
netsnmp_tdata_row *row)
|
|
{
|
|
if (!row || !table)
|
|
return NULL;
|
|
|
|
/*
|
|
* remove it from the list
|
|
*/
|
|
netsnmp_tdata_remove_row(table, row);
|
|
return netsnmp_tdata_delete_row(row);
|
|
}
|
|
|
|
|
|
/* ==================================
|
|
*
|
|
* TData API: MIB maintenance
|
|
*
|
|
* ================================== */
|
|
|
|
Netsnmp_Node_Handler _netsnmp_tdata_helper_handler;
|
|
|
|
/** Creates a tdata handler and returns it */
|
|
netsnmp_mib_handler *
|
|
netsnmp_get_tdata_handler(netsnmp_tdata *table)
|
|
{
|
|
netsnmp_mib_handler *ret = NULL;
|
|
|
|
if (!table) {
|
|
snmp_log(LOG_INFO,
|
|
"netsnmp_get_tdata_handler(NULL) called\n");
|
|
return NULL;
|
|
}
|
|
|
|
ret = netsnmp_create_handler(TABLE_TDATA_NAME,
|
|
_netsnmp_tdata_helper_handler);
|
|
if (ret) {
|
|
ret->flags |= MIB_HANDLER_AUTO_NEXT;
|
|
ret->myvoid = (void *) table;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* The helper handler that takes care of passing a specific row of
|
|
* data down to the lower handler(s). The table_container helper
|
|
* has already taken care of identifying the appropriate row of the
|
|
* table (and converting GETNEXT requests into an equivalent GET request)
|
|
* So all we need to do here is make sure that the row is accessible
|
|
* using tdata-style retrieval techniques as well.
|
|
*/
|
|
int
|
|
_netsnmp_tdata_helper_handler(netsnmp_mib_handler *handler,
|
|
netsnmp_handler_registration *reginfo,
|
|
netsnmp_agent_request_info *reqinfo,
|
|
netsnmp_request_info *requests)
|
|
{
|
|
netsnmp_tdata *table = (netsnmp_tdata *) handler->myvoid;
|
|
netsnmp_request_info *request;
|
|
netsnmp_table_request_info *table_info;
|
|
netsnmp_tdata_row *row;
|
|
int need_processing;
|
|
|
|
switch ( reqinfo->mode ) {
|
|
case MODE_GET:
|
|
#ifndef NETSNMP_NO_WRITE_SUPPORT
|
|
case MODE_SET_RESERVE1:
|
|
#endif /* NETSNMP_NO_WRITE_SUPPORT */
|
|
|
|
need_processing = reqinfo->mode == MODE_GET ? 0 : 1;
|
|
for (request = requests; request; request = request->next) {
|
|
if (request->processed)
|
|
continue;
|
|
|
|
table_info = netsnmp_extract_table_info(request);
|
|
if (!table_info) {
|
|
netsnmp_assert(table_info); /* yes, this will always hit */
|
|
netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
|
|
continue; /* eek */
|
|
}
|
|
row = (netsnmp_tdata_row*)netsnmp_container_table_row_extract( request );
|
|
if (!row && (reqinfo->mode == MODE_GET)) {
|
|
netsnmp_assert(row); /* yes, this will always hit */
|
|
netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
|
|
continue; /* eek */
|
|
}
|
|
++need_processing;
|
|
netsnmp_request_add_list_data(request,
|
|
netsnmp_create_data_list(
|
|
TABLE_TDATA_TABLE, table, NULL));
|
|
netsnmp_request_add_list_data(request,
|
|
netsnmp_create_data_list(
|
|
TABLE_TDATA_ROW, row, NULL));
|
|
}
|
|
/** skip next handler if processing not needed */
|
|
if (!need_processing)
|
|
handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
|
|
}
|
|
|
|
/* next handler called automatically - 'AUTO_NEXT' */
|
|
return SNMP_ERR_NOERROR;
|
|
}
|
|
|
|
|
|
/** registers a tdata-based MIB table */
|
|
int
|
|
netsnmp_tdata_register(netsnmp_handler_registration *reginfo,
|
|
netsnmp_tdata *table,
|
|
netsnmp_table_registration_info *table_info)
|
|
{
|
|
netsnmp_mib_handler *handler = netsnmp_get_tdata_handler(table);
|
|
|
|
if (!reginfo || !table || !table_info || !handler ||
|
|
(netsnmp_inject_handler(reginfo, handler) != SNMPERR_SUCCESS)) {
|
|
snmp_log(LOG_ERR, "could not create tdata handler\n");
|
|
netsnmp_handler_free(handler);
|
|
netsnmp_handler_registration_free(reginfo);
|
|
return SNMP_ERR_GENERR;
|
|
}
|
|
|
|
return netsnmp_container_table_register(reginfo, table_info,
|
|
table->container, TABLE_CONTAINER_KEY_NETSNMP_INDEX);
|
|
}
|
|
|
|
netsnmp_feature_child_of(tdata_unregister, table_tdata_all)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TDATA_UNREGISTER
|
|
int
|
|
netsnmp_tdata_unregister(netsnmp_handler_registration *reginfo)
|
|
{
|
|
/* free table; */
|
|
return netsnmp_container_table_unregister(reginfo);
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TDATA_UNREGISTER */
|
|
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_EXTRACT_TABLE
|
|
/** extracts the tdata table from the request structure */
|
|
netsnmp_tdata *
|
|
netsnmp_tdata_extract_table(netsnmp_request_info *request)
|
|
{
|
|
return (netsnmp_tdata *) netsnmp_request_get_list_data(request,
|
|
TABLE_TDATA_TABLE);
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_EXTRACT_TABLE */
|
|
|
|
/** extracts the tdata container from the request structure */
|
|
netsnmp_feature_child_of(tdata_extract_container, table_tdata_all)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TDATA_EXTRACT_CONTAINER
|
|
netsnmp_container *
|
|
netsnmp_tdata_extract_container(netsnmp_request_info *request)
|
|
{
|
|
netsnmp_tdata *tdata = (netsnmp_tdata*)
|
|
netsnmp_request_get_list_data(request, TABLE_TDATA_TABLE);
|
|
return ( tdata ? tdata->container : NULL );
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TDATA_EXTRACT_CONTAINER */
|
|
|
|
/** extracts the tdata row being accessed from the request structure */
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_extract_row(netsnmp_request_info *request)
|
|
{
|
|
return (netsnmp_tdata_row *) netsnmp_container_table_row_extract(request);
|
|
}
|
|
|
|
/** extracts the (table-specific) entry being accessed from the
|
|
* request structure */
|
|
void *
|
|
netsnmp_tdata_extract_entry(netsnmp_request_info *request)
|
|
{
|
|
netsnmp_tdata_row *row =
|
|
(netsnmp_tdata_row *) netsnmp_tdata_extract_row(request);
|
|
if (row)
|
|
return row->data;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_INSERT_ROW
|
|
/** inserts a newly created tdata row into a request */
|
|
NETSNMP_INLINE void
|
|
netsnmp_insert_tdata_row(netsnmp_request_info *request,
|
|
netsnmp_tdata_row *row)
|
|
{
|
|
netsnmp_container_table_row_insert(request, (netsnmp_index *)row);
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_INSERT_ROW */
|
|
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_REMOVE_ROW
|
|
/** inserts a newly created tdata row into a request */
|
|
NETSNMP_INLINE void
|
|
netsnmp_remove_tdata_row(netsnmp_request_info *request,
|
|
netsnmp_tdata_row *row)
|
|
{
|
|
netsnmp_container_table_row_remove(request, (netsnmp_index *)row);
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_REMOVE_ROW */
|
|
|
|
|
|
/* ==================================
|
|
*
|
|
* Generic API: Row operations
|
|
*
|
|
* ================================== */
|
|
|
|
/** returns the (table-specific) entry data for a given row */
|
|
void *
|
|
netsnmp_tdata_row_entry( netsnmp_tdata_row *row )
|
|
{
|
|
if (row)
|
|
return row->data;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/** returns the first row in the table */
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_row_first(netsnmp_tdata *table)
|
|
{
|
|
return (netsnmp_tdata_row *)CONTAINER_FIRST( table->container );
|
|
}
|
|
|
|
/** finds a row in the 'tdata' table given another row */
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_row_get( netsnmp_tdata *table,
|
|
netsnmp_tdata_row *row)
|
|
{
|
|
return (netsnmp_tdata_row*)CONTAINER_FIND( table->container, row );
|
|
}
|
|
|
|
/** returns the next row in the table */
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_row_next( netsnmp_tdata *table,
|
|
netsnmp_tdata_row *row)
|
|
{
|
|
return (netsnmp_tdata_row *)CONTAINER_NEXT( table->container, row );
|
|
}
|
|
|
|
/** finds a row in the 'tdata' table given the index values */
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_row_get_byidx(netsnmp_tdata *table,
|
|
netsnmp_variable_list *indexes)
|
|
{
|
|
oid searchfor[ MAX_OID_LEN];
|
|
size_t searchfor_len = MAX_OID_LEN;
|
|
|
|
build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
|
|
indexes);
|
|
return netsnmp_tdata_row_get_byoid(table, searchfor, searchfor_len);
|
|
}
|
|
|
|
/** finds a row in the 'tdata' table given the index OID */
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_row_get_byoid(netsnmp_tdata *table,
|
|
oid * searchfor, size_t searchfor_len)
|
|
{
|
|
netsnmp_index index;
|
|
if (!table)
|
|
return NULL;
|
|
|
|
index.oids = searchfor;
|
|
index.len = searchfor_len;
|
|
return (netsnmp_tdata_row*)CONTAINER_FIND( table->container, &index );
|
|
}
|
|
|
|
/** finds the lexically next row in the 'tdata' table
|
|
given the index values */
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_row_next_byidx(netsnmp_tdata *table,
|
|
netsnmp_variable_list *indexes)
|
|
{
|
|
oid searchfor[ MAX_OID_LEN];
|
|
size_t searchfor_len = MAX_OID_LEN;
|
|
|
|
build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
|
|
indexes);
|
|
return netsnmp_tdata_row_next_byoid(table, searchfor, searchfor_len);
|
|
}
|
|
|
|
/** finds the lexically next row in the 'tdata' table
|
|
given the index OID */
|
|
netsnmp_tdata_row *
|
|
netsnmp_tdata_row_next_byoid(netsnmp_tdata *table,
|
|
oid * searchfor, size_t searchfor_len)
|
|
{
|
|
netsnmp_index index;
|
|
if (!table)
|
|
return NULL;
|
|
|
|
index.oids = searchfor;
|
|
index.len = searchfor_len;
|
|
return (netsnmp_tdata_row*)CONTAINER_NEXT( table->container, &index );
|
|
}
|
|
|
|
netsnmp_feature_child_of(tdata_row_count, table_tdata_all)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TDATA_ROW_COUNT
|
|
int
|
|
netsnmp_tdata_row_count(netsnmp_tdata *table)
|
|
{
|
|
if (!table)
|
|
return 0;
|
|
return CONTAINER_SIZE( table->container );
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TDATA_ROW_COUNT */
|
|
|
|
/* ==================================
|
|
*
|
|
* Generic API: Index operations on a 'tdata' table
|
|
*
|
|
* ================================== */
|
|
|
|
|
|
/** compare a row with the given index values */
|
|
netsnmp_feature_child_of(tdata_compare_idx, table_tdata_all)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_TDATA_COMPARE_IDX
|
|
int
|
|
netsnmp_tdata_compare_idx(netsnmp_tdata_row *row,
|
|
netsnmp_variable_list *indexes)
|
|
{
|
|
oid searchfor[ MAX_OID_LEN];
|
|
size_t searchfor_len = MAX_OID_LEN;
|
|
|
|
build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
|
|
indexes);
|
|
return netsnmp_tdata_compare_oid(row, searchfor, searchfor_len);
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TDATA_COMPARE_IDX */
|
|
|
|
/** compare a row with the given index OID */
|
|
int
|
|
netsnmp_tdata_compare_oid(netsnmp_tdata_row *row,
|
|
oid * compareto, size_t compareto_len)
|
|
{
|
|
netsnmp_index *index = (netsnmp_index *)row;
|
|
return snmp_oid_compare( index->oids, index->len,
|
|
compareto, compareto_len);
|
|
}
|
|
|
|
int
|
|
netsnmp_tdata_compare_subtree_idx(netsnmp_tdata_row *row,
|
|
netsnmp_variable_list *indexes)
|
|
{
|
|
oid searchfor[ MAX_OID_LEN];
|
|
size_t searchfor_len = MAX_OID_LEN;
|
|
|
|
build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
|
|
indexes);
|
|
return netsnmp_tdata_compare_subtree_oid(row, searchfor, searchfor_len);
|
|
}
|
|
|
|
int
|
|
netsnmp_tdata_compare_subtree_oid(netsnmp_tdata_row *row,
|
|
oid * compareto, size_t compareto_len)
|
|
{
|
|
netsnmp_index *index = (netsnmp_index *)row;
|
|
return snmp_oidtree_compare( index->oids, index->len,
|
|
compareto, compareto_len);
|
|
}
|
|
#else /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA */
|
|
netsnmp_feature_unused(table_tdata);
|
|
#endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA */
|
|
|
|
|
|
/** @}
|
|
*/
|