/********************************************************************** ********************************************************************** * * * * * netsnmp_table_array_helper_handler() * * * * * ********************************************************************** **********************************************************************/ int netsnmp_table_array_helper_handler (netsnmp_mib_handler * handler, netsnmp_handler_registration * reginfo, netsnmp_agent_request_info * agtreq_info, netsnmp_request_info * requests) { /* * First off, get our pointer from the handler. This * lets us get to the table registration information we * saved in get_table_array_handler(), as well as the * container where the actual table data is stored. */ int rc = SNMP_ERR_NOERROR; table_container_data *tad = (table_container_data *) handler->myvoid; if (agtreq_info->mode < 0 || agtreq_info->mode > 5) { DEBUGMSGTL (("table_array", "Mode %d, Got request:\n", agtreq_info->mode)); } else { DEBUGMSGTL (("table_array", "Mode %s, Got request:\n", mode_name[agtreq_info->mode])); } #ifndef NETSNMP_NO_WRITE_SUPPORT if (MODE_IS_SET (agtreq_info->mode)) { /* * netsnmp_mutex_lock(&tad->lock); */ rc = process_set_requests (agtreq_info, requests, tad, handler->handler_name); /* * netsnmp_mutex_unlock(&tad->lock); */ } else #endif /* NETSNMP_NO_WRITE_SUPPORT */ rc = process_get_requests (reginfo, agtreq_info, requests, tad); if (rc != SNMP_ERR_NOERROR) { DEBUGMSGTL (("table_array", "processing returned rc %d\n", rc)); } /* * Now we've done our processing. If there is another handler below us, * call them. */ if (handler->next) { rc = netsnmp_call_next_handler (handler, reginfo, agtreq_info, requests); if (rc != SNMP_ERR_NOERROR) { DEBUGMSGTL (("table_array", "next handler returned rc %d\n", rc)); } } return rc; }
/** updates a given cache depending on whether it needs to or not. */ int _netsnmp_stash_cache_load( netsnmp_cache *cache, void *magic ) { netsnmp_mib_handler *handler = cache->cache_hint->handler; netsnmp_handler_registration *reginfo = cache->cache_hint->reginfo; netsnmp_agent_request_info *reqinfo = cache->cache_hint->reqinfo; netsnmp_request_info *requests = cache->cache_hint->requests; netsnmp_stash_cache_info *cinfo = (netsnmp_stash_cache_info*) magic; int old_mode; int ret; if (!cinfo) { cinfo = netsnmp_get_new_stash_cache(); cache->magic = cinfo; } /* change modes to the GET_STASH mode */ old_mode = reqinfo->mode; reqinfo->mode = MODE_GET_STASH; netsnmp_agent_add_list_data(reqinfo, netsnmp_create_data_list(STASH_CACHE_NAME, &cinfo->cache, NULL)); /* have the next handler fill stuff in and switch modes back */ ret = netsnmp_call_next_handler(handler->next, reginfo, reqinfo, requests); reqinfo->mode = old_mode; return ret; }
static int _count_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { int val; if (MODE_GET != reqinfo->mode) { snmp_log(LOG_ERR, "bad mode in RO handler"); return SNMP_ERR_GENERR; } if (NULL == _table->container) val = 0; else val = CONTAINER_SIZE(_table->container); snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &val, sizeof(val)); if (handler->next && handler->next->access_method) return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); return SNMP_ERR_NOERROR; }
/** * \deprecated This function is unused and scheduled for removal in Net-SNMP 5.6 */ int netsnmp_instance_counter32_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { u_long *it = (u_long *) handler->myvoid; DEBUGMSGTL(("netsnmp_instance_counter32_handler", "Got request: %d\n", reqinfo->mode)); switch (reqinfo->mode) { /* * data requests */ case MODE_GET: snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) it, sizeof(*it)); break; /* * SET requests. Should only get here if registered RWRITE */ default: snmp_log(LOG_ERR, "netsnmp_instance_counter32_handler: illegal mode\n"); netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR); return SNMP_ERR_NOERROR; } if (handler->next && handler->next->access_method) return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); return SNMP_ERR_NOERROR; }
/** @internal Implements the mode_end_call handler */ int netsnmp_mode_end_call_helper(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { int ret; int ret2 = SNMP_ERR_NOERROR; netsnmp_mode_handler_list *ptr; /* always call the real handlers first */ ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); /* then call the callback handlers */ for (ptr = (netsnmp_mode_handler_list*)handler->myvoid; ptr; ptr = ptr->next) { if (ptr->mode == NETSNMP_MODE_END_ALL_MODES || reqinfo->mode == ptr->mode) { ret2 = netsnmp_call_handler(ptr->callback_handler, reginfo, reqinfo, requests); if (ret != SNMP_ERR_NOERROR) ret = ret2; } } return ret2; }
static int mib_handle_ifNumber(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { switch(reqinfo->mode) { case MODE_GET: { u32 val =0; ifm_get_port_num_by_type(MIB_IF_TYPE, &val); snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,(u_char *) &val, sizeof(val)); break; } default: { snmp_log(LOG_ERR, "unknown mode (%d) in handle_ifNumber\n", reqinfo->mode ); return SNMP_ERR_GENERR; } } if (handler->next && handler->next->access_method) { return netsnmp_call_next_handler(handler, reginfo, reqinfo,requests); } return SNMP_ERR_NOERROR; }
/** Implements the serial handler */ int netsnmp_serialize_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_request_info *request, *requesttmp; DEBUGMSGTL(("helper:serialize", "Got request\n")); /* * loop through requests */ for (request = requests; request; request = request->next) { int ret; /* * store next pointer and delete it */ requesttmp = request->next; request->next = NULL; /* * call the next handler */ ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, request); /* * restore original next pointer */ request->next = requesttmp; if (ret != SNMP_ERR_NOERROR) return ret; } return SNMP_ERR_NOERROR; }
static int _table_row_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { int rc = SNMP_ERR_NOERROR; netsnmp_request_info *req; void *row; /** sanity checks */ netsnmp_assert((NULL != handler) && (NULL != handler->myvoid)); netsnmp_assert((NULL != reginfo) && (NULL != reqinfo)); DEBUGMSGTL(("table_row", "Mode %s, Got request:\n", se_find_label_in_slist("agent_mode",reqinfo->mode))); /* * First off, get our pointer from the handler. * This contains the row that was actually registered. * Make this available for each of the requests passed in. */ row = handler->myvoid; for (req = requests; req; req=req->next) netsnmp_request_add_list_data(req, netsnmp_create_data_list(TABLE_ROW_DATA, row, NULL)); /* * Then call the next handler, to actually process the request */ rc = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); if (rc != SNMP_ERR_NOERROR) { DEBUGMSGTL(("table_row", "next handler returned %d\n", rc)); } return rc; }
/** @internal Implements the baby_steps handler */ static int _baby_steps_helper(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_baby_steps_modes *bs_modes; int save_mode, i, rc = SNMP_ERR_NOERROR; u_short *mode_map_ptr; DEBUGMSGTL(("baby_steps", "Got request, mode %s\n", se_find_label_in_slist("agent_mode",reqinfo->mode))); bs_modes = handler->myvoid; netsnmp_assert(NULL != bs_modes); switch (reqinfo->mode) { case MODE_SET_RESERVE1: /* * clear completed modes * xxx-rks: this will break for pdus with set requests to different * rows in the same table when the handler is set up to use the row * merge helper as well (or if requests are serialized). */ bs_modes->completed = 0; /** fall through */ case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_FREE: case MODE_SET_UNDO: mode_map_ptr = set_mode_map[reqinfo->mode]; break; default: /* * clear completed modes */ bs_modes->completed = 0; mode_map_ptr = get_mode_map; } /* * NOTE: if you update this chart, please update the versions in * local/mib2c-conf.d/parent-set.m2i * agent/mibgroup/helpers/baby_steps.c * while you're at it. */ /* *********************************************************************** * Baby Steps Flow Chart (2004.06.05) * * * * +--------------+ +================+ U = unconditional path * * |optional state| ||required state|| S = path for success * * +--------------+ +================+ E = path for error * *********************************************************************** * * +--------------+ * | pre | * | request | * +--------------+ * | U * +-------------+ +==============+ * | row |f|<-------|| object || * | create |1| E || lookup || * +-------------+ +==============+ * E | | S | S * | +------------------>| * | +==============+ * | E || check || * |<---------------|| values || * | +==============+ * | | S * | +==============+ * | +<-------|| undo || * | | E || setup || * | | +==============+ * | | | S * | | +==============+ * | | || set ||-------------------------->+ * | | || value || E | * | | +==============+ | * | | | S | * | | +--------------+ | * | | | check |-------------------------->| * | | | consistency | E | * | | +--------------+ | * | | | S | * | | +==============+ +==============+ | * | | || commit ||-------->|| undo || | * | | || || E || commit || | * | | +==============+ +==============+ | * | | | S U |<--------+ * | | +--------------+ +==============+ * | | | irreversible | || undo || * | | | commit | || set || * | | +--------------+ +==============+ * | | | U U | * | +-------------->|<------------------------+ * | +==============+ * | || undo || * | || cleanup || * | +==============+ * +---------------------->| U * | * (err && f1)------------------->+ * | | * +--------------+ +--------------+ * | post |<--------| row | * | request | U | release | * +--------------+ +--------------+ * */ /* * save original mode */ save_mode = reqinfo->mode; for(i = 0; i < BABY_STEPS_PER_MODE_MAX; ++i ) { /* * break if we run out of baby steps for this mode */ if(mode_map_ptr[i] == BABY_STEP_NONE) break; DEBUGMSGTL(("baby_steps", " baby step mode %s\n", se_find_label_in_slist("babystep_mode",mode_map_ptr[i]))); /* * skip modes the handler didn't register for */ if (BSTEP_USE_ORIGINAL != mode_map_ptr[i]) { u_int mode_flag; /* * skip undo commit if commit wasn't hit, and * undo_cleanup if undo_setup wasn't hit. */ if((MODE_SET_UNDO == save_mode) && (MODE_BSTEP_UNDO_COMMIT == mode_map_ptr[i]) && !(BABY_STEP_COMMIT & bs_modes->completed)) { DEBUGMSGTL(("baby_steps", " skipping commit undo (no commit)\n")); continue; } else if((MODE_SET_FREE == save_mode) && (MODE_BSTEP_UNDO_CLEANUP == mode_map_ptr[i]) && !(BABY_STEP_UNDO_SETUP & bs_modes->completed)) { DEBUGMSGTL(("baby_steps", " skipping undo cleanup (no undo setup)\n")); continue; } reqinfo->mode = mode_map_ptr[i]; mode_flag = netsnmp_baby_step_mode2flag( mode_map_ptr[i] ); if((mode_flag & bs_modes->registered)) bs_modes->completed |= mode_flag; else { DEBUGMSGTL(("baby_steps", " skipping mode (not registered)\n")); continue; } } else { reqinfo->mode = save_mode; } #ifdef BABY_STEPS_NEXT_MODE /* * I can't remember why I wanted the next mode in the request, * but it's not used anywhere, so don't use this code. saved, * in case I remember why I thought needed it. - rstory 040911 */ if((BABY_STEPS_PER_MODE_MAX - 1) == i) reqinfo->next_mode_ok = BABY_STEP_NONE; else { if(BSTEP_USE_ORIGINAL == mode_map_ptr[i+1]) reqinfo->next_mode_ok = save_mode; else reqinfo->next_mode_ok = mode_map_ptr[i+1]; } #endif /* * call handlers for baby step */ rc = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); /* * check for error calling handler (unlikely, but...) */ if(rc) { DEBUGMSGTL(("baby_steps", " ERROR:handler error\n")); break; } /* * check for errors in any of the requests for GET-like, reserve1, * reserve2 and action. (there is no recovery from errors * in commit, free or undo.) */ if (MODE_IS_GET(save_mode) || (save_mode < SNMP_MSG_INTERNAL_SET_COMMIT)) { rc = netsnmp_check_requests_error(requests); if(rc) { DEBUGMSGTL(("baby_steps", " ERROR:request error\n")); break; } } } /* * restore original mode */ reqinfo->mode = save_mode; return rc; }
/** @internal Implements the stash_cache handler */ int netsnmp_stash_cache_helper(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_cache *cache; netsnmp_stash_cache_info *cinfo; netsnmp_oid_stash_node *cnode; netsnmp_variable_list *cdata; netsnmp_request_info *request; DEBUGMSGTL(("helper:stash_cache", "Got request\n")); cache = netsnmp_cache_reqinfo_extract( reqinfo, reginfo->handlerName ); if (!cache) { DEBUGMSGTL(("helper:stash_cache", "No cache structure\n")); return SNMP_ERR_GENERR; } cinfo = (netsnmp_stash_cache_info *) cache->magic; switch (reqinfo->mode) { case MODE_GET: DEBUGMSGTL(("helper:stash_cache", "Processing GET request\n")); for(request = requests; request; request = request->next) { cdata = (netsnmp_variable_list*) netsnmp_oid_stash_get_data(cinfo->cache, requests->requestvb->name, requests->requestvb->name_length); if (cdata && cdata->val.string && cdata->val_len) { DEBUGMSGTL(("helper:stash_cache", "Found cached GET varbind\n")); DEBUGMSGOID(("helper:stash_cache", cdata->name, cdata->name_length)); DEBUGMSG(("helper:stash_cache", "\n")); snmp_set_var_typed_value(request->requestvb, cdata->type, cdata->val.string, cdata->val_len); } } break; case MODE_GETNEXT: DEBUGMSGTL(("helper:stash_cache", "Processing GETNEXT request\n")); for(request = requests; request; request = request->next) { cnode = netsnmp_oid_stash_getnext_node(cinfo->cache, requests->requestvb->name, requests->requestvb->name_length); if (cnode && cnode->thedata) { cdata = (netsnmp_variable_list*)cnode->thedata; if (cdata->val.string && cdata->name && cdata->name_length) { DEBUGMSGTL(("helper:stash_cache", "Found cached GETNEXT varbind\n")); DEBUGMSGOID(("helper:stash_cache", cdata->name, cdata->name_length)); DEBUGMSG(("helper:stash_cache", "\n")); snmp_set_var_typed_value(request->requestvb, cdata->type, cdata->val.string, cdata->val_len); snmp_set_var_objid(request->requestvb, cdata->name, cdata->name_length); } } } break; default: cinfo->cache_valid = 0; return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); } return SNMP_ERR_NOERROR; }
/* * The helper handler that takes care of passing a specific row of * data down to the lower handler(s). It sets request->processed if * the request should not be handled. */ int netsnmp_table_data_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_table_data *table = (netsnmp_table_data *) handler->myvoid; netsnmp_request_info *request; int valid_request = 0; netsnmp_table_row *row; netsnmp_table_request_info *table_info; netsnmp_table_registration_info *table_reg_info = netsnmp_find_table_registration_info(reginfo); int result, regresult; int oldmode; for (request = requests; request; request = request->next) { if (request->processed) continue; table_info = netsnmp_extract_table_info(request); if (!table_info) continue; /* ack */ switch (reqinfo->mode) { case MODE_GET: case MODE_GETNEXT: case MODE_SET_RESERVE1: netsnmp_request_add_list_data(request, netsnmp_create_data_list( TABLE_DATA_TABLE, table, NULL)); } /* * find the row in question */ switch (reqinfo->mode) { case MODE_GETNEXT: case MODE_GETBULK: /* XXXWWW */ if (request->requestvb->type != ASN_NULL) continue; /* * loop through data till we find the next row */ result = snmp_oid_compare(request->requestvb->name, request->requestvb->name_length, reginfo->rootoid, reginfo->rootoid_len); regresult = snmp_oid_compare(request->requestvb->name, SNMP_MIN(request->requestvb-> name_length, reginfo->rootoid_len), reginfo->rootoid, reginfo->rootoid_len); if (regresult == 0 && request->requestvb->name_length < reginfo->rootoid_len) regresult = -1; if (result < 0 || 0 == result) { /* * before us entirely, return the first */ row = table->first_row; table_info->colnum = table_reg_info->min_column; } else if (regresult == 0 && request->requestvb->name_length == reginfo->rootoid_len + 1 && /* entry node must be 1, but any column is ok */ request->requestvb->name[reginfo->rootoid_len] == 1) { /* * exactly to the entry */ row = table->first_row; table_info->colnum = table_reg_info->min_column; } else if (regresult == 0 && request->requestvb->name_length == reginfo->rootoid_len + 2 && /* entry node must be 1, but any column is ok */ request->requestvb->name[reginfo->rootoid_len] == 1) { /* * exactly to the column */ row = table->first_row; } else { /* * loop through all rows looking for the first one * that is equal to the request or greater than it */ for (row = table->first_row; row; row = row->next) { /* * compare the index of the request to the row */ result = snmp_oid_compare(row->index_oid, row->index_oid_len, request->requestvb->name + 2 + reginfo->rootoid_len, request->requestvb->name_length - 2 - reginfo->rootoid_len); if (result == 0) { /* * equal match, return the next row */ if (row) { row = row->next; } break; } else if (result > 0) { /* * the current row is greater than the * request, use it */ break; } } } if (!row) { table_info->colnum++; if (table_info->colnum <= table_reg_info->max_column) { row = table->first_row; } } if (row) { valid_request = 1; netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_ROW, row, NULL)); /* * Set the name appropriately, so we can pass this * request on as a simple GET request */ netsnmp_table_data_build_result(reginfo, reqinfo, request, row, table_info->colnum, ASN_NULL, NULL, 0); } else { /* no decent result found. Give up. It's beyond us. */ request->processed = 1; } break; case MODE_GET: if (request->requestvb->type != ASN_NULL) continue; /* * find the row in question */ if (request->requestvb->name_length < (reginfo->rootoid_len + 3)) { /* table.entry.column... */ /* * request too short */ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); break; } else if (NULL == (row = netsnmp_table_data_get_from_oid(table, request-> requestvb->name + reginfo-> rootoid_len + 2, request-> requestvb-> name_length - reginfo-> rootoid_len - 2))) { /* * no such row */ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); break; } else { valid_request = 1; netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_ROW, row, NULL)); } break; case MODE_SET_RESERVE1: valid_request = 1; if (NULL != (row = netsnmp_table_data_get_from_oid(table, request->requestvb->name + reginfo->rootoid_len + 2, request->requestvb-> name_length - reginfo->rootoid_len - 2))) { netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_ROW, row, NULL)); } break; case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_FREE: case MODE_SET_UNDO: valid_request = 1; } } if (valid_request && (reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK)) { /* * If this is a GetNext or GetBulk request, then we've identified * the row that ought to include the appropriate next instance. * Convert the request into a Get request, so that the lower-level * handlers don't need to worry about skipping on, and call these * handlers ourselves (so we can undo this again afterwards). */ oldmode = reqinfo->mode; reqinfo->mode = MODE_GET; result = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reqinfo->mode = oldmode; handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; return result; } else /* next handler called automatically - 'AUTO_NEXT' */ return SNMP_ERR_NOERROR; }
int netsnmp_scalar_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_variable_list *var = requests->requestvb; int ret, cmp; int namelen; DEBUGMSGTL(("helper:scalar", "Got request:\n")); namelen = SNMP_MIN(requests->requestvb->name_length, reginfo->rootoid_len); cmp = snmp_oid_compare(requests->requestvb->name, namelen, reginfo->rootoid, reginfo->rootoid_len); DEBUGMSGTL(("helper:scalar", " oid:", cmp)); DEBUGMSGOID(("helper:scalar", var->name, var->name_length)); DEBUGMSG(("helper:scalar", "\n")); switch (reqinfo->mode) { case MODE_GET: if (cmp != 0) { netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHOBJECT); return SNMP_ERR_NOERROR; } else { reginfo->rootoid[reginfo->rootoid_len++] = 0; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reginfo->rootoid_len--; return ret; } break; case MODE_SET_RESERVE1: case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_UNDO: case MODE_SET_FREE: if (cmp != 0) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_NOCREATION); return SNMP_ERR_NOERROR; } else { reginfo->rootoid[reginfo->rootoid_len++] = 0; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reginfo->rootoid_len--; return ret; } break; case MODE_GETNEXT: reginfo->rootoid[reginfo->rootoid_len++] = 0; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reginfo->rootoid_len--; return ret; } /* * got here only if illegal mode found */ return SNMP_ERR_GENERR; }
int netsnmp_instance_num_file_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_num_file_instance *nfi; u_long it, *it_save; int rc; netsnmp_assert(NULL != handler); nfi = (netsnmp_num_file_instance *)handler->myvoid; netsnmp_assert(NULL != nfi); netsnmp_assert(NULL != nfi->file_name); DEBUGMSGTL(("netsnmp_instance_int_handler", "Got request: %d\n", reqinfo->mode)); switch (reqinfo->mode) { /* * data requests */ case MODE_GET: /* * Use a long here, otherwise on 64 bit use of an int would fail */ netsnmp_assert(NULL == nfi->filep); nfi->filep = fopen(nfi->file_name, "r"); if (NULL == nfi->filep) { netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE); return SNMP_ERR_NOERROR; } rc = fscanf(nfi->filep, (nfi->type == ASN_INTEGER) ? "%ld" : "%lu", &it); fclose(nfi->filep); nfi->filep = NULL; if (rc != 1) { netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE); return SNMP_ERR_NOERROR; } snmp_set_var_typed_value(requests->requestvb, nfi->type, (u_char *) &it, sizeof(it)); break; /* * SET requests. Should only get here if registered RWRITE */ case MODE_SET_RESERVE1: netsnmp_assert(NULL == nfi->filep); if (requests->requestvb->type != nfi->type) netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE); break; case MODE_SET_RESERVE2: netsnmp_assert(NULL == nfi->filep); nfi->filep = fopen(nfi->file_name, "w+"); if (NULL == nfi->filep) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_NOTWRITABLE); return SNMP_ERR_NOERROR; } /* * store old info for undo later */ if (fscanf(nfi->filep, (nfi->type == ASN_INTEGER) ? "%ld" : "%lu", &it) != 1) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_RESOURCEUNAVAILABLE); return SNMP_ERR_NOERROR; } memdup((u_char **) & it_save, (u_char *)&it, sizeof(u_long)); if (it_save == NULL) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_RESOURCEUNAVAILABLE); return SNMP_ERR_NOERROR; } netsnmp_request_add_list_data(requests, netsnmp_create_data_list (INSTANCE_HANDLER_NAME, it_save, free)); break; case MODE_SET_ACTION: /* * update current */ DEBUGMSGTL(("helper:instance", "updated %s -> %ld\n", nfi->file_name, *(requests->requestvb->val.integer))); it = *(requests->requestvb->val.integer); rewind(nfi->filep); /* rewind to make sure we are at the beginning */ rc = fprintf(nfi->filep, (nfi->type == ASN_INTEGER) ? "%ld" : "%lu", it); if (rc < 0) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR); return SNMP_ERR_NOERROR; } break; case MODE_SET_UNDO: it = *((u_int *) netsnmp_request_get_list_data(requests, INSTANCE_HANDLER_NAME)); rc = fprintf(nfi->filep, (nfi->type == ASN_INTEGER) ? "%ld" : "%lu", it); if (rc < 0) netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); /** fall through */ case MODE_SET_COMMIT: case MODE_SET_FREE: if (NULL != nfi->filep) { fclose(nfi->filep); nfi->filep = NULL; } break; } if (handler->next && handler->next->access_method) return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); return SNMP_ERR_NOERROR; }
/** @internal Implements the stash_to_next handler */ int netsnmp_stash_to_next_helper(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { int ret = SNMP_ERR_NOERROR; int namelen; int finished = 0; netsnmp_oid_stash_node **cinfo; netsnmp_variable_list *vb; netsnmp_request_info *reqtmp; /* * this code depends on AUTO_NEXT being set */ netsnmp_assert(handler->flags & MIB_HANDLER_AUTO_NEXT); /* * Don't do anything for any modes except GET_STASH. Just return, * and the agent will call the next handler (AUTO_NEXT). * * If the handler chain already supports GET_STASH, we don't * need to do anything here either. Once again, we just return * and the agent will call the next handler (AUTO_NEXT). * * Otherwise, we munge the mode to GET_NEXT, and call the * next handler ourselves, repeatedly until we've retrieved the * full contents of the table or subtree. * Then restore the mode and return to the calling handler * (setting AUTO_NEXT_OVERRRIDE so the agent knows what we did). */ if (MODE_GET_STASH == reqinfo->mode) { if ( reginfo->modes & HANDLER_CAN_STASH ) { return ret; } cinfo = netsnmp_extract_stash_cache( reqinfo ); reqtmp = SNMP_MALLOC_TYPEDEF(netsnmp_request_info); vb = reqtmp->requestvb = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); vb->type = ASN_NULL; snmp_set_var_objid( vb, reginfo->rootoid, reginfo->rootoid_len ); reqinfo->mode = MODE_GETNEXT; while (!finished) { ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, reqtmp); namelen = SNMP_MIN(vb->name_length, reginfo->rootoid_len); if ( !snmp_oid_compare( reginfo->rootoid, reginfo->rootoid_len, vb->name, namelen) && vb->type != ASN_NULL && vb->type != SNMP_ENDOFMIBVIEW ) { /* * This result is relevant so save it, and prepare * the request varbind for the next query. */ netsnmp_oid_stash_add_data( cinfo, vb->name, vb->name_length, snmp_clone_varbind( vb )); /* * Tidy up the response structure, * ready for retrieving the next entry */ netsnmp_free_all_list_data(reqtmp->parent_data); reqtmp->parent_data = NULL; reqtmp->processed = 0; vb->type = ASN_NULL; } else { finished = 1; } } reqinfo->mode = MODE_GET_STASH; /* * let the handler chain processing know that we've already * called the next handler */ handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; } return ret; }
int netsnmp_scalar_group_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_variable_list *var = requests->requestvb; netsnmp_scalar_group *sgroup = (netsnmp_scalar_group *)handler->myvoid; int ret, cmp; int namelen; oid subid, root_tmp[MAX_OID_LEN], *root_save; DEBUGMSGTL(("helper:scalar_group", "Got request:\n")); namelen = SNMP_MIN(requests->requestvb->name_length, reginfo->rootoid_len); cmp = snmp_oid_compare(requests->requestvb->name, namelen, reginfo->rootoid, reginfo->rootoid_len); DEBUGMSGTL(( "helper:scalar_group", " cmp=%d, oid:", cmp)); DEBUGMSGOID(("helper:scalar_group", var->name, var->name_length)); DEBUGMSG(( "helper:scalar_group", "\n")); /* * copy root oid to root_tmp, set instance to 0. (subid set later on) * save rootoid, since we'll replace it before calling next handler, * and need to restore it afterwards. */ memcpy(root_tmp, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid)); root_tmp[reginfo->rootoid_len + 1] = 0; root_save = reginfo->rootoid; ret = SNMP_ERR_NOCREATION; switch (reqinfo->mode) { /* * The handling of "exact" requests is basically the same. * The only difference between GET and SET requests is the * error/exception to return on failure. */ case MODE_GET: ret = SNMP_NOSUCHOBJECT; /* Fallthrough */ #ifndef NETSNMP_NO_WRITE_SUPPORT case MODE_SET_RESERVE1: case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_UNDO: case MODE_SET_FREE: #endif /* NETSNMP_NO_WRITE_SUPPORT */ if (cmp != 0 || requests->requestvb->name_length <= reginfo->rootoid_len) { /* * Common prefix doesn't match, or only *just* matches * the registered root (so can't possibly match a scalar) */ netsnmp_set_request_error(reqinfo, requests, ret); return SNMP_ERR_NOERROR; } else { /* * Otherwise, * extract the object subidentifier from the request, * check this is (probably) valid, and then fudge the * registered 'rootoid' to match, before passing the * request off to the next handler ('scalar'). * * Note that we don't bother checking instance subidentifiers * here. That's left to the scalar helper. */ subid = requests->requestvb->name[reginfo->rootoid_len]; if (subid < sgroup->lbound || subid > sgroup->ubound) { netsnmp_set_request_error(reqinfo, requests, ret); return SNMP_ERR_NOERROR; } root_tmp[reginfo->rootoid_len] = subid; reginfo->rootoid_len += 2; reginfo->rootoid = root_tmp; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reginfo->rootoid = root_save; reginfo->rootoid_len -= 2; return ret; } break; case MODE_GETNEXT: /* * If we're being asked for something before (or exactly matches) * the registered root OID, then start with the first object. * If we're being asked for something that exactly matches an object * OID, then that's what we pass down. * Otherwise, we pass down the OID of the *next* object.... */ if (cmp < 0 || requests->requestvb->name_length <= reginfo->rootoid_len) { subid = sgroup->lbound; } else if (requests->requestvb->name_length == reginfo->rootoid_len+1) subid = requests->requestvb->name[reginfo->rootoid_len]; else subid = requests->requestvb->name[reginfo->rootoid_len]+1; /* * ... always assuming this is (potentially) valid, of course. */ if (subid < sgroup->lbound) subid = sgroup->lbound; else if (subid > sgroup->ubound) return SNMP_ERR_NOERROR; root_tmp[reginfo->rootoid_len] = subid; reginfo->rootoid_len += 2; reginfo->rootoid = root_tmp; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); /* * If we didn't get an answer (due to holes in the group) * set things up to retry again. */ if (!requests->delegated && (requests->requestvb->type == ASN_NULL || requests->requestvb->type == SNMP_NOSUCHOBJECT || requests->requestvb->type == SNMP_NOSUCHINSTANCE)) { snmp_set_var_objid(requests->requestvb, reginfo->rootoid, reginfo->rootoid_len - 1); requests->requestvb->name[reginfo->rootoid_len - 2] = ++subid; requests->requestvb->type = ASN_PRIV_RETRY; } reginfo->rootoid = root_save; reginfo->rootoid_len -= 2; return ret; } /* * got here only if illegal mode found */ return SNMP_ERR_GENERR; }
/** * The helper handler that takes care of passing a specific row of * data down to the lower handler(s). It sets request->processed if * the request should not be handled. */ int netsnmp_table_data_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_table_data *table = (netsnmp_table_data *) handler->myvoid; netsnmp_request_info *request; int valid_request = 0; netsnmp_table_row *row; netsnmp_table_request_info *table_info; netsnmp_table_registration_info *table_reg_info = netsnmp_find_table_registration_info(reginfo); int result, regresult; int oldmode; for (request = requests; request; request = request->next) { if (request->processed) continue; table_info = netsnmp_extract_table_info(request); if (!table_info) continue; /* ack */ /* * find the row in question */ switch (reqinfo->mode) { case MODE_GETNEXT: case MODE_GETBULK: /* XXXWWW */ if (request->requestvb->type != ASN_NULL) continue; /* * loop through data till we find the next row */ result = snmp_oid_compare(request->requestvb->name, request->requestvb->name_length, reginfo->rootoid, reginfo->rootoid_len); regresult = snmp_oid_compare(request->requestvb->name, SNMP_MIN(request->requestvb-> name_length, reginfo->rootoid_len), reginfo->rootoid, reginfo->rootoid_len); if (regresult == 0 && request->requestvb->name_length < reginfo->rootoid_len) regresult = -1; if (result < 0 || 0 == result) { /* * before us entirely, return the first */ row = table->first_row; table_info->colnum = table_reg_info->min_column; } else if (regresult == 0 && request->requestvb->name_length == reginfo->rootoid_len + 1 && /* entry node must be 1, but any column is ok */ request->requestvb->name[reginfo->rootoid_len] == 1) { /* * exactly to the entry */ row = table->first_row; table_info->colnum = table_reg_info->min_column; } else if (regresult == 0 && request->requestvb->name_length == reginfo->rootoid_len + 2 && /* entry node must be 1, but any column is ok */ request->requestvb->name[reginfo->rootoid_len] == 1) { /* * exactly to the column */ row = table->first_row; } else { /* * loop through all rows looking for the first one * that is equal to the request or greater than it */ for (row = table->first_row; row; row = row->next) { /* * compare the index of the request to the row */ result = snmp_oid_compare(row->index_oid, row->index_oid_len, request->requestvb->name + 2 + reginfo->rootoid_len, request->requestvb->name_length - 2 - reginfo->rootoid_len); if (result == 0) { /* * equal match, return the next row */ if (row) { row = row->next; } break; } else if (result > 0) { /* * the current row is greater than the * request, use it */ break; } } } if (!row) { table_info->colnum++; if (table_info->colnum <= table_reg_info->max_column) { row = table->first_row; } } if (row) { valid_request = 1; netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_NAME, row, NULL)); /* * Set the name appropriately, so we can pass this * request on as a simple GET request */ netsnmp_table_data_build_result(reginfo, reqinfo, request, row, table_info->colnum, ASN_NULL, NULL, 0); } else { /* no decent result found. Give up. It's beyond us. */ request->processed = 1; } break; case MODE_GET: if (request->requestvb->type != ASN_NULL) continue; /* * find the row in question */ if (request->requestvb->name_length < (reginfo->rootoid_len + 3)) { /* table.entry.column... */ /* * request too short */ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); break; } else if (NULL == (row = netsnmp_table_data_get_from_oid(table, request-> requestvb->name + reginfo-> rootoid_len + 2, request-> requestvb-> name_length - reginfo-> rootoid_len - 2))) { /* * no such row */ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); break; } else { valid_request = 1; netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_NAME, row, NULL)); } break; case MODE_SET_RESERVE1: valid_request = 1; if (NULL != (row = netsnmp_table_data_get_from_oid(table, request->requestvb->name + reginfo->rootoid_len + 2, request->requestvb-> name_length - reginfo->rootoid_len - 2))) { netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_NAME, row, NULL)); } break; case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_FREE: case MODE_SET_UNDO: valid_request = 1; } } if (valid_request) { /* * If this is a GetNext or GetBulk request, then we've identified * the row that ought to include the appropriate next instance. * Convert the request into a Get request, so that the lower-level * handlers don't need to worry about skipping on.... */ oldmode = reqinfo->mode; if (reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK) { reqinfo->mode = MODE_GET; } result = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); if (oldmode == MODE_GETNEXT || oldmode == MODE_GETBULK) { /* XXX */ for (request = requests; request; request = request->next) { /* * ... but if the lower-level handlers aren't dealing with * skipping on to the next instance, then we must handle * this situation here. * Mark 'holes' in the table as needing to be retried. * * This approach is less efficient than handling such * holes directly in the table_dataset handler, but allows * user-provided handlers to override the dataset handler * if this proves necessary. */ if (request->requestvb->type == ASN_NULL || request->requestvb->type == SNMP_NOSUCHINSTANCE) { request->requestvb->type = ASN_PRIV_RETRY; } /* XXX - Move on to the next object */ if (request->requestvb->type == SNMP_NOSUCHOBJECT) { request->requestvb->type = ASN_PRIV_RETRY; } } reqinfo->mode = oldmode; } return result; } else return SNMP_ERR_NOERROR; }
/** implements the table_iterator helper */ int netsnmp_table_iterator_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_table_registration_info *tbl_info; oid coloid[MAX_OID_LEN]; size_t coloid_len; int ret; static oid myname[MAX_OID_LEN]; size_t myname_len; int oldmode; netsnmp_iterator_info *iinfo; iinfo = (netsnmp_iterator_info *) handler->myvoid; if (!iinfo || !reginfo || !reqinfo) return SNMPERR_GENERR; tbl_info = iinfo->table_reginfo; /* * copy in the table registration oid for later use */ coloid_len = reginfo->rootoid_len + 2; memcpy(coloid, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid)); coloid[reginfo->rootoid_len] = 1; /* table.entry node */ /* * illegally got here if these functions aren't defined */ if (iinfo->get_first_data_point == NULL || iinfo->get_next_data_point == NULL) { snmp_log(LOG_ERR, "table_iterator helper called without data accessor functions\n"); return SNMP_ERR_GENERR; } /* * XXXWWW: deal with SET caching */ #ifdef NOT_SERIALIZED while (requests) /* XXX: currently only serialized */ #endif { /* * XXXWWW: optimize by reversing loops (look through data only once) */ netsnmp_variable_list *results = NULL; netsnmp_variable_list *index_search = NULL; /* WWW: move up? */ netsnmp_variable_list *free_this_index_search = NULL; netsnmp_table_request_info *table_info = netsnmp_extract_table_info(requests); void *callback_loop_context = NULL; void *callback_data_context = NULL; void *callback_data_keep = NULL; if (requests->processed != 0) { #ifdef NOT_SERIALIZED continue; #else return SNMP_ERR_NOERROR; #endif } if (reqinfo->mode != MODE_GET && reqinfo->mode != MODE_GETNEXT && reqinfo->mode != MODE_GETBULK && /* XXX */ reqinfo->mode != MODE_SET_RESERVE1) { goto skip_processing; } if (table_info->colnum > tbl_info->max_column) { requests->processed = 1; #ifdef NOT_SERIALIZED break; #else return SNMP_ERR_NOERROR; #endif } /* * XXX: if loop through everything, these are never free'd * since iterator returns NULL and thus we forget about * these */ index_search = snmp_clone_varbind(table_info->indexes); if (!index_search) { /* * hmmm.... invalid table? */ snmp_log(LOG_WARNING, "invalid index list or failed malloc for table %s\n", reginfo->handlerName); return SNMP_ERR_NOERROR; } free_this_index_search = index_search; /* * below our minimum column? */ if (table_info->colnum < tbl_info->min_column) { results = (iinfo->get_first_data_point) (&callback_loop_context, &callback_data_context, index_search, iinfo); if (iinfo->free_loop_context) { (iinfo->free_loop_context) (callback_loop_context, iinfo); callback_loop_context = NULL; } goto got_results; } /* * XXX: do "only got some indexes" */ /* * find the next legal result to return */ /* * find the first node */ index_search = (iinfo->get_first_data_point) (&callback_loop_context, &callback_data_context, index_search, iinfo); /* * table.entry.column node */ coloid[reginfo->rootoid_len + 1] = table_info->colnum; switch (reqinfo->mode) { case MODE_GETNEXT: case MODE_GETBULK: /* XXXWWW */ /* * loop through all data and find next one */ while (index_search) { /* * compare the node with previous results */ if (netsnmp_check_getnext_reply (requests, coloid, coloid_len, index_search, &results)) { /* * result is our current choice, so keep a pointer to * the data that the lower handler wants us to * remember (possibly freeing the last known "good" * result data pointer) */ if (callback_data_keep && iinfo->free_data_context) { (iinfo->free_data_context) (callback_data_keep, iinfo); callback_data_keep = NULL; } if (iinfo->make_data_context && !callback_data_context) { callback_data_context = (iinfo-> make_data_context) (callback_loop_context, iinfo); } callback_data_keep = callback_data_context; callback_data_context = NULL; } else { if (callback_data_context && iinfo->free_data_context) (iinfo->free_data_context) (callback_data_context, iinfo); callback_data_context = NULL; } /* * get the next node in the data chain */ index_search = (iinfo->get_next_data_point) (&callback_loop_context, &callback_data_context, index_search, iinfo); if (!index_search && !results && tbl_info->max_column > table_info->colnum) { /* * restart loop. XXX: Should cache this better */ table_info->colnum++; coloid[reginfo->rootoid_len + 1] = table_info->colnum; if (free_this_index_search != NULL) snmp_free_varbind(free_this_index_search); index_search = snmp_clone_varbind(table_info->indexes); free_this_index_search = index_search; if (callback_loop_context && iinfo->free_loop_context_at_end) { (iinfo->free_loop_context_at_end)(callback_loop_context, iinfo); callback_loop_context = NULL; } if (iinfo->free_loop_context && callback_loop_context) { (iinfo->free_loop_context) (callback_loop_context, iinfo); callback_loop_context = NULL; } if (callback_data_context && iinfo->free_data_context) { (iinfo->free_data_context) (callback_data_context, iinfo); callback_data_context = NULL; } index_search = (iinfo-> get_first_data_point) (&callback_loop_context, &callback_data_context, index_search, iinfo); } } break; case MODE_GET: case MODE_SET_RESERVE1: /* * loop through all data till exact results are found */ while (index_search) { build_oid_noalloc(myname, MAX_OID_LEN, &myname_len, coloid, coloid_len, index_search); if (snmp_oid_compare(myname, myname_len, requests->requestvb->name, requests->requestvb->name_length) == 0) { /* * found the exact match, so we're done */ if (iinfo->make_data_context && !callback_data_context) { callback_data_context = (iinfo-> make_data_context) (callback_loop_context, iinfo); } callback_data_keep = callback_data_context; callback_data_context = NULL; results = snmp_clone_varbind(index_search); snmp_set_var_objid(results, myname, myname_len); goto got_results; } else { /* * free not-needed data context */ if (callback_data_context && iinfo->free_data_context) { (iinfo->free_data_context) (callback_data_context, iinfo); callback_data_context = NULL; } } /* * get the next node in the data chain */ index_search = (iinfo->get_next_data_point) (&callback_loop_context, &callback_data_context, index_search, iinfo); } break; default: /* * the rest of the set states have been dealt with already */ goto got_results; } /* * XXX: free index_search? */ if (callback_loop_context && iinfo->free_loop_context) { (iinfo->free_loop_context) (callback_loop_context, iinfo); callback_loop_context = NULL; } got_results: /* not milk */ /* * This free_data_context call is required in the event that your * get_next_data_point method allocates new memory, even during the * calls where it eventually returns a NULL */ if (callback_data_context && iinfo->free_data_context) { (iinfo->free_data_context) (callback_data_context, iinfo); callback_data_context = NULL; } if (!results && !MODE_IS_SET(reqinfo->mode)) { /* * no results found. */ /* * XXX: check for at least one entry at the very top */ #ifdef NOT_SERIALIZED break; #else if (callback_loop_context && iinfo->free_loop_context_at_end) { (iinfo->free_loop_context_at_end) (callback_loop_context, iinfo); callback_loop_context = NULL; } if (free_this_index_search != NULL) { snmp_free_varbind(free_this_index_search); } return SNMP_ERR_NOERROR; #endif } skip_processing: /* * OK, here results should be a pointer to the data that we * actually need to GET */ oldmode = reqinfo->mode; if (reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK) { /* XXX */ snmp_set_var_objid(requests->requestvb, results->name, results->name_length); reqinfo->mode = MODE_GET; } if (reqinfo->mode == MODE_GET || reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK || /* XXX */ reqinfo->mode == MODE_SET_RESERVE1) { /* * first (or only) pass stuff */ /* * let set requsets use previously constructed data */ snmp_free_varbind(results); if (callback_data_keep) netsnmp_request_add_list_data(requests, netsnmp_create_data_list (TABLE_ITERATOR_NAME, callback_data_keep, NULL)); netsnmp_request_add_list_data(requests, netsnmp_create_data_list (TABLE_ITERATOR_LAST_CONTEXT, callback_loop_context, NULL)); } DEBUGMSGTL(("table_iterator", "doing mode: %s\n", se_find_label_in_slist("agent_mode", oldmode))); ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); if (oldmode == MODE_GETNEXT || oldmode == MODE_GETBULK) { /* XXX */ if (requests->requestvb->type == ASN_NULL || requests->requestvb->type == SNMP_NOSUCHINSTANCE) { /* * get next skipped this value for this column, we * need to keep searching forward */ requests->requestvb->type = ASN_PRIV_RETRY; } reqinfo->mode = oldmode; } callback_data_keep = netsnmp_request_get_list_data(requests, TABLE_ITERATOR_NAME); callback_loop_context = netsnmp_request_get_list_data(requests, TABLE_ITERATOR_LAST_CONTEXT); /* * This has to be done to prevent a memory leak. Notice that on * SET_RESERVE1 we're assigning something to * 'free_this_index_search' at the beginning of this handler (right * above the line that says 'below our minimum column?'), * but we're not given a chance to free it below with the other * SET modes, hence our doing it here. */ if (reqinfo->mode == MODE_SET_RESERVE1) { if (free_this_index_search) { snmp_free_varbind(free_this_index_search); free_this_index_search = NULL; } } if (reqinfo->mode == MODE_GET || reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK || /* XXX */ reqinfo->mode == MODE_SET_FREE || reqinfo->mode == MODE_SET_UNDO || reqinfo->mode == MODE_SET_COMMIT) { if (callback_data_keep && iinfo->free_data_context) { (iinfo->free_data_context) (callback_data_keep, iinfo); callback_data_keep = NULL; } if (free_this_index_search) { snmp_free_varbind(free_this_index_search); free_this_index_search = NULL; } #ifndef NOT_SERIALIZED if (callback_loop_context && iinfo->free_loop_context_at_end) { (iinfo->free_loop_context_at_end) (callback_loop_context, iinfo); callback_loop_context = NULL; } #endif } #ifdef NOT_SERIALIZED return ret; #else requests = requests->next; #endif } #ifdef NOT_SERIALIZED if (reqinfo->mode == MODE_GET || reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK || /* XXX */ reqinfo->mode == MODE_SET_FREE || reqinfo->mode == MODE_SET_UNDO || reqinfo->mode == MODE_SET_COMMIT) { if (callback_loop_context && iinfo->free_loop_context_at_end) { (iinfo->free_loop_context_at_end) (callback_loop_context, iinfo); callback_loop_context = NULL; } } #endif return SNMP_ERR_NOERROR; }
/** * \deprecated This function is unused and scheduled for removal in Net-SNMP 5.6 */ int netsnmp_instance_uint_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { unsigned int *it = (unsigned int *) handler->myvoid; unsigned int *it_save; unsigned long tmp_it; DEBUGMSGTL(("netsnmp_instance_uint_handler", "Got request: %d\n", reqinfo->mode)); switch (reqinfo->mode) { /* * data requests */ case MODE_GET: /* * Use a long here, otherwise on 64 bit use of an int would fail */ tmp_it = *it; snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) &tmp_it, sizeof(unsigned long)); break; /* * SET requests. Should only get here if registered RWRITE */ case MODE_SET_RESERVE1: if (requests->requestvb->type != ASN_UNSIGNED) netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE); break; case MODE_SET_RESERVE2: /* * store old info for undo later */ memdup((u_char **) & it_save, (u_char *) it, sizeof(u_int)); if (it_save == NULL) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_RESOURCEUNAVAILABLE); return SNMP_ERR_NOERROR; } netsnmp_request_add_list_data(requests, netsnmp_create_data_list (INSTANCE_HANDLER_NAME, it_save, free)); break; case MODE_SET_ACTION: /* * update current */ DEBUGMSGTL(("testhandler", "updated uint %d -> %ld\n", *it, *(requests->requestvb->val.integer))); *it = (unsigned int) *(requests->requestvb->val.integer); break; case MODE_SET_UNDO: *it = *((u_int *) netsnmp_request_get_list_data(requests, INSTANCE_HANDLER_NAME)); break; case MODE_SET_COMMIT: case MODE_SET_FREE: /* * nothing to do */ break; } if (handler->next && handler->next->access_method) return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); return SNMP_ERR_NOERROR; }
/* implements the table_iterator helper */ int netsnmp_table_iterator_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_table_registration_info *tbl_info; netsnmp_table_request_info *table_info = NULL; oid coloid[MAX_OID_LEN]; size_t coloid_len; int ret; static oid myname[MAX_OID_LEN]; size_t myname_len; int oldmode = 0; netsnmp_iterator_info *iinfo; int notdone; netsnmp_request_info *request, *reqtmp = NULL; netsnmp_variable_list *index_search = NULL; netsnmp_variable_list *free_this_index_search = NULL; void *callback_loop_context = NULL, *last_loop_context; void *callback_data_context = NULL; ti_cache_info *ti_info = NULL; int request_count = 0; netsnmp_oid_stash_node **cinfo = NULL; netsnmp_variable_list *old_indexes = NULL, *vb; netsnmp_table_registration_info *table_reg_info = NULL; int i; netsnmp_data_list *ldata = NULL; iinfo = (netsnmp_iterator_info *) handler->myvoid; if (!iinfo || !reginfo || !reqinfo) return SNMPERR_GENERR; tbl_info = iinfo->table_reginfo; /* * copy in the table registration oid for later use */ coloid_len = reginfo->rootoid_len + 2; memcpy(coloid, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid)); coloid[reginfo->rootoid_len] = 1; /* table.entry node */ /* * illegally got here if these functions aren't defined */ if (iinfo->get_first_data_point == NULL || iinfo->get_next_data_point == NULL) { snmp_log(LOG_ERR, "table_iterator helper called without data accessor functions\n"); return SNMP_ERR_GENERR; } /* preliminary analysis */ switch (reqinfo->mode) { case MODE_GET_STASH: cinfo = netsnmp_extract_stash_cache(reqinfo); table_reg_info = netsnmp_find_table_registration_info(reginfo); /* XXX: move this malloc to stash_cache handler? */ reqtmp = SNMP_MALLOC_TYPEDEF(netsnmp_request_info); reqtmp->subtree = requests->subtree; table_info = netsnmp_extract_table_info(requests); netsnmp_request_add_list_data(reqtmp, netsnmp_create_data_list (TABLE_HANDLER_NAME, (void *) table_info, NULL)); /* remember the indexes that were originally parsed. */ old_indexes = table_info->indexes; break; case MODE_GETNEXT: for(request = requests ; request; request = request->next) { if (request->processed) continue; table_info = netsnmp_extract_table_info(request); if (table_info->colnum < tbl_info->min_column - 1) { /* XXX: optimize better than this */ /* for now, just increase to colnum-1 */ /* we need to jump to the lowest result of the min_column and take it, comparing to nothing from the request */ table_info->colnum = tbl_info->min_column - 1; } else if (table_info->colnum > tbl_info->max_column) { request->processed = TABLE_ITERATOR_NOTAGAIN; } ti_info = netsnmp_request_get_list_data(request, TI_REQUEST_CACHE); if (!ti_info) { ti_info = SNMP_MALLOC_TYPEDEF(ti_cache_info); netsnmp_request_add_list_data(request, netsnmp_create_data_list (TI_REQUEST_CACHE, ti_info, netsnmp_free_ti_cache)); } /* XXX: if no valid requests, don't even loop below */ } break; } /* * collect all information for each needed row */ if (reqinfo->mode == MODE_GET || reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GET_STASH || reqinfo->mode == MODE_SET_RESERVE1) { /* * Count the number of request in the list, * so that we'll know when we're finished */ for(request = requests ; request; request = request->next) if (!request->processed) request_count++; notdone = 1; while(notdone) { notdone = 0; /* find first data point */ if (!index_search) { if (free_this_index_search) { /* previously done */ index_search = free_this_index_search; } else { for(request=requests ; request; request=request->next) { table_info = netsnmp_extract_table_info(request); if (table_info) break; } if (!table_info) { snmp_log(LOG_WARNING, "no valid requests for iterator table %s\n", reginfo->handlerName); netsnmp_free_request_data_sets(reqtmp); SNMP_FREE(reqtmp); return SNMP_ERR_NOERROR; } index_search = snmp_clone_varbind(table_info->indexes); free_this_index_search = index_search; /* setup, malloc search data: */ if (!index_search) { /* * hmmm.... invalid table? */ snmp_log(LOG_WARNING, "invalid index list or failed malloc for table %s\n", reginfo->handlerName); netsnmp_free_request_data_sets(reqtmp); SNMP_FREE(reqtmp); return SNMP_ERR_NOERROR; } } } /* if sorted, pass in a hint */ if (iinfo->flags & NETSNMP_ITERATOR_FLAG_SORTED) { callback_loop_context = table_info; } index_search = (iinfo->get_first_data_point) (&callback_loop_context, &callback_data_context, index_search, iinfo); /* loop over each data point */ while(index_search) { /* remember to free this later */ free_this_index_search = index_search; /* compare against each request*/ for(request = requests ; request; request = request->next) { if (request->processed) continue; /* XXX: store in an array for faster retrival */ table_info = netsnmp_extract_table_info(request); coloid[reginfo->rootoid_len + 1] = table_info->colnum; ti_info = netsnmp_request_get_list_data(request, TI_REQUEST_CACHE); switch(reqinfo->mode) { case MODE_GET: case MODE_SET_RESERVE1: /* looking for exact matches */ build_oid_noalloc(myname, MAX_OID_LEN, &myname_len, coloid, coloid_len, index_search); if (snmp_oid_compare(myname, myname_len, request->requestvb->name, request->requestvb->name_length) == 0) { /* keep this */ netsnmp_iterator_remember(request, myname, myname_len, callback_data_context, callback_loop_context, iinfo); request_count--; /* One less to look for */ } else { if (iinfo->free_data_context && callback_data_context) { (iinfo->free_data_context)(callback_data_context, iinfo); } } break; case MODE_GET_STASH: /* collect data for each column for every row */ build_oid_noalloc(myname, MAX_OID_LEN, &myname_len, coloid, coloid_len, index_search); reqinfo->mode = MODE_GET; if (reqtmp) ldata = netsnmp_get_list_node(reqtmp->parent_data, TABLE_ITERATOR_NAME); if (!ldata) { netsnmp_request_add_list_data(reqtmp, netsnmp_create_data_list (TABLE_ITERATOR_NAME, callback_data_context, NULL)); } else { /* may have changed */ ldata->data = callback_data_context; } table_info->indexes = index_search; for(i = table_reg_info->min_column; i <= (int)table_reg_info->max_column; i++) { myname[reginfo->rootoid_len + 1] = i; table_info->colnum = i; vb = reqtmp->requestvb = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); vb->type = ASN_NULL; snmp_set_var_objid(vb, myname, myname_len); netsnmp_call_next_handler(handler, reginfo, reqinfo, reqtmp); reqtmp->requestvb = NULL; reqtmp->processed = 0; if (vb->type != ASN_NULL) { /* XXX, not all */ netsnmp_oid_stash_add_data(cinfo, myname, myname_len, vb); } else { snmp_free_var(vb); } } reqinfo->mode = MODE_GET_STASH; break; case MODE_GETNEXT: /* looking for "next" matches */ if (netsnmp_check_getnext_reply (request, coloid, coloid_len, index_search, &ti_info->results)) { netsnmp_iterator_remember(request, ti_info->results->name, ti_info->results->name_length, callback_data_context, callback_loop_context, iinfo); /* * If we've been told that the rows are sorted, * then the first valid one we find * must be the right one. */ if (iinfo->flags & NETSNMP_ITERATOR_FLAG_SORTED) request_count--; } else { if (iinfo->free_data_context && callback_data_context) { (iinfo->free_data_context)(callback_data_context, iinfo); } } break; case MODE_SET_RESERVE2: case MODE_SET_FREE: case MODE_SET_UNDO: case MODE_SET_COMMIT: /* needed processing already done in RESERVE1 */ break; default: snmp_log(LOG_ERR, "table_iterator called with unsupported mode\n"); break; /* XXX return */ } } /* Is there any point in carrying on? */ if (!request_count) break; /* get the next search possibility */ last_loop_context = callback_loop_context; index_search = (iinfo->get_next_data_point) (&callback_loop_context, &callback_data_context, index_search, iinfo); if (iinfo->free_loop_context && last_loop_context && callback_data_context != last_loop_context) { (iinfo->free_loop_context) (last_loop_context, iinfo); last_loop_context = NULL; } } /* free loop context before going on */ if (callback_loop_context && iinfo->free_loop_context_at_end) { (iinfo->free_loop_context_at_end) (callback_loop_context, iinfo); callback_loop_context = NULL; } /* decide which (GETNEXT) requests are not yet filled */ if (reqinfo->mode == MODE_GETNEXT) { for(request = requests ; request; request = request->next) { if (request->processed) continue; ti_info = netsnmp_request_get_list_data(request, TI_REQUEST_CACHE); if (!ti_info->results) { int nc; table_info = netsnmp_extract_table_info(request); nc = netsnmp_table_next_column(table_info); if (0 == nc) { coloid[reginfo->rootoid_len+1] = table_info->colnum+1; snmp_set_var_objid(request->requestvb, coloid, reginfo->rootoid_len+2); request->processed = TABLE_ITERATOR_NOTAGAIN; break; } else { table_info->colnum = nc; notdone = 1; } } } } } } if (reqinfo->mode == MODE_GET || reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_SET_RESERVE1) { /* per request last minute processing */ for(request = requests ; request; request = request->next) { if (request->processed) continue; ti_info = netsnmp_request_get_list_data(request, TI_REQUEST_CACHE); table_info = netsnmp_extract_table_info(request); if (!ti_info) continue; switch(reqinfo->mode) { case MODE_GETNEXT: if (ti_info->best_match_len) snmp_set_var_objid(request->requestvb, ti_info->best_match, ti_info->best_match_len); else { coloid[reginfo->rootoid_len+1] = netsnmp_table_next_column(table_info); if (0 == coloid[reginfo->rootoid_len+1]) { /* out of range. */ coloid[reginfo->rootoid_len+1] = tbl_info->max_column + 1; request->processed = TABLE_ITERATOR_NOTAGAIN; } snmp_set_var_objid(request->requestvb, coloid, reginfo->rootoid_len+2); request->processed = 1; } snmp_free_varbind(table_info->indexes); table_info->indexes = snmp_clone_varbind(ti_info->results); /* FALL THROUGH */ case MODE_GET: case MODE_SET_RESERVE1: if (ti_info->data_context) /* we don't add a free pointer, since it's in the TI_REQUEST_CACHE instead */ netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_ITERATOR_NAME, ti_info->data_context, NULL)); break; default: break; } } /* we change all GETNEXT operations into GET operations. why? because we're just so nice to the lower levels. maybe someday they'll pay us for it. doubtful though. */ oldmode = reqinfo->mode; if (reqinfo->mode == MODE_GETNEXT) { reqinfo->mode = MODE_GET; } } else if (reqinfo->mode == MODE_GET_STASH) { netsnmp_free_request_data_sets(reqtmp); SNMP_FREE(reqtmp); table_info->indexes = old_indexes; } /* Finally, we get to call the next handler below us. Boy, wasn't all that simple? They better be glad they don't have to do it! */ if (reqinfo->mode != MODE_GET_STASH) { DEBUGMSGTL(("table_iterator", "call subhandler for mode: %s\n", se_find_label_in_slist("agent_mode", oldmode))); ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); } /* reverse the previously saved mode if we were a getnext */ if (oldmode == MODE_GETNEXT) { reqinfo->mode = oldmode; } /* cleanup */ if (free_this_index_search) snmp_free_varbind(free_this_index_search); return SNMP_ERR_NOERROR; }
int netsnmp_instance_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_variable_list *var = requests->requestvb; int ret, cmp; DEBUGMSGTL(("helper:instance", "Got request:\n")); cmp = snmp_oid_compare(requests->requestvb->name, requests->requestvb->name_length, reginfo->rootoid, reginfo->rootoid_len); DEBUGMSGTL(("helper:instance", " oid:")); DEBUGMSGOID(("helper:instance", var->name, var->name_length)); DEBUGMSG(("helper:instance", "\n")); switch (reqinfo->mode) { case MODE_GET: if (cmp != 0) { netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE); return SNMP_ERR_NOERROR; } else { return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); } break; case MODE_SET_RESERVE1: case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_UNDO: case MODE_SET_FREE: if (cmp != 0) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_NOCREATION); return SNMP_ERR_NOERROR; } else { return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); } break; case MODE_GETNEXT: if (cmp < 0 || (cmp == 0 && requests->inclusive)) { reqinfo->mode = MODE_GET; snmp_set_var_objid(requests->requestvb, reginfo->rootoid, reginfo->rootoid_len); ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reqinfo->mode = MODE_GETNEXT; /* * if the instance doesn't have data, set type to ASN_NULL * to move to the next sub-tree. Ignore delegated requests; they * might have data later on. */ if (!requests->delegated && (requests->requestvb->type == SNMP_NOSUCHINSTANCE || requests->requestvb->type == SNMP_NOSUCHOBJECT)) { requests->requestvb->type = ASN_NULL; } return ret; } else { return SNMP_ERR_NOERROR; } break; } /* * got here only if illegal mode found */ return SNMP_ERR_GENERR; }