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