443 lines
12 KiB
Plaintext
443 lines
12 KiB
Plaintext
|
/* -*- C -*- */
|
||
|
#if defined(_WIN32) && !defined(_WIN32_WINNT)
|
||
|
#define _WIN32_WINNT 0x501
|
||
|
#endif
|
||
|
|
||
|
#include "EXTERN.h"
|
||
|
#include "perl.h"
|
||
|
#include "XSUB.h"
|
||
|
|
||
|
#include <net-snmp/net-snmp-config.h>
|
||
|
#include <net-snmp/net-snmp-includes.h>
|
||
|
|
||
|
/* pulled from Dave's, yet-to-be-used, net-snmp library rewrite.
|
||
|
autocompatibility for the future? */
|
||
|
|
||
|
typedef struct netsnmp_oid_s {
|
||
|
oid *name;
|
||
|
size_t len;
|
||
|
oid namebuf[ MAX_OID_LEN ];
|
||
|
} netsnmp_oid;
|
||
|
|
||
|
static int constant(double *value, const char *name, const int len)
|
||
|
{
|
||
|
return EINVAL;
|
||
|
}
|
||
|
|
||
|
netsnmp_oid *
|
||
|
nso_newarrayptr(oid *name, size_t name_len)
|
||
|
{
|
||
|
netsnmp_oid *RETVAL;
|
||
|
RETVAL = malloc(sizeof(netsnmp_oid));
|
||
|
RETVAL->name = RETVAL->namebuf;
|
||
|
RETVAL->len = name_len;
|
||
|
memcpy(RETVAL->name, name, name_len * sizeof(oid));
|
||
|
return RETVAL;
|
||
|
}
|
||
|
|
||
|
static int __sprint_num_objid _((char *, oid *, int));
|
||
|
|
||
|
/* stolen from SNMP.xs. Ug, this needs merging to snmplib */
|
||
|
/* XXX: this is only here because snmplib forces quotes around the
|
||
|
data and won't return real binary data or a numeric string. Every
|
||
|
app must do its own switch() to get around it. Ug. */
|
||
|
#define USE_BASIC 0
|
||
|
#define USE_ENUMS 1
|
||
|
#define USE_SPRINT_VALUE 2
|
||
|
static int
|
||
|
__snprint_value (buf, buf_len, var, tp, type, flag)
|
||
|
char * buf;
|
||
|
size_t buf_len;
|
||
|
netsnmp_variable_list * var;
|
||
|
struct tree * tp;
|
||
|
int type;
|
||
|
int flag;
|
||
|
{
|
||
|
int len = 0;
|
||
|
u_char* ip;
|
||
|
struct enum_list *ep;
|
||
|
|
||
|
|
||
|
buf[0] = '\0';
|
||
|
if (flag == USE_SPRINT_VALUE) {
|
||
|
snprint_value(buf, buf_len, var->name, var->name_length, var);
|
||
|
len = strlen(buf);
|
||
|
} else {
|
||
|
switch (var->type) {
|
||
|
case ASN_INTEGER:
|
||
|
if (flag == USE_ENUMS) {
|
||
|
for(ep = tp->enums; ep; ep = ep->next) {
|
||
|
if (ep->value == *var->val.integer) {
|
||
|
strcpy(buf, ep->label);
|
||
|
len = strlen(buf);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!len) {
|
||
|
sprintf(buf,"%ld", *var->val.integer);
|
||
|
len = strlen(buf);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ASN_GAUGE:
|
||
|
case ASN_COUNTER:
|
||
|
case ASN_TIMETICKS:
|
||
|
case ASN_UINTEGER:
|
||
|
sprintf(buf,"%lu", (unsigned long) *var->val.integer);
|
||
|
len = strlen(buf);
|
||
|
break;
|
||
|
|
||
|
case ASN_OCTET_STR:
|
||
|
case ASN_OPAQUE:
|
||
|
memcpy(buf, (char*)var->val.string, var->val_len);
|
||
|
len = var->val_len;
|
||
|
break;
|
||
|
|
||
|
case ASN_IPADDRESS:
|
||
|
ip = (u_char*)var->val.string;
|
||
|
sprintf(buf, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
|
||
|
len = strlen(buf);
|
||
|
break;
|
||
|
|
||
|
case ASN_NULL:
|
||
|
break;
|
||
|
|
||
|
case ASN_OBJECT_ID:
|
||
|
__sprint_num_objid(buf, (oid *)(var->val.objid),
|
||
|
var->val_len/sizeof(oid));
|
||
|
len = strlen(buf);
|
||
|
break;
|
||
|
|
||
|
case SNMP_ENDOFMIBVIEW:
|
||
|
sprintf(buf,"%s", "ENDOFMIBVIEW");
|
||
|
break;
|
||
|
case SNMP_NOSUCHOBJECT:
|
||
|
sprintf(buf,"%s", "NOSUCHOBJECT");
|
||
|
break;
|
||
|
case SNMP_NOSUCHINSTANCE:
|
||
|
sprintf(buf,"%s", "NOSUCHINSTANCE");
|
||
|
break;
|
||
|
|
||
|
case ASN_COUNTER64:
|
||
|
printU64(buf,(struct counter64 *)var->val.counter64);
|
||
|
len = strlen(buf);
|
||
|
break;
|
||
|
|
||
|
case ASN_BIT_STR:
|
||
|
snprint_bitstring(buf, buf_len, var, NULL, NULL, NULL);
|
||
|
len = strlen(buf);
|
||
|
break;
|
||
|
|
||
|
case ASN_NSAP:
|
||
|
default:
|
||
|
warn("snprint_value: asn type not handled %d\n",var->type);
|
||
|
}
|
||
|
}
|
||
|
return(len);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
__sprint_num_objid (buf, objid, len)
|
||
|
char *buf;
|
||
|
oid *objid;
|
||
|
int len;
|
||
|
{
|
||
|
int i;
|
||
|
buf[0] = '\0';
|
||
|
for (i=0; i < len; i++) {
|
||
|
sprintf(buf,".%" NETSNMP_PRIo "u",*objid++);
|
||
|
buf += strlen(buf);
|
||
|
}
|
||
|
return SNMPERR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
MODULE = NetSNMP::OID PACKAGE = NetSNMP::OID PREFIX=nso_
|
||
|
|
||
|
netsnmp_oid *
|
||
|
nso_newptr(initstring)
|
||
|
char *initstring
|
||
|
CODE:
|
||
|
if (get_tree_head() == NULL)
|
||
|
netsnmp_init_mib();
|
||
|
RETVAL = malloc(sizeof(netsnmp_oid));
|
||
|
RETVAL->name = RETVAL->namebuf;
|
||
|
RETVAL->len = sizeof(RETVAL->namebuf)/sizeof(RETVAL->namebuf[0]);
|
||
|
if (!snmp_parse_oid(initstring, (oid *) RETVAL->name, &RETVAL->len)) {
|
||
|
snmp_log(LOG_ERR, "Can't parse: %s\n", initstring);
|
||
|
RETVAL->len = 0;
|
||
|
free(RETVAL);
|
||
|
RETVAL = NULL;
|
||
|
}
|
||
|
OUTPUT:
|
||
|
RETVAL
|
||
|
|
||
|
void
|
||
|
constant(sv)
|
||
|
PREINIT:
|
||
|
STRLEN len;
|
||
|
INPUT:
|
||
|
SV * sv
|
||
|
char * s = SvPV(sv, len);
|
||
|
INIT:
|
||
|
int status;
|
||
|
double value;
|
||
|
PPCODE:
|
||
|
value = 0;
|
||
|
status = constant(&value, s, len);
|
||
|
XPUSHs(sv_2mortal(newSVuv(status)));
|
||
|
XPUSHs(sv_2mortal(newSVnv(value)));
|
||
|
|
||
|
int
|
||
|
_snmp_oid_compare(oid1, oid2)
|
||
|
netsnmp_oid *oid1;
|
||
|
netsnmp_oid *oid2;
|
||
|
CODE:
|
||
|
RETVAL = snmp_oid_compare((oid *) oid1->name, oid1->len,
|
||
|
(oid *) oid2->name, oid2->len);
|
||
|
OUTPUT:
|
||
|
RETVAL
|
||
|
|
||
|
MODULE = NetSNMP::OID PACKAGE = netsnmp_oidPtr PREFIX = nsop_
|
||
|
|
||
|
void
|
||
|
nsop_DESTROY(oid1)
|
||
|
netsnmp_oid *oid1
|
||
|
CODE:
|
||
|
{
|
||
|
if (oid1->name != oid1->namebuf) {
|
||
|
free(oid1->name);
|
||
|
}
|
||
|
free(oid1);
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
nsop_to_string(oid1)
|
||
|
netsnmp_oid *oid1
|
||
|
PREINIT:
|
||
|
static char mystr[SNMP_MAXBUF];
|
||
|
CODE:
|
||
|
{
|
||
|
if (oid1->len == 0)
|
||
|
snprintf(mystr, sizeof(mystr), "Illegal OID");
|
||
|
else
|
||
|
snprint_objid(mystr, sizeof(mystr),
|
||
|
(oid *) oid1->name, oid1->len);
|
||
|
RETVAL = mystr;
|
||
|
}
|
||
|
|
||
|
OUTPUT:
|
||
|
RETVAL
|
||
|
|
||
|
void
|
||
|
nsop_to_array(oid1)
|
||
|
netsnmp_oid *oid1;
|
||
|
PREINIT:
|
||
|
int i;
|
||
|
|
||
|
PPCODE:
|
||
|
EXTEND(SP, oid1->len);
|
||
|
for(i=0; i < (int)oid1->len; i++) {
|
||
|
PUSHs(sv_2mortal(newSVnv(oid1->name[i])));
|
||
|
}
|
||
|
|
||
|
SV *
|
||
|
nsop_get_indexes(oid1)
|
||
|
netsnmp_oid *oid1;
|
||
|
PREINIT:
|
||
|
int i, nodecount;
|
||
|
struct tree *tp, *tpe, *tpnode, *indexnode;
|
||
|
struct index_list *index;
|
||
|
netsnmp_variable_list vbdata;
|
||
|
char *buf = NULL;
|
||
|
size_t buf_len = 256, out_len = 0;
|
||
|
oid name[MAX_OID_LEN];
|
||
|
size_t name_len = MAX_OID_LEN;
|
||
|
oid *oidp;
|
||
|
size_t oidp_len;
|
||
|
AV *myret;
|
||
|
int is_private;
|
||
|
|
||
|
CODE:
|
||
|
{
|
||
|
memset(&vbdata, 0, sizeof(vbdata));
|
||
|
if (NULL == (tp = get_tree(oid1->name, oid1->len,
|
||
|
get_tree_head()))) {
|
||
|
RETVAL = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((buf = netsnmp_malloc(buf_len)) == NULL) {
|
||
|
RETVAL = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
tpe = NULL;
|
||
|
nodecount = 0;
|
||
|
for(tpnode = tp; tpnode; tpnode = tpnode->parent) {
|
||
|
nodecount++;
|
||
|
if (nodecount == 2)
|
||
|
tpe = tpnode;
|
||
|
if (nodecount == 3 &&
|
||
|
(strlen(tpnode->label) < 6 ||
|
||
|
strcmp(tpnode->label + strlen(tpnode->label) - 5,
|
||
|
"Table"))) {
|
||
|
/* we're not within a table. bad logic, little choice */
|
||
|
netsnmp_free(buf);
|
||
|
RETVAL = NULL;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!tpe) {
|
||
|
netsnmp_free(buf);
|
||
|
RETVAL = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (tpe->augments && strlen(tpe->augments) > 0) {
|
||
|
/* we're augmenting another table, so use that entry instead */
|
||
|
if (!snmp_parse_oid(tpe->augments, name, &name_len) ||
|
||
|
(NULL ==
|
||
|
(tpe = get_tree(name, name_len,
|
||
|
get_tree_head())))) {
|
||
|
netsnmp_free(buf);
|
||
|
RETVAL = NULL;
|
||
|
return; /* XXX: better error recovery needed? */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
i = 0;
|
||
|
for(index = tpe->indexes; index; index = index->next) {
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
myret = (AV *) sv_2mortal((SV *) newAV());
|
||
|
|
||
|
oidp = oid1->name + nodecount;
|
||
|
oidp_len = oid1->len - nodecount;
|
||
|
|
||
|
for(index = tpe->indexes; index; index = index->next) {
|
||
|
/* XXX: NOT efficient! */
|
||
|
name_len = MAX_OID_LEN;
|
||
|
if (!snmp_parse_oid(index->ilabel, name, &name_len) ||
|
||
|
(NULL ==
|
||
|
(indexnode = get_tree(name, name_len,
|
||
|
get_tree_head())))) {
|
||
|
netsnmp_free(buf);
|
||
|
RETVAL = NULL;
|
||
|
return; /* xxx mem leak */
|
||
|
}
|
||
|
vbdata.type = mib_to_asn_type(indexnode->type);
|
||
|
|
||
|
if (vbdata.type == (u_char) -1) {
|
||
|
netsnmp_free(buf);
|
||
|
RETVAL = NULL;
|
||
|
return; /* XXX: not good. half populated stack? */
|
||
|
}
|
||
|
|
||
|
/* check for fixed length strings */
|
||
|
if (vbdata.type == ASN_OCTET_STR &&
|
||
|
indexnode->ranges && !indexnode->ranges->next
|
||
|
&& indexnode->ranges->low == indexnode->ranges->high) {
|
||
|
vbdata.val_len = indexnode->ranges->high;
|
||
|
vbdata.type |= ASN_PRIVATE;
|
||
|
is_private = 1;
|
||
|
} else {
|
||
|
vbdata.val_len = 0;
|
||
|
if (index->isimplied) {
|
||
|
vbdata.type |= ASN_PRIVATE;
|
||
|
is_private = 1;
|
||
|
} else {
|
||
|
is_private = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (parse_one_oid_index(&oidp, &oidp_len, &vbdata, 0)
|
||
|
!= SNMPERR_SUCCESS) {
|
||
|
netsnmp_free(buf);
|
||
|
RETVAL = NULL;
|
||
|
return;
|
||
|
}
|
||
|
out_len = 0;
|
||
|
if (is_private)
|
||
|
vbdata.type ^= ASN_PRIVATE;
|
||
|
out_len =
|
||
|
__snprint_value (buf, buf_len, &vbdata, indexnode,
|
||
|
vbdata.type, 0);
|
||
|
/*
|
||
|
sprint_realloc_value(&buf, &buf_len, &out_len,
|
||
|
1, name, name_len, &vbdata);
|
||
|
*/
|
||
|
snmp_free_var_internals(&vbdata);
|
||
|
av_push(myret, newSVpv(buf, out_len));
|
||
|
}
|
||
|
netsnmp_free(buf);
|
||
|
RETVAL = newRV((SV *)myret);
|
||
|
}
|
||
|
OUTPUT:
|
||
|
RETVAL
|
||
|
|
||
|
void
|
||
|
nsop_append(oid1, string)
|
||
|
netsnmp_oid *oid1;
|
||
|
char *string;
|
||
|
PREINIT:
|
||
|
oid name[MAX_OID_LEN];
|
||
|
size_t name_len = MAX_OID_LEN;
|
||
|
int i;
|
||
|
CODE:
|
||
|
{
|
||
|
if (!snmp_parse_oid(string, (oid *) name, &name_len)) {
|
||
|
/* XXX */
|
||
|
}
|
||
|
if (oid1->len + name_len > MAX_OID_LEN) {
|
||
|
/* XXX: illegal */
|
||
|
}
|
||
|
for(i = 0; i < (int)name_len; i++) {
|
||
|
oid1->name[i+oid1->len] = name[i];
|
||
|
}
|
||
|
oid1->len += name_len;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsop_append_oid(oid1, oid2)
|
||
|
netsnmp_oid *oid1;
|
||
|
netsnmp_oid *oid2;
|
||
|
PREINIT:
|
||
|
int i;
|
||
|
CODE:
|
||
|
{
|
||
|
if (oid1->len + oid2->len > MAX_OID_LEN) {
|
||
|
/* XXX: illegal */
|
||
|
}
|
||
|
for(i = 0; i < (int)oid2->len; i++) {
|
||
|
oid1->name[i+oid1->len] = oid2->name[i];
|
||
|
}
|
||
|
oid1->len += oid2->len;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
nsop_length(oid1)
|
||
|
netsnmp_oid *oid1;
|
||
|
CODE:
|
||
|
{
|
||
|
RETVAL = oid1->len;
|
||
|
}
|
||
|
OUTPUT:
|
||
|
RETVAL
|
||
|
|
||
|
netsnmp_oid *
|
||
|
nsop_clone(oid1)
|
||
|
netsnmp_oid *oid1;
|
||
|
PREINIT:
|
||
|
netsnmp_oid *oid2;
|
||
|
CODE:
|
||
|
{
|
||
|
oid2 = nso_newarrayptr(oid1->name, oid1->len);
|
||
|
RETVAL = oid2;
|
||
|
}
|
||
|
OUTPUT:
|
||
|
RETVAL
|
||
|
|