85
85
#include <net-snmp/net-snmp-config.h>
87
#include <net-snmp/net-snmp-features.h>
88
#include <net-snmp/net-snmp-includes.h>
89
#include <net-snmp/agent/net-snmp-agent-includes.h>
91
#include <net-snmp/agent/table_iterator.h>
88
94
#include <string.h>
90
96
#include <strings.h>
93
#include <net-snmp/net-snmp-includes.h>
94
#include <net-snmp/agent/net-snmp-agent-includes.h>
96
99
#include <net-snmp/agent/table.h>
97
100
#include <net-snmp/agent/serialize.h>
98
#include <net-snmp/agent/table_iterator.h>
99
101
#include <net-snmp/agent/stash_cache.h>
103
netsnmp_feature_child_of(table_iterator_all, mib_helpers)
105
netsnmp_feature_child_of(table_iterator_insert_context, table_iterator_all)
106
netsnmp_feature_child_of(table_iterator_create_table, table_iterator_all)
107
netsnmp_feature_child_of(table_iterator_row_first, table_iterator_all)
108
netsnmp_feature_child_of(table_iterator_row_count, table_iterator_all)
110
#ifdef NETSNMP_FEATURE_REQUIRE_STASH_CACHE
111
netsnmp_feature_require(data_list_get_list_node)
112
netsnmp_feature_require(oid_stash_add_data)
113
#endif /* NETSNMP_FEATURE_REQUIRE_STASH_CACHE */
101
115
/* ==================================
103
117
* Iterator API: Table maintenance
117
131
* Time will show whether this is a sensible approach or not.
133
#ifndef NETSNMP_FEATURE_REMOVE_TABLE_ITERATOR_CREATE_TABLE
119
134
netsnmp_iterator_info *
120
135
netsnmp_iterator_create_table( Netsnmp_First_Data_Point *firstDP,
121
136
Netsnmp_Next_Data_Point *nextDP,
165
183
* ================================== */
167
/** returns a netsnmp_mib_handler object for the table_iterator helper */
185
static netsnmp_iterator_info *
186
netsnmp_iterator_ref(netsnmp_iterator_info *iinfo)
193
netsnmp_iterator_deref(netsnmp_iterator_info *iinfo)
195
if (--iinfo->refcnt == 0)
196
netsnmp_iterator_delete_table(iinfo);
199
void netsnmp_handler_owns_iterator_info(netsnmp_mib_handler *h)
202
netsnmp_assert(h->myvoid);
203
((netsnmp_iterator_info *)(h->myvoid))->refcnt++;
204
h->data_clone = (void *(*)(void *))netsnmp_iterator_ref;
205
h->data_free = (void(*)(void *))netsnmp_iterator_deref;
209
* Returns a netsnmp_mib_handler object for the table_iterator helper.
211
* The caller remains the owner of the iterator information object if
212
* the flag NETSNMP_HANDLER_OWNS_IINFO has not been set, and the created
213
* handler becomes the owner of the iterator information if the flag
214
* NETSNMP_HANDLER_OWNS_IINFO has been set.
168
216
netsnmp_mib_handler *
169
217
netsnmp_get_table_iterator_handler(netsnmp_iterator_info *iinfo)
195
245
* @param reginfo is a pointer to a netsnmp_handler_registration struct
197
* @param iinfo is a pointer to a netsnmp_iterator_info struct
247
* @param iinfo A pointer to a netsnmp_iterator_info struct. If the flag
248
* NETSNMP_HANDLER_OWNS_IINFO is not set in iinfo->flags, the caller remains
249
* the owner of this structure. And if the flag NETSNMP_HANDLER_OWNS_IINFO is
250
* set in iinfo->flags, ownership of this data structure is passed to the
199
253
* @return MIB_REGISTERED_OK is returned if the registration was a success.
200
254
* Failures are MIB_REGISTRATION_FAILED, MIB_DUPLICATE_REGISTRATION.
205
259
netsnmp_register_table_iterator(netsnmp_handler_registration *reginfo,
206
260
netsnmp_iterator_info *iinfo)
262
#ifndef NETSNMP_FEATURE_REMOVE_STASH_CACHE
208
263
reginfo->modes |= HANDLER_CAN_STASH;
264
#endif /* NETSNMP_FEATURE_REMOVE_STASH_CACHE */
209
265
netsnmp_inject_handler(reginfo,
210
266
netsnmp_get_table_iterator_handler(iinfo));
236
292
return netsnmp_request_get_list_data(request, TABLE_ITERATOR_NAME);
295
#ifndef NETSNMP_FEATURE_REMOVE_TABLE_ITERATOR_INSERT_CONTEXT
239
296
/** inserts table_iterator specific data for a newly
240
297
* created row into a request */
241
298
NETSNMP_INLINE void
316
374
netsnmp_free_ti_cache(void *it) {
317
ti_cache_info *beer = it;
375
ti_cache_info *beer = (ti_cache_info*)it;
319
377
if (beer->data_context && beer->free_context) {
320
378
(beer->free_context)(beer->data_context, beer->iinfo);
342
400
/* extract existing cached state */
343
ti_info = netsnmp_request_get_list_data(request, TI_REQUEST_CACHE);
401
ti_info = (ti_cache_info*)netsnmp_request_get_list_data(request, TI_REQUEST_CACHE);
345
403
/* no existing cached state. make a new one. */
347
405
ti_info = SNMP_MALLOC_TYPEDEF(ti_cache_info);
348
408
netsnmp_request_add_list_data(request,
349
409
netsnmp_create_data_list
350
410
(TI_REQUEST_CACHE,
400
460
void *callback_data_context = NULL;
401
461
ti_cache_info *ti_info = NULL;
402
462
int request_count = 0;
463
#ifndef NETSNMP_FEATURE_REMOVE_STASH_CACHE
403
464
netsnmp_oid_stash_node **cinfo = NULL;
404
465
netsnmp_variable_list *old_indexes = NULL, *vb;
405
466
netsnmp_table_registration_info *table_reg_info = NULL;
407
468
netsnmp_data_list *ldata = NULL;
469
#endif /* NETSNMP_FEATURE_REMOVE_STASH_CACHE */
409
471
iinfo = (netsnmp_iterator_info *) handler->myvoid;
410
472
if (!iinfo || !reginfo || !reqinfo)
411
return SNMPERR_GENERR;
473
return SNMP_ERR_GENERR;
413
475
tbl_info = iinfo->table_reginfo;
432
494
/* preliminary analysis */
433
495
switch (reqinfo->mode) {
496
#ifndef NETSNMP_FEATURE_REMOVE_STASH_CACHE
434
497
case MODE_GET_STASH:
435
498
cinfo = netsnmp_extract_stash_cache(reqinfo);
436
499
table_reg_info = netsnmp_find_table_registration_info(reginfo);
438
501
/* XXX: move this malloc to stash_cache handler? */
439
502
reqtmp = SNMP_MALLOC_TYPEDEF(netsnmp_request_info);
504
return SNMP_ERR_GENERR;
440
505
reqtmp->subtree = requests->subtree;
441
506
table_info = netsnmp_extract_table_info(requests);
442
507
netsnmp_request_add_list_data(reqtmp,
447
512
/* remember the indexes that were originally parsed. */
448
513
old_indexes = table_info->indexes;
515
#endif /* NETSNMP_FEATURE_REMOVE_STASH_CACHE */
451
517
case MODE_GETNEXT:
452
518
for(request = requests ; request; request = request->next) {
453
519
if (request->processed)
455
521
table_info = netsnmp_extract_table_info(request);
522
if (table_info == NULL) {
526
if (free_this_index_search)
527
snmp_free_varbind(free_this_index_search);
528
return SNMP_ERR_GENERR;
456
530
if (table_info->colnum < tbl_info->min_column - 1) {
457
531
/* XXX: optimize better than this */
458
532
/* for now, just increase to colnum-1 */
463
537
request->processed = TABLE_ITERATOR_NOTAGAIN;
540
ti_info = (ti_cache_info*)
467
541
netsnmp_request_get_list_data(request, TI_REQUEST_CACHE);
469
543
ti_info = SNMP_MALLOC_TYPEDEF(ti_cache_info);
544
if (ti_info == NULL) {
548
if (free_this_index_search)
549
snmp_free_varbind(free_this_index_search);
550
return SNMP_ERR_GENERR;
470
552
netsnmp_request_add_list_data(request,
471
553
netsnmp_create_data_list
472
554
(TI_REQUEST_CACHE,
485
567
if (reqinfo->mode == MODE_GET ||
486
568
reqinfo->mode == MODE_GETNEXT ||
487
reqinfo->mode == MODE_GET_STASH ||
488
reqinfo->mode == MODE_SET_RESERVE1) {
569
reqinfo->mode == MODE_GET_STASH
570
#ifndef NETSNMP_NO_WRITE_SUPPORT
571
|| reqinfo->mode == MODE_SET_RESERVE1
572
#endif /* NETSNMP_NO_WRITE_SUPPORT */
490
575
* Count the number of request in the list,
491
576
* so that we'll know when we're finished
555
640
if (request->processed)
558
/* XXX: store in an array for faster retrival */
643
/* XXX: store in an array for faster retrieval */
559
644
table_info = netsnmp_extract_table_info(request);
645
if (table_info == NULL) {
649
if (free_this_index_search)
650
snmp_free_varbind(free_this_index_search);
651
netsnmp_free_request_data_sets(reqtmp);
653
return SNMP_ERR_GENERR;
560
655
coloid[reginfo->rootoid_len + 1] = table_info->colnum;
657
ti_info = (ti_cache_info*)
563
658
netsnmp_request_get_list_data(request, TI_REQUEST_CACHE);
565
660
switch(reqinfo->mode) {
662
#ifndef NETSNMP_NO_WRITE_SUPPORT
567
663
case MODE_SET_RESERVE1:
664
#endif /* NETSNMP_NO_WRITE_SUPPORT */
568
665
/* looking for exact matches */
569
666
build_oid_noalloc(myname, MAX_OID_LEN, &myname_len,
570
667
coloid, coloid_len, index_search);
571
668
if (snmp_oid_compare(myname, myname_len,
572
669
request->requestvb->name,
573
670
request->requestvb->name_length) == 0) {
575
netsnmp_iterator_remember(request,
577
callback_data_context,
578
callback_loop_context, iinfo);
674
if (netsnmp_iterator_remember(request,
677
callback_data_context,
678
callback_loop_context,
683
if (free_this_index_search)
685
(free_this_index_search);
686
netsnmp_free_request_data_sets(reqtmp);
688
return SNMP_ERR_GENERR;
579
690
request_count--; /* One less to look for */
581
692
if (iinfo->free_data_context && callback_data_context) {
699
#ifndef NETSNMP_FEATURE_REMOVE_STASH_CACHE
588
700
case MODE_GET_STASH:
589
701
/* collect data for each column for every row */
590
702
build_oid_noalloc(myname, MAX_OID_LEN, &myname_len,
612
724
table_info->colnum = i;
613
725
vb = reqtmp->requestvb =
614
726
SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
731
if (free_this_index_search)
733
(free_this_index_search);
734
return SNMP_ERR_GENERR;
615
736
vb->type = ASN_NULL;
616
737
snmp_set_var_objid(vb, myname, myname_len);
617
738
netsnmp_call_next_handler(handler, reginfo,
628
749
reqinfo->mode = MODE_GET_STASH;
751
#endif /* NETSNMP_FEATURE_REMOVE_STASH_CACHE */
631
753
case MODE_GETNEXT:
632
754
/* looking for "next" matches */
633
755
if (netsnmp_check_getnext_reply
634
756
(request, coloid, coloid_len, index_search,
635
757
&ti_info->results)) {
636
netsnmp_iterator_remember(request,
637
ti_info->results->name,
638
ti_info->results->name_length,
639
callback_data_context,
640
callback_loop_context, iinfo);
758
if (netsnmp_iterator_remember(request,
764
callback_data_context,
765
callback_loop_context,
770
if (free_this_index_search)
772
(free_this_index_search);
773
return SNMP_ERR_GENERR;
642
776
* If we've been told that the rows are sorted,
643
777
* then the first valid one we find
724
860
if (reqinfo->mode == MODE_GET ||
725
reqinfo->mode == MODE_GETNEXT ||
726
reqinfo->mode == MODE_SET_RESERVE1) {
861
reqinfo->mode == MODE_GETNEXT
862
#ifndef NETSNMP_NO_WRITE_SUPPORT
863
|| reqinfo->mode == MODE_SET_RESERVE1
864
#endif /* NETSNMP_NO_WRITE_SUPPORT */
727
866
/* per request last minute processing */
728
867
for(request = requests ; request; request = request->next) {
729
868
if (request->processed)
870
ti_info = (ti_cache_info*)
732
871
netsnmp_request_get_list_data(request, TI_REQUEST_CACHE);
734
873
netsnmp_extract_table_info(request);
759
898
/* FALL THROUGH */
901
#ifndef NETSNMP_NO_WRITE_SUPPORT
762
902
case MODE_SET_RESERVE1:
903
#endif /* NETSNMP_NO_WRITE_SUPPORT */
763
904
if (ti_info->data_context)
764
905
/* we don't add a free pointer, since it's in the
765
906
TI_REQUEST_CACHE instead */
782
923
if (reqinfo->mode == MODE_GETNEXT) {
783
924
reqinfo->mode = MODE_GET;
926
#ifndef NETSNMP_FEATURE_REMOVE_STASH_CACHE
785
927
} else if (reqinfo->mode == MODE_GET_STASH) {
786
928
netsnmp_free_request_data_sets(reqtmp);
787
929
SNMP_FREE(reqtmp);
788
930
table_info->indexes = old_indexes;
931
#endif /* NETSNMP_FEATURE_REMOVE_STASH_CACHE */
817
960
* ================================== */
962
#ifndef NETSNMP_FEATURE_REMOVE_TABLE_ITERATOR_ROW_FIRST
820
964
netsnmp_iterator_row_first( netsnmp_iterator_info *iinfo ) {
821
965
netsnmp_variable_list *vp1, *vp2;
834
978
snmp_free_varbind( vp1 );
835
979
return ctx2; /* or *ctx2 ?? */
981
#endif /* NETSNMP_FEATURE_REMOVE_TABLE_ITERATOR_ROW_FIRST */
839
984
netsnmp_iterator_row_get( netsnmp_iterator_info *iinfo, void *row )
946
1091
vp1 = snmp_clone_varbind(iinfo->indexes);
947
1092
vp2 = iinfo->get_first_data_point( &ctx1, &ctx2, vp1, iinfo );
948
DEBUGMSGTL(("table:iterator:get", "first DP: %x %x %x\n",
1093
DEBUGMSGTL(("table:iterator:get", "first DP: %p %p %p\n",
949
1094
ctx1, ctx2, vp2));
951
1096
/* XXX - free context ? */
966
1111
vp2 = iinfo->get_next_data_point( &ctx1, &ctx2, vp2, iinfo );
967
DEBUGMSGTL(("table:iterator:get", "next DP: %x %x %x\n",
1112
DEBUGMSGTL(("table:iterator:get", "next DP: %p %p %p\n",
968
1113
ctx1, ctx2, vp2));
969
1114
/* XXX - free context ? */
995
1140
vp1 = snmp_clone_varbind(iinfo->indexes);
996
1141
vp2 = iinfo->get_first_data_point( &ctx1, &ctx2, vp1, iinfo );
997
DEBUGMSGTL(("table:iterator:get", "first DP: %x %x %x\n",
1142
DEBUGMSGTL(("table:iterator:get", "first DP: %p %p %p\n",
998
1143
ctx1, ctx2, vp2));
1000
1145
if ( !instance || !len ) {
1033
1178
vp2 = iinfo->get_next_data_point( &ctx1, &ctx2, vp2, iinfo );
1034
DEBUGMSGTL(("table:iterator:get", "next DP: %x %x %x\n",
1179
DEBUGMSGTL(("table:iterator:get", "next DP: %p %p %p\n",
1035
1180
ctx1, ctx2, vp2));
1036
1181
/* XXX - free context ? */
1063
DEBUGMSGTL(("table:iterator:count", "first DP: %x %x %x\n",
1209
DEBUGMSGTL(("table:iterator:count", "first DP: %p %p %p\n",
1064
1210
ctx1, ctx2, vp2));
1066
1212
/* XXX - free context ? */
1070
1216
vp2 = iinfo->get_next_data_point( &ctx1, &ctx2, vp2, iinfo );
1071
DEBUGMSGTL(("table:iterator:count", "next DP: %x %x %x (%d)\n",
1217
DEBUGMSGTL(("table:iterator:count", "next DP: %p %p %p (%d)\n",
1072
1218
ctx1, ctx2, vp2, i));
1073
1219
/* XXX - free context ? */