net-snmp 5.7
table_data.c
00001 #include <net-snmp/net-snmp-config.h>
00002 #include <net-snmp/net-snmp-features.h>
00003 
00004 #include <net-snmp/net-snmp-includes.h>
00005 #include <net-snmp/agent/net-snmp-agent-includes.h>
00006 
00007 #include <net-snmp/agent/table_data.h>
00008 
00009 #if HAVE_STRING_H
00010 #include <string.h>
00011 #else
00012 #include <strings.h>
00013 #endif
00014 
00015 #include <net-snmp/agent/table.h>
00016 #include <net-snmp/agent/read_only.h>
00017 
00018 netsnmp_feature_child_of(table_data_all, mib_helpers)
00019 
00020 netsnmp_feature_child_of(table_data, table_data_all)
00021 netsnmp_feature_child_of(register_read_only_table_data, table_data_all)
00022 netsnmp_feature_child_of(extract_table_row_data, table_data_all)
00023 netsnmp_feature_child_of(insert_table_row, table_data_all)
00024 netsnmp_feature_child_of(table_data_delete_table, table_data_all)
00025 
00026 netsnmp_feature_child_of(table_data_extras, table_data_all)
00027 
00028 netsnmp_feature_child_of(table_data_create_table, table_data_extras)
00029 netsnmp_feature_child_of(table_data_create_row, table_data_extras)
00030 netsnmp_feature_child_of(table_data_copy_row, table_data_extras)
00031 netsnmp_feature_child_of(table_data_remove_delete_row, table_data_extras)
00032 netsnmp_feature_child_of(table_data_unregister, table_data_extras)
00033 netsnmp_feature_child_of(table_data_row_count, table_data_extras)
00034 netsnmp_feature_child_of(table_data_row_operations, table_data_extras)
00035 netsnmp_feature_child_of(table_data_row_first, table_data_extras)
00036 
00037 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_DATA
00038 
00058 /* ==================================
00059  *
00060  * Table Data API: Table maintenance
00061  *
00062  * ================================== */
00063 
00064 /*
00065  * generates the index portion of an table oid from a varlist.
00066  */
00067 void
00068 netsnmp_table_data_generate_index_oid(netsnmp_table_row *row)
00069 {
00070     build_oid(&row->index_oid, &row->index_oid_len, NULL, 0, row->indexes);
00071 }
00072 
00074 netsnmp_table_data *
00075 netsnmp_create_table_data(const char *name)
00076 {
00077     netsnmp_table_data *table = SNMP_MALLOC_TYPEDEF(netsnmp_table_data);
00078     if (name && table)
00079         table->name = strdup(name);
00080     return table;
00081 }
00082 
00084 netsnmp_table_row *
00085 netsnmp_create_table_data_row(void)
00086 {
00087     netsnmp_table_row *row = SNMP_MALLOC_TYPEDEF(netsnmp_table_row);
00088     return row;
00089 }
00090 
00092 netsnmp_table_row *
00093 netsnmp_table_data_clone_row(netsnmp_table_row *row)
00094 {
00095     netsnmp_table_row *newrow = NULL;
00096     if (!row)
00097         return NULL;
00098 
00099     memdup((u_char **) & newrow, (u_char *) row,
00100            sizeof(netsnmp_table_row));
00101     if (!newrow)
00102         return NULL;
00103 
00104     if (row->indexes) {
00105         newrow->indexes = snmp_clone_varbind(newrow->indexes);
00106         if (!newrow->indexes) {
00107             free(newrow);
00108             return NULL;
00109         }
00110     }
00111 
00112     if (row->index_oid) {
00113         newrow->index_oid =
00114             snmp_duplicate_objid(row->index_oid, row->index_oid_len);
00115         if (!newrow->index_oid) {
00116             free(newrow->indexes);
00117             free(newrow);
00118             return NULL;
00119         }
00120     }
00121 
00122     return newrow;
00123 }
00124 
00127 void           *
00128 netsnmp_table_data_delete_row(netsnmp_table_row *row)
00129 {
00130     void           *data;
00131 
00132     if (!row)
00133         return NULL;
00134 
00135     /*
00136      * free the memory we can 
00137      */
00138     if (row->indexes)
00139         snmp_free_varbind(row->indexes);
00140     SNMP_FREE(row->index_oid);
00141     data = row->data;
00142     free(row);
00143 
00144     /*
00145      * return the void * pointer 
00146      */
00147     return data;
00148 }
00149 
00156 int
00157 netsnmp_table_data_add_row(netsnmp_table_data *table,
00158                            netsnmp_table_row *row)
00159 {
00160     int rc, dup = 0;
00161     netsnmp_table_row *nextrow = NULL, *prevrow;
00162 
00163     if (!row || !table)
00164         return SNMPERR_GENERR;
00165 
00166     if (row->indexes)
00167         netsnmp_table_data_generate_index_oid(row);
00168 
00169     /*
00170      * we don't store the index info as it
00171      * takes up memory. 
00172      */
00173     if (!table->store_indexes) {
00174         snmp_free_varbind(row->indexes);
00175         row->indexes = NULL;
00176     }
00177 
00178     if (!row->index_oid) {
00179         snmp_log(LOG_ERR,
00180                  "illegal data attempted to be added to table %s (no index)\n",
00181                  table->name);
00182         return SNMPERR_GENERR;
00183     }
00184 
00185     /*
00186      * check for simple append
00187      */
00188     if ((prevrow = table->last_row) != NULL) {
00189         rc = snmp_oid_compare(prevrow->index_oid, prevrow->index_oid_len,
00190                               row->index_oid, row->index_oid_len);
00191         if (0 == rc)
00192             dup = 1;
00193     }
00194     else
00195         rc = 1;
00196     
00197     /*
00198      * if no last row, or newrow < last row, search the table and
00199      * insert it into the table in the proper oid-lexographical order 
00200      */
00201     if (rc > 0) {
00202         for (nextrow = table->first_row, prevrow = NULL;
00203              nextrow != NULL; prevrow = nextrow, nextrow = nextrow->next) {
00204             if (NULL == nextrow->index_oid) {
00205                 DEBUGMSGT(("table_data_add_data", "row doesn't have index!\n"));
00207                 continue;
00208             }
00209             rc = snmp_oid_compare(nextrow->index_oid, nextrow->index_oid_len,
00210                                   row->index_oid, row->index_oid_len);
00211             if(rc > 0)
00212                 break;
00213             if (0 == rc) {
00214                 dup = 1;
00215                 break;
00216             }
00217         }
00218     }
00219 
00220     if (dup) {
00221         /*
00222          * exact match.  Duplicate entries illegal 
00223          */
00224         snmp_log(LOG_WARNING,
00225                  "duplicate table data attempted to be entered. row exists\n");
00226         return SNMPERR_GENERR;
00227     }
00228 
00229     /*
00230      * ok, we have the location of where it should go 
00231      */
00232     /*
00233      * (after prevrow, and before nextrow) 
00234      */
00235     row->next = nextrow;
00236     row->prev = prevrow;
00237 
00238     if (row->next)
00239         row->next->prev = row;
00240 
00241     if (row->prev)
00242         row->prev->next = row;
00243 
00244     if (NULL == row->prev)      /* it's the (new) first row */
00245         table->first_row = row;
00246     if (NULL == row->next)      /* it's the last row */
00247         table->last_row = row;
00248 
00249     DEBUGMSGTL(("table_data_add_data", "added something...\n"));
00250 
00251     return SNMPERR_SUCCESS;
00252 }
00253 
00255 void
00256 netsnmp_table_data_replace_row(netsnmp_table_data *table,
00257                                netsnmp_table_row *origrow,
00258                                netsnmp_table_row *newrow)
00259 {
00260     netsnmp_table_data_remove_row(table, origrow);
00261     netsnmp_table_data_add_row(table, newrow);
00262 }
00263 
00270 netsnmp_table_row *
00271 netsnmp_table_data_remove_row(netsnmp_table_data *table,
00272                               netsnmp_table_row *row)
00273 {
00274     if (!row || !table)
00275         return NULL;
00276 
00277     if (row->prev)
00278         row->prev->next = row->next;
00279     else
00280         table->first_row = row->next;
00281 
00282     if (row->next)
00283         row->next->prev = row->prev;
00284     else
00285         table->last_row = row->prev;
00286 
00287     return row;
00288 }
00289 
00296 void           *
00297 netsnmp_table_data_remove_and_delete_row(netsnmp_table_data *table,
00298                                          netsnmp_table_row *row)
00299 {
00300     if (!row || !table)
00301         return NULL;
00302 
00303     /*
00304      * remove it from the list 
00305      */
00306     netsnmp_table_data_remove_row(table, row);
00307     return netsnmp_table_data_delete_row(row);
00308 }
00309 
00310     /* =====================================
00311      * Generic API - mostly renamed wrappers
00312      * ===================================== */
00313 
00314 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_DATA_CREATE_TABLE
00315 netsnmp_table_data *
00316 netsnmp_table_data_create_table(const char *name, long flags)
00317 {
00318     return netsnmp_create_table_data( name );
00319 }
00320 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_DATA_CREATE_TABLE */
00321 
00322 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_DATA_DELETE_TABLE
00323 void
00324 netsnmp_table_data_delete_table( netsnmp_table_data *table )
00325 {
00326     netsnmp_table_row *row, *nextrow;
00327 
00328     if (!table)
00329         return;
00330 
00331     snmp_free_varbind(table->indexes_template);
00332     table->indexes_template = NULL;
00333 
00334     for (row = table->first_row; row; row=nextrow) {
00335         nextrow   = row->next;
00336         row->next = NULL;
00337         netsnmp_table_data_delete_row(row);
00338         /* Can't delete table-specific entry memory */
00339     }
00340     table->first_row = NULL;
00341 
00342     SNMP_FREE(table->name);
00343     SNMP_FREE(table);
00344     return;
00345 }
00346 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_DATA_DELETE_TABLE */
00347 
00348 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_DATA_CREATE_ROW
00349 netsnmp_table_row *
00350 netsnmp_table_data_create_row( void* entry )
00351 {
00352     netsnmp_table_row *row = SNMP_MALLOC_TYPEDEF(netsnmp_table_row);
00353     if (row)
00354         row->data = entry;
00355     return row;
00356 }
00357 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_DATA_CREATE_ROW */
00358 
00359     /* netsnmp_table_data_clone_row() defined above */
00360 
00361 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_DATA_COPY_ROW
00362 int
00363 netsnmp_table_data_copy_row( netsnmp_table_row  *old_row,
00364                              netsnmp_table_row  *new_row )
00365 {
00366     if (!old_row || !new_row)
00367         return -1;
00368 
00369     memcpy(new_row, old_row, sizeof(netsnmp_table_row));
00370 
00371     if (old_row->indexes)
00372         new_row->indexes = snmp_clone_varbind(old_row->indexes);
00373     if (old_row->index_oid)
00374         new_row->index_oid =
00375             snmp_duplicate_objid(old_row->index_oid, old_row->index_oid_len);
00376     /* XXX - Doesn't copy table-specific row structure */
00377     return 0;
00378 }
00379 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_DATA_COPY_ROW */
00380 
00381     /*
00382      * netsnmp_table_data_delete_row()
00383      * netsnmp_table_data_add_row()
00384      * netsnmp_table_data_replace_row()
00385      * netsnmp_table_data_remove_row()
00386      *     all defined above
00387      */
00388 
00389 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_DATA_REMOVE_DELETE_ROW
00390 void *
00391 netsnmp_table_data_remove_delete_row(netsnmp_table_data *table,
00392                                      netsnmp_table_row *row)
00393 {
00394     return netsnmp_table_data_remove_and_delete_row(table, row);
00395 }
00396 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_DATA_REMOVE_DELETE_ROW */
00397 
00398 
00399 /* ==================================
00400  *
00401  * Table Data API: MIB maintenance
00402  *
00403  * ================================== */
00404 
00406 netsnmp_mib_handler *
00407 netsnmp_get_table_data_handler(netsnmp_table_data *table)
00408 {
00409     netsnmp_mib_handler *ret = NULL;
00410 
00411     if (!table) {
00412         snmp_log(LOG_INFO,
00413                  "netsnmp_get_table_data_handler(NULL) called\n");
00414         return NULL;
00415     }
00416 
00417     ret =
00418         netsnmp_create_handler(TABLE_DATA_NAME,
00419                                netsnmp_table_data_helper_handler);
00420     if (ret) {
00421         ret->flags |= MIB_HANDLER_AUTO_NEXT;
00422         ret->myvoid = (void *) table;
00423     }
00424     return ret;
00425 }
00426 
00429 int
00430 netsnmp_register_table_data(netsnmp_handler_registration *reginfo,
00431                             netsnmp_table_data *table,
00432                             netsnmp_table_registration_info *table_info)
00433 {
00434     netsnmp_inject_handler(reginfo, netsnmp_get_table_data_handler(table));
00435     return netsnmp_register_table(reginfo, table_info);
00436 }
00437 
00438 
00439 #ifndef NETSNMP_FEATURE_REMOVE_REGISTER_READ_ONLY_TABLE_DATA
00440 
00442 int
00443 netsnmp_register_read_only_table_data(netsnmp_handler_registration *reginfo,
00444                                       netsnmp_table_data *table,
00445                                       netsnmp_table_registration_info *table_info)
00446 {
00447     netsnmp_inject_handler(reginfo, netsnmp_get_read_only_handler());
00448     return netsnmp_register_table_data(reginfo, table, table_info);
00449 }
00450 #endif /* NETSNMP_FEATURE_REMOVE_REGISTER_READ_ONLY_TABLE_DATA */
00451 
00452 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_DATA_UNREGISTER
00453 int
00454 netsnmp_unregister_table_data(netsnmp_handler_registration *reginfo)
00455 {
00456     /* free table; */
00457     return netsnmp_unregister_table(reginfo);
00458 }
00459 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_DATA_UNREGISTER */
00460 
00461 /*
00462  * The helper handler that takes care of passing a specific row of
00463  * data down to the lower handler(s).  It sets request->processed if
00464  * the request should not be handled.
00465  */
00466 int
00467 netsnmp_table_data_helper_handler(netsnmp_mib_handler *handler,
00468                                   netsnmp_handler_registration *reginfo,
00469                                   netsnmp_agent_request_info *reqinfo,
00470                                   netsnmp_request_info *requests)
00471 {
00472     netsnmp_table_data *table = (netsnmp_table_data *) handler->myvoid;
00473     netsnmp_request_info *request;
00474     int             valid_request = 0;
00475     netsnmp_table_row *row;
00476     netsnmp_table_request_info *table_info;
00477     netsnmp_table_registration_info *table_reg_info =
00478         netsnmp_find_table_registration_info(reginfo);
00479     int             result, regresult;
00480     int             oldmode;
00481 
00482     for (request = requests; request; request = request->next) {
00483         if (request->processed)
00484             continue;
00485 
00486         table_info = netsnmp_extract_table_info(request);
00487         if (!table_info)
00488             continue;           /* ack */
00489         switch (reqinfo->mode) {
00490         case MODE_GET:
00491         case MODE_GETNEXT:
00492 #ifndef NETSNMP_NO_WRITE_SUPPORT
00493         case MODE_SET_RESERVE1:
00494 #endif /* NETSNMP_NO_WRITE_SUPPORT */
00495             netsnmp_request_add_list_data(request,
00496                                       netsnmp_create_data_list(
00497                                           TABLE_DATA_TABLE, table, NULL));
00498         }
00499 
00500         /*
00501          * find the row in question 
00502          */
00503         switch (reqinfo->mode) {
00504         case MODE_GETNEXT:
00505         case MODE_GETBULK:     /* XXXWWW */
00506             if (request->requestvb->type != ASN_NULL)
00507                 continue;
00508             /*
00509              * loop through data till we find the next row 
00510              */
00511             result = snmp_oid_compare(request->requestvb->name,
00512                                       request->requestvb->name_length,
00513                                       reginfo->rootoid,
00514                                       reginfo->rootoid_len);
00515             regresult = snmp_oid_compare(request->requestvb->name,
00516                                          SNMP_MIN(request->requestvb->
00517                                                   name_length,
00518                                                   reginfo->rootoid_len),
00519                                          reginfo->rootoid,
00520                                          reginfo->rootoid_len);
00521             if (regresult == 0
00522                 && request->requestvb->name_length < reginfo->rootoid_len)
00523                 regresult = -1;
00524 
00525             if (result < 0 || 0 == result) {
00526                 /*
00527                  * before us entirely, return the first 
00528                  */
00529                 row = table->first_row;
00530                 table_info->colnum = table_reg_info->min_column;
00531             } else if (regresult == 0 && request->requestvb->name_length ==
00532                        reginfo->rootoid_len + 1 &&
00533                        /* entry node must be 1, but any column is ok */
00534                        request->requestvb->name[reginfo->rootoid_len] == 1) {
00535                 /*
00536                  * exactly to the entry 
00537                  */
00538                 row = table->first_row;
00539                 table_info->colnum = table_reg_info->min_column;
00540             } else if (regresult == 0 && request->requestvb->name_length ==
00541                        reginfo->rootoid_len + 2 &&
00542                        /* entry node must be 1, but any column is ok */
00543                        request->requestvb->name[reginfo->rootoid_len] == 1) {
00544                 /*
00545                  * exactly to the column 
00546                  */
00547                 row = table->first_row;
00548             } else {
00549                 /*
00550                  * loop through all rows looking for the first one
00551                  * that is equal to the request or greater than it 
00552                  */
00553                 for (row = table->first_row; row; row = row->next) {
00554                     /*
00555                      * compare the index of the request to the row 
00556                      */
00557                     result =
00558                         snmp_oid_compare(row->index_oid,
00559                                          row->index_oid_len,
00560                                          request->requestvb->name + 2 +
00561                                          reginfo->rootoid_len,
00562                                          request->requestvb->name_length -
00563                                          2 - reginfo->rootoid_len);
00564                     if (result == 0) {
00565                         /*
00566                          * equal match, return the next row 
00567                          */
00568                         row = row->next;
00569                         break;
00570                     } else if (result > 0) {
00571                         /*
00572                          * the current row is greater than the
00573                          * request, use it 
00574                          */
00575                         break;
00576                     }
00577                 }
00578             }
00579             if (!row) {
00580                 table_info->colnum++;
00581                 if (table_info->colnum <= table_reg_info->max_column) {
00582                     row = table->first_row;
00583                 }
00584             }
00585             if (row) {
00586                 valid_request = 1;
00587                 netsnmp_request_add_list_data(request,
00588                                               netsnmp_create_data_list
00589                                               (TABLE_DATA_ROW, row,
00590                                                NULL));
00591                 /*
00592                  * Set the name appropriately, so we can pass this
00593                  *  request on as a simple GET request
00594                  */
00595                 netsnmp_table_data_build_result(reginfo, reqinfo, request,
00596                                                 row,
00597                                                 table_info->colnum,
00598                                                 ASN_NULL, NULL, 0);
00599             } else {            /* no decent result found.  Give up. It's beyond us. */
00600                 request->processed = 1;
00601             }
00602             break;
00603 
00604         case MODE_GET:
00605             if (request->requestvb->type != ASN_NULL)
00606                 continue;
00607             /*
00608              * find the row in question 
00609              */
00610             if (request->requestvb->name_length < (reginfo->rootoid_len + 3)) { /* table.entry.column... */
00611                 /*
00612                  * request too short 
00613                  */
00614                 netsnmp_set_request_error(reqinfo, request,
00615                                           SNMP_NOSUCHINSTANCE);
00616                 break;
00617             } else if (NULL ==
00618                        (row =
00619                         netsnmp_table_data_get_from_oid(table,
00620                                                         request->
00621                                                         requestvb->name +
00622                                                         reginfo->
00623                                                         rootoid_len + 2,
00624                                                         request->
00625                                                         requestvb->
00626                                                         name_length -
00627                                                         reginfo->
00628                                                         rootoid_len -
00629                                                         2))) {
00630                 /*
00631                  * no such row 
00632                  */
00633                 netsnmp_set_request_error(reqinfo, request,
00634                                           SNMP_NOSUCHINSTANCE);
00635                 break;
00636             } else {
00637                 valid_request = 1;
00638                 netsnmp_request_add_list_data(request,
00639                                               netsnmp_create_data_list
00640                                               (TABLE_DATA_ROW, row,
00641                                                NULL));
00642             }
00643             break;
00644 
00645 #ifndef NETSNMP_NO_WRITE_SUPPORT
00646         case MODE_SET_RESERVE1:
00647             valid_request = 1;
00648             if (NULL !=
00649                 (row =
00650                  netsnmp_table_data_get_from_oid(table,
00651                                                  request->requestvb->name +
00652                                                  reginfo->rootoid_len + 2,
00653                                                  request->requestvb->
00654                                                  name_length -
00655                                                  reginfo->rootoid_len -
00656                                                  2))) {
00657                 netsnmp_request_add_list_data(request,
00658                                               netsnmp_create_data_list
00659                                               (TABLE_DATA_ROW, row,
00660                                                NULL));
00661             }
00662             break;
00663 
00664         case MODE_SET_RESERVE2:
00665         case MODE_SET_ACTION:
00666         case MODE_SET_COMMIT:
00667         case MODE_SET_FREE:
00668         case MODE_SET_UNDO:
00669             valid_request = 1;
00670 #endif /* NETSNMP_NO_WRITE_SUPPORT */
00671 
00672         }
00673     }
00674 
00675     if (valid_request &&
00676        (reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK)) {
00677         /*
00678          * If this is a GetNext or GetBulk request, then we've identified
00679          *  the row that ought to include the appropriate next instance.
00680          *  Convert the request into a Get request, so that the lower-level
00681          *  handlers don't need to worry about skipping on, and call these
00682          *  handlers ourselves (so we can undo this again afterwards).
00683          */
00684         oldmode = reqinfo->mode;
00685         reqinfo->mode = MODE_GET;
00686         result = netsnmp_call_next_handler(handler, reginfo, reqinfo,
00687                                          requests);
00688         reqinfo->mode = oldmode;
00689         handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
00690         return result;
00691     }
00692     else
00693         /* next handler called automatically - 'AUTO_NEXT' */
00694         return SNMP_ERR_NOERROR;
00695 }
00696 
00698 netsnmp_table_data *
00699 netsnmp_extract_table(netsnmp_request_info *request)
00700 {
00701     return (netsnmp_table_data *)
00702                 netsnmp_request_get_list_data(request, TABLE_DATA_TABLE);
00703 }
00704 
00706 netsnmp_table_row *
00707 netsnmp_extract_table_row(netsnmp_request_info *request)
00708 {
00709     return (netsnmp_table_row *) netsnmp_request_get_list_data(request,
00710                                                                TABLE_DATA_ROW);
00711 }
00712 
00713 #ifndef NETSNMP_FEATURE_REMOVE_EXTRACT_TABLE_ROW_DATA
00714 
00716 void           *
00717 netsnmp_extract_table_row_data(netsnmp_request_info *request)
00718 {
00719     netsnmp_table_row *row;
00720     row = (netsnmp_table_row *) netsnmp_extract_table_row(request);
00721     if (row)
00722         return row->data;
00723     else
00724         return NULL;
00725 }
00726 #endif /* NETSNMP_FEATURE_REMOVE_EXTRACT_TABLE_ROW_DATA */
00727 
00728 #ifndef NETSNMP_FEATURE_REMOVE_INSERT_TABLE_ROW
00729 
00730 void
00731 netsnmp_insert_table_row(netsnmp_request_info *request,
00732                          netsnmp_table_row *row)
00733 {
00734     netsnmp_request_info       *req;
00735     netsnmp_table_request_info *table_info = NULL;
00736     netsnmp_variable_list      *this_index = NULL;
00737     netsnmp_variable_list      *that_index = NULL;
00738     oid      base_oid[] = {0, 0};       /* Make sure index OIDs are legal! */
00739     oid      this_oid[MAX_OID_LEN];
00740     oid      that_oid[MAX_OID_LEN];
00741     size_t   this_oid_len, that_oid_len;
00742 
00743     if (!request)
00744         return;
00745 
00746     /*
00747      * We'll add the new row information to any request
00748      * structure with the same index values as the request
00749      * passed in (which includes that one!).
00750      *
00751      * So construct an OID based on these index values.
00752      */
00753 
00754     table_info = netsnmp_extract_table_info(request);
00755     this_index = table_info->indexes;
00756     build_oid_noalloc(this_oid, MAX_OID_LEN, &this_oid_len,
00757                       base_oid, 2, this_index);
00758 
00759     /*
00760      * We need to look through the whole of the request list
00761      * (as received by the current handler), as there's no
00762      * guarantee that this routine will be called by the first
00763      * varbind that refers to this row.
00764      *   In particular, a RowStatus controlled row creation
00765      * may easily occur later in the variable list.
00766      *
00767      * So first, we rewind to the head of the list....
00768      */
00769     for (req=request; req->prev; req=req->prev)
00770         ;
00771 
00772     /*
00773      * ... and then start looking for matching indexes
00774      * (by constructing OIDs from these index values)
00775      */
00776     for (; req; req=req->next) {
00777         table_info = netsnmp_extract_table_info(req);
00778         that_index = table_info->indexes;
00779         build_oid_noalloc(that_oid, MAX_OID_LEN, &that_oid_len,
00780                           base_oid, 2, that_index);
00781       
00782         /*
00783          * This request has the same index values,
00784          * so add the newly-created row information.
00785          */
00786         if (snmp_oid_compare(this_oid, this_oid_len,
00787                              that_oid, that_oid_len) == 0) {
00788             netsnmp_request_add_list_data(req,
00789                 netsnmp_create_data_list(TABLE_DATA_ROW, row, NULL));
00790         }
00791     }
00792 }
00793 #endif /* NETSNMP_FEATURE_REMOVE_INSERT_TABLE_ROW */
00794 
00795 /* builds a result given a row, a varbind to set and the data */
00796 int
00797 netsnmp_table_data_build_result(netsnmp_handler_registration *reginfo,
00798                                 netsnmp_agent_request_info *reqinfo,
00799                                 netsnmp_request_info *request,
00800                                 netsnmp_table_row *row,
00801                                 int column,
00802                                 u_char type,
00803                                 u_char * result_data,
00804                                 size_t result_data_len)
00805 {
00806     oid             build_space[MAX_OID_LEN];
00807 
00808     if (!reginfo || !reqinfo || !request)
00809         return SNMPERR_GENERR;
00810 
00811     if (reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK) {
00812         /*
00813          * only need to do this for getnext type cases where oid is changing 
00814          */
00815         memcpy(build_space, reginfo->rootoid,   /* registered oid */
00816                reginfo->rootoid_len * sizeof(oid));
00817         build_space[reginfo->rootoid_len] = 1;  /* entry */
00818         build_space[reginfo->rootoid_len + 1] = column; /* column */
00819         memcpy(build_space + reginfo->rootoid_len + 2,  /* index data */
00820                row->index_oid, row->index_oid_len * sizeof(oid));
00821         snmp_set_var_objid(request->requestvb, build_space,
00822                            reginfo->rootoid_len + 2 + row->index_oid_len);
00823     }
00824     snmp_set_var_typed_value(request->requestvb, type,
00825                              result_data, result_data_len);
00826     return SNMPERR_SUCCESS;     /* WWWXXX: check for bounds */
00827 }
00828 
00829 
00830 /* ==================================
00831  *
00832  * Table Data API: Row operations
00833  *     (table-independent rows)
00834  *
00835  * ================================== */
00836 
00838 netsnmp_table_row *
00839 netsnmp_table_data_get_first_row(netsnmp_table_data *table)
00840 {
00841     if (!table)
00842         return NULL;
00843     return table->first_row;
00844 }
00845 
00847 netsnmp_table_row *
00848 netsnmp_table_data_get_next_row(netsnmp_table_data *table,
00849                                 netsnmp_table_row  *row)
00850 {
00851     if (!row)
00852         return NULL;
00853     return row->next;
00854 }
00855 
00857 netsnmp_table_row *
00858 netsnmp_table_data_get(netsnmp_table_data *table,
00859                        netsnmp_variable_list * indexes)
00860 {
00861     oid             searchfor[MAX_OID_LEN];
00862     size_t          searchfor_len = MAX_OID_LEN;
00863 
00864     build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
00865                       indexes);
00866     return netsnmp_table_data_get_from_oid(table, searchfor,
00867                                            searchfor_len);
00868 }
00869 
00871 netsnmp_table_row *
00872 netsnmp_table_data_get_from_oid(netsnmp_table_data *table,
00873                                 oid * searchfor, size_t searchfor_len)
00874 {
00875     netsnmp_table_row *row;
00876     if (!table)
00877         return NULL;
00878 
00879     for (row = table->first_row; row != NULL; row = row->next) {
00880         if (row->index_oid &&
00881             snmp_oid_compare(searchfor, searchfor_len,
00882                              row->index_oid, row->index_oid_len) == 0)
00883             return row;
00884     }
00885     return NULL;
00886 }
00887 
00888 int
00889 netsnmp_table_data_num_rows(netsnmp_table_data *table)
00890 {
00891     int i=0;
00892     netsnmp_table_row *row;
00893     if (!table)
00894         return 0;
00895     for (row = table->first_row; row; row = row->next) {
00896         i++;
00897     }
00898     return i;
00899 }
00900 
00901     /* =====================================
00902      * Generic API - mostly renamed wrappers
00903      * ===================================== */
00904 
00905 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_DATA_ROW_FIRST
00906 netsnmp_table_row *
00907 netsnmp_table_data_row_first(netsnmp_table_data *table)
00908 {
00909     return netsnmp_table_data_get_first_row(table);
00910 }
00911 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_DATA_ROW_FIRST */
00912 
00913 netsnmp_table_row *
00914 netsnmp_table_data_row_get(  netsnmp_table_data *table,
00915                              netsnmp_table_row  *row)
00916 {
00917     if (!table || !row)
00918         return NULL;
00919     return netsnmp_table_data_get_from_oid(table, row->index_oid,
00920                                                   row->index_oid_len);
00921 }
00922 
00923 netsnmp_table_row *
00924 netsnmp_table_data_row_next( netsnmp_table_data *table,
00925                              netsnmp_table_row  *row)
00926 {
00927     return netsnmp_table_data_get_next_row(table, row);
00928 }
00929 
00930 netsnmp_table_row *
00931 netsnmp_table_data_row_get_byoid( netsnmp_table_data *table,
00932                                   oid *instance, size_t len)
00933 {
00934     return netsnmp_table_data_get_from_oid(table, instance, len);
00935 }
00936 
00937 netsnmp_table_row *
00938 netsnmp_table_data_row_next_byoid(netsnmp_table_data *table,
00939                                   oid *instance, size_t len)
00940 {
00941     netsnmp_table_row *row;
00942 
00943     if (!table || !instance)
00944         return NULL;
00945     
00946     for (row = table->first_row; row; row = row->next) {
00947         if (snmp_oid_compare(row->index_oid,
00948                              row->index_oid_len,
00949                              instance, len) > 0)
00950             return row;
00951     }
00952     return NULL;
00953 }
00954 
00955 netsnmp_table_row *
00956 netsnmp_table_data_row_get_byidx( netsnmp_table_data    *table,
00957                                   netsnmp_variable_list *indexes)
00958 {
00959     return netsnmp_table_data_get(table, indexes);
00960 }
00961 
00962 netsnmp_table_row *
00963 netsnmp_table_data_row_next_byidx(netsnmp_table_data    *table,
00964                                   netsnmp_variable_list *indexes)
00965 {
00966     oid    instance[MAX_OID_LEN];
00967     size_t len    = MAX_OID_LEN;
00968 
00969     if (!table || !indexes)
00970         return NULL;
00971 
00972     build_oid_noalloc(instance, MAX_OID_LEN, &len, NULL, 0, indexes);
00973     return netsnmp_table_data_row_next_byoid(table, instance, len);
00974 }
00975 
00976 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_DATA_ROW_COUNT
00977 int
00978 netsnmp_table_data_row_count(netsnmp_table_data *table)
00979 {
00980     return netsnmp_table_data_num_rows(table);
00981 }
00982 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_DATA_ROW_COUNT */
00983 
00984 
00985 /* ==================================
00986  *
00987  * Table Data API: Row operations
00988  *     (table-specific rows)
00989  *
00990  * ================================== */
00991 
00992 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_DATA_ROW_OPERATIONS
00993 void *
00994 netsnmp_table_data_entry_first(netsnmp_table_data *table)
00995 {
00996     netsnmp_table_row *row =
00997         netsnmp_table_data_get_first_row(table);
00998     return (row ? row->data : NULL );
00999 }
01000 
01001 void *
01002 netsnmp_table_data_entry_get(  netsnmp_table_data *table,
01003                                netsnmp_table_row  *row)
01004 {
01005     return (row ? row->data : NULL );
01006 }
01007 
01008 void *
01009 netsnmp_table_data_entry_next( netsnmp_table_data *table,
01010                                netsnmp_table_row  *row)
01011 {
01012     row =
01013         netsnmp_table_data_row_next(table, row);
01014     return (row ? row->data : NULL );
01015 }
01016 
01017 void *
01018 netsnmp_table_data_entry_get_byidx( netsnmp_table_data    *table,
01019                                     netsnmp_variable_list *indexes)
01020 {
01021     netsnmp_table_row *row =
01022         netsnmp_table_data_row_get_byidx(table, indexes);
01023     return (row ? row->data : NULL );
01024 }
01025 
01026 void *
01027 netsnmp_table_data_entry_next_byidx(netsnmp_table_data    *table,
01028                                     netsnmp_variable_list *indexes)
01029 {
01030     netsnmp_table_row *row =
01031         netsnmp_table_data_row_next_byidx(table, indexes);
01032     return (row ? row->data : NULL );
01033 }
01034 
01035 void *
01036 netsnmp_table_data_entry_get_byoid( netsnmp_table_data *table,
01037                                     oid *instance, size_t len)
01038 {
01039     netsnmp_table_row *row =
01040         netsnmp_table_data_row_get_byoid(table, instance, len);
01041     return (row ? row->data : NULL );
01042 }
01043 
01044 void *
01045 netsnmp_table_data_entry_next_byoid(netsnmp_table_data *table,
01046                                     oid *instance, size_t len)
01047 {
01048     netsnmp_table_row *row =
01049         netsnmp_table_data_row_next_byoid(table, instance, len);
01050     return (row ? row->data : NULL );
01051 }
01052 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_DATA_ROW_OPERATIONS */
01053 
01054     /* =====================================
01055      * Generic API - mostly renamed wrappers
01056      * ===================================== */
01057 
01058 /* ==================================
01059  *
01060  * Table Data API: Index operations
01061  *
01062  * ================================== */
01063 
01064 #else /* NETSNMP_FEATURE_REMOVE_TABLE_DATA */
01065 netsnmp_feature_unused(table_data);
01066 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_DATA */
01067