1 #ifdef BRCM_SNMP_SUPPORT
3 #include <net-snmp/net-snmp-config.h>
11 #include <net-snmp/net-snmp-includes.h>
12 #include <net-snmp/agent/net-snmp-agent-includes.h>
18 static netsnmp_data_list *auto_tables;
20 typedef struct data_set_tables_s {
21 netsnmp_table_data_set *table_set;
24 typedef struct data_set_cache_s {
29 #define STATE_ACTION 1
30 #define STATE_COMMIT 2
34 typedef struct newrow_stash_s {
35 netsnmp_table_row *newrow;
41 /** @defgroup table_dataset table_dataset: Helps you implement a table with automatted storage.
44 * This handler helps you implement a table where all the data is
45 * expected to be stored within the agent itself and not in some
46 * external storage location. It handles all MIB requests including
47 * GETs, GETNEXTs and SETs. It's possible to simply create a table
48 * without actually ever defining a handler to be called when SNMP
49 * requests come in. To use the data, you can either attach a
50 * sub-handler that merely uses/manipulates the data further when
51 * requests come in, or you can loop through it externally when it's
52 * actually needed. This handler is most useful in cases where a
53 * table is holding configuration data for something which gets
54 * triggered via another event.
56 * NOTE NOTE NOTE: This helper isn't complete and is likely to change
57 * somewhat over time. Specifically, the way it stores data
58 * internally may change drastically.
63 /** Create a netsnmp_table_data_set structure given a table_data definition */
64 netsnmp_table_data_set *
65 netsnmp_create_table_data_set(const char *table_name)
67 netsnmp_table_data_set *table_set =
68 SNMP_MALLOC_TYPEDEF(netsnmp_table_data_set);
71 table_set->table = netsnmp_create_table_data(table_name);
75 /** Given a netsnmp_table_data_set definition, create a handler for it */
77 netsnmp_get_table_data_set_handler(netsnmp_table_data_set *data_set)
79 netsnmp_mib_handler *ret = NULL;
83 "netsnmp_get_table_data_set_handler(NULL) called\n");
88 netsnmp_create_handler(TABLE_DATA_SET_NAME,
89 netsnmp_table_data_set_helper_handler);
91 ret->myvoid = (void *) data_set;
97 /** register a given data_set at a given oid (specified in the
98 netsnmp_handler_registration pointer). The
99 reginfo->handler->access_method *may* be null if the call doesn't
100 ever want to be called for SNMP operations.
103 netsnmp_register_table_data_set(netsnmp_handler_registration *reginfo,
104 netsnmp_table_data_set *data_set,
105 netsnmp_table_registration_info
108 if (NULL == table_info) {
110 * allocate the table if one wasn't allocated
112 table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
115 if (NULL == table_info->indexes && data_set->table->indexes_template) {
117 * copy the indexes in
119 table_info->indexes =
120 snmp_clone_varbind(data_set->table->indexes_template);
123 if ((!table_info->min_column || !table_info->max_column) &&
124 (data_set->default_row)) {
126 * determine min/max columns
128 unsigned int mincol = 0xffffffff, maxcol = 0;
129 netsnmp_table_data_set_storage *row;
131 for (row = data_set->default_row; row; row = row->next) {
132 mincol = SNMP_MIN(mincol, row->column);
133 maxcol = SNMP_MAX(maxcol, row->column);
135 if (!table_info->min_column)
136 table_info->min_column = mincol;
137 if (!table_info->max_column)
138 table_info->max_column = maxcol;
141 netsnmp_inject_handler(reginfo,
142 netsnmp_get_table_data_set_handler(data_set));
143 return netsnmp_register_table_data(reginfo, data_set->table,
147 /** Finds a column within a given storage set, given the pointer to
148 the start of the storage set list.
150 netsnmp_table_data_set_storage *
151 netsnmp_table_data_set_find_column(netsnmp_table_data_set_storage *start,
154 while (start && start->column != column)
160 * extracts a netsnmp_table_data_set pointer from a given request
162 netsnmp_table_data_set_storage *
163 netsnmp_extract_table_data_set_column(netsnmp_request_info *request,
166 netsnmp_table_data_set_storage *data =
167 netsnmp_extract_table_row_data( request );
169 data = netsnmp_table_data_set_find_column(data, column);
174 * extracts a netsnmp_table_data_set pointer from a given request
176 NETSNMP_INLINE netsnmp_table_data_set *
177 netsnmp_extract_table_data_set(netsnmp_request_info *request)
179 return (netsnmp_table_data_set *)
180 netsnmp_request_get_list_data(request, TABLE_DATA_SET_NAME);
184 * marks a given column in a row as writable or not.
187 netsnmp_mark_row_column_writable(netsnmp_table_row *row, int column,
190 netsnmp_table_data_set_storage *data;
193 return SNMPERR_GENERR;
195 data = (netsnmp_table_data_set_storage *) row->data;
196 data = netsnmp_table_data_set_find_column(data, column);
202 data = SNMP_MALLOC_TYPEDEF(netsnmp_table_data_set_storage);
204 snmp_log(LOG_CRIT, "no memory in netsnmp_set_row_column");
205 return SNMPERR_MALLOC;
207 data->column = column;
208 data->writable = writable;
209 data->next = row->data;
212 data->writable = writable;
214 return SNMPERR_SUCCESS;
219 * sets a given column in a row with data given a type, value, and
220 * length. Data is memdup'ed by the function.
223 netsnmp_set_row_column(netsnmp_table_row *row, unsigned int column,
224 int type, const char *value, size_t value_len)
226 netsnmp_table_data_set_storage *data;
229 return SNMPERR_GENERR;
231 data = (netsnmp_table_data_set_storage *) row->data;
232 data = netsnmp_table_data_set_find_column(data, column);
238 data = SNMP_MALLOC_TYPEDEF(netsnmp_table_data_set_storage);
240 snmp_log(LOG_CRIT, "no memory in netsnmp_set_row_column");
241 return SNMPERR_MALLOC;
244 data->column = column;
246 data->next = row->data;
251 if (data->type != type)
252 return SNMPERR_GENERR;
254 SNMP_FREE(data->data.voidp);
256 if (memdup(&data->data.string, value, (value_len)) !=
258 snmp_log(LOG_CRIT, "no memory in netsnmp_set_row_column");
259 return SNMPERR_MALLOC;
262 data->data.string = malloc(1);
264 data->data_len = value_len;
266 return SNMPERR_SUCCESS;
269 /** adds a new default row to a table_set.
270 * Arguments should be the table_set, column number, variable type and
271 * finally a 1 if it is allowed to be writable, or a 0 if not. If the
272 * default_value field is not NULL, it will be used to populate new
273 * valuse in that column fro newly created rows. It is copied into the
274 * storage template (free your calling argument).
276 * returns SNMPERR_SUCCESS or SNMPERR_FAILURE
279 netsnmp_table_set_add_default_row(netsnmp_table_data_set *table_set,
281 int type, int writable,
283 size_t default_value_len)
286 netsnmp_table_data_set_storage *new_col, *ptr;
289 return SNMPERR_GENERR;
295 netsnmp_table_data_set_find_column(table_set->default_row, column);
296 if (new_col != NULL) {
297 if (new_col->type == type && new_col->writable == writable)
298 return SNMPERR_SUCCESS;
299 return SNMPERR_GENERR;
302 new_col = SNMP_MALLOC_TYPEDEF(netsnmp_table_data_set_storage);
303 new_col->type = type;
304 new_col->writable = writable;
305 new_col->column = column;
307 memdup((u_char **) & (new_col->data.voidp),
308 (u_char *) default_value, default_value_len);
309 new_col->data_len = default_value_len;
311 if (table_set->default_row == NULL)
312 table_set->default_row = new_col;
314 for (ptr = table_set->default_row; ptr->next; ptr = ptr->next) {
318 return SNMPERR_SUCCESS;
321 /** clones a dataset row, including all data. */
323 netsnmp_table_data_set_clone_row(netsnmp_table_row *row)
325 netsnmp_table_data_set_storage *data, **newrowdata;
326 netsnmp_table_row *newrow = netsnmp_table_data_clone_row(row);
331 data = (netsnmp_table_data_set_storage *) row->data;
335 (netsnmp_table_data_set_storage **) &(newrow->data); data;
336 newrowdata = &((*newrowdata)->next), data = data->next) {
338 memdup((u_char **) newrowdata, (u_char *) data,
339 sizeof(netsnmp_table_data_set_storage));
343 if (data->data.voidp) {
344 memdup((u_char **) & ((*newrowdata)->data.voidp),
345 (u_char *) data->data.voidp, data->data_len);
346 if (!(*newrowdata)->data.voidp)
354 /** creates a new row from an existing defined default set */
356 netsnmp_table_data_set_create_row_from_defaults
357 (netsnmp_table_data_set_storage *defrow)
359 netsnmp_table_row *row;
360 row = netsnmp_create_table_data_row();
363 for (; defrow; defrow = defrow->next) {
364 netsnmp_set_row_column(row, defrow->column, defrow->type,
365 defrow->data.voidp, defrow->data_len);
366 if (defrow->writable)
367 netsnmp_mark_row_column_writable(row, defrow->column, 1);
375 netsnmp_table_data_set_create_newrowstash
376 (netsnmp_table_data_set *datatable,
377 netsnmp_table_request_info *table_info)
379 newrow_stash *newrowstash = NULL;
380 netsnmp_table_row *newrow = NULL;
382 newrowstash = SNMP_MALLOC_TYPEDEF(newrow_stash);
383 newrowstash->created = 1;
384 newrow = netsnmp_table_data_set_create_row_from_defaults
385 (datatable->default_row);
386 newrow->indexes = snmp_clone_varbind(table_info->indexes);
387 newrowstash->newrow = newrow;
392 /** implements the table data helper. This is the routine that takes
393 * care of all SNMP requests coming into the table. */
395 netsnmp_table_data_set_helper_handler(netsnmp_mib_handler *handler,
396 netsnmp_handler_registration
398 netsnmp_agent_request_info *reqinfo,
399 netsnmp_request_info *requests)
402 netsnmp_table_data_set_storage *data = NULL;
403 newrow_stash *newrowstash = NULL;
404 netsnmp_table_row *row, *newrow = NULL;
405 netsnmp_table_request_info *table_info;
406 netsnmp_request_info *request;
409 netsnmp_oid_stash_node **stashp = NULL;
412 return SNMPERR_GENERR;
414 DEBUGMSGTL(("netsnmp_table_data_set", "handler starting\n"));
415 for (request = requests; request; request = request->next) {
416 netsnmp_table_data_set *datatable =
417 (netsnmp_table_data_set *) handler->myvoid;
418 if (request->processed)
422 * extract our stored data and table info
424 row = netsnmp_extract_table_row(request);
425 table_info = netsnmp_extract_table_info(request);
426 suffix = requests->requestvb->name + reginfo->rootoid_len + 2;
427 suffix_len = requests->requestvb->name_length -
428 (reginfo->rootoid_len + 2);
430 if (MODE_IS_SET(reqinfo->mode)) {
432 * use a cached copy of the row for modification
436 * cache location: may have been created already by other
437 * SET requests in the same master request.
439 stashp = (netsnmp_oid_stash_node **)
440 netsnmp_table_get_or_create_row_stash(reqinfo,
441 "dataset_row_stash");
444 = netsnmp_oid_stash_get_data(*stashp, suffix, suffix_len);
448 if (datatable->allow_creation) {
450 * entirely new row. Create the row from the template
453 netsnmp_table_data_set_create_newrowstash(
454 datatable, table_info);
455 newrow = newrowstash->newrow;
456 } else if (datatable->rowstatus_column == 0) {
458 * A RowStatus object may be used to control the
459 * creation of a new row. But if this object
460 * isn't declared (and the table isn't marked as
461 * 'auto-create'), then we can't create a new row.
463 netsnmp_set_request_error(reqinfo, request,
464 SNMP_ERR_NOCREATION);
469 * existing row that needs to be modified
471 newrowstash = SNMP_MALLOC_TYPEDEF(newrow_stash);
472 newrow = netsnmp_table_data_set_clone_row(row);
473 newrowstash->newrow = newrow;
475 netsnmp_oid_stash_add_data(stashp, suffix, suffix_len,
478 newrow = newrowstash->newrow;
481 * all future SET data modification operations use this
484 if (reqinfo->mode == MODE_SET_RESERVE1 ||
485 reqinfo->mode == MODE_SET_RESERVE2)
490 data = (netsnmp_table_data_set_storage *) row->data;
492 if (!row || !table_info || !data) {
493 if (!MODE_IS_SET(reqinfo->mode)) {
494 netsnmp_set_request_error(reqinfo, request,
495 SNMP_NOSUCHINSTANCE);
501 netsnmp_table_data_set_find_column(data, table_info->colnum);
503 switch (reqinfo->mode) {
506 case MODE_GETBULK: /* XXXWWW */
507 if (data && data->data.voidp)
508 netsnmp_table_data_build_result(reginfo, reqinfo, request,
516 case MODE_SET_RESERVE1:
519 * Can we modify the existing row?
521 if (!data->writable) {
522 netsnmp_set_request_error(reqinfo, request,
523 SNMP_ERR_NOTWRITABLE);
524 } else if (request->requestvb->type != data->type) {
525 netsnmp_set_request_error(reqinfo, request,
528 } else if (datatable->rowstatus_column == table_info->colnum) {
530 * Otherwise, this is where we create a new row using
531 * the RowStatus object (essentially duplicating the
532 * steps followed earlier in the 'allow_creation' case)
534 switch (*(request->requestvb->val.integer)) {
536 case RS_CREATEANDWAIT:
538 netsnmp_table_data_set_create_newrowstash(
539 datatable, table_info);
540 newrow = newrowstash->newrow;
542 netsnmp_oid_stash_add_data(stashp, suffix, suffix_len,
548 case MODE_SET_RESERVE2:
550 * If the agent receives a SET request for an object in a non-existant
551 * row, then the RESERVE1 pass will create the row automatically.
553 * But since the row doesn't exist at that point, the test for whether
554 * the object is writable or not will be skipped. So we need to check
555 * for this possibility again here.
557 * Similarly, if row creation is under the control of the RowStatus
558 * object (i.e. allow_creation == 0), but this particular request
559 * doesn't include such an object, then the row won't have been created,
560 * and the writable check will also have been skipped. Again - check here.
562 if (data && data->writable == 0) {
563 netsnmp_set_request_error(reqinfo, request,
564 SNMP_ERR_NOTWRITABLE);
567 if (datatable->rowstatus_column == table_info->colnum) {
568 switch (*(request->requestvb->val.integer)) {
570 case RS_NOTINSERVICE:
572 * Can only operate on pre-existing rows.
574 if (!newrowstash || newrowstash->created) {
575 netsnmp_set_request_error(reqinfo, request,
576 SNMP_ERR_INCONSISTENTVALUE);
582 case RS_CREATEANDWAIT:
584 * Can only operate on newly created rows.
586 if (!(newrowstash && newrowstash->created)) {
587 netsnmp_set_request_error(reqinfo, request,
588 SNMP_ERR_INCONSISTENTVALUE);
595 * Can operate on new or pre-existing rows.
602 * Not a valid value to Set
604 netsnmp_set_request_error(reqinfo, request,
605 SNMP_ERR_WRONGVALUE);
610 netsnmp_set_request_error(reqinfo, request,
611 SNMP_ERR_NOCREATION);
616 * modify row and set new value
618 SNMP_FREE(data->data.string);
620 netsnmp_strdup_and_null(request->requestvb->val.string,
621 request->requestvb->val_len);
622 if (!data->data.string) {
623 netsnmp_set_request_error(reqinfo, requests,
624 SNMP_ERR_RESOURCEUNAVAILABLE);
626 data->data_len = request->requestvb->val_len;
628 if (datatable->rowstatus_column == table_info->colnum) {
629 switch (*(request->requestvb->val.integer)) {
632 * XXX: check legality
634 *(data->data.integer) = RS_ACTIVE;
637 case RS_CREATEANDWAIT:
639 * XXX: check legality
641 *(data->data.integer) = RS_NOTINSERVICE;
645 newrowstash->deleted = 1;
651 case MODE_SET_ACTION:
654 * Install the new row into the stored table.
655 * Do this only *once* per row ....
657 if (newrowstash->state != STATE_ACTION) {
658 newrowstash->state = STATE_ACTION;
659 if (newrowstash->created) {
660 netsnmp_table_dataset_add_row(datatable, newrow);
662 netsnmp_table_dataset_replace_row(datatable,
667 * ... but every (relevant) varbind in the request will
668 * need to know about this new row, so update the
669 * per-request row information regardless
671 if (newrowstash->created) {
672 netsnmp_request_add_list_data(request,
673 netsnmp_create_data_list(TABLE_DATA_NAME,
680 * extract the new row, replace with the old or delete
682 if (newrowstash->state != STATE_UNDO) {
683 newrowstash->state = STATE_UNDO;
684 if (newrowstash->created) {
685 netsnmp_table_dataset_remove_and_delete_row(datatable, newrow);
687 netsnmp_table_dataset_replace_row(datatable,
689 netsnmp_table_dataset_delete_row(newrow);
694 case MODE_SET_COMMIT:
695 if (newrowstash->state != STATE_COMMIT) {
696 newrowstash->state = STATE_COMMIT;
697 if (!newrowstash->created) {
698 netsnmp_table_dataset_delete_row(row);
700 if (newrowstash->deleted) {
701 netsnmp_table_dataset_remove_and_delete_row(datatable, newrow);
707 if (newrowstash && newrowstash->state != STATE_FREE) {
708 newrowstash->state = STATE_FREE;
709 netsnmp_table_dataset_delete_row(newrow);
715 if (handler->next && handler->next->access_method)
716 netsnmp_call_next_handler(handler, reginfo, reqinfo, requests);
717 return SNMP_ERR_NOERROR;
720 /** registers a table_dataset so that the "add_row" snmpd.conf token
721 * can be used to add data to this table. If registration_name is
722 * NULL then the name used when the table was created will be used
725 * @todo create a properly free'ing registeration pointer for the
726 * datalist, and get the datalist freed at shutdown.
729 netsnmp_register_auto_data_table(netsnmp_table_data_set *table_set,
730 char *registration_name)
732 data_set_tables *tables;
733 tables = SNMP_MALLOC_TYPEDEF(data_set_tables);
736 tables->table_set = table_set;
737 if (!registration_name) {
738 registration_name = table_set->table->name;
740 netsnmp_add_list_data(&auto_tables, netsnmp_create_data_list(registration_name, tables, NULL)); /* XXX */
745 netsnmp_config_parse_table_set(const char *token, char *line)
747 oid name[MAX_OID_LEN], table_name[MAX_OID_LEN];
748 size_t name_length = MAX_OID_LEN, table_name_length =
750 struct tree *tp, *indexnode;
751 netsnmp_table_data_set *table_set;
752 struct index_list *index;
753 unsigned int mincol = 0xffffff, maxcol = 0;
757 * instatiate a fake table based on MIB information
759 if (!snmp_parse_oid(line, table_name, &table_name_length) ||
760 (NULL == (tp = get_tree(table_name, table_name_length,
761 get_tree_head())))) {
763 ("can't instatiate table %s since I can't find mib information about it\n");
767 if (NULL == (tp = tp->child_list) || NULL == tp->child_list) {
769 ("can't instatiate table since it doesn't appear to be a proper table\n");
773 table_set = netsnmp_create_table_data_set(line);
776 * loop through indexes and add types
778 for (index = tp->indexes; index; index = index->next) {
779 if (!snmp_parse_oid(index->ilabel, name, &name_length) ||
781 (indexnode = get_tree(name, name_length, get_tree_head())))) {
783 ("can't instatiate table %s since I don't know anything about one index\n");
784 return; /* xxx mem leak */
787 type = mib_to_asn_type(indexnode->type);
788 if (type == (u_char) - 1) {
789 config_pwarn("unknown index type");
790 return; /* xxx mem leak */
792 if (index->isimplied) /* if implied, mark it as such */
795 DEBUGMSGTL(("table_set_add_row",
796 "adding default index of type %d\n", type));
797 netsnmp_table_dataset_add_index(table_set, type);
801 * loop through children and add each column info
803 for (tp = tp->child_list; tp; tp = tp->next_peer) {
805 type = mib_to_asn_type(tp->type);
806 if (type == (u_char) - 1) {
807 config_pwarn("unknown column type");
808 return; /* xxx mem leak */
811 DEBUGMSGTL(("table_set_add_row", "adding column %d of type %d\n",
814 switch (tp->access) {
815 case MIB_ACCESS_CREATE:
816 table_set->allow_creation = 1;
817 case MIB_ACCESS_READWRITE:
818 case MIB_ACCESS_WRITEONLY:
820 case MIB_ACCESS_READONLY:
821 DEBUGMSGTL(("table_set_add_row",
822 "adding column %d of type %d\n", tp->subid, type));
823 netsnmp_table_set_add_default_row(table_set, tp->subid, type,
825 mincol = SNMP_MIN(mincol, tp->subid);
826 maxcol = SNMP_MAX(maxcol, tp->subid);
829 case MIB_ACCESS_NOACCESS:
830 case MIB_ACCESS_NOTIFY:
834 config_pwarn("unknown column access type");
842 netsnmp_register_table_data_set(netsnmp_create_handler_registration
843 (line, NULL, table_name,
845 HANDLER_CAN_RWRITE), table_set, NULL);
847 netsnmp_register_auto_data_table(table_set, NULL);
852 netsnmp_config_parse_add_row(const char *token, char *line)
854 char buf[SNMP_MAXBUF_MEDIUM];
855 char tname[SNMP_MAXBUF_MEDIUM];
858 data_set_tables *tables;
859 netsnmp_variable_list *vb; /* containing only types */
860 netsnmp_table_row *row;
861 netsnmp_table_data_set_storage *dr;
863 line = copy_nword(line, tname, SNMP_MAXBUF_MEDIUM);
865 tables = (data_set_tables *) netsnmp_get_list_data(auto_tables, tname);
867 config_pwarn("Unknown table trying to add a row");
872 * do the indexes first
874 row = netsnmp_create_table_data_row();
876 for (vb = tables->table_set->table->indexes_template; vb;
877 vb = vb->next_variable) {
879 config_pwarn("missing an index value");
883 DEBUGMSGTL(("table_set_add_row", "adding index of type %d\n",
885 buf_size = SNMP_MAXBUF_MEDIUM;
886 line = read_config_read_memory(vb->type, line, buf, &buf_size);
887 netsnmp_table_row_add_index(row, vb->type, buf, buf_size);
893 for (dr = tables->table_set->default_row; dr; dr = dr->next) {
895 config_pwarn("missing an data value\n");
899 buf_size = SNMP_MAXBUF_MEDIUM;
900 line = read_config_read_memory(dr->type, line, buf, &buf_size);
901 DEBUGMSGTL(("table_set_add_row",
902 "adding data at column %d of type %d\n", dr->column,
904 netsnmp_set_row_column(row, dr->column, dr->type, buf, buf_size);
906 netsnmp_mark_row_column_writable(row, dr->column, 1); /* make writable */
908 netsnmp_table_data_add_row(tables->table_set->table, row);
911 /** adds an index to the table. Call this repeatly for each index. */
913 netsnmp_table_dataset_add_index(netsnmp_table_data_set *table, u_char type)
917 netsnmp_table_data_add_index(table->table, type);
920 /** adds a new row to a dataset table */
922 netsnmp_table_dataset_add_row(netsnmp_table_data_set *table,
923 netsnmp_table_row *row)
927 netsnmp_table_data_add_row(table->table, row);
930 /** adds a new row to a dataset table */
932 netsnmp_table_dataset_replace_row(netsnmp_table_data_set *table,
933 netsnmp_table_row *origrow,
934 netsnmp_table_row *newrow)
938 netsnmp_table_data_replace_row(table->table, origrow, newrow);
941 /** deletes a single dataset table data.
942 * returns the (possibly still good) next pointer of the deleted data object.
944 NETSNMP_INLINE netsnmp_table_data_set_storage *
945 netsnmp_table_dataset_delete_data(netsnmp_table_data_set_storage *data)
947 netsnmp_table_data_set_storage *nextPtr = NULL;
949 nextPtr = data->next;
950 SNMP_FREE(data->data.voidp);
956 /** deletes all the data from this node and beyond in the linked list */
958 netsnmp_table_dataset_delete_all_data(netsnmp_table_data_set_storage *data)
962 data = netsnmp_table_dataset_delete_data(data);
966 /** deletes all the data from this node and beyond in the linked list */
968 netsnmp_table_dataset_delete_row(netsnmp_table_row *row)
970 netsnmp_table_data_set_storage *data;
975 data = netsnmp_table_data_delete_row(row);
976 netsnmp_table_dataset_delete_all_data(data);
979 /** removes a row from the table, but doesn't delete/free anything */
981 netsnmp_table_dataset_remove_row(netsnmp_table_data_set *table,
982 netsnmp_table_row *row)
987 netsnmp_table_data_remove_and_delete_row(table->table, row);
990 /** removes a row from the table and then deletes it (and all it's data) */
992 netsnmp_table_dataset_remove_and_delete_row(netsnmp_table_data_set *table,
993 netsnmp_table_row *row)
995 netsnmp_table_data_set_storage *data;
1000 data = (netsnmp_table_data_set_storage *)
1001 netsnmp_table_data_remove_and_delete_row(table->table, row);
1003 netsnmp_table_dataset_delete_all_data(data);
1006 /** adds multiple data column definitions to each row. Functionally,
1007 * this is a wrapper around calling netsnmp_table_set_add_default_row
1008 * repeatedly for you.
1012 netsnmp_table_set_multi_add_default_row(netsnmp_table_data_set *tset, ...)
1014 netsnmp_table_set_multi_add_default_row(va_dcl
1020 unsigned int column;
1026 va_start(debugargs, tset);
1028 netsnmp_table_data_set *tset;
1030 va_start(debugargs);
1031 tset = va_arg(debugargs, netsnmp_table_data_set *);
1034 while ((column = va_arg(debugargs, unsigned int)) != 0) {
1035 type = va_arg(debugargs, int);
1036 writable = va_arg(debugargs, int);
1037 data = va_arg(debugargs, void *);
1038 data_len = va_arg(debugargs, size_t);
1039 netsnmp_table_set_add_default_row(tset, column, type, writable,
1046 /** adds multiple indexes to a table_dataset helper object.
1047 * To end the list, use a 0 after the list of ASN index types. */
1050 netsnmp_table_set_add_indexes(netsnmp_table_data_set *tset,
1053 netsnmp_table_set_add_indexes(va_alist)
1061 va_start(debugargs, tset);
1063 netsnmp_table_data_set *tset;
1065 va_start(debugargs);
1066 tset = va_arg(debugargs, netsnmp_table_data_set *);
1069 while ((type = va_arg(debugargs, int)) != 0) {
1070 netsnmp_table_dataset_add_index(tset, type);
1079 #endif /* BRCM_SNMP_SUPPORT */