/* * DisMan Expression MIB: * Implementation of the expValueTable MIB interface * See 'expValue.c' for active evaluation of expressions. * * (Based roughly on mib2c.raw-table.conf output) */ #include #include #include #include "expValue.h" #include "expValueTable.h" /** Initializes the expValueTable module */ void init_expValueTable(void) { static oid expValueTable_oid[] = { 1, 3, 6, 1, 2, 1, 90, 1, 3, 1 }; size_t expValueTable_oid_len = OID_LENGTH(expValueTable_oid); netsnmp_handler_registration *reg; netsnmp_table_registration_info *table_info; reg = netsnmp_create_handler_registration("expValueTable", expValueTable_handler, expValueTable_oid, expValueTable_oid_len, HANDLER_CAN_RONLY); table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); netsnmp_table_helper_add_indexes(table_info, ASN_OCTET_STR, /* expExpressionOwner */ ASN_OCTET_STR, /* expExpressionName */ /* expValueInstance */ ASN_PRIV_IMPLIED_OBJECT_ID, 0); table_info->min_column = COLUMN_EXPVALUECOUNTER32VAL; table_info->max_column = COLUMN_EXPVALUECOUNTER64VAL; netsnmp_register_table(reg, table_info); DEBUGMSGTL(("disman:expr:init", "Expression Value Table\n")); } netsnmp_variable_list * expValueTable_getEntry(netsnmp_variable_list * indexes, int mode, unsigned int colnum) { struct expExpression *exp; netsnmp_variable_list *res, *vp, *vp2; oid nullInstance[] = {0, 0, 0}; int plen; size_t len; unsigned int type = colnum-1; /* column object subIDs and type enumerations are off by one. */ if (!indexes || !indexes->next_variable || !indexes->next_variable->next_variable ) { /* XXX - Shouldn't happen! */ return NULL; } DEBUGMSGTL(( "disman:expr:val", "get (%d) entry (%s, %s, ", mode, indexes->val.string, indexes->next_variable->val.string)); DEBUGMSGOID(("disman:expr:val", indexes->next_variable->next_variable->val.objid, indexes->next_variable->next_variable->val_len/sizeof(oid))); DEBUGMSG(( "disman:expr:val", ")\n")); /* * Locate the expression that we've been asked to evaluate */ if (!indexes->val_len || !indexes->next_variable->val_len ) { /* * Incomplete expression specification */ if (mode == MODE_GETNEXT || mode == MODE_GETBULK) { exp = expExpression_getFirstEntry(); DEBUGMSGTL(( "disman:expr:val", "first entry (%p)\n", exp )); } else { DEBUGMSGTL(( "disman:expr:val", "incomplete request\n" )); return NULL; /* No match */ } } else { exp = expExpression_getEntry( (char*)indexes->val.string, (char*)indexes->next_variable->val.string); DEBUGMSGTL(( "disman:expr:val", "using entry (%p)\n", exp )); } /* * We know what type of value was requested, * so ignore any non-matching expressions. */ while (exp && exp->expValueType != type) { if (mode != MODE_GETNEXT && mode != MODE_GETBULK) { DEBUGMSGTL(( "disman:expr:val", "wrong type (%d != %ld)\n", type, (exp ? exp->expValueType : 0 ))); return NULL; /* Wrong type */ } NEXT_EXP: exp = expExpression_getNextEntry( exp->expOwner, exp->expName ); DEBUGMSGTL(( "disman:expr:val", "using next entry (%p)\n", exp )); } if (!exp) { DEBUGMSGTL(( "disman:expr:val", "no more entries\n")); return NULL; /* No match (of the required type) */ } /* * Now consider which instance of the chosen expression is needed */ vp = indexes->next_variable->next_variable; if ( mode == MODE_GET ) { /* * For a GET request, check that the specified value instance * is valid, and evaluate the expression using this. */ if ( !vp || !vp->val_len ) { DEBUGMSGTL(( "disman:expr:val", "no instance index\n")); return NULL; /* No instance provided */ } if ( vp->val.objid[0] != 0 ) { DEBUGMSGTL(( "disman:expr:val", "non-zero instance (%" NETSNMP_PRIo "d)\n", vp->val.objid[0])); return NULL; /* Invalid instance */ } if (exp->expPrefix_len == 0 ) { /* * The only valid instance for a non-wildcarded * expression is .0.0.0 */ if ( vp->val_len != 3*sizeof(oid) || vp->val.objid[1] != 0 || vp->val.objid[2] != 0 ) { DEBUGMSGTL(( "disman:expr:val", "invalid scalar instance\n")); return NULL; } res = expValue_evaluateExpression( exp, NULL, 0 ); DEBUGMSGTL(( "disman:expr:val", "scalar get returned (%p)\n", res)); } else { /* * Otherwise, skip the leading '.0' and use * the remaining instance subidentifiers. */ res = expValue_evaluateExpression( exp, vp->val.objid+1, vp->val_len/sizeof(oid)-1); DEBUGMSGTL(( "disman:expr:val", "w/card get returned (%p)\n", res)); } } else { /* * For a GETNEXT request, identify the appropriate next * value instance, and evaluate the expression using * that, updating the index list appropriately. */ if ( vp->val_len > 0 && vp->val.objid[0] != 0 ) { DEBUGMSGTL(( "disman:expr:val", "non-zero next instance (%" NETSNMP_PRIo "d)\n", vp->val.objid[0])); return NULL; /* All valid instances start with .0 */ } plen = exp->expPrefix_len; if (plen == 0 ) { /* * The only valid instances for GETNEXT on a * non-wildcarded expression are .0 and .0.0 * Anything else is too late. */ if ((vp->val_len > 2*sizeof(oid)) || (vp->val_len == 2*sizeof(oid) && vp->val.objid[1] != 0)) { DEBUGMSGTL(( "disman:expr:val", "invalid scalar next instance\n")); return NULL; /* Invalid instance */ } /* * Make sure the index varbind list refers to the * (only) valid instance of this expression, * and evaluate it. */ snmp_set_var_typed_value( indexes, ASN_OCTET_STR, (u_char*)exp->expOwner, strlen(exp->expOwner)); snmp_set_var_typed_value( indexes->next_variable, ASN_OCTET_STR, (u_char*)exp->expName, strlen(exp->expName)); snmp_set_var_typed_value( vp, ASN_PRIV_IMPLIED_OBJECT_ID, (u_char*)nullInstance, 3*sizeof(oid)); res = expValue_evaluateExpression( exp, NULL, 0 ); DEBUGMSGTL(( "disman:expr:val", "scalar next returned (%p)\n", res)); } else { /* * Now comes the interesting case - finding the * appropriate instance of a wildcarded expression. */ if ( vp->val_len == 0 ) { if ( !exp->pvars ) { DEBUGMSGTL(( "disman:expr:val", "no instances\n")); goto NEXT_EXP; } DEBUGMSGTL(( "disman:expr:val", "using first instance\n")); vp2 = exp->pvars; } else { /* * Search the list of instances for the (first) greater one * XXX - This comparison relies on the OID of the prefix * object being the same length as the wildcarded * parameter objects. It ain't necessarily so. */ for ( vp2 = exp->pvars; vp2; vp2 = vp2->next_variable ) { if ( snmp_oid_compare( vp2->name + plen, vp2->name_length - plen, vp->name, vp->name_length) < 0 ) { DEBUGMSGTL(( "disman:expr:val", "next instance ")); DEBUGMSGOID(("disman:expr:val", vp2->name, vp2->name_length )); DEBUGMSG(( "disman:expr:val", "\n")); break; } } if (!vp2) { DEBUGMSGTL(( "disman:expr:val", "no next instance\n")); goto NEXT_EXP; } } snmp_set_var_typed_value( indexes, ASN_OCTET_STR, (u_char*)exp->expOwner, strlen(exp->expOwner)); snmp_set_var_typed_value( indexes->next_variable, ASN_OCTET_STR, (u_char*)exp->expName, strlen(exp->expName)); if (vp2) { len = vp2->name_length - exp->expPrefix_len; snmp_set_var_typed_value( vp, ASN_PRIV_IMPLIED_OBJECT_ID, (u_char*)(vp2->name+exp->expPrefix_len), len); } else { len = 1; } res = expValue_evaluateExpression( exp, vp->val.objid+1, len-1); DEBUGMSGTL(( "disman:expr:val", "w/card next returned (%p)\n", res)); } } return res; } /** handles requests for the expValueTable table */ int expValueTable_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_request_info *request; netsnmp_table_request_info *tinfo; netsnmp_variable_list *value; oid expValueOID[] = { 1, 3, 6, 1, 2, 1, 90, 1, 3, 1, 1, 99 }; size_t expValueOID_len = OID_LENGTH(expValueOID); oid name_buf[ MAX_OID_LEN ]; size_t name_buf_len = MAX_OID_LEN; DEBUGMSGTL(("disman:expr:mib", "Expression Value Table handler (%d)\n", reqinfo->mode)); switch (reqinfo->mode) { case MODE_GET: case MODE_GETNEXT: for (request = requests; request; request = request->next) { tinfo = netsnmp_extract_table_info(request); value = expValueTable_getEntry(tinfo->indexes, reqinfo->mode, tinfo->colnum); if (!value || !value->val.integer) { netsnmp_set_request_error(reqinfo, request, (reqinfo->mode == MODE_GET) ? SNMP_NOSUCHINSTANCE : SNMP_ENDOFMIBVIEW); continue; } if ( reqinfo->mode == MODE_GETNEXT ) { /* * Need to update the request varbind OID * to match the instance just evaluated. * (XXX - Is this the appropriate mechanism?) */ build_oid_noalloc( name_buf, MAX_OID_LEN, &name_buf_len, expValueOID, expValueOID_len, tinfo->indexes ); name_buf[ expValueOID_len -1 ] = tinfo->colnum; snmp_set_var_objid(request->requestvb, name_buf, name_buf_len); } switch (tinfo->colnum) { case COLUMN_EXPVALUECOUNTER32VAL: snmp_set_var_typed_integer(request->requestvb, ASN_COUNTER, *value->val.integer); break; case COLUMN_EXPVALUEUNSIGNED32VAL: snmp_set_var_typed_integer(request->requestvb, ASN_UNSIGNED, *value->val.integer); break; case COLUMN_EXPVALUETIMETICKSVAL: snmp_set_var_typed_integer(request->requestvb, ASN_TIMETICKS, *value->val.integer); break; case COLUMN_EXPVALUEINTEGER32VAL: snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, *value->val.integer); break; case COLUMN_EXPVALUEIPADDRESSVAL: snmp_set_var_typed_integer(request->requestvb, ASN_IPADDRESS, *value->val.integer); break; case COLUMN_EXPVALUEOCTETSTRINGVAL: snmp_set_var_typed_value( request->requestvb, ASN_OCTET_STR, value->val.string, value->val_len); break; case COLUMN_EXPVALUEOIDVAL: snmp_set_var_typed_value( request->requestvb, ASN_OBJECT_ID, (u_char *)value->val.objid, value->val_len); break; case COLUMN_EXPVALUECOUNTER64VAL: snmp_set_var_typed_value( request->requestvb, ASN_COUNTER64, (u_char *)value->val.counter64, value->val_len); break; } /* remember to free the variable list, or we will leak here.. */ snmp_free_varbind(value); } break; } DEBUGMSGTL(("disman:expr:mib", "Expression Value handler - done \n")); return SNMP_ERR_NOERROR; }