/* -*- C -*- */ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include #include #include #include #ifndef sv_undef #define sv_undef PL_sv_undef #endif typedef struct handler_cb_data_s { SV *perl_cb; } handler_cb_data; typedef struct netsnmp_oid_s { unsigned int *name; unsigned int len; unsigned int namebuf[ MAX_OID_LEN ]; } netsnmp_oid; static int have_done_agent = 0; static int have_done_lib = 0; static int not_here(char *s) { croak("%s not implemented on this architecture", s); return -1; } static double constant_MODE_G(char *name, int len, int arg) { if (6 + 2 > len ) { errno = EINVAL; return 0; } switch (name[6 + 2]) { case '\0': if (strEQ(name + 6, "ET")) { /* MODE_G removed */ #ifdef MODE_GET return MODE_GET; #else goto not_there; #endif } case 'B': if (strEQ(name + 6, "ETBULK")) { /* MODE_G removed */ #ifdef MODE_GETBULK return MODE_GETBULK; #else goto not_there; #endif } case 'N': if (strEQ(name + 6, "ETNEXT")) { /* MODE_G removed */ #ifdef MODE_GETNEXT return MODE_GETNEXT; #else goto not_there; #endif } } errno = EINVAL; return 0; not_there: errno = ENOENT; return 0; } static double constant_MODE_SET_R(char *name, int len, int arg) { if (10 + 6 >= len ) { errno = EINVAL; return 0; } switch (name[10 + 6]) { case '1': if (strEQ(name + 10, "ESERVE1")) { /* MODE_SET_R removed */ #ifdef MODE_SET_RESERVE1 return MODE_SET_RESERVE1; #else goto not_there; #endif } case '2': if (strEQ(name + 10, "ESERVE2")) { /* MODE_SET_R removed */ #ifdef MODE_SET_RESERVE2 return MODE_SET_RESERVE2; #else goto not_there; #endif } } errno = EINVAL; return 0; not_there: errno = ENOENT; return 0; } static double constant_SNMP_ERR(char *name, int len, int arg) { if (9 + 1 >= len ) { errno = EINVAL; return 0; } switch (name[9]) { case 'A': if (strEQ(name + 10, "UTHORIZATIONERROR")) { /* SNMP_ERR_A removed */ #ifdef SNMP_ERR_AUTHORIZATIONERROR return SNMP_ERR_AUTHORIZATIONERROR; #else goto not_there; #endif } break; case 'B': if (strEQ(name + 10, "ADVALUE")) { /* SNMP_ERR_B removed */ #ifdef SNMP_ERR_BADVALUE return SNMP_ERR_BADVALUE; #else goto not_there; #endif } break; case 'C': if (strEQ(name + 10, "OMMITFAILED")) { /* SNMP_ERR_C removed */ #ifdef SNMP_ERR_COMMITFAILED return SNMP_ERR_COMMITFAILED; #else goto not_there; #endif } break; case 'G': if (strEQ(name + 10, "ENERR")) { /* SNMP_ERR_G removed */ #ifdef SNMP_ERR_GENERR return SNMP_ERR_GENERR; #else goto not_there; #endif } break; case 'I': if (strEQ(name + 10, "NCONSISTENTVALUE")) { /* SNMP_ERR_I removed */ #ifdef SNMP_ERR_INCONSISTENTVALUE return SNMP_ERR_INCONSISTENTVALUE; #else goto not_there; #endif } break; case 'N': if (strEQ(name + 10, "OACCESS")) { /* SNMP_ERR_N removed */ #ifdef SNMP_ERR_NOACCESS return SNMP_ERR_NOACCESS; #else goto not_there; #endif } if (strEQ(name + 10, "OCREATION")) { /* SNMP_ERR_N removed */ #ifdef SNMP_ERR_NOCREATION return SNMP_ERR_NOCREATION; #else goto not_there; #endif } if (strEQ(name + 10, "OERROR")) { /* SNMP_ERR_N removed */ #ifdef SNMP_ERR_NOERROR return SNMP_ERR_NOERROR; #else goto not_there; #endif } if (strEQ(name + 10, "OSUCHNAME")) { /* SNMP_ERR_N removed */ #ifdef SNMP_ERR_NOSUCHNAME return SNMP_ERR_NOSUCHNAME; #else goto not_there; #endif } if (strEQ(name + 10, "OTWRITABLE")) { /* SNMP_ERR_N removed */ #ifdef SNMP_ERR_NOTWRITABLE return SNMP_ERR_NOTWRITABLE; #else goto not_there; #endif } break; case 'R': if (strEQ(name + 10, "EADONLY")) { /* SNMP_ERR_R removed */ #ifdef SNMP_ERR_READONLY return SNMP_ERR_READONLY; #else goto not_there; #endif } if (strEQ(name + 10, "ESOURCEUNAVAILABLE")) { /* SNMP_ERR_R removed */ #ifdef SNMP_ERR_RESOURCEUNAVAILABLE return SNMP_ERR_RESOURCEUNAVAILABLE; #else goto not_there; #endif } break; case 'T': if (strEQ(name + 10, "OOBIG")) { /* SNMP_ERR_T removed */ #ifdef SNMP_ERR_TOOBIG return SNMP_ERR_TOOBIG; #else goto not_there; #endif } break; case 'U': if (strEQ(name + 10, "NDOFAILED")) { /* SNMP_ERR_U removed */ #ifdef SNMP_ERR_UNDOFAILED return SNMP_ERR_UNDOFAILED; #else goto not_there; #endif } break; case 'W': if (strEQ(name + 10, "RONGENCODING")) { /* SNMP_ERR_W removed */ #ifdef SNMP_ERR_WRONGENCODING return SNMP_ERR_WRONGENCODING; #else goto not_there; #endif } if (strEQ(name + 10, "RONGLENGTH")) { /* SNMP_ERR_W removed */ #ifdef SNMP_ERR_WRONGLENGTH return SNMP_ERR_WRONGLENGTH; #else goto not_there; #endif } if (strEQ(name + 10, "RONGTYPE")) { /* SNMP_ERR_W removed */ #ifdef SNMP_ERR_WRONGTYPE return SNMP_ERR_WRONGTYPE; #else goto not_there; #endif } if (strEQ(name + 10, "RONGVALUE")) { /* SNMP_ERR_W removed */ #ifdef SNMP_ERR_WRONGVALUE return SNMP_ERR_WRONGVALUE; #else goto not_there; #endif } } not_there: errno = ENOENT; return 0; } static double constant_MODE_S(char *name, int len, int arg) { if (6 + 3 >= len ) { errno = EINVAL; return 0; } switch (name[6 + 3]) { case 'A': if (strEQ(name + 6, "ET_ACTION")) { /* MODE_S removed */ #ifdef MODE_SET_ACTION return MODE_SET_ACTION; #else goto not_there; #endif } case 'B': if (strEQ(name + 6, "ET_BEGIN")) { /* MODE_S removed */ #ifdef MODE_SET_BEGIN return MODE_SET_BEGIN; #else goto not_there; #endif } case 'C': if (strEQ(name + 6, "ET_COMMIT")) { /* MODE_S removed */ #ifdef MODE_SET_COMMIT return MODE_SET_COMMIT; #else goto not_there; #endif } case 'F': if (strEQ(name + 6, "ET_FREE")) { /* MODE_S removed */ #ifdef MODE_SET_FREE return MODE_SET_FREE; #else goto not_there; #endif } case 'R': if (!strnEQ(name + 6,"ET_", 3)) break; return constant_MODE_SET_R(name, len, arg); case 'U': if (strEQ(name + 6, "ET_UNDO")) { /* MODE_S removed */ #ifdef MODE_SET_UNDO return MODE_SET_UNDO; #else goto not_there; #endif } } errno = EINVAL; return 0; not_there: errno = ENOENT; return 0; } static double constant(char *name, int len, int arg) { errno = 0; if (0 + 5 >= len ) { errno = EINVAL; return 0; } switch (name[0 + 5]) { case 'G': if (!strnEQ(name + 0,"MODE_", 5)) break; return constant_MODE_G(name, len, arg); case 'S': if (!strnEQ(name + 0,"MODE_", 5)) break; return constant_MODE_S(name, len, arg); case 'E': if (!strnEQ(name + 0,"SNMP_ERR_", 9)) break; return constant_SNMP_ERR(name, len, arg); } errno = EINVAL; return 0; not_there: errno = ENOENT; return 0; } int handler_wrapper(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { u_long intret = 5; handler_cb_data *cb_data = (handler_cb_data *) handler->myvoid; SV *cb; if (cb_data && (cb = cb_data->perl_cb)) { SV *arg; SV *rarg; dSP; ENTER; SAVETMPS; PUSHMARK(sp); rarg = newSViv(0); arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_mib_handler"); sv_setiv(arg, (int) handler); XPUSHs(rarg); rarg = newSViv(0); arg = newSVrv(rarg, "NetSNMP::agent::reginfo"); sv_setiv(arg, (int) reginfo); XPUSHs(rarg); rarg = newSViv(0); arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_agent_request_info"); sv_setiv(arg, (int) reqinfo); XPUSHs(rarg); rarg = newSViv(0); arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_request_infoPtr"); sv_setiv(arg, (int) requests); XPUSHs(rarg); PUTBACK; if (SvTYPE(cb) == SVt_PVCV) { perl_call_sv(cb, G_DISCARD); /* I have no idea what discard does */ /* XXX: it discards the results, which isn't right */ } else if (SvROK(cb) && SvTYPE(SvRV(cb)) == SVt_PVCV) { /* reference to code */ perl_call_sv(SvRV(cb), G_DISCARD); } SPAGAIN; PUTBACK; FREETMPS; LEAVE; } return SNMP_ERR_NOERROR; } MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent double constant(sv,arg) PREINIT: STRLEN len; INPUT: SV * sv char * s = SvPV(sv, len); int arg CODE: RETVAL = constant(s,len,arg); OUTPUT: RETVAL int __agent_check_and_process(block = 1) int block; CODE: RETVAL = agent_check_and_process(block); OUTPUT: RETVAL void init_mib() int init_agent(name) const char *name; void init_snmp(name) const char *name; int init_master_agent() void snmp_enable_stderrlog() MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent PREFIX = na_ void na_shutdown(me) SV *me; CODE: { snmp_shutdown("perl"); } MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent::netsnmp_handler_registration PREFIX = nsahr_ netsnmp_handler_registration * nsahr_new(name, regoid, perlcallback) char *name; char *regoid; SV *perlcallback; PREINIT: oid myoid[MAX_OID_LEN]; size_t myoid_len = MAX_OID_LEN; handler_cb_data *cb_data; int gotit=1; CODE: if (!snmp_parse_oid(regoid, myoid, &myoid_len)) { if (!read_objid(regoid, myoid, &myoid_len)) { snmp_log(LOG_ERR, "couldn't parse %s (reg name: %s)\n", regoid, name); RETVAL = NULL; gotit = 0; } } if (gotit) { cb_data = (handler_cb_data *) malloc(sizeof(handler_cb_data)); RETVAL = netsnmp_create_handler_registration(name, handler_wrapper, myoid, myoid_len, HANDLER_CAN_RWRITE); cb_data->perl_cb = newSVsv(perlcallback); RETVAL->handler->myvoid = cb_data; } OUTPUT: RETVAL MODULE = NetSNMP::agent PACKAGE = netsnmp_handler_registrationPtr PREFIX = nsahr_ void nsahr_DESTROY(reginfo) netsnmp_handler_registration *reginfo CODE: netsnmp_handler_registration_free(reginfo); int nsahr_register(me) SV *me; PREINIT: netsnmp_handler_registration *reginfo; CODE: { reginfo = (netsnmp_handler_registration *) SvIV(SvRV(me)); RETVAL = netsnmp_register_handler(reginfo); if (!RETVAL) { /* the agent now has a "reference" to this reg pointer */ SvREFCNT_inc(me); } } OUTPUT: RETVAL void nsahr_getRootOID(me) SV *me; PREINIT: int i; netsnmp_oid *o; netsnmp_handler_registration *reginfo; SV *arg, *rarg; PPCODE: { dSP; PUSHMARK(SP); reginfo = (netsnmp_handler_registration *) SvIV(SvRV(me)); o = SNMP_MALLOC_TYPEDEF(netsnmp_oid); o->name = o->namebuf; o->len = reginfo->rootoid_len; memcpy(o->name, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid)); rarg = newSViv((int) 0); arg = newSVrv(rarg, "netsnmp_oidPtr"); sv_setiv(arg, (int) o); XPUSHs(rarg); PUTBACK; i = perl_call_pv("NetSNMP::OID::newwithptr", G_SCALAR); SPAGAIN; if (i != 1) { snmp_log(LOG_ERR, "unhandled OID error.\n"); /* ack XXX */ } ST(0) = POPs; XSRETURN(1); } MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent::netsnmp_request_infoPtr PREFIX = nari_ void getOID(me) SV *me; PREINIT: int i; netsnmp_oid *o; netsnmp_request_info *request; SV *arg, *rarg; PPCODE: { dSP; PUSHMARK(SP); request = (netsnmp_request_info *) SvIV(SvRV(me)); o = SNMP_MALLOC_TYPEDEF(netsnmp_oid); o->name = o->namebuf; o->len = request->requestvb->name_length; memcpy(o->name, request->requestvb->name, request->requestvb->name_length * sizeof(oid)); rarg = newSViv((int) 0); arg = newSVrv(rarg, "netsnmp_oidPtr"); sv_setiv(arg, (int) o); XPUSHs(rarg); PUTBACK; i = perl_call_pv("NetSNMP::OID::newwithptr", G_SCALAR); SPAGAIN; if (i != 1) { snmp_log(LOG_ERR, "unhandled OID error.\n"); /* ack XXX */ } ST(0) = POPs; XSRETURN(1); } netsnmp_oid * nari_getOIDptr(me) SV *me; PREINIT: netsnmp_request_info *request; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); RETVAL = SNMP_MALLOC_TYPEDEF(netsnmp_oid); RETVAL->name = RETVAL->namebuf; RETVAL->len = request->requestvb->name_length; memcpy(RETVAL->name, request->requestvb->name, request->requestvb->name_length * sizeof(oid)); OUTPUT: RETVAL char * nari_getValue(me) SV *me; PREINIT: u_char *oidbuf = NULL; size_t ob_len = 0, oo_len = 0; netsnmp_request_info *request; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); sprint_realloc_by_type(&oidbuf, &ob_len, &oo_len, 1, request->requestvb, 0, 0, 0); RETVAL = oidbuf; /* mem leak */ OUTPUT: RETVAL int nari_getDelegated(me) SV *me; PREINIT: netsnmp_request_info *request; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); RETVAL = request->delegated; OUTPUT: RETVAL void nari_setDelegated(me, newdelegated) SV *me; int newdelegated; PREINIT: netsnmp_request_info *request; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); request->delegated = newdelegated; int nari_getProcessed(me) SV *me; PREINIT: netsnmp_request_info *request; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); RETVAL = request->processed; OUTPUT: RETVAL void nari_setProcessed(me, newprocessed) SV *me; int newprocessed; PREINIT: netsnmp_request_info *request; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); request->processed = newprocessed; int nari_getStatus(me) SV *me; PREINIT: netsnmp_request_info *request; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); RETVAL = request->status; OUTPUT: RETVAL void nari_setStatus(me, newstatus) SV *me; int newstatus; PREINIT: netsnmp_request_info *request; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); request->status = newstatus; int nari_getRepeat(me) SV *me; PREINIT: netsnmp_request_info *request; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); RETVAL = request->repeat; OUTPUT: RETVAL void nari_setRepeat(me, newrepeat) SV *me; int newrepeat; PREINIT: netsnmp_request_info *request; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); request->repeat = newrepeat; int nari_setValue(me, type, value) SV *me; int type; SV *value; PREINIT: u_char *oidbuf = NULL; size_t ob_len = 0, oo_len = 0; netsnmp_request_info *request; u_long utmp; long ltmp; oid myoid[MAX_OID_LEN]; size_t myoid_len; STRLEN stringlen; char * stringptr; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); switch(type) { case ASN_INTEGER: /* We want an integer here */ if ((SvTYPE(value) == SVt_IV) || (SvTYPE(value) == SVt_PVMG)) { /* Good - got a real one (or a blessed object that we hope will turn out OK) */ ltmp = SvIV(value); snmp_set_var_typed_value(request->requestvb, (u_char)type, (u_char *) <mp, sizeof(ltmp)); RETVAL = 1; break; } else if (SvPOKp(value)) { /* Might be OK - got a string, so try to convert it, allowing base 10, octal, and hex forms */ stringptr = SvPV(value, stringlen); ltmp = strtol( stringptr, NULL, 0 ); if (errno == EINVAL) { snmp_log(LOG_ERR, "Could not convert string to number in setValue: '%s'", stringptr); RETVAL = 0; break; } snmp_set_var_typed_value(request->requestvb, (u_char)type, (u_char *) <mp, sizeof(ltmp)); RETVAL = 1; break; } else { snmp_log(LOG_ERR, "Non-integer value passed to setValue with ASN_INTEGER: type was %d\n", SvTYPE(value)); RETVAL = 0; break; } case ASN_UNSIGNED: case ASN_COUNTER: case ASN_COUNTER64: case ASN_TIMETICKS: /* We want an integer here */ if ((SvTYPE(value) == SVt_IV) || (SvTYPE(value) == SVt_PVMG)) { /* Good - got a real one (or a blessed scalar which we have to hope will turn out OK) */ utmp = SvIV(value); snmp_set_var_typed_value(request->requestvb, (u_char)type, (u_char *) &utmp, sizeof(utmp)); RETVAL = 1; break; } else if (SvPOKp(value)) { /* Might be OK - got a string, so try to convert it, allowing base 10, octal, and hex forms */ stringptr = SvPV(value, stringlen); utmp = strtoul( stringptr, NULL, 0 ); if (errno == EINVAL) { snmp_log(LOG_ERR, "Could not convert string to number in setValue: '%s'", stringptr); RETVAL = 0; break; } snmp_set_var_typed_value(request->requestvb, (u_char)type, (u_char *) &utmp, sizeof(utmp)); RETVAL = 1; break; } else { snmp_log(LOG_ERR, "Non-unsigned-integer value passed to setValue with ASN_UNSIGNED/ASN_COUNTER/ASN_TIMETICKS: type was %d\n", SvTYPE(value)); RETVAL = 0; break; } case ASN_OCTET_STR: case ASN_BIT_STR: /* Check that we have been passed something with a string value (or a blessed scalar) */ if (!SvPOKp(value) && (SvTYPE(value) != SVt_PVMG)) { snmp_log(LOG_ERR, "Non-string value passed to setValue with ASN_OCTET_STR/ASN_BIT_STR: type was %d\n", SvTYPE(value)); RETVAL = 0; break; } /* Find length of string (strlen will *not* do, as these are binary strings) */ stringptr = SvPV(value, stringlen); snmp_set_var_typed_value(request->requestvb, (u_char)type, (u_char *) stringptr, stringlen); RETVAL = 1; break; case ASN_IPADDRESS: /* IP addresses are passed as *binary* strings. * In the case of IPv4 addresses, these are 4 bytes long. * NOTE: the use of binary strings rather than dotted-quad or FQDNs was * introduced here by Andrew Findlay's patch of March 17th 2003, * and is effectively a change to the previous implied API which assumed * the value was a (valid) hostname. * Responsibility for decoding and resolving has been passed up to the Perl script. */ /* Check that we have been passed something with a string value (or a blessed scalar) */ if (!SvPOKp(value) && (SvTYPE(value) != SVt_PVMG)) { snmp_log(LOG_ERR, "Non-string value passed to setValue with ASN_IPADDRESS: type was %d\n", SvTYPE(value)); RETVAL = 0; break; } /* Find length of string (strlen will *not* do, as these are binary strings) */ stringptr = SvPV(value, stringlen); # snmp_log(LOG_ERR, "IP address returned with length %d: %u.%u.%u.%u\n", stringlen, stringptr[0], # stringptr[1], stringptr[2], stringptr[3] ); # Sanity check on address length if ((stringlen != 4) && (stringlen != 16)) { snmp_log(LOG_ERR, "IP address of %d bytes passed to setValue with ASN_IPADDRESS\n", stringlen); RETVAL = 0; break; } snmp_set_var_typed_value(request->requestvb, (u_char)type, stringptr, stringlen); RETVAL = 1; break; case ASN_OBJECT_ID: /* Check that we have been passed something with a string value (or a blessed scalar) */ if (!SvPOKp(value) && (SvTYPE(value) != SVt_PVMG)) { snmp_log(LOG_ERR, "Non-string value passed to setValue with ASN_OBJECT_ID: type was %d\n", SvTYPE(value)); RETVAL = 0; break; } /* Extract the string */ stringptr = SvPV(value, stringlen); /* snmp_log(LOG_ERR, "setValue returning OID '%s'\n", stringptr); */ myoid_len = MAX_OID_LEN; if (!snmp_parse_oid(stringptr, myoid, &myoid_len)) { snmp_log(LOG_ERR, "couldn't parse %s in setValue\n", stringptr); RETVAL = 0; break; } else { /* snmp_log(LOG_ERR, "setValue returning OID length %d\n", myoid_len); */ request = (netsnmp_request_info *) SvIV(SvRV(me)); snmp_set_var_typed_value(request->requestvb, (u_char)type, (u_char *) myoid, (myoid_len * sizeof(myoid[0])) ); } RETVAL = 1; break; default: snmp_log(LOG_ERR, "unknown var value type: %d\n", type); RETVAL = 0; break; } OUTPUT: RETVAL void nari_setOID(me, value) SV *me; char *value; PREINIT: oid myoid[MAX_OID_LEN]; size_t myoid_len = MAX_OID_LEN; netsnmp_request_info *request; CODE: myoid_len = MAX_OID_LEN; if (!snmp_parse_oid(value, myoid, &myoid_len)) { snmp_log(LOG_ERR, "couldn't parse %s in setOID\n", value); } else { request = (netsnmp_request_info *) SvIV(SvRV(me)); snmp_set_var_objid(request->requestvb, myoid, myoid_len); } void nari_setError(me, rinfo, ecode) SV *me; SV *rinfo; int ecode; PREINIT: oid myoid[MAX_OID_LEN]; size_t myoid_len = MAX_OID_LEN; netsnmp_request_info *request; netsnmp_agent_request_info *reqinfo; CODE: request = (netsnmp_request_info *) SvIV(SvRV(me)); reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(rinfo)); netsnmp_set_request_error(reqinfo, request, ecode); SV * nari_next(me) SV *me; PREINIT: netsnmp_request_info *request; SV *arg, *rarg; CODE: { request = (netsnmp_request_info *) SvIV(SvRV(me)); if (request && request->next) { request = request->next; rarg = newSViv(0); arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_request_infoPtr"); sv_setiv(arg, (int) request); ST(0) = rarg; } else { ST(0) = &sv_undef; } } MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent::netsnmp_agent_request_info PREFIX = narqi_ int narqi_getMode(me) SV *me; PREINIT: netsnmp_agent_request_info *reqinfo; CODE: reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(me)); RETVAL = reqinfo->mode; OUTPUT: RETVAL void narqi_setMode(me, newvalue) SV *me; int newvalue; PREINIT: netsnmp_agent_request_info *reqinfo; CODE: reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(me)); reqinfo->mode = newvalue; MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent