3 * $Id: table_array.c,v 1.1.2.1 2004/06/20 21:54:11 nikki Exp $
6 #include <net-snmp/net-snmp-config.h>
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>
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
[] = {
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
;
60 /** do we want to group rows with the same index
61 * together when calling callbacks? */
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.
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
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
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.
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
,
158 table_container_data
*tad
= SNMP_MALLOC_TYPEDEF(table_container_data
);
160 return SNMPERR_GENERR
;
161 tad
->tblreg_info
= tabreg
; /* we need it too, but it really is not ours */
164 snmp_log(LOG_ERR
, "table_array registration with no callbacks\n" );
165 return SNMPERR_GENERR
;
168 * check for required callbacks
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
;
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
;
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
;
206 mh
= reginfo
->handler
;
208 if (mh
->access_method
== netsnmp_table_array_helper_handler
)
216 /** find the context data used by the table_array helper */
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
;
232 return SNMPERR_GENERR
;
233 row_ctx
= ag
->existing_row
;
234 undo_ctx
= ag
->undo_info
;
237 * xxx-rks: revisit row delete scenario
241 * either a new row, or change to old row.
242 * make sure new row-status is valid
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
))
264 return SNMP_ERR_INCONSISTENTVALUE
;
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
;
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
;
293 *rs_new
= RS_NOTREADY
;
295 if (cb
->can_delete
&& !cb
->can_delete(undo_ctx
, row_ctx
, ag
)) {
296 return SNMP_ERR_INCONSISTENTVALUE
;
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
;
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
;
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
;
360 while (group
->list
) {
362 group
->list
= tmp
->next
;
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
);
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
;
385 if (!tblreq_info
|| !tad
)
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
);
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.
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
);
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
];
430 if (!tblreq_info
|| !reginfo
|| !row
|| !current
)
433 coloid_len
= reginfo
->rootoid_len
+ 2;
434 memcpy(coloid
, reginfo
->rootoid
, reginfo
->rootoid_len
* sizeof(oid
));
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 **********************************************************************/
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
,
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"));
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
)) {
508 row
= find_next_row(tblreq_info
, tad
);
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"));
521 * * if data was found, make sure it has the column we want
523 /* xxx-rks: add suport for sparse tables */
528 build_new_oid(reginfo
, tblreq_info
, row
, current
);
530 } /** GETNEXT/GETBULK */
533 index
.oids
= tblreq_info
->index_oid
;
534 index
.len
= tblreq_info
->index_oid_len
;
536 row
= CONTAINER_FIND(tad
->table
, &index
);
538 DEBUGMSGTL(("table_array:get", "no row found\n"));
539 netsnmp_set_request_error(agtreq_info
, current
,
540 SNMP_NOSUCHINSTANCE
);
548 rc
= tad
->cb
->get_value(current
, row
, tblreq_info
);
550 } /** for ( ... requests ... ) */
555 /**********************************************************************
556 **********************************************************************
559 * SET procession functions *
562 **********************************************************************
563 **********************************************************************/
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"));
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.
599 tblreq_info
= netsnmp_extract_table_info(current
);
600 netsnmp_assert(tblreq_info
->colnum
<= tad
->tblreg_info
->max_column
);
605 index
.oids
= tblreq_info
->index_oid
;
606 index
.len
= tblreq_info
->index_oid_len
;
607 tmp
= CONTAINER_FIND(request_group
, &index
);
609 DEBUGMSGTL(("table_array:group",
610 " existing group:"));
611 DEBUGMSGOID(("table_array:group", index
.oids
,
613 DEBUGMSG(("table_array:group", "\n"));
614 g
= (netsnmp_request_group
*) tmp
;
615 i
= SNMP_MALLOC_TYPEDEF(netsnmp_request_group_item
);
617 i
->tri
= tblreq_info
;
621 /** xxx-rks: store map of colnum to request */
625 DEBUGMSGTL(("table_array:group", " new group"));
626 DEBUGMSGOID(("table_array:group", index
.oids
,
628 DEBUGMSG(("table_array:group", "\n"));
629 g
= SNMP_MALLOC_TYPEDEF(netsnmp_request_group
);
630 i
= SNMP_MALLOC_TYPEDEF(netsnmp_request_group_item
);
632 g
->table
= tad
->table
;
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
);
648 netsnmp_set_request_error(agtreq_info
, current
,
649 SNMP_NOSUCHINSTANCE
);
654 /** use undo_info temporarily */
655 row
= g
->existing_row
= tad
->cb
->create_row(&index
);
657 /* xxx-rks : parameter to create_row to allow
658 * for better error reporting. */
659 netsnmp_set_request_error(agtreq_info
, current
,
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
;
699 if (context
->tad
->cb
->set_reserve1
)
700 context
->tad
->cb
->set_reserve1(ag
);
703 case MODE_SET_RESERVE2
:/** -> SET_ACTION || SET_FREE */
704 if (context
->tad
->cb
->set_reserve2
)
705 context
->tad
->cb
->set_reserve2(ag
);
708 case MODE_SET_ACTION
:/** -> SET_COMMIT || SET_UNDO */
709 if (context
->tad
->cb
->set_action
)
710 context
->tad
->cb
->set_action(ag
);
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
;
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
;
736 if (context
->tad
->cb
->set_commit
)
737 context
->tad
->cb
->set_commit(ag
);
739 /** no more use for undo_info, so free it */
741 context
->tad
->cb
->delete_row(ag
->undo_info
);
742 ag
->undo_info
= NULL
;
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 */
752 context
->tad
->cb
->delete_row(ag
->undo_info
);
753 ag
->undo_info
= NULL
;
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
;
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
;
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) {
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
;
801 context
->tad
->cb
->delete_row(ag
->existing_row
);
802 ag
->existing_row
= NULL
;
807 snmp_log(LOG_ERR
, "unknown mode processing SET for "
808 "netsnmp_table_array_helper_handler\n");
809 rc
= SNMP_ERR_GENERR
;
814 netsnmp_set_request_error(context
->agtreq_info
,
820 process_set_requests(netsnmp_agent_request_info
*agtreq_info
,
821 netsnmp_request_info
*requests
,
822 table_container_data
* tad
, char *handler_name
)
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:"
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
,
843 release_netsnmp_request_groups
);
844 netsnmp_agent_add_list_data(agtreq_info
, tmp
);
848 group_requests(agtreq_info
, requests
, request_group
, tad
);
852 * process each group one at a time
854 context
.agtreq_info
= agtreq_info
;
856 context
.status
= SNMP_ERR_NOERROR
;
857 CONTAINER_FOR_EACH(request_group
,
858 (netsnmp_container_obj_func
*)process_set_group
,
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",
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);
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,
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
));
932 #endif /** DOXYGEN_SHOULD_SKIP_THIS */