SNMP integration and GUI
[tomato.git] / release / src / router / snmp / agent / helpers / table_array.c
blob9aa630e7e0c009a26498c607e5628976de6709cc
1 /*
2 * table_array.c
3 * $Id: table_array.c,v 1.1.2.1 2004/06/20 21:54:11 nikki Exp $
4 */
6 #include <net-snmp/net-snmp-config.h>
8 #if HAVE_STRING_H
9 #include <string.h>
10 #else
11 #include <strings.h>
12 #endif
14 #include <net-snmp/net-snmp-includes.h>
15 #include <net-snmp/agent/net-snmp-agent-includes.h>
17 #include <net-snmp/agent/table.h>
18 #include <net-snmp/agent/table_array.h>
19 #include <net-snmp/library/container.h>
20 #include <net-snmp/library/snmp_assert.h>
22 #if HAVE_DMALLOC_H
23 #include <dmalloc.h>
24 #endif
27 * snmp.h:#define SNMP_MSG_INTERNAL_SET_BEGIN -1
28 * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE1 0
29 * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE2 1
30 * snmp.h:#define SNMP_MSG_INTERNAL_SET_ACTION 2
31 * snmp.h:#define SNMP_MSG_INTERNAL_SET_COMMIT 3
32 * snmp.h:#define SNMP_MSG_INTERNAL_SET_FREE 4
33 * snmp.h:#define SNMP_MSG_INTERNAL_SET_UNDO 5
36 static const char *mode_name[] = {
37 "Reserve 1",
38 "Reserve 2",
39 "Action",
40 "Commit",
41 "Free",
42 "Undo"
46 * PRIVATE structure for holding important info for each table.
48 typedef struct table_container_data_s {
50 /** registration info for the table */
51 netsnmp_table_registration_info *tblreg_info;
53 /** container for the table rows */
54 netsnmp_container *table;
57 * mutex_type lock;
60 /** do we want to group rows with the same index
61 * together when calling callbacks? */
62 int group_rows;
64 /** callbacks for this table */
65 netsnmp_table_array_callbacks *cb;
67 } table_container_data;
69 /** @defgroup table_array table_array: Helps you implement a table when data can be stored locally. The data is stored in a sorted array, using a binary search for lookups.
70 * @ingroup table
72 * The table_array handler is used (automatically) in conjuntion
73 * with the @link table table@endlink handler. It is primarily
74 * intended to be used with the mib2c configuration file
75 * mib2c.array-user.conf.
77 * The code generated by mib2c is useful when you have control of
78 * the data for each row. If you cannot control when rows are added
79 * and deleted (or at least be notified of changes to row data),
80 * then this handler is probably not for you.
82 * This handler makes use of callbacks (function pointers) to
83 * handle various tasks. Code is generated for each callback,
84 * but will need to be reviewed and flushed out by the user.
86 * NOTE NOTE NOTE: Once place where mib2c is somewhat lacking
87 * is with regards to tables with external indices. If your
88 * table makes use of one or more external indices, please
89 * review the generated code very carefully for comments
90 * regarding external indices.
92 * NOTE NOTE NOTE: This helper, the API and callbacks are still
93 * being tested and may change.
95 * The generated code will define a structure for storage of table
96 * related data. This structure must be used, as it contains the index
97 * OID for the row, which is used for keeping the array sorted. You can
98 * add addition fields or data to the structure for your own use.
100 * The generated code will also have code to handle SNMP-SET processing.
101 * If your table does not support any SET operations, simply comment
102 * out the #define <PREFIX>_SET_HANDLING (where <PREFIX> is your
103 * table name) in the header file.
105 * SET processing modifies the row in-place. The duplicate_row
106 * callback will be called to save a copy of the original row.
107 * In the event of a failure before the commite phase, the
108 * row_copy callback will be called to restore the original row
109 * from the copy.
111 * Code will be generated to handle row creation. This code may be
112 * disabled by commenting out the #define <PREFIX>_ROW_CREATION
113 * in the header file.
115 * If your table contains a RowStatus object, by default the
116 * code will not allow object in an active row to be modified.
117 * To allow active rows to be modified, remove the comment block
118 * around the #define <PREFIX>_CAN_MODIFY_ACTIVE_ROW in the header
119 * file.
121 * Code will be generated to maintain a secondary index for all
122 * rows, stored in a binary tree. This is very useful for finding
123 * rows by a key other than the OID index. By default, the functions
124 * for maintaining this tree will be based on a character string.
125 * NOTE: this will likely be made into a more generic mechanism,
126 * using new callback methods, in the near future.
128 * The generated code contains many TODO comments. Make sure you
129 * check each one to see if it applies to your code. Examples include
130 * checking indices for syntax (ranges, etc), initializing default
131 * values in newly created rows, checking for row activation and
132 * deactivation requirements, etc.
134 * @{
137 /**********************************************************************
138 **********************************************************************
141 * PUBLIC Registration functions *
144 **********************************************************************
145 **********************************************************************/
146 /** register specified callbacks for the specified table/oid. If the
147 group_rows parameter is set, the row related callbacks will be
148 called once for each unique row index. Otherwise, each callback
149 will be called only once, for all objects.
152 netsnmp_table_container_register(netsnmp_handler_registration *reginfo,
153 netsnmp_table_registration_info *tabreg,
154 netsnmp_table_array_callbacks *cb,
155 netsnmp_container *container,
156 int group_rows)
158 table_container_data *tad = SNMP_MALLOC_TYPEDEF(table_container_data);
159 if (!tad)
160 return SNMPERR_GENERR;
161 tad->tblreg_info = tabreg; /* we need it too, but it really is not ours */
163 if (!cb) {
164 snmp_log(LOG_ERR, "table_array registration with no callbacks\n" );
165 return SNMPERR_GENERR;
168 * check for required callbacks
170 if ((cb->can_set &&
171 ((NULL==cb->duplicate_row) || (NULL==cb->delete_row) ||
172 (NULL==cb->row_copy)) )) {
173 snmp_log(LOG_ERR, "table_array registration with incomplete "
174 "callback structure.\n");
175 return SNMPERR_GENERR;
178 if (NULL==container) {
179 tad->table = netsnmp_container_find("table_array");
180 if (NULL==container) {
181 snmp_log(LOG_ERR,"netsnmp_table_container_register couldn't find table\n");
182 return SNMPERR_GENERR;
185 else
186 tad->table = container;
187 if (NULL==container->compare)
188 container->compare = netsnmp_compare_netsnmp_index;
189 if (NULL==container->ncompare)
190 container->ncompare = netsnmp_ncompare_netsnmp_index;
192 tad->cb = cb;
194 reginfo->handler->myvoid = tad;
196 return netsnmp_register_table(reginfo, tabreg);
199 /** find the handler for the table_array helper. */
200 netsnmp_mib_handler *
201 netsnmp_find_table_array_handler(netsnmp_handler_registration *reginfo)
203 netsnmp_mib_handler *mh;
204 if (!reginfo)
205 return NULL;
206 mh = reginfo->handler;
207 while (mh) {
208 if (mh->access_method == netsnmp_table_array_helper_handler)
209 break;
210 mh = mh->next;
213 return mh;
216 /** find the context data used by the table_array helper */
217 netsnmp_container *
218 netsnmp_extract_array_context(netsnmp_request_info *request)
220 return netsnmp_request_get_list_data(request, TABLE_ARRAY_NAME);
223 /** this function is called to validate RowStatus transitions. */
225 netsnmp_table_array_check_row_status(netsnmp_table_array_callbacks *cb,
226 netsnmp_request_group *ag,
227 long *rs_new, long *rs_old)
229 netsnmp_index *row_ctx;
230 netsnmp_index *undo_ctx;
231 if (!ag || !cb)
232 return SNMPERR_GENERR;
233 row_ctx = ag->existing_row;
234 undo_ctx = ag->undo_info;
237 * xxx-rks: revisit row delete scenario
239 if (row_ctx) {
241 * either a new row, or change to old row.
242 * make sure new row-status is valid
244 if(!rs_new)
245 return SNMPERR_GENERR;
248 * new row without row status. shouldn't happen.
250 if(*rs_new == RS_NONEXISTENT)
251 return SNMP_ERR_INCONSISTENTVALUE;
254 * is it set to active?
256 if (RS_IS_GOING_ACTIVE(*rs_new)) {
258 * is it ready to be active?
260 if ((NULL==cb->can_activate) ||
261 cb->can_activate(undo_ctx, row_ctx, ag))
262 *rs_new = RS_ACTIVE;
263 else
264 return SNMP_ERR_INCONSISTENTVALUE;
265 } else {
267 * not going active
269 if (undo_ctx) {
271 * change
273 if (RS_IS_ACTIVE(*rs_old)) {
275 * check pre-reqs for deactivation
277 if (cb->can_deactivate &&
278 !cb->can_deactivate(undo_ctx, row_ctx, ag)) {
279 return SNMP_ERR_INCONSISTENTVALUE;
282 } else {
284 * new row
288 if (*rs_new != RS_DESTROY) {
289 if ((NULL==cb->can_activate) ||
290 cb->can_activate(undo_ctx, row_ctx, ag))
291 *rs_new = RS_NOTINSERVICE;
292 else
293 *rs_new = RS_NOTREADY;
294 } else {
295 if (cb->can_delete && !cb->can_delete(undo_ctx, row_ctx, ag)) {
296 return SNMP_ERR_INCONSISTENTVALUE;
298 ag->row_deleted = 1;
301 } else {
303 * check pre-reqs for delete row
305 if (cb->can_delete && !cb->can_delete(undo_ctx, row_ctx, ag)) {
306 return SNMP_ERR_INCONSISTENTVALUE;
310 return SNMP_ERR_NOERROR;
313 /** @} */
315 #ifndef DOXYGEN_SHOULD_SKIP_THIS
316 /**********************************************************************
317 **********************************************************************
318 **********************************************************************
319 **********************************************************************
324 * EVERYTHING BELOW THIS IS PRIVATE IMPLEMENTATION DETAILS. *
329 **********************************************************************
330 **********************************************************************
331 **********************************************************************
332 **********************************************************************/
334 /**********************************************************************
335 **********************************************************************
338 * Structures, Utility/convenience functions *
341 **********************************************************************
342 **********************************************************************/
344 * context info for SET requests
346 typedef struct set_context_s {
347 netsnmp_agent_request_info *agtreq_info;
348 table_container_data *tad;
349 int status;
350 } set_context;
352 static void
353 release_netsnmp_request_group(netsnmp_index *g, void *v)
355 netsnmp_request_group_item *tmp;
356 netsnmp_request_group *group = (netsnmp_request_group *) g;
358 if (!g)
359 return;
360 while (group->list) {
361 tmp = group->list;
362 group->list = tmp->next;
363 free(tmp);
366 free(group);
369 static void
370 release_netsnmp_request_groups(void *vp)
372 netsnmp_container *c = (netsnmp_container*)vp;
373 CONTAINER_FOR_EACH(c, (netsnmp_container_obj_func*)
374 release_netsnmp_request_group, NULL);
375 CONTAINER_FREE(c);
378 NETSNMP_INLINE netsnmp_index *
379 find_next_row(netsnmp_table_request_info *tblreq_info,
380 table_container_data * tad)
382 netsnmp_index *row = NULL;
383 netsnmp_index index;
385 if (!tblreq_info || !tad)
386 return NULL;
388 netsnmp_assert(NULL != tad->table);
391 * below our minimum column?
393 if (tblreq_info->colnum < tad->tblreg_info->min_column) {
394 tblreq_info->colnum = tad->tblreg_info->min_column;
395 row = CONTAINER_FIRST(tad->table);
396 } else {
397 index.oids = tblreq_info->index_oid;
398 index.len = tblreq_info->index_oid_len;
400 row = CONTAINER_NEXT(tad->table, &index);
403 * we don't have a row, but we might be at the end of a
404 * column, so try the next one.
406 if (!row) {
407 ++tblreq_info->colnum;
408 if (tad->tblreg_info->valid_columns) {
409 tblreq_info->colnum = netsnmp_closest_column
410 (tblreq_info->colnum, tad->tblreg_info->valid_columns);
411 } else if (tblreq_info->colnum > tad->tblreg_info->max_column)
412 tblreq_info->colnum = 0;
414 if (tblreq_info->colnum != 0)
415 row = CONTAINER_FIRST(tad->table);
419 return row;
422 NETSNMP_INLINE void
423 build_new_oid(netsnmp_handler_registration *reginfo,
424 netsnmp_table_request_info *tblreq_info,
425 netsnmp_index *row, netsnmp_request_info *current)
427 oid coloid[MAX_OID_LEN];
428 int coloid_len;
430 if (!tblreq_info || !reginfo || !row || !current)
431 return;
433 coloid_len = reginfo->rootoid_len + 2;
434 memcpy(coloid, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid));
436 /** table.entry */
437 coloid[reginfo->rootoid_len] = 1;
439 /** table.entry.column */
440 coloid[reginfo->rootoid_len + 1] = tblreq_info->colnum;
442 /** table.entry.column.index */
443 memcpy(&coloid[reginfo->rootoid_len + 2], row->oids,
444 row->len * sizeof(oid));
446 snmp_set_var_objid(current->requestvb, coloid,
447 reginfo->rootoid_len + 2 + row->len);
450 /**********************************************************************
451 **********************************************************************
454 * GET procession functions *
457 **********************************************************************
458 **********************************************************************/
459 NETSNMP_INLINE int
460 process_get_requests(netsnmp_handler_registration *reginfo,
461 netsnmp_agent_request_info *agtreq_info,
462 netsnmp_request_info *requests,
463 table_container_data * tad)
465 int rc = SNMP_ERR_NOERROR;
466 netsnmp_request_info *current;
467 netsnmp_index *row = NULL;
468 netsnmp_table_request_info *tblreq_info;
469 netsnmp_variable_list *var;
471 netsnmp_assert(NULL != tad->table);
474 * Loop through each of the requests, and
475 * try to find the appropriate row from the container.
477 for (current = requests; current; current = current->next) {
479 var = current->requestvb;
480 DEBUGMSGTL(("table_array:get",
481 " process_get_request oid:"));
482 DEBUGMSGOID(("table_array:get", var->name,
483 var->name_length));
484 DEBUGMSG(("table_array:get", "\n"));
487 * skip anything that doesn't need processing.
489 if (current->processed != 0) {
490 DEBUGMSGTL(("table_array:get", "already processed\n"));
491 continue;
495 * Get pointer to the table information for this request. This
496 * information was saved by table_helper_handler. When
497 * debugging, we double check a few assumptions. For example,
498 * the table_helper_handler should enforce column boundaries.
500 tblreq_info = netsnmp_extract_table_info(current);
501 netsnmp_assert(tblreq_info->colnum <= tad->tblreg_info->max_column);
503 if ((agtreq_info->mode == MODE_GETNEXT) ||
504 (agtreq_info->mode == MODE_GETBULK)) {
506 * find the row
508 row = find_next_row(tblreq_info, tad);
509 if (!row) {
511 * no results found.
513 * xxx-rks: how do we skip this entry for the next handler,
514 * but still allow it a chance to hit another handler?
516 DEBUGMSGTL(("table_array:get", "no row found\n"));
517 continue;
521 * * if data was found, make sure it has the column we want
523 /* xxx-rks: add suport for sparse tables */
526 * build new oid
528 build_new_oid(reginfo, tblreq_info, row, current);
530 } /** GETNEXT/GETBULK */
531 else {
532 netsnmp_index index;
533 index.oids = tblreq_info->index_oid;
534 index.len = tblreq_info->index_oid_len;
536 row = CONTAINER_FIND(tad->table, &index);
537 if (!row) {
538 DEBUGMSGTL(("table_array:get", "no row found\n"));
539 netsnmp_set_request_error(agtreq_info, current,
540 SNMP_NOSUCHINSTANCE);
541 continue;
543 } /** GET */
546 * get the data
548 rc = tad->cb->get_value(current, row, tblreq_info);
550 } /** for ( ... requests ... ) */
552 return rc;
555 /**********************************************************************
556 **********************************************************************
559 * SET procession functions *
562 **********************************************************************
563 **********************************************************************/
565 NETSNMP_INLINE void
566 group_requests(netsnmp_agent_request_info *agtreq_info,
567 netsnmp_request_info *requests,
568 netsnmp_container *request_group, table_container_data * tad)
570 netsnmp_table_request_info *tblreq_info;
571 netsnmp_variable_list *var;
572 netsnmp_index *row, *tmp, index;
573 netsnmp_request_info *current;
574 netsnmp_request_group *g;
575 netsnmp_request_group_item *i;
577 for (current = requests; current; current = current->next) {
579 var = current->requestvb;
582 * skip anything that doesn't need processing.
584 if (current->processed != 0) {
585 DEBUGMSGTL(("table_array:group",
586 "already processed\n"));
587 continue;
591 * 3.2.1 Setup and paranoia
593 * * Get pointer to the table information for this request. This
594 * * information was saved by table_helper_handler. When
595 * * debugging, we double check a few assumptions. For example,
596 * * the table_helper_handler should enforce column boundaries.
598 row = NULL;
599 tblreq_info = netsnmp_extract_table_info(current);
600 netsnmp_assert(tblreq_info->colnum <= tad->tblreg_info->max_column);
603 * search for index
605 index.oids = tblreq_info->index_oid;
606 index.len = tblreq_info->index_oid_len;
607 tmp = CONTAINER_FIND(request_group, &index);
608 if (tmp) {
609 DEBUGMSGTL(("table_array:group",
610 " existing group:"));
611 DEBUGMSGOID(("table_array:group", index.oids,
612 index.len));
613 DEBUGMSG(("table_array:group", "\n"));
614 g = (netsnmp_request_group *) tmp;
615 i = SNMP_MALLOC_TYPEDEF(netsnmp_request_group_item);
616 i->ri = current;
617 i->tri = tblreq_info;
618 i->next = g->list;
619 g->list = i;
621 /** xxx-rks: store map of colnum to request */
622 continue;
625 DEBUGMSGTL(("table_array:group", " new group"));
626 DEBUGMSGOID(("table_array:group", index.oids,
627 index.len));
628 DEBUGMSG(("table_array:group", "\n"));
629 g = SNMP_MALLOC_TYPEDEF(netsnmp_request_group);
630 i = SNMP_MALLOC_TYPEDEF(netsnmp_request_group_item);
631 g->list = i;
632 g->table = tad->table;
633 i->ri = current;
634 i->tri = tblreq_info;
635 /** xxx-rks: store map of colnum to request */
638 * search for row. all changes are made to the original row,
639 * later, we'll make a copy in undo_info before we start processing.
641 row = g->existing_row = CONTAINER_FIND(tad->table, &index);
642 if (!g->existing_row) {
643 if (!tad->cb->create_row) {
644 if(MODE_IS_SET(agtreq_info->mode))
645 netsnmp_set_request_error(agtreq_info, current,
646 SNMP_ERR_NOTWRITABLE);
647 else
648 netsnmp_set_request_error(agtreq_info, current,
649 SNMP_NOSUCHINSTANCE);
650 free(g);
651 free(i);
652 continue;
654 /** use undo_info temporarily */
655 row = g->existing_row = tad->cb->create_row(&index);
656 if (!row) {
657 /* xxx-rks : parameter to create_row to allow
658 * for better error reporting. */
659 netsnmp_set_request_error(agtreq_info, current,
660 SNMP_ERR_GENERR);
661 free(g);
662 free(i);
663 continue;
665 g->row_created = 1;
668 g->index.oids = row->oids;
669 g->index.len = row->len;
671 CONTAINER_INSERT(request_group, g);
673 } /** for( current ... ) */
676 static NETSNMP_INLINE void
677 process_set_group(netsnmp_index *o, void *c)
679 /* xxx-rks: should we continue processing after an error?? */
680 set_context *context = (set_context *) c;
681 netsnmp_request_group *ag = (netsnmp_request_group *) o;
682 int rc = SNMP_ERR_NOERROR;
684 switch (context->agtreq_info->mode) {
686 case MODE_SET_RESERVE1:/** -> SET_RESERVE2 || SET_FREE */
689 * if not a new row, save undo info
691 if (ag->row_created == 0) {
692 ag->undo_info = context->tad->cb->duplicate_row(ag->existing_row);
693 if (NULL == ag->undo_info) {
694 rc = SNMP_ERR_RESOURCEUNAVAILABLE;
695 break;
699 if (context->tad->cb->set_reserve1)
700 context->tad->cb->set_reserve1(ag);
701 break;
703 case MODE_SET_RESERVE2:/** -> SET_ACTION || SET_FREE */
704 if (context->tad->cb->set_reserve2)
705 context->tad->cb->set_reserve2(ag);
706 break;
708 case MODE_SET_ACTION:/** -> SET_COMMIT || SET_UNDO */
709 if (context->tad->cb->set_action)
710 context->tad->cb->set_action(ag);
711 break;
713 case MODE_SET_COMMIT:/** FINAL CHANCE ON SUCCESS */
714 if (ag->row_created == 0) {
716 * this is an existing row, has it been deleted?
718 if (ag->row_deleted == 1) {
719 DEBUGMSGT((TABLE_ARRAY_NAME, "action: deleting row\n"));
720 if (CONTAINER_REMOVE(ag->table, ag->existing_row) != 0) {
721 rc = SNMP_ERR_COMMITFAILED;
722 break;
725 } else if (ag->row_deleted == 0) {
727 * new row (that hasn't been deleted) should be inserted
729 DEBUGMSGT((TABLE_ARRAY_NAME, "action: inserting row\n"));
730 if (CONTAINER_INSERT(ag->table, ag->existing_row) != 0) {
731 rc = SNMP_ERR_COMMITFAILED;
732 break;
736 if (context->tad->cb->set_commit)
737 context->tad->cb->set_commit(ag);
739 /** no more use for undo_info, so free it */
740 if (ag->undo_info) {
741 context->tad->cb->delete_row(ag->undo_info);
742 ag->undo_info = NULL;
744 break;
746 case MODE_SET_FREE:/** FINAL CHANCE ON FAILURE of RESERVE1 or RESERVE2 */
747 if (context->tad->cb->set_free)
748 context->tad->cb->set_free(ag);
750 /** no more use for undo_info, so free it */
751 if (ag->undo_info) {
752 context->tad->cb->delete_row(ag->undo_info);
753 ag->undo_info = NULL;
755 break;
757 case MODE_SET_UNDO:/** FINAL CHANCE ON FAILURE of ACTION */
758 if (ag->row_created == 0) {
760 * this row existed before.
762 if (ag->row_deleted == 1) {
764 * re-insert undo_info
766 DEBUGMSGT((TABLE_ARRAY_NAME, "undo: re-inserting row\n"));
767 if (CONTAINER_INSERT(ag->table, ag->existing_row) != 0) {
768 rc = SNMP_ERR_UNDOFAILED;
769 break;
772 } else if (ag->row_deleted == 0) {
774 * new row that wasn't deleted should be removed
776 DEBUGMSGT((TABLE_ARRAY_NAME, "undo: removing new row\n"));
777 if (CONTAINER_REMOVE(ag->table, ag->existing_row) != 0) {
778 rc = SNMP_ERR_UNDOFAILED;
779 break;
784 * status already set - don't change it now
786 if (context->tad->cb->set_undo)
787 context->tad->cb->set_undo(ag);
790 * no more use for undo_info, so free it
792 if (ag->row_created == 0) {
794 * restore old values
796 context->tad->cb->row_copy(ag->existing_row, ag->undo_info);
797 context->tad->cb->delete_row(ag->undo_info);
798 ag->undo_info = NULL;
800 else {
801 context->tad->cb->delete_row(ag->existing_row);
802 ag->existing_row = NULL;
804 break;
806 default:
807 snmp_log(LOG_ERR, "unknown mode processing SET for "
808 "netsnmp_table_array_helper_handler\n");
809 rc = SNMP_ERR_GENERR;
810 break;
813 if (rc)
814 netsnmp_set_request_error(context->agtreq_info,
815 ag->list->ri, rc);
820 process_set_requests(netsnmp_agent_request_info *agtreq_info,
821 netsnmp_request_info *requests,
822 table_container_data * tad, char *handler_name)
824 set_context context;
825 netsnmp_container *request_group;
828 * create and save structure for set info
830 request_group = (netsnmp_container*) netsnmp_agent_get_list_data
831 (agtreq_info, handler_name);
832 if (request_group == NULL) {
833 netsnmp_data_list *tmp;
834 request_group = netsnmp_container_find("request_group:"
835 "table_container");
836 request_group->compare = netsnmp_compare_netsnmp_index;
837 request_group->ncompare = netsnmp_ncompare_netsnmp_index;
839 DEBUGMSGTL(("table_array", "Grouping requests by oid\n"));
841 tmp = netsnmp_create_data_list(handler_name,
842 request_group,
843 release_netsnmp_request_groups);
844 netsnmp_agent_add_list_data(agtreq_info, tmp);
846 * group requests.
848 group_requests(agtreq_info, requests, request_group, tad);
852 * process each group one at a time
854 context.agtreq_info = agtreq_info;
855 context.tad = tad;
856 context.status = SNMP_ERR_NOERROR;
857 CONTAINER_FOR_EACH(request_group,
858 (netsnmp_container_obj_func*)process_set_group,
859 &context);
861 return context.status;
865 /**********************************************************************
866 **********************************************************************
869 * netsnmp_table_array_helper_handler() *
872 **********************************************************************
873 **********************************************************************/
875 netsnmp_table_array_helper_handler(netsnmp_mib_handler *handler,
876 netsnmp_handler_registration *reginfo,
877 netsnmp_agent_request_info *agtreq_info,
878 netsnmp_request_info *requests)
882 * First off, get our pointer from the handler. This
883 * lets us get to the table registration information we
884 * saved in get_table_array_handler(), as well as the
885 * container where the actual table data is stored.
887 int rc = SNMP_ERR_NOERROR;
888 table_container_data *tad = (table_container_data *)handler->myvoid;
890 if((NULL == tad) || (NULL == tad->table)) {
891 snmp_log(LOG_ERR,"process_get_requests called without a table\n");
892 return SNMP_ERR_GENERR;
895 if (agtreq_info->mode < 0 || agtreq_info->mode > 5) {
896 DEBUGMSGTL(("table_array", "Mode %d, Got request:\n",
897 agtreq_info->mode));
898 } else {
899 DEBUGMSGTL(("table_array", "Mode %s, Got request:\n",
900 mode_name[agtreq_info->mode]));
903 if (MODE_IS_SET(agtreq_info->mode)) {
905 * netsnmp_mutex_lock(&tad->lock);
907 rc = process_set_requests(agtreq_info, requests,
908 tad, handler->handler_name);
910 * netsnmp_mutex_unlock(&tad->lock);
912 } else
913 rc = process_get_requests(reginfo, agtreq_info, requests, tad);
915 if (rc != SNMP_ERR_NOERROR) {
916 DEBUGMSGTL(("table_array", "processing returned rc %d\n", rc));
920 * Now we've done out processing. If there is another handler below us,
921 * call them.
923 if (handler->next) {
924 rc = netsnmp_call_next_handler(handler, reginfo, agtreq_info, requests);
925 if (rc != SNMP_ERR_NOERROR) {
926 DEBUGMSGTL(("table_array", "next handler returned rc %d\n", rc));
930 return rc;
932 #endif /** DOXYGEN_SHOULD_SKIP_THIS */