/** handles requests for the netSnmpHostsTable table, if anything else needs to be done */ int netSnmpHostsTable_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_request_info *request; netsnmp_table_request_info *table_info; struct commitInfo *ci = NULL; void *data_context = NULL; for (request = requests; request; request = request->next) { /* column and row index encoded portion */ netsnmp_variable_list *var = request->requestvb; const oid * const suffix = var->name + reginfo->rootoid_len + 1; const size_t suffix_len = var->name_length - (reginfo->rootoid_len + 1); if (request->processed != 0) continue; switch (reqinfo->mode) { case MODE_GET: case MODE_SET_RESERVE1: data_context = netsnmp_extract_iterator_context(request); if (data_context == NULL) { if (reqinfo->mode == MODE_GET) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } } break; default: /* == the other SET modes */ ci = netsnmp_oid_stash_get_data(commitStorage, suffix + 1, suffix_len - 1); break; } /** extracts the information about the table from the request */ table_info = netsnmp_extract_table_info(request); /** table_info->colnum contains the column number requested */ /** table_info->indexes contains a linked list of snmp variable bindings for the indexes of the table. Values in the list have been set corresponding to the indexes of the request */ if (table_info == NULL) { continue; } switch (reqinfo->mode) { case MODE_GET: switch (table_info->colnum) { case COLUMN_NETSNMPHOSTADDRESSTYPE: { long *retval; size_t retval_len = 0; retval = get_netSnmpHostAddressType(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_NETSNMPHOSTADDRESS: { char *retval; size_t retval_len = 0; retval = get_netSnmpHostAddress(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_OCTET_STR, (const u_char *) retval, retval_len); } break; case COLUMN_NETSNMPHOSTSTORAGE: { long *retval; size_t retval_len = 0; retval = get_netSnmpHostStorage(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_NETSNMPHOSTROWSTATUS: { long *retval; size_t retval_len = 0; retval = get_netSnmpHostRowStatus(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; default: /** We shouldn't get here */ snmp_log(LOG_ERR, "problem encountered in netSnmpHostsTable_handler: unknown column\n"); } break; case MODE_SET_RESERVE1: ci = netsnmp_oid_stash_get_data(commitStorage, suffix + 1, suffix_len - 1); if (!ci) { /** create the commit storage info */ ci = SNMP_MALLOC_STRUCT(commitInfo); if (!data_context) { ci->data_context = netSnmpHostsTable_create_data_context(table_info-> indexes); ci->new_row = 1; } else { ci->data_context = data_context; } netsnmp_oid_stash_add_data(&commitStorage, suffix + 1, suffix_len - 1, ci); } break; case MODE_SET_RESERVE2: switch (table_info->colnum) { case COLUMN_NETSNMPHOSTADDRESSTYPE: { long *retval; size_t retval_len = 0; struct undoInfo *ui = NULL; int ret; /** first, get the old value */ retval = get_netSnmpHostAddressType(ci->data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); } /** check the new value, possibly against the older value for a valid state transition */ ret = check_netSnmpHostAddressType(request->requestvb-> type, (long *) request-> requestvb->val.string, request->requestvb-> val_len, retval, retval_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, request, ret); netSnmpHostsTable_free_undoInfo(ui); } else if (ui) { /** remember information for undo purposes later */ netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_NETSNMPHOSTADDRESS: { char *retval; size_t retval_len = 0; struct undoInfo *ui = NULL; int ret; /** first, get the old value */ retval = get_netSnmpHostAddress(ci->data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); } /** check the new value, possibly against the older value for a valid state transition */ ret = check_netSnmpHostAddress(request->requestvb->type, (char *) request-> requestvb->val.string, request->requestvb-> val_len, retval, retval_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, request, ret); netSnmpHostsTable_free_undoInfo(ui); } else if (ui) { /** remember information for undo purposes later */ netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_NETSNMPHOSTSTORAGE: { long *retval; size_t retval_len = 0; struct undoInfo *ui = NULL; int ret; /** first, get the old value */ retval = get_netSnmpHostStorage(ci->data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); } /** check the new value, possibly against the older value for a valid state transition */ ret = check_netSnmpHostStorage(request->requestvb->type, (long *) request-> requestvb->val.string, request->requestvb-> val_len, retval, retval_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, request, ret); netSnmpHostsTable_free_undoInfo(ui); } else if (ui) { /** remember information for undo purposes later */ netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_NETSNMPHOSTROWSTATUS: { long *retval; size_t retval_len = 0; struct undoInfo *ui = NULL; int ret; /** first, get the old value */ retval = get_netSnmpHostRowStatus(ci->data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); } /** check the new value, possibly against the older value for a valid state transition */ ret = check_netSnmpHostRowStatus(request->requestvb-> type, (long *) request-> requestvb->val.string, request->requestvb-> val_len, retval, retval_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, request, ret); netSnmpHostsTable_free_undoInfo(ui); } else if (ui) { /** remember information for undo purposes later */ netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; default: netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE); break; } break; case MODE_SET_ACTION: /** save a variable copy */ switch (table_info->colnum) { case COLUMN_NETSNMPHOSTADDRESSTYPE: { int ret; ret = set_netSnmpHostAddressType(ci->data_context, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, request, ret); } } break; case COLUMN_NETSNMPHOSTADDRESS: { int ret; ret = set_netSnmpHostAddress(ci->data_context, (char *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, request, ret); } } break; case COLUMN_NETSNMPHOSTSTORAGE: { int ret; ret = set_netSnmpHostStorage(ci->data_context, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, request, ret); } } break; case COLUMN_NETSNMPHOSTROWSTATUS: { int ret; ret = set_netSnmpHostRowStatus(ci->data_context, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, request, ret); } if (*request->requestvb->val.integer == RS_DESTROY) { ci->new_row = -1; } } break; } break; case MODE_SET_COMMIT: if (!ci->have_committed) { /** do this once per row only */ netSnmpHostsTable_commit_row(&ci->data_context, ci->new_row); ci->have_committed = 1; } break; case MODE_SET_UNDO: /** save a variable copy */ switch (table_info->colnum) { case COLUMN_NETSNMPHOSTADDRESSTYPE: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_netSnmpHostAddressType(ci->data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_NETSNMPHOSTADDRESS: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_netSnmpHostAddress(ci->data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_NETSNMPHOSTSTORAGE: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_netSnmpHostStorage(ci->data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_NETSNMPHOSTROWSTATUS: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_netSnmpHostRowStatus(ci->data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_UNDOFAILED); } } break; } break; case MODE_SET_FREE: break; default: snmp_log(LOG_ERR, "problem encountered in netSnmpHostsTable_handler: unsupported mode\n"); } } /** clean up after all requset processing has ended */ switch (reqinfo->mode) { case MODE_SET_UNDO: case MODE_SET_FREE: case MODE_SET_COMMIT: /** clear out the undo cache */ netsnmp_oid_stash_free(&undoStorage, netSnmpHostsTable_free_undoInfo); netsnmp_oid_stash_free(&commitStorage, netsnmp_oid_stash_no_free); } 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; }
/** handles requests for the ipCidrRouteTable table, if anything else needs to be done */ int ipCidrRouteTable_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_request_info *request; netsnmp_table_request_info *table_info; netsnmp_variable_list *var; void *data_context; oid *suffix; size_t suffix_len; /** column and row index encoded portion */ suffix = requests->requestvb->name + reginfo->rootoid_len + 1; suffix_len = requests->requestvb->name_length - (reginfo->rootoid_len + 1); for (request = requests; request; request = request->next) { var = request->requestvb; if (request->processed != 0) continue; data_context = netsnmp_extract_iterator_context(request); if (data_context == NULL) { if (reqinfo->mode == MODE_GET) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } /** XXX: no row existed, if you support creation and this is a set, start dealing with it here, else continue */ } /** extracts the information about the table from the request */ table_info = netsnmp_extract_table_info(request); /** table_info->colnum contains the column number requested */ /** table_info->indexes contains a linked list of snmp variable bindings for the indexes of the table. Values in the list have been set corresponding to the indexes of the request */ if (table_info == NULL) { continue; } switch (reqinfo->mode) { case MODE_GET: switch (table_info->colnum) { case COLUMN_IPCIDRROUTEDEST: { u_long *retval; size_t retval_len = 0; retval = get_ipCidrRouteDest(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_IPADDRESS, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTEMASK: { u_long *retval; size_t retval_len = 0; retval = get_ipCidrRouteMask(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_IPADDRESS, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTETOS: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteTos(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTENEXTHOP: { u_long *retval; size_t retval_len = 0; retval = get_ipCidrRouteNextHop(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_IPADDRESS, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTEIFINDEX: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteIfIndex(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTETYPE: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteType(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTEPROTO: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteProto(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTEAGE: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteAge(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTEINFO: { oid *retval; size_t retval_len = 0; retval = get_ipCidrRouteInfo(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_OBJECT_ID, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTENEXTHOPAS: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteNextHopAS(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTEMETRIC1: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteMetric1(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTEMETRIC2: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteMetric2(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTEMETRIC3: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteMetric3(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTEMETRIC4: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteMetric4(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTEMETRIC5: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteMetric5(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_IPCIDRROUTESTATUS: { long *retval; size_t retval_len = 0; retval = get_ipCidrRouteStatus(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; default: /** We shouldn't get here */ snmp_log(LOG_ERR, "problem encountered in ipCidrRouteTable_handler: unknown column\n"); } break; case MODE_SET_RESERVE1: /** mib2cXXX: clear out old undo info if we have any. Remove if table_iterator becomes un-serialized */ netsnmp_oid_stash_free(&undoStorage, free_undoInfo); switch (table_info->colnum) { case COLUMN_IPCIDRROUTEIFINDEX: { int ret = check_ipCidrRouteIfIndex(request->requestvb->type, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTETYPE: { int ret = check_ipCidrRouteType(request->requestvb->type, (long *) request->requestvb-> val.string, request->requestvb->val_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEINFO: { int ret = check_ipCidrRouteInfo(request->requestvb->type, (oid *) request->requestvb-> val.string, request->requestvb->val_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTENEXTHOPAS: { int ret = check_ipCidrRouteNextHopAS(request->requestvb-> type, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEMETRIC1: { int ret = check_ipCidrRouteMetric1(request->requestvb->type, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEMETRIC2: { int ret = check_ipCidrRouteMetric2(request->requestvb->type, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEMETRIC3: { int ret = check_ipCidrRouteMetric3(request->requestvb->type, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEMETRIC4: { int ret = check_ipCidrRouteMetric4(request->requestvb->type, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEMETRIC5: { int ret = check_ipCidrRouteMetric5(request->requestvb->type, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTESTATUS: { int ret = check_ipCidrRouteStatus(request->requestvb->type, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; default: netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_NOTWRITABLE); break; } break; case MODE_SET_RESERVE2: /** save a variable copy */ switch (table_info->colnum) { case COLUMN_IPCIDRROUTEIFINDEX: { long *retval; size_t retval_len = 0; struct undoInfo *ui; retval = get_ipCidrRouteIfIndex(data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_IPCIDRROUTETYPE: { long *retval; size_t retval_len = 0; struct undoInfo *ui; retval = get_ipCidrRouteType(data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_IPCIDRROUTEINFO: { oid *retval; size_t retval_len = 0; struct undoInfo *ui; retval = get_ipCidrRouteInfo(data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_IPCIDRROUTENEXTHOPAS: { long *retval; size_t retval_len = 0; struct undoInfo *ui; retval = get_ipCidrRouteNextHopAS(data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_IPCIDRROUTEMETRIC1: { long *retval; size_t retval_len = 0; struct undoInfo *ui; retval = get_ipCidrRouteMetric1(data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_IPCIDRROUTEMETRIC2: { long *retval; size_t retval_len = 0; struct undoInfo *ui; retval = get_ipCidrRouteMetric2(data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_IPCIDRROUTEMETRIC3: { long *retval; size_t retval_len = 0; struct undoInfo *ui; retval = get_ipCidrRouteMetric3(data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_IPCIDRROUTEMETRIC4: { long *retval; size_t retval_len = 0; struct undoInfo *ui; retval = get_ipCidrRouteMetric4(data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_IPCIDRROUTEMETRIC5: { long *retval; size_t retval_len = 0; struct undoInfo *ui; retval = get_ipCidrRouteMetric5(data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; case COLUMN_IPCIDRROUTESTATUS: { long *retval; size_t retval_len = 0; struct undoInfo *ui; retval = get_ipCidrRouteStatus(data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; memdup((u_char **) & ui->ptr, (u_char *) retval, ui->len); netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; } break; case MODE_SET_FREE: /** Forget undo data, if exists */ netsnmp_oid_stash_free(&undoStorage, free_undoInfo); break; case MODE_SET_ACTION: /** save a variable copy */ switch (table_info->colnum) { case COLUMN_IPCIDRROUTEIFINDEX: { int ret = set_ipCidrRouteIfIndex(data_context, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTETYPE: { int ret = set_ipCidrRouteType(data_context, (long *) request-> requestvb-> val.string, request-> requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEINFO: { int ret = set_ipCidrRouteInfo(data_context, (oid *) request-> requestvb-> val.string, request-> requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTENEXTHOPAS: { int ret = set_ipCidrRouteNextHopAS(data_context, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEMETRIC1: { int ret = set_ipCidrRouteMetric1(data_context, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEMETRIC2: { int ret = set_ipCidrRouteMetric2(data_context, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEMETRIC3: { int ret = set_ipCidrRouteMetric3(data_context, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEMETRIC4: { int ret = set_ipCidrRouteMetric4(data_context, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTEMETRIC5: { int ret = set_ipCidrRouteMetric5(data_context, (long *) request-> requestvb->val.string, request->requestvb-> val_len); if (ret) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; case COLUMN_IPCIDRROUTESTATUS: { int ret = set_ipCidrRouteStatus(data_context, (long *) request->requestvb-> val.string, request->requestvb->val_len); if (ret) { netsnmp_set_request_error(reqinfo, requests, ret); } } break; } break; case MODE_SET_COMMIT: /** answers were all good. Forget undo data */ netsnmp_oid_stash_free(&undoStorage, free_undoInfo); /** mib2cXXX: call commit hook */ break; case MODE_SET_UNDO: /** save a variable copy */ switch (table_info->colnum) { case COLUMN_IPCIDRROUTEIFINDEX: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_ipCidrRouteIfIndex(data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_IPCIDRROUTETYPE: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_ipCidrRouteType(data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_IPCIDRROUTEINFO: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_ipCidrRouteInfo(data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_IPCIDRROUTENEXTHOPAS: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_ipCidrRouteNextHopAS(data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_IPCIDRROUTEMETRIC1: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_ipCidrRouteMetric1(data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_IPCIDRROUTEMETRIC2: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_ipCidrRouteMetric2(data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_IPCIDRROUTEMETRIC3: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_ipCidrRouteMetric3(data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_IPCIDRROUTEMETRIC4: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_ipCidrRouteMetric4(data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_IPCIDRROUTEMETRIC5: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_ipCidrRouteMetric5(data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); } } break; case COLUMN_IPCIDRROUTESTATUS: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_ipCidrRouteStatus(data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); } } break; } /** mib2cXXX: remove cache! hard to do when serialized, however */ break; default: snmp_log(LOG_ERR, "problem encountered in ipCidrRouteTable_handler: unsupported mode\n"); } } return SNMP_ERR_NOERROR; }
/** implements the table data helper. This is the routine that takes * care of all SNMP requests coming into the table. */ int netsnmp_table_data_set_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_table_data_set_storage *data = NULL; newrow_stash *newrowstash = NULL; netsnmp_table_row *row, *newrow = NULL; netsnmp_table_request_info *table_info; netsnmp_request_info *request; oid *suffix; size_t suffix_len; netsnmp_oid_stash_node **stashp = NULL; if (!handler) return SNMPERR_GENERR; DEBUGMSGTL(("netsnmp_table_data_set", "handler starting\n")); for (request = requests; request; request = request->next) { netsnmp_table_data_set *datatable = (netsnmp_table_data_set *) handler->myvoid; if (request->processed) continue; /* * extract our stored data and table info */ row = netsnmp_extract_table_row(request); table_info = netsnmp_extract_table_info(request); suffix = requests->requestvb->name + reginfo->rootoid_len + 2; suffix_len = requests->requestvb->name_length - (reginfo->rootoid_len + 2); if (MODE_IS_SET(reqinfo->mode)) { char buf[256]; /* is this reasonable size?? */ int rc; size_t len; /* * use a cached copy of the row for modification */ /* * cache location: may have been created already by other * SET requests in the same master request. */ rc = snprintf(buf, sizeof(buf), "dataset_row_stash:%s:", datatable->table->name); if ((-1 == rc) || (rc >= sizeof(buf))) { snmp_log(LOG_ERR,"%s handler name too long\n", datatable->table->name); netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR); continue; } len = sizeof(buf) - rc; rc = snprint_objid(&buf[rc], len, table_info->index_oid, table_info->index_oid_len); if (-1 == rc) { snmp_log(LOG_ERR,"%s oid or name too long\n", datatable->table->name); netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR); continue; } stashp = (netsnmp_oid_stash_node **) netsnmp_table_get_or_create_row_stash(reqinfo, buf); newrowstash = netsnmp_oid_stash_get_data(*stashp, suffix, suffix_len); if (!newrowstash) { if (!row) { if (datatable->allow_creation) { /* * entirely new row. Create the row from the template */ newrowstash = netsnmp_table_data_set_create_newrowstash( datatable, table_info); newrow = newrowstash->newrow; } else if (datatable->rowstatus_column == 0) { /* * A RowStatus object may be used to control the * creation of a new row. But if this object * isn't declared (and the table isn't marked as * 'auto-create'), then we can't create a new row. */ netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION); continue; } } else { /* * existing row that needs to be modified */ newrowstash = SNMP_MALLOC_TYPEDEF(newrow_stash); newrow = netsnmp_table_data_set_clone_row(row); newrowstash->newrow = newrow; } netsnmp_oid_stash_add_data(stashp, suffix, suffix_len, newrowstash); } else { newrow = newrowstash->newrow; } /* * all future SET data modification operations use this * temp pointer */ if (reqinfo->mode == MODE_SET_RESERVE1 || reqinfo->mode == MODE_SET_RESERVE2) row = newrow; } if (row) data = (netsnmp_table_data_set_storage *) row->data; if (!row || !table_info || !data) { if (!MODE_IS_SET(reqinfo->mode)) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } } data = netsnmp_table_data_set_find_column(data, table_info->colnum); switch (reqinfo->mode) { case MODE_GET: case MODE_GETNEXT: case MODE_GETBULK: /* XXXWWW */ if (data && data->data.voidp) netsnmp_table_data_build_result(reginfo, reqinfo, request, row, table_info->colnum, data->type, data->data.voidp, data->data_len); break; case MODE_SET_RESERVE1: if (data) { /* * Can we modify the existing row? */ if (!data->writable) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE); } else if (request->requestvb->type != data->type) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE); } } else if (datatable->rowstatus_column == table_info->colnum) { /* * Otherwise, this is where we create a new row using * the RowStatus object (essentially duplicating the * steps followed earlier in the 'allow_creation' case) */ switch (*(request->requestvb->val.integer)) { case RS_CREATEANDGO: case RS_CREATEANDWAIT: newrowstash = netsnmp_table_data_set_create_newrowstash( datatable, table_info); newrow = newrowstash->newrow; row = newrow; netsnmp_oid_stash_add_data(stashp, suffix, suffix_len, newrowstash); } } break; case MODE_SET_RESERVE2: /* * If the agent receives a SET request for an object in a non-existant * row, then the RESERVE1 pass will create the row automatically. * * But since the row doesn't exist at that point, the test for whether * the object is writable or not will be skipped. So we need to check * for this possibility again here. * * Similarly, if row creation is under the control of the RowStatus * object (i.e. allow_creation == 0), but this particular request * doesn't include such an object, then the row won't have been created, * and the writable check will also have been skipped. Again - check here. */ if (data && data->writable == 0) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE); continue; } if (datatable->rowstatus_column == table_info->colnum) { switch (*(request->requestvb->val.integer)) { case RS_ACTIVE: case RS_NOTINSERVICE: /* * Can only operate on pre-existing rows. */ if (!newrowstash || newrowstash->created) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_INCONSISTENTVALUE); continue; } break; case RS_CREATEANDGO: case RS_CREATEANDWAIT: /* * Can only operate on newly created rows. */ if (!(newrowstash && newrowstash->created)) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_INCONSISTENTVALUE); continue; } break; case RS_DESTROY: /* * Can operate on new or pre-existing rows. */ break; case RS_NOTREADY: default: /* * Not a valid value to Set */ netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE); continue; } } if (!data ) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION); continue; } /* * modify row and set new value */ SNMP_FREE(data->data.string); data->data.string = netsnmp_strdup_and_null(request->requestvb->val.string, request->requestvb->val_len); if (!data->data.string) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_RESOURCEUNAVAILABLE); } data->data_len = request->requestvb->val_len; if (datatable->rowstatus_column == table_info->colnum) { switch (*(request->requestvb->val.integer)) { case RS_CREATEANDGO: /* * XXX: check legality */ *(data->data.integer) = RS_ACTIVE; break; case RS_CREATEANDWAIT: /* * XXX: check legality */ *(data->data.integer) = RS_NOTINSERVICE; break; case RS_DESTROY: newrowstash->deleted = 1; break; } } break; case MODE_SET_ACTION: /* * Install the new row into the stored table. * Do this only *once* per row .... */ if (newrowstash->state != STATE_ACTION) { newrowstash->state = STATE_ACTION; if (newrowstash->created) { netsnmp_table_dataset_add_row(datatable, newrow); } else { netsnmp_table_dataset_replace_row(datatable, row, newrow); } } /* * ... but every (relevant) varbind in the request will * need to know about this new row, so update the * per-request row information regardless */ if (newrowstash->created) { netsnmp_request_add_list_data(request, netsnmp_create_data_list(TABLE_DATA_NAME, newrow, NULL)); } break; case MODE_SET_UNDO: /* * extract the new row, replace with the old or delete */ if (newrowstash->state != STATE_UNDO) { newrowstash->state = STATE_UNDO; if (newrowstash->created) { netsnmp_table_dataset_remove_and_delete_row(datatable, newrow); } else { netsnmp_table_dataset_replace_row(datatable, newrow, row); netsnmp_table_dataset_delete_row(newrow); } } break; case MODE_SET_COMMIT: if (newrowstash->state != STATE_COMMIT) { newrowstash->state = STATE_COMMIT; if (!newrowstash->created) { netsnmp_table_dataset_delete_row(row); } if (newrowstash->deleted) { netsnmp_table_dataset_remove_and_delete_row(datatable, newrow); } } break; case MODE_SET_FREE: if (newrowstash && newrowstash->state != STATE_FREE) { newrowstash->state = STATE_FREE; netsnmp_table_dataset_delete_row(newrow); } break; } } /* next handler called automatically - 'AUTO_NEXT' */ 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; }
/** handles requests for the qosObjectTable table, if anything else needs to be done */ int qosObjectTable_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_request_info *request; netsnmp_table_request_info *table_info; netsnmp_variable_list *var; struct commitInfo *ci = NULL; void *data_context = NULL; oid *suffix; size_t suffix_len; /** column and row index encoded portion */ suffix = requests->requestvb->name + reginfo->rootoid_len + 1; suffix_len = requests->requestvb->name_length - (reginfo->rootoid_len + 1); for (request = requests; request; request = request->next) { var = request->requestvb; if (request->processed != 0) continue; switch (reqinfo->mode) { case MODE_GET: case MODE_SET_RESERVE1: data_context = netsnmp_extract_iterator_context(request); if (data_context == NULL) { if (reqinfo->mode == MODE_GET) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } } break; default: /* == the other SET modes */ ci = netsnmp_oid_stash_get_data(commitStorage, suffix + 1, suffix_len - 1); break; } /** extracts the information about the table from the request */ table_info = netsnmp_extract_table_info(request); /** table_info->colnum contains the column number requested */ /** table_info->indexes contains a linked list of snmp variable bindings for the indexes of the table. Values in the list have been set corresponding to the indexes of the request */ if (table_info == NULL) { continue; } switch (reqinfo->mode) { case MODE_GET: switch (table_info->colnum) { case COLUMN_QOSDEVICETYPE: { long *retval; size_t retval_len = 0; retval = get_qosDeviceIndex(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSDEVICEINDEX: { long *retval; size_t retval_len = 0; retval = get_qosDeviceIndex(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSMAJORHANDLE: { long *retval; size_t retval_len = 0; retval = get_qosMajorHandle(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len); } break; case COLUMN_QOSMINORHANDLE: { long *retval; size_t retval_len = 0; retval = get_qosMinorHandle(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len); } break; case COLUMN_QOSTEXTHANDLE: { char *retval; size_t retval_len = 0; retval = get_qosTextHandle(data_context, &retval_len); snmp_set_var_typed_value(var,ASN_OCTET_STR, (const u_char *) retval, retval_len); } break; case COLUMN_QOSTEXTLEAF: { char *retval; size_t retval_len = 0; retval = get_qosTextLeaf(data_context, &retval_len); snmp_set_var_typed_value(var,ASN_OCTET_STR, (const u_char *) retval, retval_len); } break; case COLUMN_QOSPARENT: { long *retval; size_t retval_len = 0; retval = get_qosParent(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len); } break; case COLUMN_QOSTEXTPARENT: { char *retval; size_t retval_len = 0; retval = get_qosTextParent(data_context, &retval_len); snmp_set_var_typed_value(var,ASN_OCTET_STR, (const u_char *) retval, retval_len); } break; case COLUMN_QOSDEVICENAME: { char *retval; size_t retval_len = 0; retval = get_qosDeviceName(data_context, &retval_len); snmp_set_var_typed_value(var,ASN_OCTET_STR, (const u_char *) retval, retval_len); } break; case COLUMN_QOSTYPE: { char *retval; size_t retval_len = 0; retval = get_qosType(data_context, &retval_len); snmp_set_var_typed_value(var,ASN_OCTET_STR, (const u_char *) retval, retval_len); } break; case COLUMN_QOSBYTES: { unsigned long long *retval; // u_long *retval; size_t retval_len = 0; retval = get_qosBytes(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER64, (const u_char *) retval, retval_len); } break; case COLUMN_QOSPACKETS: { u_long *retval; size_t retval_len = 0; retval = get_qosPackets(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSDROPPED: { u_long *retval; size_t retval_len = 0; retval = get_qosDropped(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSOVERLIMIT: { u_long *retval; size_t retval_len = 0; retval = get_qosOverlimit(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSBPS: { u_long *retval; size_t retval_len = 0; retval = get_qosBps(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len); } break; case COLUMN_QOSPPS: { u_long *retval; size_t retval_len = 0; retval = get_qosPps(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len); } break; case COLUMN_QOSQLEN: { u_long *retval; size_t retval_len = 0; retval = get_qosQlen(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len); } break; case COLUMN_QOSBACKLOG: { u_long *retval; size_t retval_len = 0; retval = get_qosBacklog(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len); } break; case COLUMN_QOSREDEARLY: { u_long *retval; size_t retval_len = 0; retval = get_redEarly(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSREDPDROP: { u_long *retval; size_t retval_len = 0; retval = get_redPdrop(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSREDOTHER: { u_long *retval; size_t retval_len = 0; retval = get_redOther(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSREDMARKED: { u_long *retval; size_t retval_len = 0; retval = get_redMarked(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSHTBLENDS: { u_long *retval; size_t retval_len = 0; retval = get_htbLends(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSHTBBORROWS: { u_long *retval; size_t retval_len = 0; retval = get_htbBorrows(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSHTBGIANTS: { u_long *retval; size_t retval_len = 0; retval = get_htbGiants(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSHTBTOKENS: { u_long *retval; size_t retval_len = 0; retval = get_htbTokens(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSHTBCTOKENS: { u_long *retval; size_t retval_len = 0; retval = get_htbCTokens(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSHTBRATE: { u_long *retval; size_t retval_len = 0; retval = get_htbRate(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len); } break; case COLUMN_QOSHTBCEIL: { u_long *retval; size_t retval_len = 0; retval = get_htbCeil(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len); } break; case COLUMN_QOSHTBPRIO: { u_long *retval; size_t retval_len = 0; retval = get_htbPrio(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len); } break; case COLUMN_QOSCBQBORROWS: { u_long *retval; size_t retval_len = 0; retval = get_cbqBorrows(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSCBQOVERACTIONS: { u_long *retval; size_t retval_len = 0; retval = get_cbqOveractions(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_COUNTER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSCBQAVGIDLE: { long *retval; size_t retval_len = 0; retval = get_cbqUndertime(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSCBQUNDERTIME: { long *retval; size_t retval_len = 0; retval = get_cbqUndertime(data_context, &retval_len); snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len); } break; case COLUMN_QOSINFO: { char *retval; size_t retval_len = 0; retval = get_qosInfo(data_context, &retval_len); snmp_set_var_typed_value(var,ASN_OCTET_STR, (const u_char *) retval, retval_len); } break; default: /** We shouldn't get here */ snmp_log(LOG_ERR, "problem encountered in qosObjectTable_handler: unknown column\n"); } break; case MODE_SET_RESERVE1: ci = netsnmp_oid_stash_get_data(commitStorage, suffix + 1, suffix_len - 1); if (!ci) { /** create the commit storage info */ ci = SNMP_MALLOC_STRUCT(commitInfo); if (!data_context) { ci->data_context = qosObjectTable_create_data_context(table_info-> indexes); ci->new_row = 1; } else { ci->data_context = data_context; } netsnmp_oid_stash_add_data(&commitStorage, suffix + 1, suffix_len - 1, ci); } break; case MODE_SET_RESERVE2: switch (table_info->colnum) { default: netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE); break; } break; case MODE_SET_ACTION: /** save a variable copy */ switch (table_info->colnum) { } break; case MODE_SET_COMMIT: if (!ci->have_committed) { /** do this once per row only */ qosObjectTable_commit_row(&ci->data_context, ci->new_row); ci->have_committed = 1; } break; case MODE_SET_UNDO: /** save a variable copy */ switch (table_info->colnum) { } break; case MODE_SET_FREE: break; default: snmp_log(LOG_ERR, "problem encountered in qosObjectTable_handler: unsupported mode\n"); } } /** clean up after all requset processing has ended */ switch (reqinfo->mode) { case MODE_SET_UNDO: case MODE_SET_FREE: case MODE_SET_COMMIT: /** clear out the undo cache */ netsnmp_oid_stash_free(&undoStorage, qos_free_undoInfo); netsnmp_oid_stash_free(&commitStorage, netsnmp_oid_stash_no_free); } return SNMP_ERR_NOERROR; }