| /* |
| * header complex: More complex storage and data sorting for mib modules |
| */ |
| |
| #include <net-snmp/net-snmp-config.h> |
| |
| #include <sys/types.h> |
| #if HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| #include "header_complex.h" |
| |
| #include <net-snmp/net-snmp-features.h> |
| |
| netsnmp_feature_child_of(header_complex_all, libnetsnmpmibs) |
| |
| netsnmp_feature_child_of(header_complex_free_all, header_complex_all) |
| netsnmp_feature_child_of(header_complex_find_entry, header_complex_all) |
| |
| int |
| header_complex_generate_varoid(netsnmp_variable_list * var) |
| { |
| int i; |
| |
| if (var->name == NULL) { |
| /* |
| * assume cached value is correct |
| */ |
| switch (var->type) { |
| case ASN_INTEGER: |
| case ASN_COUNTER: |
| case ASN_GAUGE: |
| case ASN_TIMETICKS: |
| var->name_length = 1; |
| var->name = (oid *) malloc(sizeof(oid)); |
| if (var->name == NULL) |
| return SNMPERR_GENERR; |
| var->name[0] = *(var->val.integer); |
| break; |
| |
| case ASN_PRIV_IMPLIED_OBJECT_ID: |
| var->name_length = var->val_len / sizeof(oid); |
| var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); |
| if (var->name == NULL) |
| return SNMPERR_GENERR; |
| |
| for (i = 0; i < (int) var->name_length; i++) |
| var->name[i] = var->val.objid[i]; |
| break; |
| |
| case ASN_OBJECT_ID: |
| var->name_length = var->val_len / sizeof(oid) + 1; |
| var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); |
| if (var->name == NULL) |
| return SNMPERR_GENERR; |
| |
| var->name[0] = var->name_length - 1; |
| for (i = 0; i < (int) var->name_length - 1; i++) |
| var->name[i + 1] = var->val.objid[i]; |
| break; |
| |
| case ASN_PRIV_IMPLIED_OCTET_STR: |
| var->name_length = var->val_len; |
| var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); |
| if (var->name == NULL) |
| return SNMPERR_GENERR; |
| |
| for (i = 0; i < (int) var->val_len; i++) |
| var->name[i] = (oid) var->val.string[i]; |
| break; |
| |
| case ASN_OPAQUE: |
| case ASN_OCTET_STR: |
| var->name_length = var->val_len + 1; |
| var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); |
| if (var->name == NULL) |
| return SNMPERR_GENERR; |
| |
| var->name[0] = (oid) var->val_len; |
| for (i = 0; i < (int) var->val_len; i++) |
| var->name[i + 1] = (oid) var->val.string[i]; |
| break; |
| |
| default: |
| DEBUGMSGTL(("header_complex_generate_varoid", |
| "invalid asn type: %d\n", var->type)); |
| return SNMPERR_GENERR; |
| } |
| } |
| if (var->name_length > MAX_OID_LEN) { |
| DEBUGMSGTL(("header_complex_generate_varoid", |
| "Something terribly wrong, namelen = %d\n", |
| (int)var->name_length)); |
| return SNMPERR_GENERR; |
| } |
| |
| return SNMPERR_SUCCESS; |
| } |
| |
| /* |
| * header_complex_parse_oid(): parses an index to the usmTable to |
| * break it down into a engineID component and a name component. |
| * The results are stored in the data pointer, as a varbindlist: |
| * |
| * |
| * returns 1 if an error is encountered, or 0 if successful. |
| */ |
| int |
| header_complex_parse_oid(oid * oidIndex, size_t oidLen, |
| netsnmp_variable_list * data) |
| { |
| netsnmp_variable_list *var = data; |
| int i, itmp; |
| |
| while (var && oidLen > 0) { |
| switch (var->type) { |
| case ASN_INTEGER: |
| case ASN_COUNTER: |
| case ASN_GAUGE: |
| case ASN_TIMETICKS: |
| var->val.integer = (long *) calloc(1, sizeof(long)); |
| if (var->val.string == NULL) |
| return SNMPERR_GENERR; |
| |
| *var->val.integer = (long) *oidIndex++; |
| var->val_len = sizeof(long); |
| oidLen--; |
| DEBUGMSGTL(("header_complex_parse_oid", |
| "Parsed int(%d): %ld\n", var->type, |
| *var->val.integer)); |
| break; |
| |
| case ASN_OBJECT_ID: |
| case ASN_PRIV_IMPLIED_OBJECT_ID: |
| if (var->type == ASN_PRIV_IMPLIED_OBJECT_ID) { |
| itmp = oidLen; |
| } else { |
| itmp = (long) *oidIndex++; |
| oidLen--; |
| if (itmp > (int) oidLen) |
| return SNMPERR_GENERR; |
| } |
| |
| if (itmp == 0) |
| break; /* zero length strings shouldn't malloc */ |
| |
| var->val_len = itmp * sizeof(oid); |
| var->val.objid = (oid *) calloc(1, var->val_len); |
| if (var->val.objid == NULL) |
| return SNMPERR_GENERR; |
| |
| for (i = 0; i < itmp; i++) |
| var->val.objid[i] = (u_char) * oidIndex++; |
| oidLen -= itmp; |
| |
| DEBUGMSGTL(("header_complex_parse_oid", "Parsed oid: ")); |
| DEBUGMSGOID(("header_complex_parse_oid", var->val.objid, |
| var->val_len / sizeof(oid))); |
| DEBUGMSG(("header_complex_parse_oid", "\n")); |
| break; |
| |
| case ASN_OPAQUE: |
| case ASN_OCTET_STR: |
| case ASN_PRIV_IMPLIED_OCTET_STR: |
| if (var->type == ASN_PRIV_IMPLIED_OCTET_STR) { |
| itmp = oidLen; |
| } else { |
| itmp = (long) *oidIndex++; |
| oidLen--; |
| if (itmp > (int) oidLen) |
| return SNMPERR_GENERR; |
| } |
| |
| if (itmp == 0) |
| break; /* zero length strings shouldn't malloc */ |
| |
| /* |
| * malloc by size+1 to allow a null to be appended. |
| */ |
| var->val_len = itmp; |
| var->val.string = (u_char *) calloc(1, itmp + 1); |
| if (var->val.string == NULL) |
| return SNMPERR_GENERR; |
| |
| for (i = 0; i < itmp; i++) |
| var->val.string[i] = (u_char) * oidIndex++; |
| var->val.string[itmp] = '\0'; |
| oidLen -= itmp; |
| |
| DEBUGMSGTL(("header_complex_parse_oid", |
| "Parsed str(%d): %s\n", var->type, |
| var->val.string)); |
| break; |
| |
| default: |
| DEBUGMSGTL(("header_complex_parse_oid", |
| "invalid asn type: %d\n", var->type)); |
| return SNMPERR_GENERR; |
| } |
| var = var->next_variable; |
| } |
| if (var != NULL || oidLen > 0) |
| return SNMPERR_GENERR; |
| return SNMPERR_SUCCESS; |
| } |
| |
| |
| void |
| header_complex_generate_oid(oid * name, /* out */ |
| size_t * length, /* out */ |
| oid * prefix, |
| size_t prefix_len, |
| netsnmp_variable_list * data) |
| { |
| |
| oid *oidptr; |
| netsnmp_variable_list *var; |
| |
| if (prefix) { |
| memcpy(name, prefix, prefix_len * sizeof(oid)); |
| oidptr = (name + (prefix_len)); |
| *length = prefix_len; |
| } else { |
| oidptr = name; |
| *length = 0; |
| } |
| |
| for (var = data; var != NULL; var = var->next_variable) { |
| header_complex_generate_varoid(var); |
| memcpy(oidptr, var->name, sizeof(oid) * var->name_length); |
| oidptr = oidptr + var->name_length; |
| *length += var->name_length; |
| } |
| |
| DEBUGMSGTL(("header_complex_generate_oid", "generated: ")); |
| DEBUGMSGOID(("header_complex_generate_oid", name, *length)); |
| DEBUGMSG(("header_complex_generate_oid", "\n")); |
| } |
| |
| /* |
| * finds the data in "datalist" stored at "index" |
| */ |
| void * |
| header_complex_get(struct header_complex_index *datalist, |
| netsnmp_variable_list * index) |
| { |
| oid searchfor[MAX_OID_LEN]; |
| size_t searchfor_len; |
| |
| header_complex_generate_oid(searchfor, /* out */ |
| &searchfor_len, /* out */ |
| NULL, 0, index); |
| return header_complex_get_from_oid(datalist, searchfor, searchfor_len); |
| } |
| |
| void * |
| header_complex_get_from_oid(struct header_complex_index *datalist, |
| oid * searchfor, size_t searchfor_len) |
| { |
| struct header_complex_index *nptr; |
| for (nptr = datalist; nptr != NULL; nptr = nptr->next) { |
| if (netsnmp_oid_equals(searchfor, searchfor_len, |
| nptr->name, nptr->namelen) == 0) |
| return nptr->data; |
| } |
| return NULL; |
| } |
| |
| |
| void * |
| header_complex(struct header_complex_index *datalist, |
| struct variable *vp, |
| oid * name, |
| size_t * length, |
| int exact, size_t * var_len, WriteMethod ** write_method) |
| { |
| |
| struct header_complex_index *nptr, *found = NULL; |
| oid indexOid[MAX_OID_LEN]; |
| size_t len; |
| int result; |
| |
| /* |
| * set up some nice defaults for the user |
| */ |
| if (write_method) |
| *write_method = NULL; |
| if (var_len) |
| *var_len = sizeof(long); |
| |
| for (nptr = datalist; nptr != NULL && found == NULL; nptr = nptr->next) { |
| if (vp) { |
| memcpy(indexOid, vp->name, vp->namelen * sizeof(oid)); |
| memcpy(indexOid + vp->namelen, nptr->name, |
| nptr->namelen * sizeof(oid)); |
| len = vp->namelen + nptr->namelen; |
| } else { |
| memcpy(indexOid, nptr->name, nptr->namelen * sizeof(oid)); |
| len = nptr->namelen; |
| } |
| result = snmp_oid_compare(name, *length, indexOid, len); |
| DEBUGMSGTL(("header_complex", "Checking: ")); |
| DEBUGMSGOID(("header_complex", indexOid, len)); |
| DEBUGMSG(("header_complex", "\n")); |
| |
| if (exact) { |
| if (result == 0) { |
| found = nptr; |
| } |
| } else { |
| if (result == 0) { |
| /* |
| * found an exact match. Need the next one for !exact |
| */ |
| if (nptr->next) |
| found = nptr->next; |
| } else if (result == -1) { |
| found = nptr; |
| } |
| } |
| } |
| if (found) { |
| if (vp) { |
| memcpy(name, vp->name, vp->namelen * sizeof(oid)); |
| memcpy(name + vp->namelen, found->name, |
| found->namelen * sizeof(oid)); |
| *length = vp->namelen + found->namelen; |
| } else { |
| memcpy(name, found->name, found->namelen * sizeof(oid)); |
| *length = found->namelen; |
| } |
| return found->data; |
| } |
| |
| return NULL; |
| } |
| |
| struct header_complex_index * |
| header_complex_maybe_add_data(struct header_complex_index **thedata, |
| netsnmp_variable_list * var, void *data, |
| int dont_allow_duplicates) |
| { |
| oid newoid[MAX_OID_LEN]; |
| size_t newoid_len; |
| struct header_complex_index *ret; |
| |
| if (thedata == NULL || var == NULL || data == NULL) |
| return NULL; |
| |
| header_complex_generate_oid(newoid, &newoid_len, NULL, 0, var); |
| ret = |
| header_complex_maybe_add_data_by_oid(thedata, newoid, newoid_len, data, |
| dont_allow_duplicates); |
| /* |
| * free the variable list, but not the enclosed data! it's not ours! |
| */ |
| snmp_free_varbind(var); |
| return (ret); |
| } |
| |
| struct header_complex_index * |
| header_complex_add_data(struct header_complex_index **thedata, |
| netsnmp_variable_list * var, void *data) |
| { |
| return |
| header_complex_maybe_add_data(thedata, var, data, 0); |
| } |
| |
| |
| struct header_complex_index * |
| _header_complex_add_between(struct header_complex_index **thedata, |
| struct header_complex_index *hciptrp, |
| struct header_complex_index *hciptrn, |
| oid * newoid, size_t newoid_len, void *data) |
| { |
| struct header_complex_index *ourself; |
| |
| /* |
| * nptr should now point to the spot that we need to add ourselves |
| * in front of, and pptr should be our new 'prev'. |
| */ |
| |
| /* |
| * create ourselves |
| */ |
| ourself = (struct header_complex_index *) |
| SNMP_MALLOC_STRUCT(header_complex_index); |
| if (ourself == NULL) |
| return NULL; |
| |
| /* |
| * change our pointers |
| */ |
| ourself->prev = hciptrp; |
| ourself->next = hciptrn; |
| |
| if (ourself->next) |
| ourself->next->prev = ourself; |
| |
| if (ourself->prev) |
| ourself->prev->next = ourself; |
| |
| ourself->data = data; |
| ourself->name = snmp_duplicate_objid(newoid, newoid_len); |
| ourself->namelen = newoid_len; |
| |
| /* |
| * rewind to the head of the list and return it (since the new head |
| * could be us, we need to notify the above routine who the head now is. |
| */ |
| for (hciptrp = ourself; hciptrp->prev != NULL; |
| hciptrp = hciptrp->prev); |
| |
| *thedata = hciptrp; |
| DEBUGMSGTL(("header_complex_add_data", "adding something...\n")); |
| |
| return hciptrp; |
| } |
| |
| |
| struct header_complex_index * |
| header_complex_maybe_add_data_by_oid(struct header_complex_index **thedata, |
| oid * newoid, size_t newoid_len, void *data, |
| int dont_allow_duplicates) |
| { |
| struct header_complex_index *hciptrn, *hciptrp; |
| int rc; |
| |
| if (thedata == NULL || newoid == NULL || data == NULL) |
| return NULL; |
| |
| for (hciptrn = *thedata, hciptrp = NULL; |
| hciptrn != NULL; hciptrp = hciptrn, hciptrn = hciptrn->next) { |
| /* |
| * XXX: check for == and error (overlapping table entries) |
| * 8/2005 rks Ok, I added duplicate entry check, but only log |
| * warning and continue, because it seems that nobody |
| * that calls this fucntion does error checking!. |
| */ |
| rc = snmp_oid_compare(hciptrn->name, hciptrn->namelen, |
| newoid, newoid_len); |
| if (rc > 0) |
| break; |
| else if (0 == rc) { |
| snmp_log(LOG_WARNING, "header_complex_add_data_by_oid with " |
| "duplicate index.\n"); |
| if (dont_allow_duplicates) |
| return NULL; |
| } |
| } |
| |
| return _header_complex_add_between(thedata, hciptrp, hciptrn, |
| newoid, newoid_len, data); |
| } |
| |
| struct header_complex_index * |
| header_complex_add_data_by_oid(struct header_complex_index **thedata, |
| oid * newoid, size_t newoid_len, void *data) |
| { |
| return header_complex_maybe_add_data_by_oid(thedata, newoid, newoid_len, |
| data, 0); |
| } |
| |
| /* |
| * extracts an entry from the storage space (removing it from future |
| * accesses) and returns the data stored there |
| * |
| * Modifies "thetop" pointer as needed (and if present) if were |
| * extracting the first node. |
| */ |
| |
| void * |
| header_complex_extract_entry(struct header_complex_index **thetop, |
| struct header_complex_index *thespot) |
| { |
| struct header_complex_index *hciptrp, *hciptrn; |
| void *retdata; |
| |
| if (thespot == NULL) { |
| DEBUGMSGTL(("header_complex_extract_entry", |
| "Null pointer asked to be extracted\n")); |
| return NULL; |
| } |
| |
| retdata = thespot->data; |
| |
| hciptrp = thespot->prev; |
| hciptrn = thespot->next; |
| |
| if (hciptrp) |
| hciptrp->next = hciptrn; |
| else if (thetop) |
| *thetop = hciptrn; |
| |
| if (hciptrn) |
| hciptrn->prev = hciptrp; |
| |
| if (thespot->name) |
| free(thespot->name); |
| |
| free(thespot); |
| return retdata; |
| } |
| |
| /* |
| * wipe out a single entry |
| */ |
| void |
| header_complex_free_entry(struct header_complex_index *theentry, |
| HeaderComplexCleaner * cleaner) |
| { |
| void *data; |
| data = header_complex_extract_entry(NULL, theentry); |
| (*cleaner) (data); |
| } |
| |
| /* |
| * completely wipe out all entries in our data store |
| */ |
| #ifndef NETSNMP_FEATURE_REMOVE_HEADER_COMPLEX_FREE_ALL |
| void |
| header_complex_free_all(struct header_complex_index *thestuff, |
| HeaderComplexCleaner * cleaner) |
| { |
| struct header_complex_index *hciptr, *hciptrn; |
| |
| for (hciptr = thestuff; hciptr != NULL; hciptr = hciptrn) { |
| hciptrn = hciptr->next; /* need to extract this before deleting it */ |
| header_complex_free_entry(hciptr, cleaner); |
| } |
| } |
| #endif /* NETSNMP_FEATURE_REMOVE_HEADER_COMPLEX_FREE_ALL */ |
| |
| #ifndef NETSNMP_FEATURE_REMOVE_HEADER_COMPLEX_FIND_ENTRY |
| struct header_complex_index * |
| header_complex_find_entry(struct header_complex_index *thestuff, |
| void *theentry) |
| { |
| struct header_complex_index *hciptr; |
| |
| for (hciptr = thestuff; hciptr != NULL && hciptr->data != theentry; |
| hciptr = hciptr->next); |
| return hciptr; |
| } |
| #endif /* NETSNMP_FEATURE_REMOVE_HEADER_COMPLEX_FIND_ENTRY */ |
| |
| #ifdef TESTING |
| |
| void |
| header_complex_dump(struct header_complex_index *thestuff) |
| { |
| struct header_complex_index *hciptr; |
| oid oidsave[MAX_OID_LEN]; |
| size_t len; |
| |
| for (hciptr = thestuff; hciptr != NULL; hciptr = hciptr->next) { |
| DEBUGMSGTL(("header_complex_dump", "var: ")); |
| header_complex_generate_oid(oidsave, &len, NULL, 0, hciptr->); |
| DEBUGMSGOID(("header_complex_dump", oidsave, len)); |
| DEBUGMSG(("header_complex_dump", "\n")); |
| } |
| } |
| |
| main() |
| { |
| oid oidsave[MAX_OID_LEN]; |
| int len = MAX_OID_LEN, len2; |
| netsnmp_variable_list *vars; |
| long ltmp = 4242, ltmp2 = 88, ltmp3 = 1, ltmp4 = 4200; |
| oid ourprefix[] = { 1, 2, 3, 4 }; |
| oid testparse[] = { 4, 116, 101, 115, 116, 4200 }; |
| int ret; |
| |
| char *string = "wes", *string2 = "dawn", *string3 = "test"; |
| |
| struct header_complex_index *thestorage = NULL; |
| |
| debug_register_tokens("header_complex"); |
| snmp_set_do_debugging(1); |
| |
| vars = NULL; |
| len2 = sizeof(ltmp); |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_INTEGER, (char *) <mp, |
| len2); |
| header_complex_add_data(&thestorage, vars, ourprefix); |
| |
| vars = NULL; |
| len2 = strlen(string); |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, string, len2); |
| header_complex_add_data(&thestorage, vars, ourprefix); |
| |
| vars = NULL; |
| len2 = sizeof(ltmp2); |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_INTEGER, (char *) <mp2, |
| len2); |
| header_complex_add_data(&thestorage, vars, ourprefix); |
| |
| vars = NULL; |
| len2 = strlen(string2); |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, string2, |
| len2); |
| header_complex_add_data(&thestorage, vars, ourprefix); |
| |
| vars = NULL; |
| len2 = sizeof(ltmp3); |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_INTEGER, (char *) <mp3, |
| len2); |
| header_complex_add_data(&thestorage, vars, ourprefix); |
| |
| vars = NULL; |
| len2 = strlen(string3); |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, string3, |
| len2); |
| len2 = sizeof(ltmp4); |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_INTEGER, (char *) <mp4, |
| len2); |
| header_complex_add_data(&thestorage, vars, ourprefix); |
| |
| header_complex_dump(thestorage); |
| |
| vars = NULL; |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, NULL, 0); |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_INTEGER, NULL, 0); |
| ret = |
| header_complex_parse_oid(testparse, |
| sizeof(testparse) / sizeof(oid), vars); |
| DEBUGMSGTL(("header_complex_test", "parse returned %d...\n", ret)); |
| |
| } |
| #endif |