net-snmp 5.7
table_container.c
00001 /*
00002  * table_container.c
00003  * $Id$
00004  */
00005 
00006 #include <net-snmp/net-snmp-config.h>
00007 #include <net-snmp/net-snmp-features.h>
00008 
00009 #include <net-snmp/net-snmp-includes.h>
00010 #include <net-snmp/agent/net-snmp-agent-includes.h>
00011 
00012 #include <net-snmp/agent/table_container.h>
00013 
00014 #if HAVE_STRING_H
00015 #include <string.h>
00016 #else
00017 #include <strings.h>
00018 #endif
00019 
00020 #include <net-snmp/agent/table.h>
00021 #include <net-snmp/library/container.h>
00022 #include <net-snmp/library/snmp_assert.h>
00023 
00024 netsnmp_feature_provide(table_container)
00025 netsnmp_feature_child_of(table_container, table_container_all)
00026 netsnmp_feature_child_of(table_container_replace_row, table_container_all)
00027 netsnmp_feature_child_of(table_container_extract, table_container_all)
00028 netsnmp_feature_child_of(table_container_management, table_container_all)
00029 netsnmp_feature_child_of(table_container_row_remove, table_container_all)
00030 netsnmp_feature_child_of(table_container_row_insert, table_container_all)
00031 netsnmp_feature_child_of(table_container_all, mib_helpers)
00032 
00033 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER
00034 
00035 /*
00036  * snmp.h:#define SNMP_MSG_INTERNAL_SET_BEGIN        -1 
00037  * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE1     0 
00038  * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE2     1 
00039  * snmp.h:#define SNMP_MSG_INTERNAL_SET_ACTION       2 
00040  * snmp.h:#define SNMP_MSG_INTERNAL_SET_COMMIT       3 
00041  * snmp.h:#define SNMP_MSG_INTERNAL_SET_FREE         4 
00042  * snmp.h:#define SNMP_MSG_INTERNAL_SET_UNDO         5 
00043  */
00044 
00045 /*
00046  * PRIVATE structure for holding important info for each table.
00047  */
00048 typedef struct container_table_data_s {
00049 
00051     int refcnt;
00052 
00054     netsnmp_table_registration_info *tblreg_info;
00055 
00057    netsnmp_container          *table;
00058 
00059     /*
00060      * mutex_type                lock;
00061      */
00062 
00063    /* what type of key do we want? */
00064    char            key_type;
00065 
00066 } container_table_data;
00067 
00151 static int
00152 _container_table_handler(netsnmp_mib_handler *handler,
00153                          netsnmp_handler_registration *reginfo,
00154                          netsnmp_agent_request_info *agtreq_info,
00155                          netsnmp_request_info *requests);
00156 
00157 static void *
00158 _find_next_row(netsnmp_container *c,
00159                netsnmp_table_request_info *tblreq,
00160                void * key);
00161 
00162 /**********************************************************************
00163  **********************************************************************
00164  *                                                                    *
00165  *                                                                    *
00166  * PUBLIC Registration functions                                      *
00167  *                                                                    *
00168  *                                                                    *
00169  **********************************************************************
00170  **********************************************************************/
00171 
00172 /* ==================================
00173  *
00174  * Container Table API: Table maintenance
00175  *
00176  * ================================== */
00177 
00178 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER_MANAGEMENT
00179 container_table_data *
00180 netsnmp_tcontainer_create_table( const char *name,
00181                                  netsnmp_container *container, long flags )
00182 {
00183     container_table_data *table;
00184 
00185     table = SNMP_MALLOC_TYPEDEF(container_table_data);
00186     if (!table)
00187         return NULL;
00188     if (container)
00189         table->table = container;
00190     else {
00191         table->table = netsnmp_container_find("table_container");
00192         if (!table->table) {
00193             SNMP_FREE(table);
00194             return NULL;
00195         }
00196     }
00197 
00198     if (flags)
00199         table->key_type = (char)(flags & 0x03);  /* Use lowest two bits */
00200     else
00201         table->key_type = TABLE_CONTAINER_KEY_NETSNMP_INDEX;
00202 
00203     if (!table->table->compare)
00204          table->table->compare  = netsnmp_compare_netsnmp_index;
00205     if (!table->table->ncompare)
00206          table->table->ncompare = netsnmp_ncompare_netsnmp_index;
00207 
00208     return table;
00209 }
00210 
00211 void
00212 netsnmp_tcontainer_delete_table( container_table_data *table )
00213 {
00214     if (!table)
00215        return;
00216 
00217     if (table->table)
00218        CONTAINER_FREE(table->table);
00219     
00220     SNMP_FREE(table);
00221     return;
00222 }
00223 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER_MANAGEMENT */
00224 
00225     /*
00226      * The various standalone row operation routines
00227      *    (create/clone/copy/delete)
00228      * will be specific to a particular table,
00229      *    so can't be implemented here.
00230      */
00231 
00232 int
00233 netsnmp_tcontainer_add_row( container_table_data *table, netsnmp_index *row )
00234 {
00235     if (!table || !table->table || !row)
00236         return -1;
00237     CONTAINER_INSERT( table->table, row );
00238     return 0;
00239 }
00240 
00241 netsnmp_index *
00242 netsnmp_tcontainer_remove_row( container_table_data *table, netsnmp_index *row )
00243 {
00244     if (!table || !table->table || !row)
00245         return NULL;
00246     CONTAINER_REMOVE( table->table, row );
00247     return NULL;
00248 }
00249 
00250 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER_REPLACE_ROW
00251 int
00252 netsnmp_tcontainer_replace_row( container_table_data *table,
00253                                 netsnmp_index *old_row, netsnmp_index *new_row )
00254 {
00255     if (!table || !table->table || !old_row || !new_row)
00256         return -1;
00257     netsnmp_tcontainer_remove_row( table, old_row );
00258     netsnmp_tcontainer_add_row(    table, new_row );
00259     return 0;
00260 }
00261 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER_REPLACE_ROW */
00262 
00263     /* netsnmp_tcontainer_remove_delete_row() will be table-specific too */
00264 
00265 
00266 /* ==================================
00267  *
00268  * Container Table API: MIB maintenance
00269  *
00270  * ================================== */
00271 
00272 static container_table_data *
00273 netsnmp_container_table_data_clone(container_table_data *tad)
00274 {
00275     ++tad->refcnt;
00276     return tad;
00277 }
00278 
00279 static void
00280 netsnmp_container_table_data_free(container_table_data *tad)
00281 {
00282     if (--tad->refcnt == 0)
00283         free(tad);
00284 }
00285 
00287 netsnmp_mib_handler *
00288 netsnmp_container_table_handler_get(netsnmp_table_registration_info *tabreg,
00289                                     netsnmp_container *container, char key_type)
00290 {
00291     container_table_data *tad;
00292     netsnmp_mib_handler *handler;
00293 
00294     if (NULL == tabreg) {
00295         snmp_log(LOG_ERR, "bad param in netsnmp_container_table_register\n");
00296         return NULL;
00297     }
00298 
00299     tad = SNMP_MALLOC_TYPEDEF(container_table_data);
00300     handler = netsnmp_create_handler("table_container",
00301                                      _container_table_handler);
00302     if((NULL == tad) || (NULL == handler)) {
00303         if(tad) free(tad); /* SNMP_FREE wasted on locals */
00304         if(handler) free(handler); /* SNMP_FREE wasted on locals */
00305         snmp_log(LOG_ERR,
00306                  "malloc failure in netsnmp_container_table_register\n");
00307         return NULL;
00308     }
00309 
00310     tad->refcnt = 1;
00311     tad->tblreg_info = tabreg;  /* we need it too, but it really is not ours */
00312     if(key_type)
00313         tad->key_type = key_type;
00314     else
00315         tad->key_type = TABLE_CONTAINER_KEY_NETSNMP_INDEX;
00316 
00317     if(NULL == container)
00318         container = netsnmp_container_find("table_container");
00319     tad->table = container;
00320 
00321     if (NULL==container->compare)
00322         container->compare = netsnmp_compare_netsnmp_index;
00323     if (NULL==container->ncompare)
00324         container->ncompare = netsnmp_ncompare_netsnmp_index;
00325     
00326     handler->myvoid = (void*)tad;
00327     handler->data_clone = (void *(*)(void *))netsnmp_container_table_data_clone;
00328     handler->data_free = (void (*)(void *))netsnmp_container_table_data_free;
00329     handler->flags |= MIB_HANDLER_AUTO_NEXT;
00330     
00331     return handler;
00332 }
00333 
00334 int
00335 netsnmp_container_table_register(netsnmp_handler_registration *reginfo,
00336                                  netsnmp_table_registration_info *tabreg,
00337                                  netsnmp_container *container, char key_type )
00338 {
00339     netsnmp_mib_handler *handler;
00340 
00341     if ((NULL == reginfo) || (NULL == reginfo->handler) || (NULL == tabreg)) {
00342         snmp_log(LOG_ERR, "bad param in netsnmp_container_table_register\n");
00343         return SNMPERR_GENERR;
00344     }
00345 
00346     if (NULL==container)
00347         container = netsnmp_container_find(reginfo->handlerName);
00348 
00349     handler = netsnmp_container_table_handler_get(tabreg, container, key_type);
00350     netsnmp_inject_handler(reginfo, handler );
00351 
00352     return netsnmp_register_table(reginfo, tabreg);
00353 }
00354 
00355 int
00356 netsnmp_container_table_unregister(netsnmp_handler_registration *reginfo)
00357 {
00358     container_table_data *tad;
00359 
00360     if (!reginfo)
00361         return MIB_UNREGISTRATION_FAILED;
00362     tad = (container_table_data *)
00363         netsnmp_find_handler_data_by_name(reginfo, "table_container");
00364     if (tad) {
00365         CONTAINER_FREE( tad->table );
00366         tad->table = NULL;
00367         /*
00368          * Note: don't free the memory tad points at here - that is done
00369          * by netsnmp_container_table_data_free().
00370          */
00371     }
00372     return netsnmp_unregister_table( reginfo );
00373 }
00374 
00376 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER_EXTRACT
00377 netsnmp_container*
00378 netsnmp_container_table_container_extract(netsnmp_request_info *request)
00379 {
00380     return (netsnmp_container *)
00381          netsnmp_request_get_list_data(request, TABLE_CONTAINER_CONTAINER);
00382 }
00383 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER_EXTRACT */
00384 
00385 #ifndef NETSNMP_USE_INLINE
00386 
00387 void *
00388 netsnmp_container_table_row_extract(netsnmp_request_info *request)
00389 {
00390     /*
00391      * NOTE: this function must match in table_container.c and table_container.h.
00392      *       if you change one, change them both!
00393      */
00394     return netsnmp_request_get_list_data(request, TABLE_CONTAINER_ROW);
00395 }
00397 void *
00398 netsnmp_container_table_extract_context(netsnmp_request_info *request)
00399 {
00400     /*
00401      * NOTE: this function must match in table_container.c and table_container.h.
00402      *       if you change one, change them both!
00403      */
00404     return netsnmp_request_get_list_data(request, TABLE_CONTAINER_ROW);
00405 }
00406 #endif /* inline */
00407 
00408 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER_ROW_INSERT
00409 
00410 void
00411 netsnmp_container_table_row_insert(netsnmp_request_info *request,
00412                                    netsnmp_index        *row)
00413 {
00414     netsnmp_request_info       *req;
00415     netsnmp_table_request_info *table_info = NULL;
00416     netsnmp_variable_list      *this_index = NULL;
00417     netsnmp_variable_list      *that_index = NULL;
00418     oid      base_oid[] = {0, 0};       /* Make sure index OIDs are legal! */
00419     oid      this_oid[MAX_OID_LEN];
00420     oid      that_oid[MAX_OID_LEN];
00421     size_t   this_oid_len, that_oid_len;
00422 
00423     if (!request)
00424         return;
00425 
00426     /*
00427      * We'll add the new row information to any request
00428      * structure with the same index values as the request
00429      * passed in (which includes that one!).
00430      *
00431      * So construct an OID based on these index values.
00432      */
00433 
00434     table_info = netsnmp_extract_table_info(request);
00435     this_index = table_info->indexes;
00436     build_oid_noalloc(this_oid, MAX_OID_LEN, &this_oid_len,
00437                       base_oid, 2, this_index);
00438 
00439     /*
00440      * We need to look through the whole of the request list
00441      * (as received by the current handler), as there's no
00442      * guarantee that this routine will be called by the first
00443      * varbind that refers to this row.
00444      *   In particular, a RowStatus controlled row creation
00445      * may easily occur later in the variable list.
00446      *
00447      * So first, we rewind to the head of the list....
00448      */
00449     for (req=request; req->prev; req=req->prev)
00450         ;
00451 
00452     /*
00453      * ... and then start looking for matching indexes
00454      * (by constructing OIDs from these index values)
00455      */
00456     for (; req; req=req->next) {
00457         if (req->processed) 
00458             continue;
00459         
00460         table_info = netsnmp_extract_table_info(req);
00461         that_index = table_info->indexes;
00462         build_oid_noalloc(that_oid, MAX_OID_LEN, &that_oid_len,
00463                           base_oid, 2, that_index);
00464       
00465         /*
00466          * This request has the same index values,
00467          * so add the newly-created row information.
00468          */
00469         if (snmp_oid_compare(this_oid, this_oid_len,
00470                              that_oid, that_oid_len) == 0) {
00471             netsnmp_request_add_list_data(req,
00472                 netsnmp_create_data_list(TABLE_CONTAINER_ROW, row, NULL));
00473         }
00474     }
00475 }
00476 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER_ROW_INSERT */
00477 
00478 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER_ROW_REMOVE
00479 
00480 void
00481 netsnmp_container_table_row_remove(netsnmp_request_info *request,
00482                                    netsnmp_index        *row)
00483 {
00484     netsnmp_request_info       *req;
00485     netsnmp_table_request_info *table_info = NULL;
00486     netsnmp_variable_list      *this_index = NULL;
00487     netsnmp_variable_list      *that_index = NULL;
00488     oid      base_oid[] = {0, 0};       /* Make sure index OIDs are legal! */
00489     oid      this_oid[MAX_OID_LEN];
00490     oid      that_oid[MAX_OID_LEN];
00491     size_t   this_oid_len, that_oid_len;
00492 
00493     if (!request)
00494         return;
00495 
00496     /*
00497      * We'll add the new row information to any request
00498      * structure with the same index values as the request
00499      * passed in (which includes that one!).
00500      *
00501      * So construct an OID based on these index values.
00502      */
00503 
00504     table_info = netsnmp_extract_table_info(request);
00505     this_index = table_info->indexes;
00506     build_oid_noalloc(this_oid, MAX_OID_LEN, &this_oid_len,
00507                       base_oid, 2, this_index);
00508 
00509     /*
00510      * We need to look through the whole of the request list
00511      * (as received by the current handler), as there's no
00512      * guarantee that this routine will be called by the first
00513      * varbind that refers to this row.
00514      *   In particular, a RowStatus controlled row creation
00515      * may easily occur later in the variable list.
00516      *
00517      * So first, we rewind to the head of the list....
00518      */
00519     for (req=request; req->prev; req=req->prev)
00520         ;
00521 
00522     /*
00523      * ... and then start looking for matching indexes
00524      * (by constructing OIDs from these index values)
00525      */
00526     for (; req; req=req->next) {
00527         if (req->processed) 
00528             continue;
00529         
00530         table_info = netsnmp_extract_table_info(req);
00531         that_index = table_info->indexes;
00532         build_oid_noalloc(that_oid, MAX_OID_LEN, &that_oid_len,
00533                           base_oid, 2, that_index);
00534       
00535         /*
00536          * This request has the same index values,
00537          * so add the newly-created row information.
00538          */
00539         if (snmp_oid_compare(this_oid, this_oid_len,
00540                              that_oid, that_oid_len) == 0) {
00541             netsnmp_request_remove_list_data(req, TABLE_CONTAINER_ROW);
00542         }
00543     }
00544 }
00545 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER_ROW_REMOVE */
00546 
00548 /**********************************************************************
00549  **********************************************************************
00550  *                                                                    *
00551  *                                                                    *
00552  * DATA LOOKUP functions                                              *
00553  *                                                                    *
00554  *                                                                    *
00555  **********************************************************************
00556  **********************************************************************/
00557 NETSNMP_STATIC_INLINE void
00558 _set_key( container_table_data * tad, netsnmp_request_info *request,
00559           netsnmp_table_request_info *tblreq_info,
00560           void **key, netsnmp_index *index )
00561 {
00562     if (TABLE_CONTAINER_KEY_NETSNMP_INDEX == tad->key_type) {
00563         index->oids = tblreq_info->index_oid;
00564         index->len = tblreq_info->index_oid_len;
00565         *key = index;
00566     }
00567     else if (TABLE_CONTAINER_KEY_VARBIND_INDEX == tad->key_type) {
00568         *key = tblreq_info->indexes;
00569     }
00570 #if 0
00571     else if (TABLE_CONTAINER_KEY_VARBIND_RAW == tad->key_type) {
00572         *key = request->requestvb;
00573     }
00574 #endif
00575     else
00576         *key = NULL;
00577 }
00578 
00579 
00580 NETSNMP_STATIC_INLINE void
00581 _data_lookup(netsnmp_handler_registration *reginfo,
00582             netsnmp_agent_request_info *agtreq_info,
00583             netsnmp_request_info *request, container_table_data * tad)
00584 {
00585     netsnmp_index *row = NULL;
00586     netsnmp_table_request_info *tblreq_info;
00587     netsnmp_variable_list *var;
00588     netsnmp_index index;
00589     void *key;
00590 
00591     var = request->requestvb;
00592 
00593     DEBUGIF("table_container") {
00594         DEBUGMSGTL(("table_container", "  data_lookup oid:"));
00595         DEBUGMSGOID(("table_container", var->name, var->name_length));
00596         DEBUGMSG(("table_container", "\n"));
00597     }
00598 
00599     /*
00600      * Get pointer to the table information for this request. This
00601      * information was saved by table_helper_handler.
00602      */
00603     tblreq_info = netsnmp_extract_table_info(request);
00605     netsnmp_assert((NULL != tblreq_info) &&
00606                    (tblreq_info->colnum <= tad->tblreg_info->max_column));
00607     
00608     if ((agtreq_info->mode == MODE_GETNEXT) ||
00609         (agtreq_info->mode == MODE_GETBULK)) {
00610         /*
00611          * find the row. This will automatically move to the next
00612          * column, if necessary.
00613          */
00614         _set_key( tad, request, tblreq_info, &key, &index );
00615         row = (netsnmp_index*)_find_next_row(tad->table, tblreq_info, key);
00616         if (row) {
00617             /*
00618              * update indexes in tblreq_info (index & varbind),
00619              * then update request varbind oid
00620              */
00621             if(TABLE_CONTAINER_KEY_NETSNMP_INDEX == tad->key_type) {
00622                 tblreq_info->index_oid_len = row->len;
00623                 memcpy(tblreq_info->index_oid, row->oids,
00624                        row->len * sizeof(oid));
00625                 netsnmp_update_variable_list_from_index(tblreq_info);
00626             }
00627             else if (TABLE_CONTAINER_KEY_VARBIND_INDEX == tad->key_type) {
00630                 netsnmp_update_indexes_from_variable_list(tblreq_info);
00631             }
00632 
00633             if (TABLE_CONTAINER_KEY_VARBIND_RAW != tad->key_type) {
00634                 netsnmp_table_build_oid_from_index(reginfo, request,
00635                                                    tblreq_info);
00636             }
00637         }
00638         else {
00639             /*
00640              * no results found. Flag the request so lower handlers will
00641              * ignore it, but it is not an error - getnext will move
00642              * on to another handler to process this request.
00643              */
00644             netsnmp_set_request_error(agtreq_info, request, SNMP_ENDOFMIBVIEW);
00645             DEBUGMSGTL(("table_container", "no row found\n"));
00646         }
00647     } 
00648     else {
00649 
00650         _set_key( tad, request, tblreq_info, &key, &index );
00651         row = (netsnmp_index*)CONTAINER_FIND(tad->table, key);
00652         if (NULL == row) {
00653             /*
00654              * not results found. For a get, that is an error
00655              */
00656             DEBUGMSGTL(("table_container", "no row found\n"));
00657 #ifndef NETSNMP_NO_WRITE_SUPPORT
00658             if((agtreq_info->mode != MODE_SET_RESERVE1) || /* get */
00659                (reginfo->modes & HANDLER_CAN_NOT_CREATE)) { /* no create */
00660 #endif /* NETSNMP_NO_WRITE_SUPPORT */
00661                 netsnmp_set_request_error(agtreq_info, request,
00662                                           SNMP_NOSUCHINSTANCE);
00663 #ifndef NETSNMP_NO_WRITE_SUPPORT
00664             }
00665 #endif /* NETSNMP_NO_WRITE_SUPPORT */
00666         }
00667     } 
00669     /*
00670      * save the data and table in the request.
00671      */
00672     if (SNMP_ENDOFMIBVIEW != request->requestvb->type) {
00673         if (NULL != row)
00674             netsnmp_request_add_list_data(request,
00675                                           netsnmp_create_data_list
00676                                           (TABLE_CONTAINER_ROW,
00677                                            row, NULL));
00678         netsnmp_request_add_list_data(request,
00679                                       netsnmp_create_data_list
00680                                       (TABLE_CONTAINER_CONTAINER,
00681                                        tad->table, NULL));
00682     }
00683 }
00684 
00685 /**********************************************************************
00686  **********************************************************************
00687  *                                                                    *
00688  *                                                                    *
00689  * netsnmp_table_container_helper_handler()                           *
00690  *                                                                    *
00691  *                                                                    *
00692  **********************************************************************
00693  **********************************************************************/
00694 static int
00695 _container_table_handler(netsnmp_mib_handler *handler,
00696                          netsnmp_handler_registration *reginfo,
00697                          netsnmp_agent_request_info *agtreq_info,
00698                          netsnmp_request_info *requests)
00699 {
00700     int             rc = SNMP_ERR_NOERROR;
00701     int             oldmode, need_processing = 0;
00702     container_table_data *tad;
00703 
00705     netsnmp_assert((NULL != handler) && (NULL != handler->myvoid));
00706     netsnmp_assert((NULL != reginfo) && (NULL != agtreq_info));
00707 
00708     DEBUGMSGTL(("table_container", "Mode %s, Got request:\n",
00709                 se_find_label_in_slist("agent_mode",agtreq_info->mode)));
00710 
00711     /*
00712      * First off, get our pointer from the handler. This
00713      * lets us get to the table registration information we
00714      * saved in get_table_container_handler(), as well as the
00715      * container where the actual table data is stored.
00716      */
00717     tad = (container_table_data *)handler->myvoid;
00718 
00719     /*
00720      * only do data lookup for first pass
00721      *
00722      * xxx-rks: this should really be handled up one level. we should
00723      * be able to say what modes we want to be called for during table
00724      * registration.
00725      */
00726     oldmode = agtreq_info->mode;
00727     if(MODE_IS_GET(oldmode)
00728 #ifndef NETSNMP_NO_WRITE_SUPPORT
00729        || (MODE_SET_RESERVE1 == oldmode)
00730 #endif /* NETSNMP_NO_WRITE_SUPPORT */
00731         ) {
00732         netsnmp_request_info *curr_request;
00733         /*
00734          * Loop through each of the requests, and
00735          * try to find the appropriate row from the container.
00736          */
00737         for (curr_request = requests; curr_request; curr_request = curr_request->next) {
00738             /*
00739              * skip anything that doesn't need processing.
00740              */
00741             if (curr_request->processed != 0) {
00742                 DEBUGMSGTL(("table_container", "already processed\n"));
00743                 continue;
00744             }
00745             
00746             /*
00747              * find data for this request
00748              */
00749             _data_lookup(reginfo, agtreq_info, curr_request, tad);
00750 
00751             if(curr_request->processed)
00752                 continue;
00753 
00754             ++need_processing;
00755         } 
00756     }
00757     
00758     /*
00759      * send GET instead of GETNEXT to sub-handlers
00760      * xxx-rks: again, this should be handled further up.
00761      */
00762     if ((oldmode == MODE_GETNEXT) && (handler->next)) {
00763         /*
00764          * tell agent handlder not to auto call next handler
00765          */
00766         handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
00767 
00768         /*
00769          * if we found rows to process, pretend to be a get request
00770          * and call handler below us.
00771          */
00772         if(need_processing > 0) {
00773             agtreq_info->mode = MODE_GET;
00774             rc = netsnmp_call_next_handler(handler, reginfo, agtreq_info,
00775                                            requests);
00776             if (rc != SNMP_ERR_NOERROR) {
00777                 DEBUGMSGTL(("table_container",
00778                             "next handler returned %d\n", rc));
00779             }
00780 
00781             agtreq_info->mode = oldmode; /* restore saved mode */
00782         }
00783     }
00784 
00785     return rc;
00786 }
00790 /* ==================================
00791  *
00792  * Container Table API: Row operations
00793  *
00794  * ================================== */
00795 
00796 static void *
00797 _find_next_row(netsnmp_container *c,
00798                netsnmp_table_request_info *tblreq,
00799                void * key)
00800 {
00801     void *row = NULL;
00802 
00803     if (!c || !tblreq || !tblreq->reg_info ) {
00804         snmp_log(LOG_ERR,"_find_next_row param error\n");
00805         return NULL;
00806     }
00807 
00808     /*
00809      * table helper should have made sure we aren't below our minimum column
00810      */
00811     netsnmp_assert(tblreq->colnum >= tblreq->reg_info->min_column);
00812 
00813     /*
00814      * if no indexes then use first row.
00815      */
00816     if(tblreq->number_indexes == 0) {
00817         row = CONTAINER_FIRST(c);
00818     } else {
00819 
00820         if(NULL == key) {
00821             netsnmp_index index;
00822             index.oids = tblreq->index_oid;
00823             index.len = tblreq->index_oid_len;
00824             row = CONTAINER_NEXT(c, &index);
00825         }
00826         else
00827             row = CONTAINER_NEXT(c, key);
00828 
00829         /*
00830          * we don't have a row, but we might be at the end of a
00831          * column, so try the next column.
00832          */
00833         if (NULL == row) {
00834             /*
00835              * don't set tblreq next_col unless we know there is one,
00836              * so we don't mess up table handler sparse table processing.
00837              */
00838             oid next_col = netsnmp_table_next_column(tblreq);
00839             if (0 != next_col) {
00840                 tblreq->colnum = next_col;
00841                 row = CONTAINER_FIRST(c);
00842             }
00843         }
00844     }
00845     
00846     return row;
00847 }
00848 
00858 netsnmp_index *
00859 netsnmp_table_index_find_next_row(netsnmp_container *c,
00860                                   netsnmp_table_request_info *tblreq)
00861 {
00862     return (netsnmp_index*)_find_next_row(c, tblreq, NULL );
00863 }
00864 
00865 /* ==================================
00866  *
00867  * Container Table API: Index operations
00868  *
00869  * ================================== */
00870 
00871 #else /* NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER */
00872 netsnmp_feature_unused(table_container);
00873 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_CONTAINER */
00874