net-snmp 5.7
|
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