00001 /*
00002 * table.c
00003 */
00004
00005 #include <config.h>
00006
00007 #if HAVE_STRING_H
00008 #include <string.h>
00009 #else
00010 #include <strings.h>
00011 #endif
00012 #include <assert.h>
00013
00014 #include "mibincl.h"
00015 #include "tools.h"
00016 #include "snmp_agent.h"
00017 #include "table.h"
00018
00019 #if HAVE_DMALLOC_H
00020 #include <dmalloc.h>
00021 #endif
00022
00023
00024 mib_handler *
00025 get_table_handler(table_registration_info * tabreq)
00026 {
00027 mib_handler *ret = NULL;
00028
00029 if (!tabreq) {
00030 snmp_log(LOG_INFO, "get_table_handler(NULL) called\n");
00031 return NULL;
00032 }
00033
00034 ret = create_handler("table", table_helper_handler);
00035 if (ret) {
00036 ret->myvoid = (void *) tabreq;
00037 tabreq->number_indexes = count_varbinds(tabreq->indexes);
00038 }
00039 return ret;
00040 }
00041
00042
00043 int
00044 register_table(handler_registration * reginfo,
00045 table_registration_info * tabreq)
00046 {
00047 inject_handler(reginfo, get_table_handler(tabreq));
00048 return register_handler(reginfo);
00049 }
00050
00051 static void
00052 table_helper_cleanup(agent_request_info * reqinfo, request_info * request,
00053 int status)
00054 {
00055
00056 set_request_error(reqinfo, request, status);
00057 if (request->parent_data) {
00058 snmp_free_varbind(((table_request_info *) request->parent_data)->
00059 indexes);
00060 free(request->parent_data);
00061 request->parent_data = NULL;
00062 }
00063 }
00064
00065
00066 unsigned int
00067 closest_column(unsigned int current, column_info * valid_columns)
00068 {
00069 unsigned int closest = 0;
00070 char done = 0;
00071 char idx;
00072 assert(valid_columns != NULL);
00073
00074 do {
00075
00076 if (valid_columns->isRange) {
00077
00078 if (current < valid_columns->details.range[0]) {
00079 if (valid_columns->details.range[0] < closest) {
00080 closest = valid_columns->details.range[0];
00081 }
00082 } else if (current <= valid_columns->details.range[1]) {
00083 closest = current;
00084 done = 1; /* can not get any closer! */
00085 }
00086
00087 } /* range */
00088 else { /* list */
00089
00090 if (current < valid_columns->details.list[0]) {
00091 if (valid_columns->details.list[0] < closest)
00092 closest = valid_columns->details.list[0];
00093 continue;
00094 }
00095
00096 if (current >
00097 valid_columns->details.list[valid_columns->list_count])
00098 continue; /* not in list range. */
00099
00100 for (idx = 0; idx < valid_columns->list_count; ++idx) {
00101 if (current == valid_columns->details.list[idx]) {
00102 closest = current;
00103 done = 1; /* can not get any closer! */
00104 break; /* for */
00105 } else if (current < valid_columns->details.list[idx]) {
00106 if (valid_columns->details.list[idx] < closest)
00107 closest = valid_columns->details.list[idx];
00108 break; /* list should be sorted */
00109 }
00110 } /* for */
00111
00112 } /* list */
00113
00114 valid_columns = valid_columns->next;
00115
00116 } while (!done && valid_columns);
00117
00118 return closest;
00119 }
00120
00121 int
00122 table_helper_handler(mib_handler * handler,
00123 handler_registration * reginfo,
00124 agent_request_info * reqinfo, request_info * requests)
00125 {
00126
00127 request_info *request;
00128
00129 table_registration_info *tbl_info;
00130 int oid_index_pos = reginfo->rootoid_len + 2;
00131 int oid_column_pos = reginfo->rootoid_len + 1;
00132 int tmp_idx, tmp_len;
00133 int incomplete, out_of_range;
00134 int status = SNMP_ERR_NOERROR, need_processing = 0;
00135 oid *tmp_name;
00136 table_request_info *tbl_req_info;
00137 struct variable_list *vb;
00138
00139 tbl_info = (table_registration_info *) handler->myvoid;
00140
00141 if ((!handler->myvoid) || (!tbl_info->indexes)) {
00142 snmp_log(LOG_INFO, "improperly registered table found\n");
00143
00144 /*
00145 * XXX-rks: unregister table?
00146 */
00147 return SNMP_ERR_GENERR;
00148 }
00149
00150 /*
00151 * * if the agent request info has a state reference, then * this is a
00152 * later pass of a set request and we can * skip all the lookup stuff.
00153 */
00154 if (reqinfo->state_reference) {
00155 if (MODE_IS_SET(reqinfo->mode)) {
00156 return call_next_handler(handler, reginfo, reqinfo, requests);
00157 } else {
00158 #warning "XXX-rks: memory leak. add cleanup handler?"
00159 reqinfo->state_reference = NULL;
00160 }
00161 }
00162
00163
00164 /*
00165 * loop through requests
00166 */
00167
00168 DEBUGMSGTL(("helper:table", "Got request:\n"));
00169 for (request = requests; request; request = request->next) {
00170 struct variable_list *var = request->requestvb;
00171
00172 assert(request->parent_data == NULL);
00173
00174 DEBUGMSGTL(("helper:table", " oid:"));
00175 DEBUGMSGOID(("helper:table", var->name, var->name_length));
00176 DEBUGMSG(("helper:table", "\n"));
00177
00178 if (request->status)
00179 continue;
00180 ++need_processing;
00181
00182 /*
00183 * this should probably be handled further up
00184 */
00185 if ((reqinfo->mode == MODE_GET) && (var->type != ASN_NULL)) { /* valid
00186 * request
00187 * if
00188 * ASN_NULL
00189 */
00190 DEBUGMSGTL(("helper:table",
00191 " GET var type is not ASN_NULL\n"));
00192 set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
00193 continue;
00194 }
00195
00196 /*
00197 * check to make sure its in table range
00198 */
00199
00200 out_of_range = 0;
00201 /*
00202 * if our root oid i > var->name and this is not a GETNEXT,
00203 */
00204 /*
00205 * then the oid is out of range
00206 */
00207 if (snmp_oid_compare(reginfo->rootoid, reginfo->rootoid_len,
00208 var->name, reginfo->rootoid_len) > 0) {
00209 if (reqinfo->mode == MODE_GETNEXT) {
00210 if (var->name != var->name_loc)
00211 free(var->name);
00212 snmp_set_var_objid(var, reginfo->rootoid,
00213 reginfo->rootoid_len);
00214 } else {
00215 DEBUGMSGTL(("helper:table", " oid is out of range.\n"));
00216 out_of_range = 1;
00217 }
00218 }
00219 /*
00220 * if var->name is longer than the root, make sure it is
00221 */
00222 /*
00223 * table.1 (table.ENTRY).
00224 */
00225 else if ((var->name_length > reginfo->rootoid_len) &&
00226 (var->name[reginfo->rootoid_len] != 1)) {
00227 if ((var->name[reginfo->rootoid_len] < 1) &&
00228 (reqinfo->mode == MODE_GETNEXT)) {
00229 var->name[reginfo->rootoid_len] = 1;
00230 var->name_length = reginfo->rootoid_len;
00231 } else {
00232 out_of_range = 1;
00233 DEBUGMSGTL(("helper:table", " oid is out of range.\n"));
00234 }
00235 }
00236 /*
00237 * if it is not in range, then remove it from the request list
00238 */
00239 /*
00240 * because we can't process it. If the request is not a GETNEXT
00241 */
00242 /*
00243 * then set the error to NOSUCHOBJECT so nobody else wastes time
00244 */
00245 /*
00246 * trying to process it.
00247 */
00248 if (out_of_range) {
00249 DEBUGMSGTL(("helper:table", " Not processed.\n"));
00250 if (reqinfo->mode != MODE_GETNEXT) {
00251 table_helper_cleanup(reqinfo, request,
00252 SNMP_ERR_NOSUCHNAME);
00253 }
00254 continue;
00255 }
00256
00257
00258 /*
00259 * Check column ranges; set-up to pull out indexes from OID.
00260 */
00261
00262 incomplete = 0;
00263 tbl_req_info = SNMP_MALLOC_TYPEDEF(table_request_info);
00264 tbl_req_info->indexes = snmp_clone_varbind(tbl_info->indexes);
00265 tbl_req_info->number_indexes = 0; /* none yet */
00266 if (var->name_length > oid_column_pos) {
00267 if (var->name[oid_column_pos] < tbl_info->min_column) {
00268 /*
00269 * fix column, truncate useless index info
00270 */
00271 var->name_length = oid_column_pos;
00272 tbl_req_info->colnum = tbl_info->min_column;
00273 } else if (var->name[oid_column_pos] > tbl_info->max_column) {
00274 /*
00275 * this is out of range... remove from requests, free
00276 * memory
00277 */
00278 DEBUGMSGTL(("helper:table",
00279 " oid is out of range. Not processed.\n"));
00280 if (reqinfo->mode != MODE_GETNEXT) {
00281 table_helper_cleanup(reqinfo, request,
00282 SNMP_ERR_NOSUCHNAME);
00283 }
00284 continue;
00285 }
00286 /*
00287 * use column verification
00288 */
00289 else if (tbl_info->valid_columns) {
00290 tbl_req_info->colnum =
00291 closest_column(var->name[oid_column_pos],
00292 tbl_info->valid_columns);
00293 if (tbl_req_info->colnum == 0)
00294 continue;
00295 if (tbl_req_info->colnum != var->name[oid_column_pos]) {
00296 /*
00297 * different column! truncate useless index info
00298 */
00299 var->name_length = oid_column_pos;
00300 }
00301 }
00302 /*
00303 * var->name_length may have changed - check again
00304 */
00305 if (var->name_length <= oid_column_pos) { /* none available */
00306 tbl_req_info->index_oid_len = 0;
00307 } else {
00308 tbl_req_info->colnum = var->name[oid_column_pos];
00309 tbl_req_info->index_oid_len =
00310 var->name_length - oid_index_pos;
00311 assert(tbl_req_info->index_oid_len < MAX_OID_LEN);
00312 memcpy(tbl_req_info->index_oid, &var->name[oid_index_pos],
00313 tbl_req_info->index_oid_len * sizeof(oid));
00314 tmp_name = tbl_req_info->index_oid;
00315 }
00316 }
00317 if (tbl_req_info->index_oid_len == 0) {
00318 incomplete = 1;
00319 tmp_len = -1;
00320 } else
00321 tmp_len = tbl_req_info->index_oid_len;
00322
00323
00324 /*
00325 * for each index type, try to extract the index from var->name
00326 */
00327
00328 for (tmp_idx = 0, vb = tbl_req_info->indexes;
00329 tmp_idx < tbl_info->number_indexes;
00330 ++tmp_idx, vb = vb->next_variable) {
00331 if (incomplete && tmp_len) {
00332 /*
00333 * incomplete/illegal OID, set up dummy 0 to parse
00334 */
00335 DEBUGMSGTL(("helper:table",
00336 " oid indexes not complete.\n"));
00337 /*
00338 * no sense in trying anymore if this is a GET/SET.
00339 */
00340 if (reqinfo->mode != MODE_GETNEXT) {
00341 table_helper_cleanup(reqinfo, requests,
00342 SNMP_ERR_NOSUCHNAME);
00343 }
00344 tmp_len = 0;
00345 tmp_name = (oid *) & tmp_len;
00346 }
00347 /*
00348 * try and parse current index
00349 */
00350 if (parse_one_oid_index(&tmp_name, &tmp_len,
00351 vb, 1) != SNMPERR_SUCCESS) {
00352 incomplete = 1;
00353 tmp_len = -1; /* is this necessary? Better safe than
00354 * sorry */
00355 } else {
00356 /*
00357 * do not count incomplete indexes
00358 */
00359 if (incomplete)
00360 continue;
00361 ++tbl_req_info->number_indexes; /* got one ok */
00362 if (tmp_len <= 0) {
00363 incomplete = 1;
00364 tmp_len = -1; /* is this necessary? Better safe
00365 * than sorry */
00366 }
00367 }
00368 } /* for loop */
00369
00370
00371 /*
00372 * do we have sufficent index info to continue?
00373 */
00374
00375 if ((reqinfo->mode != MODE_GETNEXT) &&
00376 ((tbl_req_info->number_indexes != tbl_info->number_indexes) ||
00377 (tmp_len != -1))) {
00378 table_helper_cleanup(reqinfo, request, SNMP_ERR_NOSUCHNAME);
00379 }
00380
00381 DEBUGIF("helper:table") {
00382 int count;
00383 char buf[SPRINT_MAX_LEN];
00384 DEBUGMSGTL(("helper:table", " column: %d, indexes: %d\n",
00385 tbl_req_info->colnum,
00386 tbl_req_info->number_indexes));
00387 for (vb = tbl_req_info->indexes, count = 0;
00388 vb && count < tbl_info->number_indexes;
00389 count++, vb = vb->next_variable) {
00390 sprint_by_type(buf, vb, 0, 0, 0);
00391 DEBUGMSGTL(("helper:table",
00392 " index: type=%d, value=%s\n", vb->type,
00393 buf));
00394 }
00395 }
00396
00397 /*
00398 * save table_req_info
00399 */
00400 request->parent_data = (void *) tbl_req_info;
00401
00402 } /* for each request */
00403
00404
00405 /*
00406 * * call our child access function
00407 */
00408 if (need_processing)
00409 status = call_next_handler(handler, reginfo, reqinfo, requests);
00410
00411 return status;
00412 }
00413
00414 int
00415 table_build_oid(handler_registration * reginfo,
00416 request_info * reqinfo, table_request_info * table_info)
00417 {
00418 oid tmpoid[MAX_OID_LEN];
00419 struct variable_list *var;
00420
00421 if (!reginfo || !reqinfo || !table_info)
00422 return SNMPERR_GENERR;
00423
00424 memcpy(tmpoid, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid));
00425 tmpoid[reginfo->rootoid_len] = 1; /* .Entry */
00426 tmpoid[reginfo->rootoid_len + 1] = table_info->colnum; /* .column
00427 */
00428
00429 var = reqinfo->requestvb;
00430 if (build_oid(&var->name, &var->name_length,
00431 tmpoid, reginfo->rootoid_len + 2, table_info->indexes)
00432 != SNMPERR_SUCCESS)
00433 return SNMPERR_GENERR;
00434
00435 return SNMPERR_SUCCESS;
00436 }
00437
00438 int
00439 table_build_oid_from_index(handler_registration * reginfo,
00440 request_info * reqinfo,
00441 table_request_info * table_info)
00442 {
00443 oid tmpoid[MAX_OID_LEN];
00444 struct variable_list *var;
00445 int len;
00446
00447 if (!reginfo || !reqinfo || !table_info)
00448 return SNMPERR_GENERR;
00449
00450 var = reqinfo->requestvb;
00451 len = reginfo->rootoid_len;
00452 memcpy(tmpoid, reginfo->rootoid, len * sizeof(oid));
00453 tmpoid[len++] = 1; /* .Entry */
00454 tmpoid[len++] = table_info->colnum; /* .column */
00455 memcpy(&tmpoid[len], table_info->index_oid,
00456 table_info->index_oid_len * sizeof(oid));
00457 len += table_info->index_oid_len;
00458 snmp_clone_mem((void **) &var->name, tmpoid, len * sizeof(oid));
00459 var->name_length = len;
00460
00461 return SNMPERR_SUCCESS;
00462 }
00463
00464 int
00465 table_build_result(handler_registration * reginfo,
00466 request_info * reqinfo,
00467 table_request_info * table_info, u_char type,
00468 u_char * result, size_t result_len)
00469 {
00470
00471 struct variable_list *var;
00472
00473 if (!reqinfo || !table_info)
00474 return SNMPERR_GENERR;
00475
00476 var = reqinfo->requestvb;
00477
00478 if (var->name != var->name_loc)
00479 free(var->name);
00480 var->name = NULL;
00481
00482 if (table_build_oid(reginfo, reqinfo, table_info) != SNMPERR_SUCCESS)
00483 return SNMPERR_GENERR;
00484
00485 snmp_set_var_typed_value(var, type, result, result_len);
00486
00487 return SNMPERR_SUCCESS;
00488 }
00489
00490 int
00491 update_variable_list_from_index(table_request_info * tri)
00492 {
00493 return parse_oid_indexes(tri->index_oid, tri->index_oid_len,
00494 tri->indexes);
00495 }
00496
00497 int
00498 update_indexes_from_variable_list(table_request_info * tri)
00499 {
00500 return build_oid_noalloc(tri->index_oid, sizeof(tri->index_oid),
00501 &tri->index_oid_len, NULL, 0, tri->indexes);
00502 }
00503
00504 /*
00505 * checks the original request against the current data being passed in if
00506 * its greater than the request oid but less than the current valid
00507 * return, set the current valid return to the new value.
00508 *
00509 * returns 1 if outvar was replaced with the oid from newvar (success).
00510 * returns 0 if not.
00511 */
00512 int
00513 check_getnext_reply(request_info * request,
00514 oid * prefix,
00515 size_t prefix_len,
00516 struct variable_list *newvar,
00517 struct variable_list **outvar)
00518 {
00519 static oid myname[MAX_OID_LEN];
00520 static int myname_len;
00521
00522 build_oid_noalloc(myname, MAX_OID_LEN, &myname_len,
00523 prefix, prefix_len, newvar);
00524 /*
00525 * is the build of the new indexes less than our current result
00526 */
00527 if ((!(*outvar) || snmp_oid_compare(myname + prefix_len,
00528 myname_len - prefix_len,
00529 (*outvar)->name,
00530 (*outvar)->name_length) < 0)) {
00531 /*
00532 * and greater than the requested oid
00533 */
00534 if (snmp_oid_compare(myname, myname_len,
00535 request->requestvb->name,
00536 request->requestvb->name_length) > 0) {
00537 /*
00538 * the new result must be better than the old
00539 */
00540 if (!*outvar)
00541 *outvar = snmp_clone_varbind(newvar);
00542 snmp_set_var_objid(*outvar, myname, myname_len);
00543
00544 return 1;
00545 }
00546 }
00547 return 0;
00548 }
1.2.11 written by Dimitri van Heesch,
© 1997-2001
[an error occurred while processing this directive]
[an error occurred while processing this directive]
Last modified: Wednesday, 01-Aug-2018 04:41:28 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.