/* builds a result given a row, a varbind to set and the data */ int netsnmp_table_data_build_result(netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *request, netsnmp_table_row *row, int column, u_char type, u_char * result_data, size_t result_data_len) { oid build_space[MAX_OID_LEN]; if (!reginfo || !reqinfo || !request) return SNMPERR_GENERR; if (reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK) { /* * only need to do this for getnext type cases where oid is changing */ memcpy(build_space, reginfo->rootoid, /* registered oid */ reginfo->rootoid_len * sizeof(oid)); build_space[reginfo->rootoid_len] = 1; /* entry */ build_space[reginfo->rootoid_len + 1] = column; /* column */ memcpy(build_space + reginfo->rootoid_len + 2, /* index data */ row->index_oid, row->index_oid_len * sizeof(oid)); snmp_set_var_objid(request->requestvb, build_space, reginfo->rootoid_len + 2 + row->index_oid_len); } snmp_set_var_typed_value(request->requestvb, type, result_data, result_data_len); return SNMPERR_SUCCESS; /* WWWXXX: check for bounds */ }
char * register_string_index(oid * name, size_t name_len, char *cp) { netsnmp_variable_list varbind, *res; memset(&varbind, 0, sizeof(netsnmp_variable_list)); varbind.type = ASN_OCTET_STR; snmp_set_var_objid(&varbind, name, name_len); if (cp != ANY_STRING_INDEX) { snmp_set_var_value(&varbind, (u_char *) cp, strlen(cp)); res = register_index(&varbind, ALLOCATE_THIS_INDEX, main_session); } else { res = register_index(&varbind, ALLOCATE_ANY_INDEX, main_session); } if (res == NULL) { return NULL; } else { char *rv = (char *)malloc(res->val_len + 1); if (rv) { memcpy(rv, res->val.string, res->val_len); rv[res->val_len] = 0; } free(res); return rv; } }
int register_int_index(oid * name, size_t name_len, int val) { netsnmp_variable_list varbind, *res; memset(&varbind, 0, sizeof(netsnmp_variable_list)); varbind.type = ASN_INTEGER; snmp_set_var_objid(&varbind, name, name_len); varbind.val.string = varbind.buf; if (val != ANY_INTEGER_INDEX) { varbind.val_len = sizeof(long); *varbind.val.integer = val; res = register_index(&varbind, ALLOCATE_THIS_INDEX, main_session); } else { res = register_index(&varbind, ALLOCATE_ANY_INDEX, main_session); } if (res == NULL) { return -1; } else { int rv = *(res->val.integer); free(res); return rv; } }
void build_new_oid(netsnmp_handler_registration *reginfo, netsnmp_table_request_info *tblreq_info, netsnmp_index *row, netsnmp_request_info *current) { oid coloid[MAX_OID_LEN]; if (!tblreq_info || !reginfo || !row || !current) return; memcpy(coloid, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid)); /** table.entry */ coloid[reginfo->rootoid_len] = 1; /** table.entry.column */ coloid[reginfo->rootoid_len + 1] = tblreq_info->colnum; /** table.entry.column.index */ memcpy(&coloid[reginfo->rootoid_len + 2], row->oids, row->len * sizeof(oid)); snmp_set_var_objid(current->requestvb, coloid, reginfo->rootoid_len + 2 + row->len); }
netsnmp_variable_list * _expObject_buildList( oid *root, size_t root_len, size_t prefix_len, netsnmp_variable_list *template_list ) { netsnmp_variable_list *query_list = NULL; netsnmp_variable_list *vp1, *vp2 = NULL; oid name[ MAX_OID_LEN ]; int i; if ( prefix_len ) { /* * For wildcarded objects, build a list of all relevant * instances, using the template_list to provide the * necessary instance suffixes. */ memset( name, 0, sizeof(name)); memcpy( name, root, root_len*sizeof(oid)); for ( vp1 = template_list; vp1; vp1=vp1->next_variable ) { /* * Append a new varbind to the list for this object ... */ if ( !query_list ) { query_list = (netsnmp_variable_list*) SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); vp2 = query_list; } else { vp2->next_variable = (netsnmp_variable_list*) SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); vp2 = vp2->next_variable; } /* * ... and set the OID using the template suffix */ for ( i=0; i <= vp1->name_length - prefix_len; i++) name[ root_len+i ] = vp1->name[ prefix_len+i ]; snmp_set_var_objid( vp2, name, root_len+i ); } } else { /* * Otherwise, just use the (single) OID provided. */ query_list = (netsnmp_variable_list*) SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); snmp_set_var_objid( query_list, root, root_len ); } return query_list; }
void AlarmTrapSender::send_trap(AlarmTableDef& alarm_table_def) { static const oid snmp_trap_oid[] = {1,3,6,1,6,3,1,1,4,1,0}; static const oid clear_oid[] = {1,3,6,1,2,1,118,0,3}; static const oid active_oid[] = {1,3,6,1,2,1,118,0,2}; static const oid model_ptr_oid[] = {1,3,6,1,2,1,118,1,2,2,1,13,0}; static const oid model_row_oid[] = {1,3,6,1,2,1,118,1,1,2,1,3,0,1,2}; static const oid resource_id_oid[] = {1,3,6,1,2,1,118,1,2,2,1,10,0}; static const oid zero_dot_zero[] = {0,0}; netsnmp_variable_list var_trap; netsnmp_variable_list var_model_row; netsnmp_variable_list var_resource_id; memset(&var_trap, 0x00, sizeof(var_trap)); memset(&var_model_row, 0x00, sizeof(var_model_row)); memset(&var_resource_id, 0x00, sizeof(var_resource_id)); var_trap.next_variable = &var_model_row; var_model_row.next_variable = &var_resource_id; var_resource_id.next_variable = NULL; snmp_set_var_objid(&var_trap, snmp_trap_oid, OID_LENGTH(snmp_trap_oid)); if (alarm_table_def.severity() == AlarmDef::CLEARED) { snmp_set_var_typed_value(&var_trap, ASN_OBJECT_ID, (u_char*) clear_oid, sizeof(clear_oid)); } else { snmp_set_var_typed_value(&var_trap, ASN_OBJECT_ID, (u_char*) active_oid, sizeof(active_oid)); } snmp_set_var_objid(&var_model_row, model_ptr_oid, OID_LENGTH(model_ptr_oid)); snmp_set_var_typed_value(&var_model_row, ASN_OBJECT_ID, (u_char*) model_row_oid, sizeof(model_row_oid)); var_model_row.val.objid[ALARMMODELTABLEROW_INDEX] = alarm_table_def.index(); var_model_row.val.objid[ALARMMODELTABLEROW_STATE] = alarm_table_def.state(); snmp_set_var_objid(&var_resource_id, resource_id_oid, OID_LENGTH(resource_id_oid)); snmp_set_var_typed_value(&var_resource_id, ASN_OBJECT_ID, (u_char*) zero_dot_zero, sizeof(zero_dot_zero)); send_v2trap(&var_trap); snmp_reset_var_buffers(&var_trap); }
int unregister_string_index(oid * name, size_t name_len, char *cp) { netsnmp_variable_list varbind; memset(&varbind, 0, sizeof(netsnmp_variable_list)); varbind.type = ASN_OCTET_STR; snmp_set_var_objid(&varbind, name, name_len); snmp_set_var_value(&varbind, (u_char *) cp, strlen(cp)); return (unregister_index(&varbind, FALSE, main_session)); }
int my_test_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { oid myoid1[] = { 1, 2, 3, 4, 5, 6 }; static u_long accesses = 0; DEBUGMSGTL(("testhandler", "Got request:\n")); /* * loop through requests */ while (requests) { netsnmp_variable_list *var = requests->requestvb; DEBUGMSGTL(("testhandler", " oid:")); DEBUGMSGOID(("testhandler", var->name, var->name_length)); DEBUGMSG(("testhandler", "\n")); switch (reqinfo->mode) { case MODE_GET: if (netsnmp_oid_equals(var->name, var->name_length, myoid1, 6) == 0) { snmp_set_var_typed_value(var, ASN_INTEGER, (u_char *) & accesses, sizeof(accesses)); return SNMP_ERR_NOERROR; } break; case MODE_GETNEXT: if (snmp_oid_compare(var->name, var->name_length, myoid1, 6) < 0) { snmp_set_var_objid(var, myoid1, 6); snmp_set_var_typed_value(var, ASN_INTEGER, (u_char *) & accesses, sizeof(accesses)); return SNMP_ERR_NOERROR; } break; default: netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR); break; } requests = requests->next; } return SNMP_ERR_NOERROR; }
int unregister_int_index(oid * name, size_t name_len, int val) { netsnmp_variable_list varbind; memset(&varbind, 0, sizeof(netsnmp_variable_list)); varbind.type = ASN_INTEGER; snmp_set_var_objid(&varbind, name, name_len); varbind.val.string = varbind.buf; varbind.val_len = sizeof(long); *varbind.val.integer = val; return (unregister_index(&varbind, FALSE, main_session)); }
int unregister_oid_index(oid * name, size_t name_len, oid * value, size_t value_len) { netsnmp_variable_list varbind; memset(&varbind, 0, sizeof(netsnmp_variable_list)); varbind.type = ASN_OBJECT_ID; snmp_set_var_objid(&varbind, name, name_len); snmp_set_var_value(&varbind, (u_char *) value, value_len * sizeof(oid)); return (unregister_index(&varbind, FALSE, main_session)); }
struct variable_list * register_oid_index( oid *name, size_t name_len, oid *value, size_t value_len ) { struct variable_list varbind; memset( &varbind, 0, sizeof(struct variable_list)); varbind.type = ASN_OBJECT_ID; snmp_set_var_objid( &varbind, name, name_len ); if ( value != ANY_OID_INDEX ) { snmp_set_var_value( &varbind, (u_char*)value, value_len*sizeof(oid) ); return( register_index( &varbind, ALLOCATE_THIS_INDEX, main_session )); } else return( register_index( &varbind, ALLOCATE_ANY_INDEX, main_session )); }
/* * Clone an SNMP variable data structure. * Sets pointers to structure private storage, or * allocates larger object identifiers and values as needed. * * Caller must make list association for cloned variable. * * Returns 0 if successful. */ int snmp_clone_var(netsnmp_variable_list * var, netsnmp_variable_list * newvar) { if (!newvar || !var) return 1; memmove(newvar, var, sizeof(netsnmp_variable_list)); newvar->next_variable = 0; newvar->name = 0; newvar->val.string = 0; newvar->data = 0; newvar->dataFreeHook = 0; newvar->index = 0; /* * Clone the object identifier and the value. * Allocate memory iff original will not fit into local storage. */ if (snmp_set_var_objid(newvar, var->name, var->name_length)) return 1; /* * need a pointer and a length to copy a string value. */ if (var->val.string && var->val_len) { if (var->val.string != &var->buf[0]) { if (var->val_len <= sizeof(var->buf)) newvar->val.string = newvar->buf; else { newvar->val.string = (u_char *) malloc(var->val_len); if (!newvar->val.string) return 1; } memmove(newvar->val.string, var->val.string, var->val_len); } else { /* fix the pointer to new local store */ newvar->val.string = newvar->buf; } } else { newvar->val.string = 0; newvar->val_len = 0; } return 0; }
int _mteEvent_fire_set (struct mteEvent *entry, /* The event to fire */ struct mteTrigger *trigger, /* Trigger that fired */ oid * suffix, size_t sfx_len) /* Matching instance */ { netsnmp_variable_list var; oid set_oid[MAX_OID_LEN]; size_t set_len; /* * Set the basic assignment OID... */ memset (set_oid, 0, sizeof (set_oid)); memcpy (set_oid, entry->mteSetOID, entry->mteSetOID_len * sizeof (oid)); set_len = entry->mteSetOID_len; /* * ... if the trigger value is wildcarded (sfx_len > 0), * *and* the SET event entry is wildcarded, * then add the supplied instance suffix... */ if (sfx_len && entry->flags & MTE_SET_FLAG_OBJWILD) { memcpy (&set_oid[set_len], suffix, sfx_len * sizeof (oid)); set_len += sfx_len; } /* * ... finally build the assignment varbind, * and pass it to be acted on. * * XXX: Need to handle (remote) targets and non-default contexts */ memset (&var, 0, sizeof (var)); snmp_set_var_objid (&var, set_oid, set_len); snmp_set_var_typed_integer (&var, ASN_INTEGER, entry->mteSetValue); if (entry->session) return netsnmp_query_set (&var, entry->session); else return netsnmp_query_set (&var, trigger->session); /* XXX - Need to check result */ }
static netsnmp_variable_list * oa_bind_var(netsnmp_variable_list * prev, void *value, int type, size_t sz_val, oid * oid, size_t sz_oid) { netsnmp_variable_list *var; var = (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list)); if (!var) { ag_trace("FATAL: cannot malloc in oa_bind_var\n"); exit(-1); /* Sorry :( */ } memset(var, 0, sizeof(netsnmp_variable_list)); var->next_variable = prev; snmp_set_var_objid(var, oid, sz_oid); snmp_set_var_value(var, (u_char *) value, sz_val); var->type = type; return var; }
char * register_string_index( oid *name, size_t name_len, char *cp ) { struct variable_list varbind, *res; memset( &varbind, 0, sizeof(struct variable_list)); varbind.type = ASN_OCTET_STR; snmp_set_var_objid( &varbind, name, name_len ); if ( cp != ANY_STRING_INDEX ) { snmp_set_var_value( &varbind, (u_char *)cp, strlen(cp) ); res = register_index( &varbind, ALLOCATE_THIS_INDEX, main_session ); } else res = register_index( &varbind, ALLOCATE_ANY_INDEX, main_session ); if ( res == NULL ) return NULL; else return (char *)res->val.string; }
void send_enterprise_trap_vars (int trap, int specific, oid *enterprise, int enterprise_length, struct variable_list *vars) { struct variable_list uptime_var, snmptrap_var, enterprise_var; struct variable_list *v2_vars, *last_var=NULL; struct snmp_pdu *template_pdu, *pdu; struct timeval now; long uptime; struct sockaddr_in *pduIp; struct trap_sink *sink; oid temp_oid[MAX_OID_LEN]; /* * Initialise SNMPv2 required variables */ gettimeofday(&now, NULL); uptime = calculate_time_diff(&now, &starttime); memset (&uptime_var, 0, sizeof (struct variable_list)); snmp_set_var_objid( &uptime_var, sysuptime_oid, OID_LENGTH(sysuptime_oid)); snmp_set_var_value( &uptime_var, (u_char *)&uptime, sizeof(uptime) ); uptime_var.type = ASN_TIMETICKS; uptime_var.next_variable = &snmptrap_var; memset (&snmptrap_var, 0, sizeof (struct variable_list)); snmp_set_var_objid( &snmptrap_var, snmptrap_oid, OID_LENGTH(snmptrap_oid)); /* value set later .... */ snmptrap_var.type = ASN_OBJECT_ID; if ( vars ) snmptrap_var.next_variable = vars; else snmptrap_var.next_variable = &enterprise_var; /* find end of provided varbind list, ready to append the enterprise info if necessary */ last_var = vars; while ( last_var && last_var->next_variable ) last_var = last_var->next_variable; memset (&enterprise_var, 0, sizeof (struct variable_list)); snmp_set_var_objid( &enterprise_var, snmptrapenterprise_oid, OID_LENGTH(snmptrapenterprise_oid)); snmp_set_var_value( &enterprise_var, (u_char *)enterprise, enterprise_length*sizeof(oid)); enterprise_var.type = ASN_OBJECT_ID; enterprise_var.next_variable = NULL; v2_vars = &uptime_var; /* * Create a template PDU, ready for sending */ template_pdu = snmp_pdu_create( SNMP_MSG_TRAP ); if ( template_pdu == NULL ) { /* Free memory if value stored dynamically */ snmp_set_var_value( &enterprise_var, NULL, 0); return; } template_pdu->trap_type = trap; template_pdu->specific_type = specific; if ( snmp_clone_mem((void **)&template_pdu->enterprise, enterprise, enterprise_length*sizeof(oid))) { snmp_free_pdu( template_pdu ); snmp_set_var_value( &enterprise_var, NULL, 0); return; } template_pdu->enterprise_length = enterprise_length; template_pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY; pduIp = (struct sockaddr_in *)&template_pdu->agent_addr; pduIp->sin_family = AF_INET; pduIp->sin_len = sizeof(*pduIp); pduIp->sin_addr.s_addr = get_myaddr(); template_pdu->time = uptime; /* * Now use the parameters to determine * which v2 variables are needed, * and what values they should take. */ switch ( trap ) { case -1: /* * SNMPv2 only * Check to see whether the variables provided * are sufficient for SNMPv2 notifications */ if (vars && snmp_oid_compare(vars->name, vars->name_length, sysuptime_oid, OID_LENGTH(sysuptime_oid)) == 0 ) v2_vars = vars; else if (vars && snmp_oid_compare(vars->name, vars->name_length, snmptrap_oid, OID_LENGTH(snmptrap_oid)) == 0 ) uptime_var.next_variable = vars; else { /* Hmmm... we don't seem to have a value - oops! */ snmptrap_var.next_variable = vars; } last_var = NULL; /* Don't need enterprise info */ break; /* "Standard" SNMPv1 traps */ case SNMP_TRAP_COLDSTART: snmp_set_var_value( &snmptrap_var, (u_char *)cold_start_oid, sizeof(cold_start_oid)); break; case SNMP_TRAP_WARMSTART: snmp_set_var_value( &snmptrap_var, (u_char *)warm_start_oid, sizeof(warm_start_oid)); break; case SNMP_TRAP_LINKDOWN: snmp_set_var_value( &snmptrap_var, (u_char *)link_down_oid, sizeof(link_down_oid)); break; case SNMP_TRAP_LINKUP: snmp_set_var_value( &snmptrap_var, (u_char *)link_up_oid, sizeof(link_up_oid)); break; case SNMP_TRAP_AUTHFAIL: if (snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED) { snmp_free_pdu( template_pdu ); snmp_set_var_value( &enterprise_var, NULL, 0); return; } snmp_set_var_value( &snmptrap_var, (u_char *)auth_fail_oid, sizeof(auth_fail_oid)); break; case SNMP_TRAP_EGPNEIGHBORLOSS: snmp_set_var_value( &snmptrap_var, (u_char *)egp_xxx_oid, sizeof(egp_xxx_oid)); break; case SNMP_TRAP_ENTERPRISESPECIFIC: memcpy( &temp_oid, (char *)enterprise, (enterprise_length)*sizeof(oid)); temp_oid[ enterprise_length ] = 0; temp_oid[ enterprise_length+1 ] = specific; snmp_set_var_value( &snmptrap_var, (u_char *)&temp_oid, (enterprise_length+2)*sizeof(oid)); snmptrap_var.next_variable = vars; last_var = NULL; /* Don't need version info */ break; } /* * Now loop through the list of trap sinks, * sending an appropriately formatted PDU to each */ for ( sink = sinks ; sink ; sink=sink->next ) { if ( sink->version == SNMP_VERSION_1 && trap == -1 ) continue; /* Skip v1 sinks for v2 only traps */ template_pdu->version = sink->version; template_pdu->command = sink->pdutype; if ( sink->version != SNMP_VERSION_1 ) { template_pdu->variables = v2_vars; if ( last_var ) last_var->next_variable = &enterprise_var; } else template_pdu->variables = vars; pdu = snmp_clone_pdu( template_pdu ); pdu->sessid = sink->sesp->sessid; /* AgentX only ? */ if ( snmp_send( sink->sesp, pdu) == 0 ) { snmp_sess_perror ("snmpd: send_trap", sink->sesp); snmp_free_pdu( pdu ); } else { snmp_increment_statistic(STAT_SNMPOUTTRAPS); snmp_increment_statistic(STAT_SNMPOUTPKTS); } if ( sink->version != SNMP_VERSION_1 && last_var ) last_var->next_variable = NULL; } /* Free memory if values stored dynamically */ snmp_set_var_value( &enterprise_var, NULL, 0); snmp_set_var_value( &snmptrap_var, NULL, 0); /* Ensure we don't free anything we shouldn't */ if ( last_var ) last_var->next_variable = NULL; template_pdu->variables = NULL; snmp_free_pdu( template_pdu ); }
/* 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; }
/** @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; }
/** 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; }
/** implements the old_api handler */ int netsnmp_old_api_helper(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { #if MIB_CLIENTS_ARE_EVIL oid save[MAX_OID_LEN]; size_t savelen = 0; #endif struct variable compat_var, *cvp = &compat_var; int exact = 1; int status; struct variable *vp; netsnmp_old_api_cache *cacheptr; netsnmp_agent_session *oldasp = NULL; u_char *access = NULL; WriteMethod *write_method = NULL; size_t len; size_t tmp_len; oid tmp_name[MAX_OID_LEN]; vp = (struct variable *) handler->myvoid; /* * create old variable structure with right information */ memcpy(cvp->name, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid)); cvp->namelen = reginfo->rootoid_len; cvp->type = vp->type; cvp->magic = vp->magic; cvp->acl = vp->acl; cvp->findVar = vp->findVar; switch (reqinfo->mode) { case MODE_GETNEXT: case MODE_GETBULK: exact = 0; } for (; requests; requests = requests->next) { #if MIB_CLIENTS_ARE_EVIL savelen = requests->requestvb->name_length; memcpy(save, requests->requestvb->name, savelen * sizeof(oid)); #endif switch (reqinfo->mode) { case MODE_GET: case MODE_GETNEXT: #ifndef NETSNMP_NO_WRITE_SUPPORT case MODE_SET_RESERVE1: #endif /* !NETSNMP_NO_WRITE_SUPPORT */ /* * Actually call the old mib-module function */ if (vp && vp->findVar) { memcpy(tmp_name, requests->requestvb->name, requests->requestvb->name_length*sizeof(oid)); tmp_len = requests->requestvb->name_length; access = (*(vp->findVar)) (cvp, tmp_name, &tmp_len, exact, &len, &write_method); snmp_set_var_objid( requests->requestvb, tmp_name, tmp_len ); } else access = NULL; #ifdef WWW_FIX if (IS_DELEGATED(cvp->type)) { add_method = (AddVarMethod *) statP; requests->delayed = 1; have_delegated = 1; continue; /* WWW: This may not get to the right place */ } #endif /* * WWW: end range checking */ if (access) { /* * result returned */ #ifndef NETSNMP_NO_WRITE_SUPPORT if (reqinfo->mode != MODE_SET_RESERVE1) #endif /* !NETSNMP_NO_WRITE_SUPPORT */ snmp_set_var_typed_value(requests->requestvb, cvp->type, access, len); } else { /* * no result returned */ #if MIB_CLIENTS_ARE_EVIL if (access == NULL) { if (netsnmp_oid_equals(requests->requestvb->name, requests->requestvb->name_length, save, savelen) != 0) { DEBUGMSGTL(("old_api", "evil_client: %s\n", reginfo->handlerName)); memcpy(requests->requestvb->name, save, savelen * sizeof(oid)); requests->requestvb->name_length = savelen; } } #endif } /* * AAA: fall through for everything that is a set (see BBB) */ #ifndef NETSNMP_NO_WRITE_SUPPORT if (reqinfo->mode != MODE_SET_RESERVE1) #endif /* !NETSNMP_NO_WRITE_SUPPORT */ break; cacheptr = SNMP_MALLOC_TYPEDEF(netsnmp_old_api_cache); if (!cacheptr) return netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_RESOURCEUNAVAILABLE); cacheptr->data = access; cacheptr->write_method = write_method; write_method = NULL; netsnmp_request_add_list_data(requests, netsnmp_create_data_list (OLD_API_NAME, cacheptr, &free_wrapper)); /* * BBB: fall through for everything that is a set (see AAA) */ default: /* * WWW: explicitly list the SET conditions */ /* * (the rest of the) SET contions */ cacheptr = (netsnmp_old_api_cache *) netsnmp_request_get_list_data(requests, OLD_API_NAME); if (cacheptr == NULL || cacheptr->write_method == NULL) { /* * WWW: try to set ourselves if possible? */ return netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_NOTWRITABLE); } oldasp = netsnmp_get_current_agent_session(); set_current_agent_session(reqinfo->asp); status = (*(cacheptr->write_method)) (reqinfo->mode, requests->requestvb->val. string, requests->requestvb->type, requests->requestvb->val_len, cacheptr->data, requests->requestvb->name, requests->requestvb-> name_length); set_current_agent_session(oldasp); if (status != SNMP_ERR_NOERROR) { netsnmp_set_request_error(reqinfo, requests, status); } /* * clean up is done by the automatic freeing of the * cache stored in the request. */ break; } } return SNMP_ERR_NOERROR; }
void main(int argc, char argv[]) { oid name[] = { 1, 2, 3, 4, 0 }; int i; memset(&varbind, 0, sizeof(netsnmp_variable_list)); snmp_set_var_objid(&varbind, name, 5); varbind->type = ASN_OCTET_STR; /* * Test index structure linking: * a) sorted by OID */ test_string_register(20, "empty OID"); test_string_register(10, "first OID"); test_string_register(40, "last OID"); test_string_register(30, "middle OID"); /* * b) sorted by index value */ test_string_register(25, "eee: empty IDX"); test_string_register(25, "aaa: first IDX"); test_string_register(25, "zzz: last IDX"); test_string_register(25, "mmm: middle IDX"); printf("This next one should fail....\n"); test_string_register(25, "eee: empty IDX"); /* duplicate */ printf("done\n"); /* * c) test initial index linking */ test_string_register(5, "eee: empty initial IDX"); test_string_register(5, "aaa: replace initial IDX"); /* * Did it all work? */ dump_idx_registry(); unregister_index_by_session(main_session); /* * Now test index allocation * a) integer values */ test_int_register(110, -1); /* empty */ test_int_register(110, -1); /* append */ test_int_register(110, 10); /* append exact */ printf("This next one should fail....\n"); test_int_register(110, 10); /* exact duplicate */ printf("done\n"); test_int_register(110, -1); /* append */ test_int_register(110, 5); /* insert exact */ /* * b) string values */ test_string_register(120, NULL); /* empty */ test_string_register(120, NULL); /* append */ test_string_register(120, "aaaz"); test_string_register(120, NULL); /* minor rollover */ test_string_register(120, "zzzz"); test_string_register(120, NULL); /* major rollover */ /* * c) OID values */ test_oid_register(130, -1); /* empty */ test_oid_register(130, -1); /* append */ varbind->val_len = varbind.name_length * sizeof(oid); memcpy(varbind->buf, varbind.name, varbind.val_len); varbind->val.objid = (oid *) varbind.buf; varbind->val_len += sizeof(oid); test_oid_register(130, 255); /* append exact */ test_oid_register(130, -1); /* minor rollover */ test_oid_register(130, 100); /* insert exact */ printf("This next one should fail....\n"); test_oid_register(130, 100); /* exact duplicate */ printf("done\n"); varbind->val.objid = (oid *) varbind.buf; for (i = 0; i < 6; i++) varbind->val.objid[i] = 255; varbind->val.objid[0] = 1; test_oid_register(130, 255); /* set up rollover */ test_oid_register(130, -1); /* medium rollover */ for (i = 0; i < 6; i++) varbind->val.objid[i] = 255; varbind->val.objid[0] = 2; test_oid_register(130, 255); /* set up rollover */ test_oid_register(130, -1); /* major rollover */ /* * Did it all work? */ dump_idx_registry(); /* * Test the various "invalid" requests * (unsupported types, mis-matched types, etc) */ printf("The rest of these should fail....\n"); test_oid_register(110, -1); test_oid_register(110, 100); test_oid_register(120, -1); test_oid_register(120, 100); test_string_register(110, NULL); test_string_register(110, "aaaa"); test_string_register(130, NULL); test_string_register(130, "aaaa"); test_int_register(120, -1); test_int_register(120, 1); test_int_register(130, -1); test_int_register(130, 1); printf("done - this dump should be the same as before\n"); dump_idx_registry(); }
/** @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; }
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; }
int handle_subagent_response(int op, netsnmp_session * session, int reqid, netsnmp_pdu *pdu, void *magic) { ns_subagent_magic *smagic = (ns_subagent_magic *) magic; netsnmp_variable_list *u = NULL, *v = NULL; int rc = 0; if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE || magic == NULL) { return 1; } pdu = snmp_clone_pdu(pdu); DEBUGMSGTL(("agentx/subagent", "handling AgentX response (cmd 0x%02x orig_cmd 0x%02x)\n", pdu->command, smagic->original_command)); if (pdu->command == SNMP_MSG_INTERNAL_SET_FREE || pdu->command == SNMP_MSG_INTERNAL_SET_UNDO || pdu->command == SNMP_MSG_INTERNAL_SET_COMMIT) { free_set_vars(smagic->session, pdu); } if (smagic->original_command == AGENTX_MSG_GETNEXT) { DEBUGMSGTL(("agentx/subagent", "do getNext scope processing %p %p\n", smagic->ovars, pdu->variables)); for (u = smagic->ovars, v = pdu->variables; u != NULL && v != NULL; u = u->next_variable, v = v->next_variable) { if (snmp_oid_compare (u->val.objid, u->val_len / sizeof(oid), nullOid, nullOidLen) != 0) { /* * The master agent requested scoping for this variable. */ rc = snmp_oid_compare(v->name, v->name_length, u->val.objid, u->val_len / sizeof(oid)); DEBUGMSGTL(("agentx/subagent", "result ")); DEBUGMSGOID(("agentx/subagent", v->name, v->name_length)); DEBUGMSG(("agentx/subagent", " scope to ")); DEBUGMSGOID(("agentx/subagent", u->val.objid, u->val_len / sizeof(oid))); DEBUGMSG(("agentx/subagent", " result %d\n", rc)); if (rc >= 0) { /* * The varbind is out of scope. From RFC2741, p. 66: "If * the subagent cannot locate an appropriate variable, * v.name is set to the starting OID, and the VarBind is * set to `endOfMibView'". */ snmp_set_var_objid(v, u->name, u->name_length); snmp_set_var_typed_value(v, SNMP_ENDOFMIBVIEW, 0, 0); DEBUGMSGTL(("agentx/subagent", "scope violation -- return endOfMibView\n")); } } else { DEBUGMSGTL(("agentx/subagent", "unscoped var\n")); } } } /* * XXXJBPN: similar for GETBULK but the varbinds can get re-ordered I * think which makes it er more difficult. */ if (smagic->ovars != NULL) { snmp_free_varbind(smagic->ovars); } pdu->command = AGENTX_MSG_RESPONSE; pdu->version = smagic->session->version; if (!snmp_send(smagic->session, pdu)) { snmp_free_pdu(pdu); } DEBUGMSGTL(("agentx/subagent", " FINISHED\n")); free(smagic); return 1; }
/* * Gather the data necessary for evaluating an expression. * * This will retrieve *all* the data relevant for all * instances of this expression, rather than just the * just the values needed for expanding a given instance. */ void expExpression_getData( unsigned int reg, void *clientarg ) { struct expExpression *entry = (struct expExpression *)clientarg; netsnmp_tdata_row *row; netsnmp_variable_list *var; int ret; if ( !entry && reg ) { snmp_alarm_unregister( reg ); return; } if (( entry->expExpression[0] == '\0' ) || !(entry->flags & EXP_FLAG_ACTIVE) || !(entry->flags & EXP_FLAG_VALID)) return; DEBUGMSGTL(("disman:expr:run", "Gathering expression data (%s, %s)\n", entry->expOwner, entry->expName)); /* * This routine can be called in two situations: * - regularly by 'snmp_alarm' (reg != 0) * (as part of ongoing delta-value sampling) * - on-demand (reg == 0) * (for evaluating a particular entry) * * If a regularly sampled expression (entry->alarm != 0) * is invoked on-demand (reg == 0), then use the most * recent sampled values, rather than retrieving them again. */ if ( !reg && entry->alarm ) return; /* * XXX - may want to implement caching for on-demand evaluation * of non-regularly sampled expressions. */ /* * For a wildcarded expression, expExpressionPrefix is used * to determine which object instances to retrieve. * (For a non-wildcarded expression, we already know * explicitly which object instances will be needed). * * If we walk this object here, then the results can be * used to build the necessary GET requests for each * individual parameter object (within expObject_getData) * * This will probably be simpler (and definitely more efficient) * than walking the object instances separately and merging * merging the results). * * NB: Releasing any old results is handled by expObject_getData. * Assigning to 'entry->pvars' without first releasing the * previous contents does *not* introduce a memory leak. */ if ( entry->expPrefix_len ) { var = (netsnmp_variable_list *) SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); snmp_set_var_objid( var, entry->expPrefix, entry->expPrefix_len); ret = netsnmp_query_walk( var, entry->session ); DEBUGMSGTL(("disman:expr:run", "Walk returned %d\n", ret )); entry->pvars = var; } /* XXX - retrieve sysUpTime.0 value, and check for discontinuity */ /* entry->flags &= ~EXP_FLAG_SYSUT; var = (netsnmp_variable_list *) SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); snmp_set_var_objid( var, sysUT_oid, sysUT_oid_len ); netsnmp_query_get( var, entry->session ); if ( *var->val.integer != entry->sysUpTime ) { entry->flags |= EXP_FLAG_SYSUT; entry->sysUpTime = *var->val.integer; } snmp_free_varbind(var); */ /* * Loop through the list of relevant objects, * and retrieve the corresponding values. */ for ( row = expObject_getFirst( entry->expOwner, entry->expName ); row; row = expObject_getNext( row )) { /* XXX - may need to check whether owner/name still match */ expObject_getData( entry, (struct expObject *)row->data); } }
int decode_vbind (unsigned char *data, unsigned int vb_len) { unsigned char *var_val; oid var_name[MAX_OID_LEN]; /* To test the objid */ size_t name_len = MAX_OID_LEN; /* To test the objid */ int badtype=0; size_t len; struct variable_list *vp; oid objid[MAX_OID_LEN]; char _docsis_snmp_label[50]; /* To hold the 'name' of the type, i.e. Integer etc */ char *enum_string = NULL; static char outbuf[16384]; struct tree *subtree; struct enum_list *enums; memset (outbuf, 0, 16384); vp = (struct variable_list *) malloc (sizeof (struct variable_list)); if (vp == NULL) { fprintf (stderr, "Out of memory\n"); return 0; } memset (vp, 0, sizeof (struct variable_list)); vp->next_variable = NULL; vp->val.string = NULL; vp->name_length = MAX_OID_LEN; vp->name = 0; data = snmp_parse_var_op (data, objid, &vp->name_length, &vp->type, &vp->val_len, &var_val, (size_t *) & vb_len); if (data == NULL) return -1; if (snmp_set_var_objid (vp, objid, vp->name_length)) return -1; len = PACKET_LENGTH; if (netsnmp_ds_get_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_EXTENDED_INDEX)) { netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_EXTENDED_INDEX); } /* Disable extended index format ... makes it harder to parse tokens in lex */ if (!netsnmp_ds_get_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM)) { netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM); } /* Enable printing numeric enums */ if (netsnmp_ds_get_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES)) { netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES); } /* Disable escape quotes in string index output */ netsnmp_ds_set_int (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_SUFFIX); if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_OID_OUTPUT_NUMERIC)) { netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_NUMERIC); } snprint_objid (outbuf, 1023, vp->name, vp->name_length); if (!get_node (outbuf, var_name, &name_len)) { if (!read_objid (outbuf, var_name, &name_len)) { fprintf (stderr, "/* Hmm ... can't find oid %s at line %d ... perhaps the MIBs are not installed ? */\n", outbuf, line); /* temporarily set full output format */ netsnmp_ds_set_int (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_FULL); memset (outbuf, 0, 1024); snprint_objid (outbuf, 1023, vp->name, vp->name_length); /* Go back to suffix-mode for better readability */ netsnmp_ds_set_int (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_SUFFIX); } } printf("%s", outbuf); /* save the subtree - we need it later to show enums */ subtree = get_tree (var_name, name_len, get_tree_head() ); /* This first switch is just for saving the type in the format we actually want to print. */ switch ((short) vp->type) { case ASN_INTEGER: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "Integer"); break; case ASN_COUNTER: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "Counter32"); break; case ASN_GAUGE: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "Gauge32"); break; case ASN_TIMETICKS: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "TimeTicks"); break; case ASN_UINTEGER: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "Unsigned32"); break; #ifdef OPAQUE_SPECIAL_TYPES case ASN_OPAQUE_COUNTER64: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "OpaqueCounter64"); break; case ASN_OPAQUE_U64: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "OpaqueU64"); break; #endif /* OPAQUE_SPECIAL_TYPES */ case ASN_COUNTER64: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "Counter64"); break; #ifdef OPAQUE_SPECIAL_TYPES case ASN_OPAQUE_FLOAT: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "OpaqueFloat"); break; case ASN_OPAQUE_DOUBLE: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "OpaqueDouble"); break; case ASN_OPAQUE_I64: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "OpaqueI64"); break; #endif /* OPAQUE_SPECIAL_TYPES */ case ASN_OCTET_STR: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "String"); break; case ASN_IPADDRESS: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "IPAddress"); break; case ASN_OPAQUE: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "Opaque"); break; case ASN_NSAP: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "NSAP"); break; case ASN_OBJECT_ID: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "ObjectID"); break; case ASN_BIT_STR: memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "BitString"); break; } switch ((short) vp->type) { case ASN_INTEGER: vp->val.integer = (long *) vp->buf; vp->val_len = sizeof (long); asn_parse_int (var_val, &len, &vp->type, (long *) vp->val.integer, sizeof (vp->val.integer)); break; case ASN_COUNTER: case ASN_GAUGE: case ASN_TIMETICKS: case ASN_UINTEGER: vp->val.integer = (long *) vp->buf; vp->val_len = sizeof (u_long); asn_parse_unsigned_int (var_val, &len, &vp->type, (u_long *) vp->val.integer, sizeof (vp->val.integer)); break; #ifdef OPAQUE_SPECIAL_TYPES case ASN_OPAQUE_COUNTER64: case ASN_OPAQUE_U64: #endif /* OPAQUE_SPECIAL_TYPES */ case ASN_COUNTER64: vp->val.counter64 = (struct counter64 *) vp->buf; vp->val_len = sizeof (struct counter64); asn_parse_unsigned_int64 (var_val, &len, &vp->type, (struct counter64 *) vp->val.counter64, sizeof (*vp->val.counter64)); break; #ifdef OPAQUE_SPECIAL_TYPES case ASN_OPAQUE_FLOAT: vp->val.floatVal = (float *) vp->buf; vp->val_len = sizeof (float); asn_parse_float (var_val, &len, &vp->type, vp->val.floatVal, vp->val_len); break; case ASN_OPAQUE_DOUBLE: vp->val.doubleVal = (double *) vp->buf; vp->val_len = sizeof (double); asn_parse_double (var_val, &len, &vp->type, vp->val.doubleVal, vp->val_len); break; case ASN_OPAQUE_I64: vp->val.counter64 = (struct counter64 *) vp->buf; vp->val_len = sizeof (struct counter64); asn_parse_signed_int64 (var_val, &len, &vp->type, (struct counter64 *) vp->val.counter64, sizeof (*vp->val.counter64)); break; #endif /* OPAQUE_SPECIAL_TYPES */ case ASN_OCTET_STR: case ASN_IPADDRESS: case ASN_OPAQUE: case ASN_NSAP: if (vp->val_len < sizeof (vp->buf)) { vp->val.string = (u_char *) vp->buf; } else { vp->val.string = (u_char *) malloc ((unsigned) vp->val_len+1); memset(vp->val.string, 0, vp->val_len+1); } asn_parse_string (var_val, &len, &vp->type, vp->val.string, &vp->val_len); break; case ASN_OBJECT_ID: vp->val_len = MAX_OID_LEN; asn_parse_objid (var_val, &len, &vp->type, objid, &vp->val_len); vp->val_len *= sizeof (oid); vp->val.objid = (oid *) malloc ((unsigned) vp->val_len); memmove (vp->val.objid, objid, vp->val_len); break; case SNMP_NOSUCHOBJECT: case SNMP_NOSUCHINSTANCE: case SNMP_ENDOFMIBVIEW: case ASN_NULL: break; case ASN_BIT_STR: vp->val.bitstring = (u_char *) malloc (vp->val_len); asn_parse_bitstring (var_val, &len, &vp->type, vp->val.bitstring, &vp->val_len); break; default: fprintf(stderr, "Error: bad type returned (%x)\n", vp->type); badtype = 1; break; } if (!netsnmp_ds_get_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID)) { netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID); } if (!netsnmp_ds_get_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS)) { netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS); } if (!netsnmp_ds_get_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT); } if (!strcmp (_docsis_snmp_label, "String")) /* Strings need special treatment - see below */ { netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT); netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES); } switch ((short) vp->type) { case ASN_OCTET_STR: if (str_isprint((char *) vp->val.string, vp->val_len)) { snprintf(outbuf, vp->val_len+5, "\"%s\"", vp->val.string); } else { snprint_hexadecimal (outbuf, 16383, (char *) vp->val.string, vp->val_len); memset (_docsis_snmp_label, 0, 50); sprintf (_docsis_snmp_label, "HexString"); } break; case ASN_BIT_STR: snprint_hexadecimal (outbuf, 1023, (char *) vp->val.bitstring, vp->val_len); break; case ASN_OBJECT_ID: netsnmp_ds_set_int (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_NUMERIC); snprint_value (outbuf, 1023, vp->name, vp->name_length, vp); netsnmp_ds_set_int (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_SUFFIX); break; default: snprint_value (outbuf, 1023, vp->name, vp->name_length, vp); } if ( subtree ) { enums = subtree->enums; for (; enums; enums = enums->next) { if (enums->value == *vp->val.integer) { enum_string = enums->label; break; } } } if (enum_string) printf(" %s %s; /* %s */", _docsis_snmp_label, outbuf, enum_string); else printf(" %s %s;", _docsis_snmp_label, outbuf); snmp_free_var (vp); return badtype; }
void mteTrigger_run( unsigned int reg, void *clientarg) { struct mteTrigger *entry = (struct mteTrigger *)clientarg; netsnmp_variable_list *var, *vtmp; netsnmp_variable_list *vp1, *vp1_prev; netsnmp_variable_list *vp2, *vp2_prev; netsnmp_variable_list *dvar = NULL; netsnmp_variable_list *dv1 = NULL, *dv2 = NULL; netsnmp_variable_list sysUT_var; int cmp = 0, n, n2; long value; const char *reason; if (!entry) { snmp_alarm_unregister( reg ); return; } if (!(entry->flags & MTE_TRIGGER_FLAG_ENABLED ) || !(entry->flags & MTE_TRIGGER_FLAG_ACTIVE ) || !(entry->flags & MTE_TRIGGER_FLAG_VALID )) { return; } { extern netsnmp_agent_session *netsnmp_processing_set; if (netsnmp_processing_set) { /* * netsnmp_handle_request will not be responsive to our efforts to * Retrieve the requested MIB value(s)... * so we will skip it. * https://sourceforge.net/tracker/ * index.php?func=detail&aid=1557406&group_id=12694&atid=112694 */ DEBUGMSGTL(("disman:event:trigger:monitor", "Skipping trigger (%s) while netsnmp_processing_set\n", entry->mteTName)); return; } } /* * Retrieve the requested MIB value(s)... */ DEBUGMSGTL(( "disman:event:trigger:monitor", "Running trigger (%s)\n", entry->mteTName)); var = (netsnmp_variable_list *)SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); if (!var) { _mteTrigger_failure("failed to create mteTrigger query varbind"); return; } snmp_set_var_objid( var, entry->mteTriggerValueID, entry->mteTriggerValueID_len ); if ( entry->flags & MTE_TRIGGER_FLAG_VWILD ) { n = netsnmp_query_walk( var, entry->session ); } else { n = netsnmp_query_get( var, entry->session ); } if ( n != SNMP_ERR_NOERROR ) { DEBUGMSGTL(( "disman:event:trigger:monitor", "Trigger query (%s) failed: %d\n", (( entry->flags & MTE_TRIGGER_FLAG_VWILD ) ? "walk" : "get"), n)); _mteTrigger_failure( "failed to run mteTrigger query" ); snmp_free_varbind(var); return; } /* * ... canonicalise the results (to simplify later comparisons)... */ vp1 = var; vp1_prev = NULL; vp2 = entry->old_results; vp2_prev = NULL; entry->count=0; while (vp1) { /* * Flatten various missing values/exceptions into a single form */ switch (vp1->type) { case SNMP_NOSUCHINSTANCE: case SNMP_NOSUCHOBJECT: case ASN_PRIV_RETRY: /* Internal only ? */ vp1->type = ASN_NULL; } /* * Keep track of how many entries have been retrieved. */ entry->count++; /* * Ensure previous and current result match * (with corresponding entries in both lists) * and set the flags indicating which triggers are armed */ if (vp2) { cmp = snmp_oid_compare(vp1->name, vp1->name_length, vp2->name, vp2->name_length); if ( cmp < 0 ) { /* * If a new value has appeared, insert a matching * dummy entry into the previous result list. * * XXX - check how this is best done. */ vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); if (!vtmp) { _mteTrigger_failure( "failed to create mteTrigger temp varbind"); snmp_free_varbind(var); return; } vtmp->type = ASN_NULL; snmp_set_var_objid( vtmp, vp1->name, vp1->name_length ); vtmp->next_variable = vp2; if (vp2_prev) { vp2_prev->next_variable = vtmp; } else { entry->old_results = vtmp; } vp2_prev = vtmp; vp1->index = MTE_ARMED_ALL; /* XXX - plus a new flag */ vp1_prev = vp1; vp1 = vp1->next_variable; } else if ( cmp == 0 ) { /* * If it's a continuing entry, just copy across the armed flags */ vp1->index = vp2->index; vp1_prev = vp1; vp1 = vp1->next_variable; vp2_prev = vp2; vp2 = vp2->next_variable; } else { /* * If a value has just disappeared, insert a * matching dummy entry into the current result list. * * XXX - check how this is best done. * */ if ( vp2->type != ASN_NULL ) { vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); if (!vtmp) { _mteTrigger_failure( "failed to create mteTrigger temp varbind"); snmp_free_varbind(var); return; } vtmp->type = ASN_NULL; snmp_set_var_objid( vtmp, vp2->name, vp2->name_length ); vtmp->next_variable = vp1; if (vp1_prev) { vp1_prev->next_variable = vtmp; } else { var = vtmp; } vp1_prev = vtmp; vp2_prev = vp2; vp2 = vp2->next_variable; } else { /* * But only if this entry has *just* disappeared. If the * entry from the last run was a dummy too, then remove it. * (leaving vp2_prev unchanged) */ vtmp = vp2; if (vp2_prev) { vp2_prev->next_variable = vp2->next_variable; } else { entry->old_results = vp2->next_variable; } vp2 = vp2->next_variable; vtmp->next_variable = NULL; snmp_free_varbind( vtmp ); } } } else { /* * No more old results to compare. * Either all remaining values have only just been created ... * (and we need to create dummy 'old' entries for them) */ if ( vp2_prev ) { vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); if (!vtmp) { _mteTrigger_failure( "failed to create mteTrigger temp varbind"); snmp_free_varbind(var); return; } vtmp->type = ASN_NULL; snmp_set_var_objid( vtmp, vp1->name, vp1->name_length ); vtmp->next_variable = vp2_prev->next_variable; vp2_prev->next_variable = vtmp; vp2_prev = vtmp; } /* * ... or this is the first run through * (and there were no old results at all) * * In either case, mark the current entry as armed and new. * Note that we no longer need to maintain 'vp1_prev' */ vp1->index = MTE_ARMED_ALL; /* XXX - plus a new flag */ vp1 = vp1->next_variable; } } /* * ... and then work through these result(s), deciding * whether or not to trigger the corresponding event. * * Note that there's no point in evaluating Existence or * Boolean tests if there's no corresponding event. * (Even if the trigger matched, nothing would be done anyway). */ if ((entry->mteTriggerTest & MTE_TRIGGER_EXISTENCE) && (entry->mteTExEvent[0] != '\0' )) { /* * If we don't have a record of previous results, * this must be the first time through, so consider * the mteTriggerExistenceStartup tests. */ if ( !entry->old_results ) { /* * With the 'present(0)' test, the trigger should fire * for each value in the varbind list returned * (whether the monitored value is wildcarded or not). */ if (entry->mteTExTest & entry->mteTExStartup & MTE_EXIST_PRESENT) { for (vp1 = var; vp1; vp1=vp1->next_variable) { DEBUGMSGTL(( "disman:event:trigger:fire", "Firing initial existence test: ")); DEBUGMSGOID(("disman:event:trigger:fire", vp1->name, vp1->name_length)); DEBUGMSG(( "disman:event:trigger:fire", " (present)\n"));; entry->mteTriggerXOwner = entry->mteTExObjOwner; entry->mteTriggerXObjects = entry->mteTExObjects; entry->mteTriggerFired = vp1; n = entry->mteTriggerValueID_len; mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent, entry, vp1->name+n, vp1->name_length-n); } } /* * An initial 'absent(1)' test only makes sense when * monitoring a non-wildcarded OID (how would we know * which rows of the table "ought" to exist, but don't?) */ if (entry->mteTExTest & entry->mteTExStartup & MTE_EXIST_ABSENT) { if (!(entry->flags & MTE_TRIGGER_FLAG_VWILD) && var->type == ASN_NULL ) { DEBUGMSGTL(( "disman:event:trigger:fire", "Firing initial existence test: ")); DEBUGMSGOID(("disman:event:trigger:fire", var->name, var->name_length)); DEBUGMSG(( "disman:event:trigger:fire", " (absent)\n"));; entry->mteTriggerXOwner = entry->mteTExObjOwner; entry->mteTriggerXObjects = entry->mteTExObjects; /* * It's unclear what value the 'mteHotValue' payload * should take when a monitored instance does not * exist on startup. The only sensible option is * to report a NULL value, but this clashes with * the syntax of the mteHotValue MIB object. */ entry->mteTriggerFired = var; n = entry->mteTriggerValueID_len; mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent, entry, var->name+n, var->name_length-n); } } } /* !old_results */ /* * Otherwise, compare the current set of results with * the previous ones, looking for changes. We can * assume that the two lists match (see above). */ else { for (vp1 = var, vp2 = entry->old_results; vp1; vp1=vp1->next_variable, vp2=vp2->next_variable) { /* Use this field to indicate that the trigger should fire */ entry->mteTriggerFired = NULL; reason = NULL; if ((entry->mteTExTest & MTE_EXIST_PRESENT) && (vp1->type != ASN_NULL) && (vp2->type == ASN_NULL)) { /* A new instance has appeared */ entry->mteTriggerFired = vp1; reason = "(present)"; } else if ((entry->mteTExTest & MTE_EXIST_ABSENT) && (vp1->type == ASN_NULL) && (vp2->type != ASN_NULL)) { /* * A previous instance has disappeared. * * It's unclear what value the 'mteHotValue' payload * should take when this happens - the previous * value (vp2), or a NULL value (vp1) ? * NULL makes more sense logically, but clashes * with the syntax of the mteHotValue MIB object. */ entry->mteTriggerFired = vp2; reason = "(absent)"; } else if ((entry->mteTExTest & MTE_EXIST_CHANGED) && ((vp1->val_len != vp2->val_len) || (memcmp( vp1->val.string, vp2->val.string, vp1->val_len) != 0 ))) { /* * This comparison detects changes in *any* type * of value, numeric or string (or even OID). * * Unfortunately, the default 'mteTriggerFired' * notification payload can't report non-numeric * changes properly (see syntax of 'mteHotValue') */ entry->mteTriggerFired = vp1; reason = "(changed)"; } if ( entry->mteTriggerFired ) { /* * One of the above tests has matched, * so fire the trigger. */ DEBUGMSGTL(( "disman:event:trigger:fire", "Firing existence test: ")); DEBUGMSGOID(("disman:event:trigger:fire", vp1->name, vp1->name_length)); DEBUGMSG(( "disman:event:trigger:fire", " %s\n", reason));; entry->mteTriggerXOwner = entry->mteTExObjOwner; entry->mteTriggerXObjects = entry->mteTExObjects; n = entry->mteTriggerValueID_len; mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent, entry, vp1->name+n, vp1->name_length-n); } } } /* !old_results - end of else block */ } /* MTE_TRIGGER_EXISTENCE */ if (( entry->mteTriggerTest & MTE_TRIGGER_BOOLEAN ) || ( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD )) { /* * Although Existence tests can work with any syntax values, * Boolean and Threshold tests are integer-only. Ensure that * the returned value(s) are appropriate. * * Note that we only need to check the first value, since all * instances of a given object should have the same syntax. */ switch (var->type) { case ASN_INTEGER: case ASN_COUNTER: case ASN_GAUGE: case ASN_TIMETICKS: case ASN_UINTEGER: case ASN_COUNTER64: #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES case ASN_OPAQUE_COUNTER64: case ASN_OPAQUE_U64: case ASN_OPAQUE_I64: #endif /* OK */ break; default: /* * Other syntax values can't be used for Boolean/Theshold * tests. Report this as an error, and then rotate the * results ready for the next run, (which will presumably * also detect this as an error once again!) */ DEBUGMSGTL(( "disman:event:trigger:fire", "Returned non-integer result(s): ")); DEBUGMSGOID(("disman:event:trigger:fire", var->name, var->name_length)); DEBUGMSG(( "disman:event:trigger:fire", " (boolean/threshold) %d\n", var->type));; snmp_free_varbind( entry->old_results ); entry->old_results = var; return; } /* * Retrieve the discontinuity markers for delta-valued samples. * (including sysUpTime.0 if not specified explicitly). */ if ( entry->flags & MTE_TRIGGER_FLAG_DELTA ) { /* * We'll need sysUpTime.0 regardless... */ DEBUGMSGTL(("disman:event:delta", "retrieve sysUpTime.0\n")); memset( &sysUT_var, 0, sizeof( netsnmp_variable_list )); snmp_set_var_objid( &sysUT_var, _sysUpTime_instance, _sysUpTime_inst_len ); netsnmp_query_get( &sysUT_var, entry->session ); if (!(entry->flags & MTE_TRIGGER_FLAG_SYSUPT)) { /* * ... but only retrieve the configured discontinuity * marker(s) if they refer to something different. */ DEBUGMSGTL(( "disman:event:delta", "retrieve discontinuity marker(s): ")); DEBUGMSGOID(("disman:event:delta", entry->mteDeltaDiscontID, entry->mteDeltaDiscontID_len )); DEBUGMSG(( "disman:event:delta", " %s\n", (entry->flags & MTE_TRIGGER_FLAG_DWILD ? " (wild)" : ""))); dvar = (netsnmp_variable_list *) SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); if (!dvar) { _mteTrigger_failure( "failed to create mteTrigger delta query varbind"); return; } snmp_set_var_objid( dvar, entry->mteDeltaDiscontID, entry->mteDeltaDiscontID_len ); if ( entry->flags & MTE_TRIGGER_FLAG_DWILD ) { n = netsnmp_query_walk( dvar, entry->session ); } else { n = netsnmp_query_get( dvar, entry->session ); } if ( n != SNMP_ERR_NOERROR ) { _mteTrigger_failure( "failed to run mteTrigger delta query" ); snmp_free_varbind( dvar ); return; } } /* * We can't calculate delta values the first time through, * so there's no point in evaluating the remaining tests. * * Save the results (and discontinuity markers), * ready for the next run. */ if ( !entry->old_results ) { entry->old_results = var; entry->old_deltaDs = dvar; entry->sysUpTime = *sysUT_var.val.integer; return; } /* * If the sysUpTime marker has been reset (or strictly, * has advanced by less than the monitor frequency), * there's no point in trying the remaining tests. */ if (*sysUT_var.val.integer < entry->sysUpTime) { DEBUGMSGTL(( "disman:event:delta", "single discontinuity: (sysUT)\n")); snmp_free_varbind( entry->old_results ); snmp_free_varbind( entry->old_deltaDs ); entry->old_results = var; entry->old_deltaDs = dvar; entry->sysUpTime = *sysUT_var.val.integer; return; } /* * Similarly if a separate (non-wildcarded) discontinuity * marker has changed, then there's no * point in trying to evaluate these tests either. */ if (!(entry->flags & MTE_TRIGGER_FLAG_DWILD) && !(entry->flags & MTE_TRIGGER_FLAG_SYSUPT) && (!entry->old_deltaDs || (entry->old_deltaDs->val.integer != dvar->val.integer))) { DEBUGMSGTL(( "disman:event:delta", "single discontinuity: (")); DEBUGMSGOID(( "disman:event:delta", entry->mteDeltaDiscontID, entry->mteDeltaDiscontID_len)); DEBUGMSG(( "disman:event:delta", ")\n")); snmp_free_varbind( entry->old_results ); snmp_free_varbind( entry->old_deltaDs ); entry->old_results = var; entry->old_deltaDs = dvar; entry->sysUpTime = *sysUT_var.val.integer; return; } /* * Ensure that the list of (wildcarded) discontinuity * markers matches the list of monitored values * (inserting/removing discontinuity varbinds as needed) * * XXX - An alternative approach would be to use the list * of monitored values (instance subidentifiers) to build * the exact list of delta markers to retrieve earlier. */ if (entry->flags & MTE_TRIGGER_FLAG_DWILD) { vp1 = var; vp2 = dvar; vp2_prev = NULL; n = entry->mteTriggerValueID_len; n2 = entry->mteDeltaDiscontID_len; while (vp1) { /* * For each monitored instance, check whether * there's a matching discontinuity entry. */ cmp = snmp_oid_compare(vp1->name+n, vp1->name_length-n, vp2->name+n2, vp2->name_length-n2 ); if ( cmp < 0 ) { /* * If a discontinuity entry is missing, * insert a (dummy) varbind. * The corresponding delta calculation will * fail, but this simplifies the later code. */ vtmp = (netsnmp_variable_list *) SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); if (!vtmp) { _mteTrigger_failure( "failed to create mteTrigger discontinuity varbind"); snmp_free_varbind(dvar); return; } snmp_set_var_objid(vtmp, entry->mteDeltaDiscontID, entry->mteDeltaDiscontID_len); /* XXX - append instance subids */ vtmp->next_variable = vp2; vp2_prev->next_variable = vtmp; vp2_prev = vtmp; vp1 = vp1->next_variable; } else if ( cmp == 0 ) { /* * Matching discontinuity entry - all OK. */ vp2_prev = vp2; vp2 = vp2->next_variable; vp1 = vp1->next_variable; } else { /* * Remove unneeded discontinuity entry */ vtmp = vp2; vp2_prev->next_variable = vp2->next_variable; vp2 = vp2->next_variable; vtmp->next_variable = NULL; snmp_free_varbind( vtmp ); } } /* * XXX - Now need to ensure that the old list of * delta discontinuity markers matches as well. */ } } /* delta samples */ } /* Boolean/Threshold test checks */ /* * Only run the Boolean tests if there's an event to be triggered */ if ((entry->mteTriggerTest & MTE_TRIGGER_BOOLEAN) && (entry->mteTBoolEvent[0] != '\0' )) { if (entry->flags & MTE_TRIGGER_FLAG_DELTA) { vp2 = entry->old_results; if (entry->flags & MTE_TRIGGER_FLAG_DWILD) { dv1 = dvar; dv2 = entry->old_deltaDs; } } for ( vp1 = var; vp1; vp1=vp1->next_variable ) { /* * Determine the value to be monitored... */ if ( !vp1->val.integer ) { /* No value */ if ( vp2 ) vp2 = vp2->next_variable; continue; } if (entry->flags & MTE_TRIGGER_FLAG_DELTA) { if (entry->flags & MTE_TRIGGER_FLAG_DWILD) { /* * We've already checked any non-wildcarded * discontinuity markers (inc. sysUpTime.0). * Validate this particular sample against * the relevant wildcarded marker... */ if ((dv1->type == ASN_NULL) || (dv1->type != dv2->type) || (*dv1->val.integer != *dv2->val.integer)) { /* * Bogus or changed discontinuity marker. * Need to skip this sample. */ DEBUGMSGTL(( "disman:event:delta", "discontinuity occurred: ")); DEBUGMSGOID(("disman:event:delta", vp1->name, vp1->name_length )); DEBUGMSG(( "disman:event:delta", " \n" )); vp2 = vp2->next_variable; continue; } } /* * ... and check there is a previous sample to calculate * the delta value against (regardless of whether the * discontinuity marker was wildcarded or not). */ if (vp2->type == ASN_NULL) { DEBUGMSGTL(( "disman:event:delta", "missing sample: ")); DEBUGMSGOID(("disman:event:delta", vp1->name, vp1->name_length )); DEBUGMSG(( "disman:event:delta", " \n" )); vp2 = vp2->next_variable; continue; } value = (*vp1->val.integer - *vp2->val.integer); DEBUGMSGTL(( "disman:event:delta", "delta sample: ")); DEBUGMSGOID(("disman:event:delta", vp1->name, vp1->name_length )); DEBUGMSG(( "disman:event:delta", " (%ld - %ld) = %ld\n", *vp1->val.integer, *vp2->val.integer, value)); vp2 = vp2->next_variable; } else { value = *vp1->val.integer; } /* * ... evaluate the comparison ... */ switch (entry->mteTBoolComparison) { case MTE_BOOL_UNEQUAL: cmp = ( value != entry->mteTBoolValue ); break; case MTE_BOOL_EQUAL: cmp = ( value == entry->mteTBoolValue ); break; case MTE_BOOL_LESS: cmp = ( value < entry->mteTBoolValue ); break; case MTE_BOOL_LESSEQUAL: cmp = ( value <= entry->mteTBoolValue ); break; case MTE_BOOL_GREATER: cmp = ( value > entry->mteTBoolValue ); break; case MTE_BOOL_GREATEREQUAL: cmp = ( value >= entry->mteTBoolValue ); break; } DEBUGMSGTL(( "disman:event:delta", "Bool comparison: (%ld %s %ld) %d\n", value, _ops[entry->mteTBoolComparison], entry->mteTBoolValue, cmp)); /* * ... and decide whether to trigger the event. * (using the 'index' field of the varbind structure * to remember whether the trigger has already fired) */ if ( cmp ) { if (vp1->index & MTE_ARMED_BOOLEAN ) { vp1->index &= ~MTE_ARMED_BOOLEAN; /* * NB: Clear the trigger armed flag even if the * (starting) event dosn't actually fire. * Otherwise initially true (but suppressed) * triggers will fire on the *second* probe. */ if ( entry->old_results || (entry->flags & MTE_TRIGGER_FLAG_BSTART)) { DEBUGMSGTL(( "disman:event:trigger:fire", "Firing boolean test: ")); DEBUGMSGOID(("disman:event:trigger:fire", vp1->name, vp1->name_length)); DEBUGMSG(( "disman:event:trigger:fire", "%s\n", (entry->old_results ? "" : " (startup)"))); entry->mteTriggerXOwner = entry->mteTBoolObjOwner; entry->mteTriggerXObjects = entry->mteTBoolObjects; /* * XXX - when firing a delta-based trigger, should * 'mteHotValue' report the actual value sampled * (as here), or the delta that triggered the event ? */ entry->mteTriggerFired = vp1; n = entry->mteTriggerValueID_len; mteEvent_fire(entry->mteTBoolEvOwner, entry->mteTBoolEvent, entry, vp1->name+n, vp1->name_length-n); } } } else { vp1->index |= MTE_ARMED_BOOLEAN; } } } /* * Only run the basic threshold tests if there's an event to * be triggered. (Either rising or falling will do) */ if (( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD ) && ((entry->mteTThRiseEvent[0] != '\0' ) || (entry->mteTThFallEvent[0] != '\0' ))) { /* * The same delta-sample validation from Boolean * tests also applies here too. */ if (entry->flags & MTE_TRIGGER_FLAG_DELTA) { vp2 = entry->old_results; if (entry->flags & MTE_TRIGGER_FLAG_DWILD) { dv1 = dvar; dv2 = entry->old_deltaDs; } } for ( vp1 = var; vp1; vp1=vp1->next_variable ) { /* * Determine the value to be monitored... */ if ( !vp1->val.integer ) { /* No value */ if ( vp2 ) vp2 = vp2->next_variable; continue; } if (entry->flags & MTE_TRIGGER_FLAG_DELTA) { if (entry->flags & MTE_TRIGGER_FLAG_DWILD) { /* * We've already checked any non-wildcarded * discontinuity markers (inc. sysUpTime.0). * Validate this particular sample against * the relevant wildcarded marker... */ if ((dv1->type == ASN_NULL) || (dv1->type != dv2->type) || (*dv1->val.integer != *dv2->val.integer)) { /* * Bogus or changed discontinuity marker. * Need to skip this sample. */ vp2 = vp2->next_variable; continue; } } /* * ... and check there is a previous sample to calculate * the delta value against (regardless of whether the * discontinuity marker was wildcarded or not). */ if (vp2->type == ASN_NULL) { vp2 = vp2->next_variable; continue; } value = (*vp1->val.integer - *vp2->val.integer); vp2 = vp2->next_variable; } else { value = *vp1->val.integer; } /* * ... evaluate the single-value comparisons, * and decide whether to trigger the event. */ cmp = vp1->index; /* working copy of 'armed' flags */ if ( value >= entry->mteTThRiseValue ) { if (cmp & MTE_ARMED_TH_RISE ) { cmp &= ~MTE_ARMED_TH_RISE; cmp |= MTE_ARMED_TH_FALL; /* * NB: Clear the trigger armed flag even if the * (starting) event dosn't actually fire. * Otherwise initially true (but suppressed) * triggers will fire on the *second* probe. * Similarly for falling thresholds (see below). */ if ( entry->old_results || (entry->mteTThStartup & MTE_THRESH_START_RISE)) { DEBUGMSGTL(( "disman:event:trigger:fire", "Firing rising threshold test: ")); DEBUGMSGOID(("disman:event:trigger:fire", vp1->name, vp1->name_length)); DEBUGMSG(( "disman:event:trigger:fire", "%s\n", (entry->old_results ? "" : " (startup)"))); /* * If no riseEvent is configured, we need still to * set the armed flags appropriately, but there's * no point in trying to fire the (missing) event. */ if (entry->mteTThRiseEvent[0] != '\0' ) { entry->mteTriggerXOwner = entry->mteTThObjOwner; entry->mteTriggerXObjects = entry->mteTThObjects; entry->mteTriggerFired = vp1; n = entry->mteTriggerValueID_len; mteEvent_fire(entry->mteTThRiseOwner, entry->mteTThRiseEvent, entry, vp1->name+n, vp1->name_length-n); } } } } if ( value <= entry->mteTThFallValue ) { if (cmp & MTE_ARMED_TH_FALL ) { cmp &= ~MTE_ARMED_TH_FALL; cmp |= MTE_ARMED_TH_RISE; /* Clear the trigger armed flag (see above) */ if ( entry->old_results || (entry->mteTThStartup & MTE_THRESH_START_FALL)) { DEBUGMSGTL(( "disman:event:trigger:fire", "Firing falling threshold test: ")); DEBUGMSGOID(("disman:event:trigger:fire", vp1->name, vp1->name_length)); DEBUGMSG(( "disman:event:trigger:fire", "%s\n", (entry->old_results ? "" : " (startup)"))); /* * Similarly, if no fallEvent is configured, * there's no point in trying to fire it either. */ if (entry->mteTThRiseEvent[0] != '\0' ) { entry->mteTriggerXOwner = entry->mteTThObjOwner; entry->mteTriggerXObjects = entry->mteTThObjects; entry->mteTriggerFired = vp1; n = entry->mteTriggerValueID_len; mteEvent_fire(entry->mteTThFallOwner, entry->mteTThFallEvent, entry, vp1->name+n, vp1->name_length-n); } } } } vp1->index = cmp; } } /* * The same processing also works for delta-threshold tests (if configured) */ if (( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD ) && ((entry->mteTThDRiseEvent[0] != '\0' ) || (entry->mteTThDFallEvent[0] != '\0' ))) { /* * Delta-threshold tests can only be used with * absolute valued samples. */ vp2 = entry->old_results; if (entry->flags & MTE_TRIGGER_FLAG_DELTA) { DEBUGMSGTL(( "disman:event:trigger", "Delta-threshold on delta-sample\n")); } else if ( vp2 != NULL ) { for ( vp1 = var; vp1; vp1=vp1->next_variable ) { /* * Determine the value to be monitored... * (similar to previous delta-sample processing, * but without the discontinuity marker checks) */ if (!vp2) { break; /* Run out of 'old' values */ } if (( !vp1->val.integer ) || (vp2->type == ASN_NULL)) { vp2 = vp2->next_variable; continue; } value = (*vp1->val.integer - *vp2->val.integer); vp2 = vp2->next_variable; /* * ... evaluate the single-value comparisons, * and decide whether to trigger the event. */ cmp = vp1->index; /* working copy of 'armed' flags */ if ( value >= entry->mteTThDRiseValue ) { if (vp1->index & MTE_ARMED_TH_DRISE ) { DEBUGMSGTL(( "disman:event:trigger:fire", "Firing rising delta threshold test: ")); DEBUGMSGOID(("disman:event:trigger:fire", vp1->name, vp1->name_length)); DEBUGMSG(( "disman:event:trigger:fire", "\n")); cmp &= ~MTE_ARMED_TH_DRISE; cmp |= MTE_ARMED_TH_DFALL; /* * If no riseEvent is configured, we need still to * set the armed flags appropriately, but there's * no point in trying to fire the (missing) event. */ if (entry->mteTThDRiseEvent[0] != '\0' ) { entry->mteTriggerXOwner = entry->mteTThObjOwner; entry->mteTriggerXObjects = entry->mteTThObjects; entry->mteTriggerFired = vp1; n = entry->mteTriggerValueID_len; mteEvent_fire(entry->mteTThDRiseOwner, entry->mteTThDRiseEvent, entry, vp1->name+n, vp1->name_length-n); } } } if ( value <= entry->mteTThDFallValue ) { if (vp1->index & MTE_ARMED_TH_DFALL ) { DEBUGMSGTL(( "disman:event:trigger:fire", "Firing falling delta threshold test: ")); DEBUGMSGOID(("disman:event:trigger:fire", vp1->name, vp1->name_length)); DEBUGMSG(( "disman:event:trigger:fire", "\n")); cmp &= ~MTE_ARMED_TH_DFALL; cmp |= MTE_ARMED_TH_DRISE; /* * Similarly, if no fallEvent is configured, * there's no point in trying to fire it either. */ if (entry->mteTThDRiseEvent[0] != '\0' ) { entry->mteTriggerXOwner = entry->mteTThObjOwner; entry->mteTriggerXObjects = entry->mteTThObjects; entry->mteTriggerFired = vp1; n = entry->mteTriggerValueID_len; mteEvent_fire(entry->mteTThDFallOwner, entry->mteTThDFallEvent, entry, vp1->name+n, vp1->name_length-n); } } } vp1->index = cmp; } } } /* * Finally, rotate the results - ready for the next run. */ snmp_free_varbind( entry->old_results ); entry->old_results = var; if ( entry->flags & MTE_TRIGGER_FLAG_DELTA ) { snmp_free_varbind( entry->old_deltaDs ); entry->old_deltaDs = dvar; entry->sysUpTime = *sysUT_var.val.integer; } }
int proxy_got_response(int operation, netsnmp_session * sess, int reqid, netsnmp_pdu *pdu, void *cb_data) { netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) cb_data; netsnmp_request_info *requests, *request = NULL; netsnmp_variable_list *vars, *var = NULL; struct simple_proxy *sp; oid myname[MAX_OID_LEN]; size_t myname_len = MAX_OID_LEN; cache = netsnmp_handler_check_cache(cache); if (!cache) { DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n")); return SNMP_ERR_NOERROR; } requests = cache->requests; sp = (struct simple_proxy *) cache->localinfo; if (!sp) { DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n")); return SNMP_ERR_NOERROR; } switch (operation) { case NETSNMP_CALLBACK_OP_TIMED_OUT: /* * WWWXXX: don't leave requests delayed if operation is * something like TIMEOUT */ DEBUGMSGTL(("proxy", "got timed out... requests = %08p\n", requests)); netsnmp_handler_mark_requests_as_delegated(requests, REQUEST_IS_NOT_DELEGATED); if(cache->reqinfo->mode != MODE_GETNEXT) { DEBUGMSGTL(("proxy", " ignoring timeout\n")); netsnmp_set_request_error(cache->reqinfo, requests, /* XXXWWW: should be index = 0 */ SNMP_ERR_GENERR); } netsnmp_free_delegated_cache(cache); return 0; case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE: vars = pdu->variables; if (pdu->errstat != SNMP_ERR_NOERROR) { /* * If we receive an error from the proxy agent, pass it on up. * The higher-level processing seems to Do The Right Thing. * * 2005/06 rks: actually, it doesn't do the right thing for * a get-next request that returns NOSUCHNAME. If we do nothing, * it passes that error back to the comman initiator. What it should * do is ignore the error and move on to the next tree. To * accomplish that, all we need to do is clear the delegated flag. * Not sure if any other error codes need the same treatment. Left * as an exercise to the reader... */ DEBUGMSGTL(("proxy", "got error response (%d)\n", pdu->errstat)); if((cache->reqinfo->mode == MODE_GETNEXT) && (SNMP_ERR_NOSUCHNAME == pdu->errstat)) { DEBUGMSGTL(("proxy", " ignoring error response\n")); netsnmp_handler_mark_requests_as_delegated(requests, REQUEST_IS_NOT_DELEGATED); } else netsnmp_set_request_error(cache->reqinfo, requests, pdu->errstat); /* * update the original request varbinds with the results */ } else for (var = vars, request = requests; request && var; request = request->next, var = var->next_variable) { /* * XXX - should this be done here? * Or wait until we know it's OK? */ snmp_set_var_typed_value(request->requestvb, var->type, var->val.string, var->val_len); DEBUGMSGTL(("proxy", "got response... ")); DEBUGMSGOID(("proxy", var->name, var->name_length)); DEBUGMSG(("proxy", "\n")); request->delegated = 0; /* * Check the response oid is legitimate, * and discard the value if not. * * XXX - what's the difference between these cases? */ if (sp->base_len && (var->name_length < sp->base_len || snmp_oid_compare(var->name, sp->base_len, sp->base, sp->base_len) != 0)) { DEBUGMSGTL(( "proxy", "out of registered range... ")); DEBUGMSGOID(("proxy", var->name, sp->base_len)); DEBUGMSG(( "proxy", " (%d) != ", sp->base_len)); DEBUGMSGOID(("proxy", sp->base, sp->base_len)); DEBUGMSG(( "proxy", "\n")); snmp_set_var_typed_value(request->requestvb, ASN_NULL, NULL, 0); continue; } else if (!sp->base_len && (var->name_length < sp->name_len || snmp_oid_compare(var->name, sp->name_len, sp->name, sp->name_len) != 0)) { DEBUGMSGTL(( "proxy", "out of registered base range... ")); DEBUGMSGOID(("proxy", var->name, sp->name_len)); DEBUGMSG(( "proxy", " (%d) != ", sp->name_len)); DEBUGMSGOID(("proxy", sp->name, sp->name_len)); DEBUGMSG(( "proxy", "\n")); snmp_set_var_typed_value(request->requestvb, ASN_NULL, NULL, 0); continue; } else { /* * If the returned OID is legitimate, then update * the original request varbind accordingly. */ if (sp->base_len) { /* * XXX: oid size maxed? */ memcpy(myname, sp->name, sizeof(oid) * sp->name_len); myname_len = sp->name_len + var->name_length - sp->base_len; if (myname_len > MAX_OID_LEN) { snmp_log(LOG_WARNING, "proxy OID return length too long.\n"); netsnmp_set_request_error(cache->reqinfo, requests, SNMP_ERR_GENERR); if (pdu) snmp_free_pdu(pdu); netsnmp_free_delegated_cache(cache); return 1; } if (var->name_length > sp->base_len) memcpy(&myname[sp->name_len], &var->name[sp->base_len], sizeof(oid) * (var->name_length - sp->base_len)); snmp_set_var_objid(request->requestvb, myname, myname_len); } else { snmp_set_var_objid(request->requestvb, var->name, var->name_length); } } } if (request || var) { /* * ack, this is bad. The # of varbinds don't match and * there is no way to fix the problem */ if (pdu) snmp_free_pdu(pdu); snmp_log(LOG_ERR, "response to proxy request illegal. We're screwed.\n"); netsnmp_set_request_error(cache->reqinfo, requests, SNMP_ERR_GENERR); } /* fix bulk_to_next operations */ if (cache->reqinfo->mode == MODE_GETBULK) netsnmp_bulk_to_next_fix_requests(requests); /* * free the response */ if (pdu && 0) snmp_free_pdu(pdu); break; default: DEBUGMSGTL(("proxy", "no response received: op = %d\n", operation)); break; } netsnmp_free_delegated_cache(cache); return 1; }
/* * Handle the response from an AgentX subagent, * merging the answers back into the original query */ int agentx_got_response(int operation, netsnmp_session * session, int reqid, netsnmp_pdu *pdu, void *magic) { netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) magic; int i, ret; netsnmp_request_info *requests, *request; netsnmp_variable_list *var; netsnmp_session *ax_session; cache = netsnmp_handler_check_cache(cache); if (!cache) { DEBUGMSGTL(("agentx/master", "response too late on session %8p\n", session)); return 0; } requests = cache->requests; switch (operation) { case NETSNMP_CALLBACK_OP_TIMED_OUT:{ void *s = snmp_sess_pointer(session); DEBUGMSGTL(("agentx/master", "timeout on session %8p\n", session)); netsnmp_handler_mark_requests_as_delegated(requests, REQUEST_IS_NOT_DELEGATED); netsnmp_set_request_error(cache->reqinfo, requests, /* XXXWWW: should be index=0 */ SNMP_ERR_GENERR); /* * This is a bit sledgehammer because the other sessions on this * transport may be okay (e.g. some thread in the subagent has * wedged, but the others are alright). OTOH the overwhelming * probability is that the whole agent has died somehow. */ if (s != NULL) { netsnmp_transport *t = snmp_sess_transport(s); close_agentx_session(session, -1); if (t != NULL) { DEBUGMSGTL(("agentx/master", "close transport\n")); t->f_close(t); } else { DEBUGMSGTL(("agentx/master", "NULL transport??\n")); } } else { DEBUGMSGTL(("agentx/master", "NULL sess_pointer??\n")); } ax_session = (netsnmp_session *) cache->localinfo; netsnmp_free_agent_snmp_session_by_session(ax_session, NULL); netsnmp_free_delegated_cache(cache); return 0; } case NETSNMP_CALLBACK_OP_DISCONNECT: case NETSNMP_CALLBACK_OP_SEND_FAILED: if (operation == NETSNMP_CALLBACK_OP_DISCONNECT) { DEBUGMSGTL(("agentx/master", "disconnect on session %8p\n", session)); } else { DEBUGMSGTL(("agentx/master", "send failed on session %8p\n", session)); } close_agentx_session(session, -1); netsnmp_handler_mark_requests_as_delegated(requests, REQUEST_IS_NOT_DELEGATED); netsnmp_set_request_error(cache->reqinfo, requests, /* XXXWWW: should be index=0 */ SNMP_ERR_GENERR); netsnmp_free_delegated_cache(cache); return 0; case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE: /* * This session is alive */ CLEAR_SNMP_STRIKE_FLAGS(session->flags); break; default: snmp_log(LOG_ERR, "Unknown operation %d in agentx_got_response\n", operation); netsnmp_free_delegated_cache(cache); return 0; } DEBUGMSGTL(("agentx/master", "got response errstat=%ld, (req=0x%x,trans=" "0x%x,sess=0x%x)\n", pdu->errstat, (unsigned)pdu->reqid, (unsigned)pdu->transid, (unsigned)pdu->sessid)); if (pdu->errstat != AGENTX_ERR_NOERROR) { /* [RFC 2471 - 7.2.5.2.] * * 1) For any received AgentX response PDU, if res.error is * not `noError', the SNMP response PDU's error code is * set to this value. If res.error contains an AgentX * specific value (e.g. `parseError'), the SNMP response * PDU's error code is set to a value of genErr instead. * Also, the SNMP response PDU's error index is set to * the index of the variable binding corresponding to the * failed VarBind in the subagent's AgentX response PDU. * * All other AgentX response PDUs received due to * processing this SNMP request are ignored. Processing * is complete; the SNMP Response PDU is ready to be sent * (see section 7.2.6, "Sending the SNMP Response-PDU"). */ int err; DEBUGMSGTL(("agentx/master", "agentx_got_response() error branch\n")); switch (pdu->errstat) { case AGENTX_ERR_PARSE_FAILED: case AGENTX_ERR_REQUEST_DENIED: case AGENTX_ERR_PROCESSING_ERROR: err = SNMP_ERR_GENERR; break; default: err = pdu->errstat; } ret = 0; for (request = requests, i = 1; request; request = request->next, i++) { if (i == pdu->errindex) { /* * Mark this varbind as the one generating the error. * Note that the AgentX errindex may not match the * position in the original SNMP PDU (request->index) */ netsnmp_set_request_error(cache->reqinfo, request, err); ret = 1; } request->delegated = REQUEST_IS_NOT_DELEGATED; } if (!ret) { /* * ack, unknown, mark the first one */ netsnmp_set_request_error(cache->reqinfo, requests, SNMP_ERR_GENERR); } netsnmp_free_delegated_cache(cache); DEBUGMSGTL(("agentx/master", "end error branch\n")); return 1; } else if (cache->reqinfo->mode == MODE_GET || cache->reqinfo->mode == MODE_GETNEXT || cache->reqinfo->mode == MODE_GETBULK) { /* * Replace varbinds for data request types, but not SETs. */ DEBUGMSGTL(("agentx/master", "agentx_got_response() beginning...\n")); for (var = pdu->variables, request = requests; request && var; request = request->next, var = var->next_variable) { /* * Otherwise, process successful requests */ DEBUGMSGTL(("agentx/master", " handle_agentx_response: processing: ")); DEBUGMSGOID(("agentx/master", var->name, var->name_length)); DEBUGMSG(("agentx/master", "\n")); if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE)) { DEBUGMSGTL(("snmp_agent", " >> ")); DEBUGMSGVAR(("snmp_agent", var)); DEBUGMSG(("snmp_agent", "\n")); } /* * update the oid in the original request */ if (var->type != SNMP_ENDOFMIBVIEW) { snmp_set_var_typed_value(request->requestvb, var->type, var->val.string, var->val_len); snmp_set_var_objid(request->requestvb, var->name, var->name_length); } request->delegated = REQUEST_IS_NOT_DELEGATED; } if (request || var) { /* * ack, this is bad. The # of varbinds don't match and * there is no way to fix the problem */ snmp_log(LOG_ERR, "response to agentx request illegal. bailing out.\n"); netsnmp_set_request_error(cache->reqinfo, requests, SNMP_ERR_GENERR); } if (cache->reqinfo->mode == MODE_GETBULK) netsnmp_bulk_to_next_fix_requests(requests); } else { /* * mark set requests as handled */ for (request = requests; request; request = request->next) { request->delegated = REQUEST_IS_NOT_DELEGATED; } } DEBUGMSGTL(("agentx/master", "handle_agentx_response() finishing...\n")); netsnmp_free_delegated_cache(cache); return 1; }