00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <net-snmp/net-snmp-config.h>
00017
00018 #if HAVE_STRING_H
00019 #include <string.h>
00020 #else
00021 #include <strings.h>
00022 #endif
00023
00024
00025 #include <net-snmp/net-snmp-includes.h>
00026 #include <net-snmp/agent/net-snmp-agent-includes.h>
00027
00028 #include <net-snmp/agent/table.h>
00029 #include <net-snmp/library/snmp_assert.h>
00030
00031 static void table_helper_cleanup(netsnmp_agent_request_info *reqinfo,
00032 netsnmp_request_info *request,
00033 int status);
00034 static void table_data_free_func(void *data);
00035 static int
00036 sparse_table_helper_handler(netsnmp_mib_handler *handler,
00037 netsnmp_handler_registration *reginfo,
00038 netsnmp_agent_request_info *reqinfo,
00039 netsnmp_request_info *requests);
00040
00084 netsnmp_mib_handler *
00085 netsnmp_get_table_handler(netsnmp_table_registration_info *tabreq)
00086 {
00087 netsnmp_mib_handler *ret = NULL;
00088
00089 if (!tabreq) {
00090 snmp_log(LOG_INFO, "netsnmp_get_table_handler(NULL) called\n");
00091 return NULL;
00092 }
00093
00094 ret = netsnmp_create_handler(TABLE_HANDLER_NAME, table_helper_handler);
00095 if (ret) {
00096 ret->myvoid = (void *) tabreq;
00097 tabreq->number_indexes = count_varbinds(tabreq->indexes);
00098 }
00099 return ret;
00100 }
00101
00102
00107 int
00108 netsnmp_register_table(netsnmp_handler_registration *reginfo,
00109 netsnmp_table_registration_info *tabreq)
00110 {
00111 netsnmp_inject_handler(reginfo, netsnmp_get_table_handler(tabreq));
00112 return netsnmp_register_handler(reginfo);
00113 }
00114
00124 NETSNMP_INLINE netsnmp_table_request_info *
00125 netsnmp_extract_table_info(netsnmp_request_info *request)
00126 {
00127 return (netsnmp_table_request_info *)
00128 netsnmp_request_get_list_data(request, TABLE_HANDLER_NAME);
00129 }
00130
00133 netsnmp_table_registration_info *
00134 netsnmp_find_table_registration_info(netsnmp_handler_registration *reginfo)
00135 {
00136 return (netsnmp_table_registration_info *)
00137 netsnmp_find_handler_data_by_name(reginfo, TABLE_HANDLER_NAME);
00138 }
00139
00141 int
00142 table_helper_handler(netsnmp_mib_handler *handler,
00143 netsnmp_handler_registration *reginfo,
00144 netsnmp_agent_request_info *reqinfo,
00145 netsnmp_request_info *requests)
00146 {
00147
00148 netsnmp_request_info *request;
00149 netsnmp_table_registration_info *tbl_info;
00150 int oid_index_pos;
00151 unsigned int oid_column_pos;
00152 unsigned int tmp_idx;
00153 size_t tmp_len;
00154 int incomplete, out_of_range, cleaned_up = 0;
00155 int status = SNMP_ERR_NOERROR, need_processing = 0;
00156 oid *tmp_name;
00157 netsnmp_table_request_info *tbl_req_info;
00158 netsnmp_variable_list *vb;
00159
00160 if (!reginfo || !handler)
00161 return SNMPERR_GENERR;
00162
00163 oid_index_pos = reginfo->rootoid_len + 2;
00164 oid_column_pos = reginfo->rootoid_len + 1;
00165 tbl_info = (netsnmp_table_registration_info *) handler->myvoid;
00166
00167 if ((!handler->myvoid) || (!tbl_info->indexes)) {
00168 snmp_log(LOG_ERR, "improperly registered table found\n");
00169 snmp_log(LOG_ERR, "name: %s, table info: %p, indexes: %p\n",
00170 handler->handler_name, handler->myvoid, tbl_info->indexes);
00171
00172
00173
00174
00175 return SNMP_ERR_GENERR;
00176 }
00177
00178 DEBUGIF("helper:table:req") {
00179 DEBUGMSGTL(("helper:table:req",
00180 "Got request for handler %s: base oid:",
00181 handler->handler_name));
00182 DEBUGMSGOID(("helper:table:req", reginfo->rootoid,
00183 reginfo->rootoid_len));
00184 DEBUGMSG(("helper:table:req", "\n"));
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 if (netsnmp_agent_get_list_data(reqinfo, handler->next->handler_name)) {
00196 if (MODE_IS_SET(reqinfo->mode)) {
00197 return netsnmp_call_next_handler(handler, reginfo, reqinfo,
00198 requests);
00199 } else {
00201 netsnmp_free_agent_data_sets(reqinfo);
00202 }
00203 }
00204
00205 if ( MODE_IS_SET(reqinfo->mode) &&
00206 (reqinfo->mode != MODE_SET_RESERVE1)) {
00207
00208
00209
00210
00211
00212
00213 if(NULL == netsnmp_extract_table_info(requests)) {
00214 DEBUGMSGTL(("table:helper","no table info for set - skipping\n"));
00215 }
00216 else
00217 need_processing = 1;
00218 }
00219 else {
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 for (request = requests; request; request = request->next) {
00230 netsnmp_variable_list *var = request->requestvb;
00231
00232 DEBUGMSGOID(("verbose:table", var->name, var->name_length));
00233 DEBUGMSG(("verbose:table", "\n"));
00234
00235 if (request->processed) {
00236 DEBUGMSG(("verbose:table", "already processed\n"));
00237 continue;
00238 }
00239 netsnmp_assert(request->status == SNMP_ERR_NOERROR);
00240
00241
00242
00243
00244 if ((reqinfo->mode == MODE_GET) && (var->type != ASN_NULL)) {
00245
00246
00247
00248 DEBUGMSGTL(("helper:table",
00249 " GET var type is not ASN_NULL\n"));
00250 netsnmp_set_request_error(reqinfo, request,
00251 SNMP_ERR_WRONGTYPE);
00252 continue;
00253 }
00254
00255 if (reqinfo->mode == MODE_SET_RESERVE1) {
00256 DEBUGIF("helper:table:set") {
00257 u_char *buf = NULL;
00258 size_t buf_len = 0, out_len = 0;
00259 DEBUGMSGTL(("helper:table:set", " SET_REQUEST for OID: "));
00260 DEBUGMSGOID(("helper:table:set", var->name, var->name_length));
00261 out_len = 0;
00262 if (sprint_realloc_by_type(&buf, &buf_len, &out_len, 1,
00263 var, 0, 0, 0)) {
00264 DEBUGMSG(("helper:table:set"," type=%d(%02x), value=%s\n",
00265 var->type, var->type, buf));
00266 } else {
00267 if (buf != NULL) {
00268 DEBUGMSG(("helper:table:set",
00269 " type=%d(%02x), value=%s [TRUNCATED]\n",
00270 var->type, var->type, buf));
00271 } else {
00272 DEBUGMSG(("helper:table:set",
00273 " type=%d(%02x), value=[NIL] [TRUNCATED]\n",
00274 var->type, var->type));
00275 }
00276 }
00277 if (buf != NULL) {
00278 free(buf);
00279 }
00280 }
00281 }
00282
00283
00284
00285
00286
00287 out_of_range = 0;
00288
00289
00290
00291
00292
00293 if (reginfo->rootoid_len > var->name_length)
00294 tmp_len = var->name_length;
00295 else
00296 tmp_len = reginfo->rootoid_len;
00297 if (snmp_oid_compare(reginfo->rootoid, reginfo->rootoid_len,
00298 var->name, tmp_len) > 0) {
00299 if (reqinfo->mode == MODE_GETNEXT) {
00300 if (var->name != var->name_loc)
00301 SNMP_FREE(var->name);
00302 snmp_set_var_objid(var, reginfo->rootoid,
00303 reginfo->rootoid_len);
00304 } else {
00305 DEBUGMSGTL(("helper:table", " oid is out of range.\n"));
00306 out_of_range = 1;
00307 }
00308 }
00309
00310
00311
00312
00313 else if ((var->name_length > reginfo->rootoid_len) &&
00314 (var->name[reginfo->rootoid_len] != 1)) {
00315 if ((var->name[reginfo->rootoid_len] < 1) &&
00316 (reqinfo->mode == MODE_GETNEXT)) {
00317 var->name[reginfo->rootoid_len] = 1;
00318 var->name_length = reginfo->rootoid_len;
00319 } else {
00320 out_of_range = 1;
00321 DEBUGMSGTL(("helper:table", " oid is out of range.\n"));
00322 }
00323 }
00324
00325
00326
00327
00328
00329 if (out_of_range) {
00330 DEBUGMSGTL(("helper:table", " Not processed: "));
00331 DEBUGMSGOID(("helper:table", var->name, var->name_length));
00332 DEBUGMSG(("helper:table", "\n"));
00333
00334
00335
00336
00337 if (reqinfo->mode == MODE_SET_RESERVE1)
00338 table_helper_cleanup(reqinfo, request,
00339 SNMP_ERR_NOTWRITABLE);
00340 else if (reqinfo->mode == MODE_GET)
00341 table_helper_cleanup(reqinfo, request,
00342 SNMP_NOSUCHOBJECT);
00343 continue;
00344 }
00345
00346
00347
00348
00349
00350
00351 incomplete = 0;
00352 tbl_req_info = netsnmp_extract_table_info(request);
00353 if (NULL == tbl_req_info) {
00354 tbl_req_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_request_info);
00355 tbl_req_info->reg_info = tbl_info;
00356 tbl_req_info->indexes = snmp_clone_varbind(tbl_info->indexes);
00357 tbl_req_info->number_indexes = 0;
00358 netsnmp_request_add_list_data(request,
00359 netsnmp_create_data_list
00360 (TABLE_HANDLER_NAME,
00361 (void *) tbl_req_info,
00362 table_data_free_func));
00363 } else {
00364 DEBUGMSGTL(("helper:table", " using existing tbl_req_info\n "));
00365 }
00366
00367
00368
00369
00370 if (var->name_length > oid_column_pos) {
00371
00372
00373
00374 DEBUGMSGTL(("helper:table:col", " have at least a column (%d)\n",
00375 var->name[oid_column_pos]));
00376 if (var->name[oid_column_pos] < tbl_info->min_column) {
00377 DEBUGMSGTL(("helper:table:col",
00378 " but it's less than min (%d)\n",
00379 tbl_info->min_column));
00380 if (reqinfo->mode == MODE_GETNEXT) {
00381
00382
00383
00384 var->name_length = oid_column_pos;
00385 tbl_req_info->colnum = tbl_info->min_column;
00386 } else
00387 out_of_range = 1;
00388 } else if (var->name[oid_column_pos] > tbl_info->max_column)
00389 out_of_range = 1;
00390 else
00391 tbl_req_info->colnum = var->name[oid_column_pos];
00392
00393 if (out_of_range) {
00394
00395
00396
00397
00398 DEBUGMSGTL(("helper:table",
00399 " oid is out of range. Not processed: "));
00400 DEBUGMSGOID(("helper:table", var->name, var->name_length));
00401 DEBUGMSG(("helper:table", "\n"));
00402
00403
00404
00405
00406 if (reqinfo->mode == MODE_SET_RESERVE1)
00407 table_helper_cleanup(reqinfo, request,
00408 SNMP_ERR_NOTWRITABLE);
00409 else if (reqinfo->mode == MODE_GET)
00410 table_helper_cleanup(reqinfo, request,
00411 SNMP_NOSUCHOBJECT);
00412 continue;
00413 }
00414
00415
00416
00417 else if (tbl_info->valid_columns) {
00418 tbl_req_info->colnum =
00419 netsnmp_closest_column(var->name[oid_column_pos],
00420 tbl_info->valid_columns);
00421 DEBUGMSGTL(("helper:table:col", " closest column is %d\n",
00422 tbl_req_info->colnum));
00423
00424
00425
00426 if (tbl_req_info->colnum == 0)
00427 continue;
00428 if (tbl_req_info->colnum != var->name[oid_column_pos]) {
00429 DEBUGMSGTL(("helper:table:col",
00430 " which doesn't match req %d - truncating index info\n",
00431 var->name[oid_column_pos]));
00432
00433
00434
00435 var->name_length = oid_column_pos + 1;
00436 }
00437 }
00438
00439
00440
00441 if ((int)var->name_length <= oid_index_pos) {
00442 DEBUGMSGTL(("helper:table", " not enough for indexes\n"));
00443 tbl_req_info->index_oid_len = 0;
00444 } else {
00445
00446
00447
00448 tbl_req_info->index_oid_len =
00449 var->name_length - oid_index_pos;
00450 DEBUGMSGTL(("helper:table", " have %d bytes of index\n",
00451 tbl_req_info->index_oid_len));
00452 netsnmp_assert(tbl_req_info->index_oid_len < MAX_OID_LEN);
00453 memcpy(tbl_req_info->index_oid, &var->name[oid_index_pos],
00454 tbl_req_info->index_oid_len * sizeof(oid));
00455 tmp_name = tbl_req_info->index_oid;
00456 }
00457 } else if (reqinfo->mode == MODE_GETNEXT ||
00458 reqinfo->mode == MODE_GETBULK) {
00459
00460
00461
00462
00463
00464 DEBUGMSGTL(("helper:table", " no column/index in request\n"));
00465 tbl_req_info->index_oid_len = 0;
00466 tbl_req_info->colnum = tbl_info->min_column;
00467 } else {
00468
00469
00470
00471
00472
00473
00474 if (reqinfo->mode == MODE_GET ) {
00475 table_helper_cleanup(reqinfo, request, SNMP_NOSUCHOBJECT);
00476 } else if (reqinfo->mode == MODE_SET_RESERVE1 ) {
00477 table_helper_cleanup(reqinfo, request, SNMP_ERR_NOTWRITABLE);
00478 }
00479 continue;
00480 }
00481
00482
00483
00484
00485
00486
00487
00488 if (tbl_req_info->index_oid_len == 0) {
00489 incomplete = 1;
00490 tmp_len = -1;
00491 } else
00492 tmp_len = tbl_req_info->index_oid_len;
00493
00494
00495
00496
00497
00498 DEBUGMSGTL(("helper:table", " looking for %d indexes\n",
00499 tbl_info->number_indexes));
00500 for (tmp_idx = 0, vb = tbl_req_info->indexes;
00501 tmp_idx < tbl_info->number_indexes;
00502 ++tmp_idx, vb = vb->next_variable) {
00503 if (incomplete && tmp_len) {
00504
00505
00506
00507 DEBUGMSGTL(("helper:table",
00508 " oid indexes not complete: "));
00509 DEBUGMSGOID(("helper:table", var->name, var->name_length));
00510 DEBUGMSG(("helper:table", "\n"));
00511
00512
00513
00514
00515
00516
00517 if (reqinfo->mode != MODE_GETNEXT) {
00518 table_helper_cleanup(reqinfo, requests,
00519 SNMP_NOSUCHINSTANCE);
00520 cleaned_up = 1;
00521 }
00522 tmp_len = 0;
00523 tmp_name = (oid *) & tmp_len;
00524 break;
00525 }
00526
00527
00528
00529 if (parse_one_oid_index(&tmp_name, &tmp_len,
00530 vb, 1) != SNMPERR_SUCCESS) {
00531 incomplete = 1;
00532 tmp_len = -1;
00533
00534 } else {
00535
00536
00537
00538 DEBUGMSGTL(("helper:table", " got 1 (incomplete=%d)\n",
00539 incomplete));
00540 if (incomplete)
00541 continue;
00542 ++tbl_req_info->number_indexes;
00543 if (tmp_len <= 0) {
00544 incomplete = 1;
00545 tmp_len = -1;
00546
00547 }
00548 }
00549 }
00551 DEBUGIF("helper:table:results") {
00552 DEBUGMSGTL(("helper:table:results", " found %d indexes\n",
00553 tbl_req_info->number_indexes));
00554 if (!cleaned_up) {
00555 unsigned int count;
00556 u_char *buf = NULL;
00557 size_t buf_len = 0, out_len = 0;
00558 DEBUGMSGTL(("helper:table:results",
00559 " column: %d, indexes: %d",
00560 tbl_req_info->colnum,
00561 tbl_req_info->number_indexes));
00562 for (vb = tbl_req_info->indexes, count = 0;
00563 vb && count < tbl_req_info->number_indexes;
00564 count++, vb = vb->next_variable) {
00565 out_len = 0;
00566 if (sprint_realloc_by_type(&buf, &buf_len, &out_len, 1,
00567 vb, 0, 0, 0)) {
00568 DEBUGMSG(("helper:table:results",
00569 " index: type=%d(%02x), value=%s",
00570 vb->type, vb->type, buf));
00571 } else {
00572 if (buf != NULL) {
00573 DEBUGMSG(("helper:table:results",
00574 " index: type=%d(%02x), value=%s [TRUNCATED]",
00575 vb->type, vb->type, buf));
00576 } else {
00577 DEBUGMSG(("helper:table:results",
00578 " index: type=%d(%02x), value=[NIL] [TRUNCATED]",
00579 vb->type, vb->type));
00580 }
00581 }
00582 }
00583 if (buf != NULL) {
00584 free(buf);
00585 }
00586 DEBUGMSG(("helper:table:results", "\n"));
00587 }
00588 }
00589
00590
00591
00592
00593
00594
00595 if ((reqinfo->mode != MODE_GETNEXT) &&
00596 ((tbl_req_info->number_indexes != tbl_info->number_indexes) ||
00597 (tmp_len != -1))) {
00598 DEBUGMSGTL(("helper:table",
00599 "invalid index(es) for table - skipping\n"));
00600 table_helper_cleanup(reqinfo, request, SNMP_NOSUCHINSTANCE);
00601 continue;
00602 }
00603 netsnmp_assert(request->status == SNMP_ERR_NOERROR);
00604
00605 ++need_processing;
00606
00607 }
00608 }
00609
00610
00611
00612
00613 if (0 == need_processing)
00614 return status;
00615
00616
00617
00618
00619 status =
00620 netsnmp_call_next_handler(handler, reginfo, reqinfo, requests);
00621
00622
00623
00624
00625 if (reqinfo->mode == MODE_GETNEXT)
00626 sparse_table_helper_handler( handler, reginfo, reqinfo, requests );
00627
00628 return status;
00629 }
00630
00631 #define SPARSE_TABLE_HANDLER_NAME "sparse_table"
00632
00641 static int
00642 sparse_table_helper_handler(netsnmp_mib_handler *handler,
00643 netsnmp_handler_registration *reginfo,
00644 netsnmp_agent_request_info *reqinfo,
00645 netsnmp_request_info *requests)
00646 {
00647 int status = SNMP_ERR_NOERROR;
00648 netsnmp_request_info *request;
00649 oid coloid[MAX_OID_LEN];
00650 netsnmp_table_request_info *table_info;
00651
00652
00653
00654
00655
00656
00657 if((table_helper_handler != handler->access_method) &&
00658 (NULL != handler->next)) {
00659
00660
00661
00662
00663 if((sparse_table_helper_handler != handler->access_method) ||
00664 !(handler->flags & MIB_HANDLER_CUSTOM1)) {
00665 snmp_log(LOG_WARNING, "handler (%s) registered after sparse table "
00666 "hander will not be called\n",
00667 handler->next->handler_name ?
00668 handler->next->handler_name : "" );
00669 if(sparse_table_helper_handler == handler->access_method)
00670 handler->flags |= MIB_HANDLER_CUSTOM1;
00671 }
00672 }
00673
00674 if (reqinfo->mode == MODE_GETNEXT) {
00675 for(request = requests ; request; request = request->next) {
00676 if ((request->requestvb->type == ASN_NULL && request->processed) ||
00677 request->delegated)
00678 continue;
00679 if (request->requestvb->type == SNMP_NOSUCHINSTANCE) {
00680
00681
00682
00683
00684 DEBUGMSGT(("sparse", "retry for NOSUCHINSTANCE\n"));
00685 request->requestvb->type = ASN_PRIV_RETRY;
00686 }
00687 if (request->requestvb->type == SNMP_NOSUCHOBJECT ||
00688 request->requestvb->type == SNMP_ENDOFMIBVIEW) {
00689
00690
00691
00692
00693 DEBUGMSGT(("sparse", "retry for NOSUCHOBJECT\n"));
00694 table_info = netsnmp_extract_table_info(request);
00695 table_info->colnum = netsnmp_table_next_column(table_info);
00696 if (0 != table_info->colnum) {
00697 memcpy(coloid, reginfo->rootoid,
00698 reginfo->rootoid_len * sizeof(oid));
00699 coloid[reginfo->rootoid_len] = 1;
00700 coloid[reginfo->rootoid_len+1] = table_info->colnum;
00701 snmp_set_var_objid(request->requestvb,
00702 coloid, reginfo->rootoid_len + 2);
00703
00704 request->requestvb->type = ASN_PRIV_RETRY;
00705 }
00706 else {
00707
00708
00709
00710
00711 request->requestvb->type = ASN_NULL;
00712 }
00713 }
00714 }
00715 }
00716 return status;
00717 }
00718
00721 netsnmp_mib_handler *
00722 netsnmp_sparse_table_handler_get(void)
00723 {
00724 return netsnmp_create_handler(SPARSE_TABLE_HANDLER_NAME,
00725 sparse_table_helper_handler);
00726 }
00727
00732 int
00733 netsnmp_sparse_table_register(netsnmp_handler_registration *reginfo,
00734 netsnmp_table_registration_info *tabreq)
00735 {
00736 netsnmp_inject_handler(reginfo,
00737 netsnmp_create_handler(SPARSE_TABLE_HANDLER_NAME,
00738 sparse_table_helper_handler));
00739 netsnmp_inject_handler(reginfo, netsnmp_get_table_handler(tabreq));
00740 return netsnmp_register_handler(reginfo);
00741 }
00742
00743
00750 int
00751 netsnmp_table_build_result(netsnmp_handler_registration *reginfo,
00752 netsnmp_request_info *reqinfo,
00753 netsnmp_table_request_info *table_info,
00754 u_char type, u_char * result, size_t result_len)
00755 {
00756
00757 netsnmp_variable_list *var;
00758
00759 if (!reqinfo || !table_info)
00760 return SNMPERR_GENERR;
00761
00762 var = reqinfo->requestvb;
00763
00764 if (var->name != var->name_loc)
00765 free(var->name);
00766 var->name = NULL;
00767
00768 if (netsnmp_table_build_oid(reginfo, reqinfo, table_info) !=
00769 SNMPERR_SUCCESS)
00770 return SNMPERR_GENERR;
00771
00772 snmp_set_var_typed_value(var, type, result, result_len);
00773
00774 return SNMPERR_SUCCESS;
00775 }
00776
00777
00783 int
00784 netsnmp_table_build_oid(netsnmp_handler_registration *reginfo,
00785 netsnmp_request_info *reqinfo,
00786 netsnmp_table_request_info *table_info)
00787 {
00788 oid tmpoid[MAX_OID_LEN];
00789 netsnmp_variable_list *var;
00790
00791 if (!reginfo || !reqinfo || !table_info)
00792 return SNMPERR_GENERR;
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802 memcpy(tmpoid, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid));
00803 tmpoid[reginfo->rootoid_len] = 1;
00804 tmpoid[reginfo->rootoid_len + 1] = table_info->colnum;
00806 var = reqinfo->requestvb;
00807 if (build_oid(&var->name, &var->name_length,
00808 tmpoid, reginfo->rootoid_len + 2, table_info->indexes)
00809 != SNMPERR_SUCCESS)
00810 return SNMPERR_GENERR;
00811
00812 return SNMPERR_SUCCESS;
00813 }
00814
00820 int
00821 netsnmp_table_build_oid_from_index(netsnmp_handler_registration *reginfo,
00822 netsnmp_request_info *reqinfo,
00823 netsnmp_table_request_info *table_info)
00824 {
00825 oid tmpoid[MAX_OID_LEN];
00826 netsnmp_variable_list *var;
00827 int len;
00828
00829 if (!reginfo || !reqinfo || !table_info)
00830 return SNMPERR_GENERR;
00831
00832 var = reqinfo->requestvb;
00833 len = reginfo->rootoid_len;
00834 memcpy(tmpoid, reginfo->rootoid, len * sizeof(oid));
00835 tmpoid[len++] = 1;
00836 tmpoid[len++] = table_info->colnum;
00837 memcpy(&tmpoid[len], table_info->index_oid,
00838 table_info->index_oid_len * sizeof(oid));
00839 len += table_info->index_oid_len;
00840 if (var->name && var->name != var->name_loc)
00841 SNMP_FREE(var->name);
00842 snmp_clone_mem((void **) &var->name, tmpoid, len * sizeof(oid));
00843 var->name_length = len;
00844
00845 return SNMPERR_SUCCESS;
00846 }
00847
00849 int
00850 netsnmp_update_variable_list_from_index(netsnmp_table_request_info *tri)
00851 {
00852 if (!tri)
00853 return SNMPERR_GENERR;
00854
00855
00856
00857
00858 snmp_reset_var_buffers( tri->indexes);
00859
00860 return parse_oid_indexes(tri->index_oid, tri->index_oid_len,
00861 tri->indexes);
00862 }
00863
00865 int
00866 netsnmp_update_indexes_from_variable_list(netsnmp_table_request_info *tri)
00867 {
00868 if (!tri)
00869 return SNMPERR_GENERR;
00870
00871 return build_oid_noalloc(tri->index_oid, sizeof(tri->index_oid),
00872 &tri->index_oid_len, NULL, 0, tri->indexes);
00873 }
00874
00883 int
00884 netsnmp_check_getnext_reply(netsnmp_request_info *request,
00885 oid * prefix,
00886 size_t prefix_len,
00887 netsnmp_variable_list * newvar,
00888 netsnmp_variable_list ** outvar)
00889 {
00890 oid myname[MAX_OID_LEN];
00891 size_t myname_len;
00892
00893 build_oid_noalloc(myname, MAX_OID_LEN, &myname_len,
00894 prefix, prefix_len, newvar);
00895
00896
00897
00898 if ((!(*outvar) || snmp_oid_compare(myname + prefix_len,
00899 myname_len - prefix_len,
00900 (*outvar)->name + prefix_len,
00901 (*outvar)->name_length -
00902 prefix_len) < 0)) {
00903
00904
00905
00906 if (snmp_oid_compare(myname, myname_len,
00907 request->requestvb->name,
00908 request->requestvb->name_length) > 0) {
00909
00910
00911
00912 #ifdef ONLY_WORKS_WITH_ONE_VARBIND
00913 if (!*outvar)
00914 *outvar = snmp_clone_varbind(newvar);
00915 else
00916
00917
00918
00919
00920 snmp_set_var_typed_value(*outvar, newvar->type,
00921 newvar->val.string, newvar->val_len);
00922 #else
00923 if (*outvar)
00924 snmp_free_varbind(*outvar);
00925 *outvar = snmp_clone_varbind(newvar);
00926 #endif
00927 snmp_set_var_objid(*outvar, myname, myname_len);
00928
00929 return 1;
00930 }
00931 }
00932 return 0;
00933 }
00934
00937
00938
00939
00940 void
00941 table_data_free_func(void *data)
00942 {
00943 netsnmp_table_request_info *info = (netsnmp_table_request_info *) data;
00944 if (!info)
00945 return;
00946 snmp_free_varbind(info->indexes);
00947 free(info);
00948 }
00949
00950
00951
00952 static void
00953 table_helper_cleanup(netsnmp_agent_request_info *reqinfo,
00954 netsnmp_request_info *request, int status)
00955 {
00956 netsnmp_set_request_error(reqinfo, request, status);
00957 netsnmp_free_request_data_sets(request);
00958 if (!request)
00959 return;
00960 request->parent_data = NULL;
00961 }
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973 unsigned int
00974 netsnmp_closest_column(unsigned int current,
00975 netsnmp_column_info *valid_columns)
00976 {
00977 unsigned int closest = 0;
00978 int idx;
00979
00980 if (valid_columns == NULL)
00981 return 0;
00982
00983 for( ; valid_columns; valid_columns = valid_columns->next) {
00984
00985 if (valid_columns->isRange) {
00986
00987
00988
00989
00990
00991 if (current < valid_columns->details.range[0]) {
00992 if ( (valid_columns->details.range[0] < closest) ||
00993 (0 == closest)) {
00994 closest = valid_columns->details.range[0];
00995 }
00996 } else if (current <= valid_columns->details.range[1]) {
00997 closest = current;
00998 break;
00999 }
01000
01001 }
01002 else {
01003
01004
01005
01006
01007 if (current < valid_columns->details.list[0]) {
01008 if ((valid_columns->details.list[0] < closest) ||
01009 (0 == closest))
01010 closest = valid_columns->details.list[0];
01011 continue;
01012 }
01013
01015 if (current >
01016 valid_columns->details.list[(int)valid_columns->list_count - 1])
01017 continue;
01018
01020 for (idx = 0; valid_columns->details.list[idx] < current; ++idx)
01021 ;
01022
01024 if (current == valid_columns->details.list[idx]) {
01025 closest = current;
01026 break;
01027 }
01028
01030 if ((valid_columns->details.list[idx] < closest) ||
01031 (0 == closest))
01032 closest = valid_columns->details.list[idx];
01033
01034 }
01035 }
01036
01037 return closest;
01038 }
01039
01059 void
01060 #if HAVE_STDARG_H
01061 netsnmp_table_helper_add_indexes(netsnmp_table_registration_info *tinfo,
01062 ...)
01063 #else
01064 netsnmp_table_helper_add_indexes(va_alist)
01065 va_dcl
01066 #endif
01067 {
01068 va_list debugargs;
01069 int type;
01070
01071 #if HAVE_STDARG_H
01072 va_start(debugargs, tinfo);
01073 #else
01074 netsnmp_table_registration_info *tinfo;
01075
01076 va_start(debugargs);
01077 tinfo = va_arg(debugargs, netsnmp_table_registration_info *);
01078 #endif
01079
01080 while ((type = va_arg(debugargs, int)) != 0) {
01081 netsnmp_table_helper_add_index(tinfo, type);
01082 }
01083
01084 va_end(debugargs);
01085 }
01086
01087 static void
01088 _row_stash_data_list_free(void *ptr) {
01089 netsnmp_oid_stash_node **tmp = (netsnmp_oid_stash_node **)ptr;
01090 netsnmp_oid_stash_free(tmp, NULL);
01091 free(ptr);
01092 }
01093
01096 netsnmp_oid_stash_node **
01097 netsnmp_table_get_or_create_row_stash(netsnmp_agent_request_info *reqinfo,
01098 const u_char * storage_name)
01099 {
01100 netsnmp_oid_stash_node **stashp = NULL;
01101 stashp = (netsnmp_oid_stash_node **)
01102 netsnmp_agent_get_list_data(reqinfo, storage_name);
01103
01104 if (!stashp) {
01105
01106
01107
01108 stashp = SNMP_MALLOC_TYPEDEF(netsnmp_oid_stash_node *);
01109
01110 if (!stashp)
01111 return NULL;
01112
01113 netsnmp_agent_add_list_data(reqinfo,
01114 netsnmp_create_data_list(storage_name,
01115 stashp,
01116 _row_stash_data_list_free));
01117 }
01118 return stashp;
01119 }
01120
01121
01122
01123
01124
01125
01126 unsigned int
01127 netsnmp_table_next_column(netsnmp_table_request_info *table_info)
01128 {
01129 if (NULL == table_info)
01130 return 0;
01131
01132
01133
01134
01135 if (table_info->reg_info->valid_columns)
01136 return netsnmp_closest_column(table_info->colnum + 1,
01137 table_info->reg_info->valid_columns);
01138
01139
01140
01141
01142 if (table_info->colnum < table_info->reg_info->max_column)
01143 return table_info->colnum + 1;
01144
01145 return 0;
01146 }