wireshark/epan/oids.c
Stig Bjørlykke a2d1e9005d This patch adds support for configuration profiles, which can be used to
configure and use more than one set of preferences and configuration files.

This can be found in the "Configuration Profiles..." menu item from the Edit
menu, or by pressing Shift-Ctrl-A.  It's also possible to start wireshark
and tshark with a named profile by using the "-C ProfileName" option.
A new status pane in the main window will show the current profile.

The configuration files currently stored in the Profiles are:
- Preferences
- Capture Filters
- Display Filters
- Coloring Rules
- Disabled Protocols
- User Accessible Tables

The recent data are by design not added to the profile.

Planned future enhancements:
- make a more convenient function to switch between profiles
- add a "clone profile" button to copy an existing profile
- make the profiles list active and accept return as OK
- save users "Decode as" in the profile
- make new, clone and deletion of profiles more secure
- make some of the recent values available in the profile

This patch also fixes:
- setting default status pane sizes
- a bug setting status pane for packets when not having main lower pane.

svn path=/trunk/; revision=24089
2008-01-14 16:40:23 +00:00

1137 lines
31 KiB
C

/* oids.c
* Object IDentifier Support
*
* (c) 2007, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "emem.h"
#include "uat.h"
#include "prefs.h"
#include "proto.h"
#include "packet.h"
#include "report_err.h"
#include "filesystem.h"
#include "dissectors/packet-ber.h"
#ifdef HAVE_LIBSMI
#include <smi.h>
#endif
#define D(level,args) do if (debuglevel >= level) { printf args; printf("\n"); fflush(stdout); } while(0)
#include "oids.h"
static int debuglevel = 0;
static const oid_value_type_t integer_type = { FT_INT32, BASE_DEC, BER_CLASS_UNI, BER_UNI_TAG_INTEGER, 1, 4, OID_KEY_TYPE_INTEGER, 1};
static const oid_value_type_t bytes_type = { FT_BYTES, BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 0, -1, OID_KEY_TYPE_BYTES, 0};
static const oid_value_type_t oid_type = { FT_OID, BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OID, 1, -1, OID_KEY_TYPE_OID, 0};
static const oid_value_type_t ipv4_type = { FT_IPv4, BASE_NONE, BER_CLASS_APP, 0, 4, 4, OID_KEY_TYPE_IPADDR, 4};
static const oid_value_type_t counter32_type = { FT_UINT32, BASE_DEC, BER_CLASS_APP, 1, 1, 4, OID_KEY_TYPE_INTEGER, 1};
static const oid_value_type_t unsigned32_type = { FT_UINT32, BASE_DEC, BER_CLASS_APP, 2, 1, 4, OID_KEY_TYPE_INTEGER, 1};
static const oid_value_type_t timeticks_type = { FT_UINT32, BASE_DEC, BER_CLASS_APP, 3, 1, 4, OID_KEY_TYPE_INTEGER, 1};
static const oid_value_type_t opaque_type = { FT_BYTES, BASE_NONE, BER_CLASS_APP, 4, 1, 4, OID_KEY_TYPE_BYTES, 0};
static const oid_value_type_t nsap_type = { FT_BYTES, BASE_NONE, BER_CLASS_APP, 5, 0, -1, OID_KEY_TYPE_NSAP, 0};
static const oid_value_type_t counter64_type = { FT_UINT64, BASE_DEC, BER_CLASS_APP, 6, 1, 8, OID_KEY_TYPE_INTEGER, 1};
static const oid_value_type_t ipv6_type = { FT_IPv6, BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 16, 16, OID_KEY_TYPE_BYTES, 16};
static const oid_value_type_t float_type = { FT_FLOAT, BASE_DEC, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 4, 4, OID_KEY_TYPE_WRONG, 0};
static const oid_value_type_t double_type = { FT_DOUBLE, BASE_DEC, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 8, 8, OID_KEY_TYPE_WRONG, 0};
static const oid_value_type_t ether_type = { FT_ETHER, BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 6, 6, OID_KEY_TYPE_BYTES, 6};
static const oid_value_type_t string_type = { FT_STRING, BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 0, -1, OID_KEY_TYPE_STRING, 0};
static const oid_value_type_t unknown_type = { FT_BYTES, BASE_NONE, BER_CLASS_ANY, BER_TAG_ANY, 0, -1, OID_KEY_TYPE_WRONG, 0};
static oid_info_t oid_root = { 0, NULL, OID_KIND_UNKNOWN, NULL, &unknown_type, -2, NULL, NULL, NULL};
static oid_info_t* add_oid(const char* name, oid_kind_t kind, const oid_value_type_t* type, oid_key_t* key, guint oid_len, guint32 *subids) {
guint i = 0;
oid_info_t* c = &oid_root;
if (!oid_root.children) {
char* debug_env = getenv("WIRESHARK_DEBUG_MIBS");
guint32 subid;
debuglevel = debug_env ? strtoul(debug_env,NULL,10) : 0;
oid_root.children = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"oid_root");
/*
* make sure we got strings at least in the three root-children oids
* that way oid_resolved() will always have a string to print
*/
subid = 0; oid_add("itu-t",1,&subid);
subid = 1; oid_add("iso",1,&subid);
subid = 2; oid_add("joint-iso-itu-t",1,&subid);
}
oid_len--;
do {
oid_info_t* n = emem_tree_lookup32(c->children,subids[i]);
if(n) {
if (i == oid_len) {
if (n->name) {
if (!g_str_equal(n->name,name)) {
D(2,("Renaming Oid from: %s -> %s, this means the same oid is registered more than once",n->name,name));
}
/* XXX - Don't free n->name here. It may be part of an hf_register_info
* struct that has been appended to the hfa GArray. */
}
n->name = g_strdup(name);
if (! n->value_type) {
n->value_type = type;
}
return n;
}
} else {
n = g_malloc(sizeof(oid_info_t));
n->subid = subids[i];
n->kind = kind;
n->children = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"oid_children");
n->value_hfid = -2;
n->key = key;
n->parent = c;
n->bits = NULL;
emem_tree_insert32(c->children,n->subid,n);
if (i == oid_len) {
n->name = g_strdup(name);
n->value_type = type;
n->kind = kind;
return n;
} else {
n->name = NULL;
n->value_type = NULL;
n->kind = OID_KIND_UNKNOWN;
}
}
c = n;
} while(++i);
g_assert_not_reached();
return NULL;
}
void oid_add(const char* name, guint oid_len, guint32 *subids) {
g_assert(subids && *subids <= 2);
if (oid_len) {
D(3,("\tOid (from subids): %s %s ",name?name:"NULL", oid_subid2string(subids,oid_len)));
add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
} else {
D(1,("Failed to add Oid: %s (from subids)",name?name:"NULL"));
}
}
void oid_add_from_string(const char* name, const gchar *oid_str) {
guint32* subids;
guint oid_len = oid_string2subid(oid_str, &subids);
if (oid_len) {
D(3,("\tOid (from string): %s %s ",name?name:"NULL", oid_subid2string(subids,oid_len)));
add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
} else {
D(1,("Failed to add Oid: %s %s ",name?name:"NULL", oid_str?oid_str:NULL));
}
}
extern void oid_add_from_encoded(const char* name, const guint8 *oid, gint oid_len) {
guint32* subids;
guint subids_len = oid_encoded2subid(oid, oid_len, &subids);
if (subids_len) {
D(3,("\tOid (from encoded): %s %s ",name, oid_subid2string(subids,subids_len)));
add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,subids_len,subids);
} else {
D(1,("Failed to add Oid: %s [%d]%s ",name?name:"NULL", oid_len,bytestring_to_str(oid, oid_len, ':')));
}
}
#ifdef HAVE_LIBSMI
typedef struct smi_module_t {
char* name;
} smi_module_t;
static smi_module_t* smi_paths = NULL;
static guint num_smi_paths = 0;
static uat_t* smi_paths_uat = NULL;
static smi_module_t* smi_modules = NULL;
static guint num_smi_modules = 0;
static uat_t* smi_modules_uat = NULL;
static GString* smi_errors;
UAT_CSTRING_CB_DEF(smi_mod,name,smi_module_t)
static void smi_error_handler(char *path, int line, int severity, char *msg, char *tag) {
g_string_sprintfa(smi_errors,"%s:%d %d %s %s\n",
path ? path : "-",
line, severity,
tag ? tag : "-",
msg ? msg : "");
}
static void* smi_mod_copy_cb(void* dest, const void* orig, unsigned len _U_) {
const smi_module_t* m = orig;
smi_module_t* d = dest;
d->name = g_strdup(m->name);
return d;
}
static void smi_mod_free_cb(void* p) {
smi_module_t* m = p;
if (m->name) g_free(m->name);
}
static char* alnumerize(const char* name) {
char* s = g_strdup(name);
char* r = s;
char* w = r;
char c;
for (;(c = *r); r++) {
if (isalnum(c) || c == '_' || c == '-' || c == '.') {
*(w++) = c;
} else if (c == ':' && r[1] == ':') {
*(w++) = '.';
}
}
*w = '\0';
return s;
}
const oid_value_type_t* get_typedata(SmiType* smiType) {
/*
* There has to be a better way to know if a given
* OCTETSTRING type is actually human readable text,
* an address of some type or some moe specific FT_
* Until that is found, this is the mappping between
* SNMP Types and our FT_s
*/
static const struct _type_mapping_t {
char* name;
SmiBasetype base;
const oid_value_type_t* type;
} types[] = {
{"IpAddress", SMI_BASETYPE_UNKNOWN, &ipv4_type},
{"InetAddressIPv4",SMI_BASETYPE_UNKNOWN,&ipv4_type},
{"InetAddressIPv6",SMI_BASETYPE_UNKNOWN,&ipv6_type},
{"NetworkAddress",SMI_BASETYPE_UNKNOWN,&ipv4_type},
{"MacAddress",SMI_BASETYPE_UNKNOWN,&ether_type},
{"TimeTicks",SMI_BASETYPE_UNKNOWN,&timeticks_type},
{"Ipv6Address",SMI_BASETYPE_UNKNOWN,&ipv6_type},
{"TimeStamp",SMI_BASETYPE_UNKNOWN,&integer_type},
{"DisplayString",SMI_BASETYPE_UNKNOWN,&string_type},
{"SnmpAdminString",SMI_BASETYPE_UNKNOWN,&string_type},
{"DateAndTime",SMI_BASETYPE_UNKNOWN,&string_type},
{"Counter",SMI_BASETYPE_UNKNOWN,&counter32_type},
{"Counter32",SMI_BASETYPE_UNKNOWN,&counter32_type},
{"Unsigned32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
{"Gauge",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
{"Gauge32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
{"NsapAddress",SMI_BASETYPE_UNKNOWN,&nsap_type},
{"i32",SMI_BASETYPE_INTEGER32,&integer_type},
{"octets",SMI_BASETYPE_OCTETSTRING,&bytes_type},
{"oid",SMI_BASETYPE_OBJECTIDENTIFIER,&oid_type},
{"u32",SMI_BASETYPE_UNSIGNED32,&unsigned32_type},
{"u64",SMI_BASETYPE_UNSIGNED64,&counter64_type},
{"f32",SMI_BASETYPE_FLOAT32,&float_type},
{"f64",SMI_BASETYPE_FLOAT64,&double_type},
{"f128",SMI_BASETYPE_FLOAT128,&bytes_type},
{"enum",SMI_BASETYPE_ENUM,&integer_type},
{"bits",SMI_BASETYPE_BITS,&bytes_type},
{"unk",SMI_BASETYPE_UNKNOWN,&unknown_type},
{NULL,0,NULL}
};
const struct _type_mapping_t* t;
SmiType* sT = smiType;
if (!smiType) return NULL;
do {
for (t = types; t->type ; t++ ) {
const char* name = smiRenderType(sT, SMI_RENDER_NAME);
if (name && t->name && g_str_equal(name, t->name )) {
return t->type;
}
}
} while(( sT = smiGetParentType(sT) ));
for (t = types; t->type ; t++ ) {
if(smiType->basetype == t->base) {
return t->type;
}
}
return &unknown_type;
}
static guint get_non_implicit_size(SmiType* sT) {
SmiRange *sR;
guint size = 0xffffffff;
switch (sT->basetype) {
case SMI_BASETYPE_OCTETSTRING:
case SMI_BASETYPE_OBJECTIDENTIFIER:
break;
default:
return 0;
}
for ( ; sT; sT = smiGetParentType(sT) ) {
for (sR = smiGetFirstRange(sT); sR ; sR = smiGetNextRange(sR)) {
if (size == 0xffffffff) {
if (sR->minValue.value.unsigned32 == sR->maxValue.value.unsigned32) {
size = sR->minValue.value.unsigned32;
} else {
return 0;
}
} else {
if (sR->minValue.value.unsigned32 != size || sR->maxValue.value.unsigned32 != size) {
return 0;
}
}
}
}
return size == 0xffffffff ? 0 : size;
}
static inline oid_kind_t smikind(SmiNode* sN, oid_key_t** key_p) {
*key_p = NULL;
switch(sN->nodekind) {
case SMI_NODEKIND_ROW: {
SmiElement* sE;
oid_key_t* kl = NULL;
const oid_value_type_t* typedata = NULL;
gboolean implied;
switch (sN->indexkind) {
case SMI_INDEX_INDEX:
break;
case SMI_INDEX_AUGMENT:
case SMI_INDEX_REORDER:
case SMI_INDEX_SPARSE:
case SMI_INDEX_EXPAND:
sN = smiGetRelatedNode(sN);
break;
case SMI_INDEX_UNKNOWN:
return OID_KIND_UNKNOWN;
};
implied = sN->implied;
for (sE = smiGetFirstElement(sN); sE; sE = smiGetNextElement(sE)) {
SmiNode* elNode = smiGetElementNode(sE) ;
SmiType* elType = smiGetNodeType(elNode);
oid_key_t* k;
guint non_implicit_size = 0;
if (elType) {
non_implicit_size = get_non_implicit_size(elType);
}
typedata = get_typedata(elType);
k = g_malloc(sizeof(oid_key_t));
k->name = g_strdup_printf("%s.%s",
smiRenderOID(sN->oidlen, sN->oid, SMI_RENDER_QUALIFIED),
smiRenderOID(elNode->oidlen, elNode->oid, SMI_RENDER_NAME));
k->hfid = -2;
k->ft_type = typedata ? typedata->ft_type : FT_BYTES;
k->display = typedata ? typedata->display : BASE_NONE;
k->next = NULL;
if (typedata) {
k->key_type = typedata->keytype;
k->num_subids = typedata->keysize;
} else {
if (elType) {
switch (elType->basetype) {
case SMI_BASETYPE_BITS:
case SMI_BASETYPE_OCTETSTRING: {
k->key_type = OID_KEY_TYPE_BYTES;
k->num_subids = non_implicit_size;
break;
}
case SMI_BASETYPE_ENUM:
case SMI_BASETYPE_OBJECTIDENTIFIER:
case SMI_BASETYPE_INTEGER32:
case SMI_BASETYPE_UNSIGNED32:
case SMI_BASETYPE_INTEGER64:
case SMI_BASETYPE_UNSIGNED64:
k->key_type = OID_KEY_TYPE_INTEGER;
k->num_subids = 1;
break;
default:
k->key_type = OID_KEY_TYPE_WRONG;
k->num_subids = 0;
break;
}
} else {
k->key_type = OID_KEY_TYPE_WRONG;
k->num_subids = 0;
break;
}
}
if (!*key_p) *key_p = k;
if (kl) kl->next = k;
kl = k;
}
if (implied) {
switch (kl->key_type) {
case OID_KEY_TYPE_BYTES: kl->key_type = OID_KEY_TYPE_IMPLIED_BYTES; break;
case OID_KEY_TYPE_STRING: kl->key_type = OID_KEY_TYPE_IMPLIED_STRING; break;
case OID_KEY_TYPE_OID: kl->key_type = OID_KEY_TYPE_IMPLIED_OID; break;
default: break;
}
}
return OID_KIND_ROW;
}
case SMI_NODEKIND_NODE: return OID_KIND_NODE;
case SMI_NODEKIND_SCALAR: return OID_KIND_SCALAR;
case SMI_NODEKIND_TABLE: return OID_KIND_TABLE;
case SMI_NODEKIND_COLUMN: return OID_KIND_COLUMN;
case SMI_NODEKIND_NOTIFICATION: return OID_KIND_NOTIFICATION;
case SMI_NODEKIND_GROUP: return OID_KIND_GROUP;
case SMI_NODEKIND_COMPLIANCE: return OID_KIND_COMPLIANCE;
case SMI_NODEKIND_CAPABILITIES: return OID_KIND_CAPABILITIES;
default: return OID_KIND_UNKNOWN;
}
}
#define IS_ENUMABLE(ft) ( (ft == FT_UINT8) || (ft == FT_UINT16) || (ft == FT_UINT24) || (ft == FT_UINT32) \
|| (ft == FT_INT8) || (ft == FT_INT16) || (ft == FT_INT24) || (ft == FT_INT32) \
|| (ft == FT_UINT64) || (ft == FT_INT64) )
#ifdef WIN32
#define PATH_SEPARATOR ";"
#define DEFAULT_PATH_FMT "%s;%s"
#define DEFAULT_PATH_ARGS get_datafile_path("snmp\\mibs"), get_persconffile_path("snmp\\mibs", FALSE, FALSE)
#else
#define PATH_SEPARATOR ":"
#define DEFAULT_PATH_FMT "%s"
#define DEFAULT_PATH_ARGS smiGetPath()
#endif
void register_mibs(void) {
SmiModule *smiModule;
SmiNode *smiNode;
guint i;
int proto_mibs = -1;
module_t* mibs_module;
GArray* hfa = g_array_new(FALSE,TRUE,sizeof(hf_register_info));
GArray* etta = g_array_new(FALSE,TRUE,sizeof(gint*));
static uat_field_t smi_fields[] = {
UAT_FLD_CSTRING(smi_mod,name,"The module's name"),
UAT_END_FIELDS
};
static uat_field_t smi_paths_fields[] = {
UAT_FLD_CSTRING(smi_mod,name,"The directory name"),
UAT_END_FIELDS
};
char* smi_load_error = NULL;
gchar* path_str;
smi_modules_uat = uat_new("SMI Modules",
sizeof(smi_module_t),
"smi_modules",
(void*)&smi_modules,
&num_smi_modules,
UAT_CAT_GENERAL,
"ChSNMPSMIModules",
smi_mod_copy_cb,
NULL,
smi_mod_free_cb,
smi_fields);
smi_paths_uat = uat_new("SMI Paths",
sizeof(smi_module_t),
"smi_paths",
(void*)&smi_paths,
&num_smi_paths,
UAT_CAT_GENERAL,
"ChSNMPSMIPaths",
smi_mod_copy_cb,
NULL,
smi_mod_free_cb,
smi_paths_fields);
smiInit(NULL);
uat_load(smi_modules_uat, &smi_load_error);
if (smi_load_error) {
report_failure("Error Loading SMI Modules Table: %s",smi_load_error);
return;
}
uat_load(smi_paths_uat, &smi_load_error);
if (smi_load_error) {
report_failure("Error Loading SMI Paths Table: %s",smi_load_error);
return;
}
path_str = oid_get_default_mib_path();
D(1,("SMI Path: '%s'",path_str));
smiSetPath(path_str);
smi_errors = g_string_new("");
smiSetErrorHandler(smi_error_handler);
for(i=0;i<num_smi_modules;i++) {
if (!smi_modules[i].name) continue;
if (smiIsLoaded(smi_modules[i].name)) {
continue;
} else {
char* mod_name = smiLoadModule(smi_modules[i].name);
if (mod_name)
D(2,("Loaded: '%s'[%d] as %s",smi_modules[i].name,i,mod_name ));
else
D(1,("Failed to load: '%s'[%d]",smi_modules[i].name,i));
}
}
if (smi_errors->len) {
report_failure("The following errors were found while loading the MIBS:\n%s\n\n"
"The Current Path is: %s\n" , smi_errors->str , path_str);
D(1,("Errors while loading:\n%s\n",smi_errors->str));
}
g_free(path_str);
g_string_free(smi_errors,TRUE);
for (smiModule = smiGetFirstModule();
smiModule;
smiModule = smiGetNextModule(smiModule)) {
D(3,("\tModule: %s", smiModule->name));
for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
smiNode;
smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
SmiType* smiType = smiGetNodeType(smiNode);
const oid_value_type_t* typedata = get_typedata(smiType);
oid_key_t* key;
oid_kind_t kind = smikind(smiNode,&key);
oid_info_t* oid_data = add_oid(smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_QUALIFIED),
kind,
typedata,
key,
smiNode->oidlen,
smiNode->oid);
D(4,("\t\tNode: kind=%d oid=%s name=%s ",
oid_data->kind, oid_subid2string(smiNode->oid, smiNode->oidlen), oid_data->name ));
if ( typedata && oid_data->value_hfid == -2 ) {
SmiNamedNumber* smiEnum;
hf_register_info hf = { &(oid_data->value_hfid), {
oid_data->name,
alnumerize(oid_data->name),
typedata->ft_type,
typedata->display,
NULL,
0,
g_strdup(smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_ALL)),
HFILL }};
oid_data->value_hfid = -1;
if ( IS_ENUMABLE(hf.hfinfo.type) && (smiEnum = smiGetFirstNamedNumber(smiType))) {
GArray* vals = g_array_new(TRUE,TRUE,sizeof(value_string));
for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum)) {
if (smiEnum->name) {
value_string val = {smiEnum->value.value.integer32,g_strdup(smiEnum->name)};
g_array_append_val(vals,val);
}
}
hf.hfinfo.strings = VALS(vals->data);
g_array_free(vals,FALSE);
}
#if 0 /* packet-snmp does not hanldle bits yet */
} else if (smiType->basetype == SMI_BASETYPE_BITS && ( smiEnum = smiGetFirstNamedNumber(smiType) )) {
guint n = 0;
oid_bits_info_t* bits = g_malloc(sizeof(oid_bits_info_t));
gint* ettp = &(bits->ett);
bits->num = 0;
bits->ett = -1;
g_array_append_val(etta,ettp);
for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum), bits->num++);
bits->data = g_malloc(sizeof(struct _oid_bit_t)*bits->num);
for(smiEnum = smiGetFirstNamedNumber(smiType),n=0;
smiEnum;
smiEnum = smiGetNextNamedNumber(smiEnum),n++) {
guint mask = 1 << (smiEnum->value.value.integer32 % 8);
char* base = alnumerize(oid_data->name);
char* ext = alnumerize(smiEnum->name);
hf_register_info hf2 = { &(bits->data[n].hfid), { NULL, NULL, FT_UINT8, BASE_HEX, NULL, mask, "", HFILL }};
bits->data[n].hfid = -1;
bits->data[n].offset = smiEnum->value.value.integer32 / 8;
hf2.hfinfo.name = g_strdup_printf("%s:%s",oid_data->name,smiEnum->name);
hf2.hfinfo.abbrev = g_strdup_printf("%s.%s",base,ext);
g_free(base);
g_free(ext);
g_array_append_val(hfa,hf2);
}
#endif /* packet-snmp does not use this yet */
g_array_append_val(hfa,hf);
}
if ((key = oid_data->key)) {
for(; key; key = key->next) {
hf_register_info hf = { &(key->hfid), {
key->name,
alnumerize(key->name),
key->ft_type,
key->display,
NULL,
0,
"",
HFILL }};
D(5,("\t\t\tIndex: name=%s subids=%d key_type=%d",
key->name, key->num_subids, key->key_type ));
if (key->hfid == -2) {
g_array_append_val(hfa,hf);
key->hfid = -1;
} else {
g_free((void*)hf.hfinfo.abbrev);
}
}
}
}
}
proto_mibs = proto_register_protocol("MIBs", "MIBS", "mibs");
proto_register_field_array(proto_mibs, (hf_register_info*)hfa->data, hfa->len);
mibs_module = prefs_register_protocol(proto_mibs, NULL);
prefs_register_uat_preference(mibs_module, "smi_paths",
"MIB paths",
"List of directories where MIBs are to be looked for",
smi_paths_uat);
prefs_register_uat_preference(mibs_module, "smi_modules",
"MIB modules",
"List of MIB modules to be loaded",
smi_modules_uat);
proto_register_subtree_array((gint**)etta->data, etta->len);
g_array_free(etta,TRUE);
g_array_free(hfa,FALSE);
}
#endif
void oids_init(void) {
#ifdef HAVE_LIBSMI
register_mibs();
#else
D(1,("libsmi disabled oid resolution not enabled"));
#endif
}
const char* oid_subid2string(guint32* subids, guint len) {
char* s = ep_alloc0(((len)*11)+1);
char* w = s;
if(!subids)
return "*** Empty OID ***";
do {
w += sprintf(w,"%u.",*subids++);
} while(--len);
if (w!=s) *(w-1) = '\0'; else *(s) = '\0';
return s;
}
guint check_num_oid(const char* str) {
const char* r = str;
char c = '\0';
guint n = 0;
D(8,("check_num_oid: '%s'",str));
if (*r == '.' || *r == '\0') return 0;
do {
D(9,("\tcheck_num_oid: '%c' %d",*r,n));
switch(*r) {
case '.':
n++;
if (c == '.') return 0;
case '1' : case '2' : case '3' : case '4' : case '5' :
case '6' : case '7' : case '8' : case '9' : case '0' :
continue;
case '\0':
n++;
break;
default:
return 0;
}
} while((c = *r++));
if (c == '.') return 0;
return n;
}
guint oid_string2subid(const char* str, guint32** subids_p) {
const char* r = str;
guint32* subids;
guint32* subids_overflow;
guint n = check_num_oid(str);
/*
* we cannot handle sub-ids greater than 32bytes
* keep a pilot subid of 64 bytes to check the limit
*/
guint64 subid = 0;
D(6,("oid_string2subid: str='%s'",str));
if (!n) {
*subids_p = NULL;
return 0;
}
*subids_p = subids = ep_alloc0(sizeof(guint32)*n);
subids_overflow = subids + n;
do switch(*r) {
case '.':
subid = 0;
subids++;
continue;
case '1' : case '2' : case '3' : case '4' : case '5' :
case '6' : case '7' : case '8' : case '9' : case '0' :
subid *= 10;
subid += *r - '0';
if( subids >= subids_overflow || subid > 0xffffffff) {
*subids_p=NULL;
return 0;
}
*(subids) *= 10;
*(subids) += *r - '0';
continue;
case '\0':
break;
default:
return 0;
} while(*r++);
return n;
}
guint oid_encoded2subid(const guint8 *oid_bytes, gint oid_len, guint32** subids_p) {
gint i;
guint n = 1;
gboolean is_first = TRUE;
guint32* subids;
guint32* subid_overflow;
/*
* we cannot handle sub-ids greater than 32bytes
* have the subid in 64 bytes to be able to check the limit
*/
guint64 subid = 0;
for (i=0; i<oid_len; i++) { if (! (oid_bytes[i] & 0x80 )) n++; }
*subids_p = subids = ep_alloc(sizeof(guint32)*n);
subid_overflow = subids+n;
for (i=0; i<oid_len; i++){
guint8 byte = oid_bytes[i];
subid <<= 7;
subid |= byte & 0x7F;
if (byte & 0x80) {
continue;
}
if (is_first) {
guint32 subid0 = 0;
if (subid >= 40) { subid0++; subid-=40; }
if (subid >= 40) { subid0++; subid-=40; }
*subids++ = subid0;
is_first = FALSE;
}
if( subids >= subid_overflow || subid > 0xffffffff) {
*subids_p=NULL;
return 0;
}
*subids++ = (guint32)subid;
subid = 0;
}
return n;
}
oid_info_t* oid_get(guint len, guint32* subids, guint* matched, guint* left) {
oid_info_t* curr_oid = &oid_root;
guint i;
if(!(subids && *subids <= 2)) {
*matched = 0;
*left = len;
return curr_oid;
}
for( i=0; i < len; i++) {
oid_info_t* next_oid = emem_tree_lookup32(curr_oid->children,subids[i]);
if (next_oid) {
curr_oid = next_oid;
} else {
goto done;
}
}
done:
*matched = i;
*left = len - i;
return curr_oid;
}
oid_info_t* oid_get_from_encoded(const guint8 *bytes, gint byteslen, guint32** subids_p, guint* matched_p, guint* left_p) {
guint subids_len = oid_encoded2subid(bytes, byteslen, subids_p);
return oid_get(subids_len, *subids_p, matched_p, left_p);
}
oid_info_t* oid_get_from_string(const gchar *oid_str, guint32** subids_p, guint* matched, guint* left) {
guint subids_len = oid_string2subid(oid_str, subids_p);
return oid_get(subids_len, *subids_p, matched, left);
}
const gchar *oid_resolved_from_encoded(const guint8 *oid, gint oid_len) {
guint32 *subid_oid;
guint subid_oid_length = oid_encoded2subid(oid, oid_len, &subid_oid);
return oid_resolved(subid_oid_length, subid_oid);
}
guint oid_subid2encoded(guint subids_len, guint32* subids, guint8** bytes_p) {
guint bytelen = 0;
guint i;
guint32 subid;
guint8* bytes;
guint8* b;
if ( !subids || subids_len <= 0) {
*bytes_p = NULL;
return 0;
}
subid = (subids[0] * 40) + subids[1];
i = 2;
do {
if (subid <= 0x0000007F) {
bytelen += 1;
} else if (subid <= 0x00003FFF ) {
bytelen += 2;
} else if (subid <= 0x001FFFFF ) {
bytelen += 3;
} else if (subid <= 0x0FFFFFFF ) {
bytelen += 4;
} else {
bytelen += 5;
}
subid = subids[i];
} while ( i++ < subids_len );
*bytes_p = b = bytes = ep_alloc(bytelen);
subid = (subids[0] * 40) + subids[1];
i = 2;
do {
guint len;
if ((subid <= 0x0000007F )) len = 1;
else if ((subid <= 0x00003FFF )) len = 2;
else if ((subid <= 0x001FFFFF )) len = 3;
else if ((subid <= 0x0FFFFFFF )) len = 4;
else len = 5;
switch(len) {
default: *bytes_p=NULL; return 0;
case 5: *(b++) = ((subid & 0xF0000000) << 28) | 0x80;
case 4: *(b++) = ((subid & 0x0FE00000 ) >> 21) | 0x80;
case 3: *(b++) = ((subid & 0x001FC000 ) >> 14) | 0x80;
case 2: *(b++) = ((subid & 0x00003F10 ) >> 7) | 0x80;
case 1: *(b++) = subid & 0x0000007F ; break;
}
subid = subids[i];
} while ( i++ < subids_len);
return bytelen;
}
const gchar* oid_encoded2string(const guint8* encoded, guint len) {
guint32* subids;
guint subids_len = oid_encoded2subid(encoded, len, &subids);
if (subids_len) {
return oid_subid2string(subids,subids_len);
} else {
return "";
}
}
guint oid_string2encoded(const char *oid_str, guint8 **bytes) {
guint32* subids;
guint32 subids_len;
guint byteslen;
if ( ( subids_len = oid_string2subid(oid_str, &subids) )
&&
( byteslen = oid_subid2encoded(subids_len, subids, bytes) ) ) {
return byteslen;
}
return 0;
}
char* oid2str(oid_info_t* oid, guint32* subids, guint len, guint left) {
if (left == 0) {
return oid->name;
} else {
return ep_strdup_printf("%s.%s",oid->name,oid_subid2string(subids+(len-left),left));
}
}
const gchar *oid_resolved_from_string(const gchar *oid_str) {
guint32 *subid_oid;
guint subid_oid_length = oid_string2subid(oid_str, &subid_oid);
return oid_resolved(subid_oid_length, subid_oid);
}
const gchar *oid_resolved(guint32 num_subids, guint32* subids) {
guint matched;
guint left;
oid_info_t* oid;
if(! (subids && *subids <= 2 ))
return "*** Malformed OID ***";
oid = oid_get(num_subids, subids, &matched, &left);
while (! oid->name ) {
if (!(oid = oid->parent)) {
return oid_subid2string(subids,num_subids);
}
left++;
matched--;
}
if (left) {
return ep_strdup_printf("%s.%s",
oid->name ? oid->name : oid_subid2string(subids,matched),
oid_subid2string(&(subids[matched]),left));
} else {
return oid->name ? oid->name : oid_subid2string(subids,matched);
}
}
extern void oid_both(guint oid_len, guint32 *subids, char** resolved_p, char** numeric_p) {
*resolved_p = (void*)oid_resolved(oid_len,subids);
*numeric_p = (void*)oid_subid2string(subids,oid_len);
}
extern void oid_both_from_encoded(const guint8 *oid, gint oid_len, char** resolved_p, char** numeric_p) {
guint32* subids;
guint subids_len = oid_encoded2subid(oid, oid_len, &subids);
*resolved_p = (void*)oid_resolved(subids_len,subids);
*numeric_p = (void*)oid_subid2string(subids,subids_len);
}
extern void oid_both_from_string(const gchar *oid_str, char** resolved_p, char** numeric_p) {
guint32* subids;
guint subids_len = oid_string2subid(oid_str, &subids);
*resolved_p = (void*)oid_resolved(subids_len,subids);
*numeric_p = (void*)oid_subid2string(subids,subids_len);
}
#ifdef HAVE_LIBSMI
/**
* Fetch the default OID path.
*/
extern gchar *
oid_get_default_mib_path(void) {
GString* path_str;
gchar *path_ret;
guint i;
path_str = g_string_new("");
g_string_sprintfa(path_str, DEFAULT_PATH_FMT, DEFAULT_PATH_ARGS);
for(i=0;i<num_smi_paths;i++) {
if (!( smi_paths[i].name && *smi_paths[i].name))
continue;
g_string_sprintfa(path_str,PATH_SEPARATOR "%s",smi_paths[i].name);
}
path_ret = path_str->str;
g_string_free(path_str, FALSE);
return path_ret;
}
#endif
#ifdef DEBUG_OIDS
char* oid_test_a2b(guint32 num_subids, guint32* subids) {
guint8* sub2enc;
guint8* str2enc;
guint32* enc2sub;
guint32* str2sub;
const char* sub2str = oid_subid2string(subids, num_subids);
guint sub2enc_len = oid_subid2encoded(num_subids, subids,&sub2enc);
guint enc2sub_len = oid_encoded2subid(sub2enc, sub2enc_len, &enc2sub);
const char* enc2str = oid_encoded2string(sub2enc, sub2enc_len);
guint str2enc_len = oid_string2encoded(sub2str,&str2enc);
guint str2sub_len = oid_string2subid(sub2str,&str2sub);
return ep_strdup_printf(
"oid_subid2string=%s \n"
"oid_subid2encoded=[%d]%s \n"
"oid_encoded2subid=%s \n "
"oid_encoded2string=%s \n"
"oid_string2encoded=[%d]%s \n"
"oid_string2subid=%s \n "
,sub2str
,sub2enc_len,bytestring_to_str(sub2enc, sub2enc_len, ':')
,enc2sub ? oid_subid2string(enc2sub,enc2sub_len) : "-"
,enc2str
,str2enc_len,bytestring_to_str(str2enc, str2enc_len, ':')
,str2sub ? oid_subid2string(str2sub,str2sub_len) : "-"
);
}
void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree) {
static const char* oid_kinds[] = { "Unknown", "Node", "Scalar", "Table", "Row", "Column", "Notification", "Group", "Compliance", "Capabilities"};
static const char* key_types[] = {"OID_KEY_TYPE_WRONG","OID_KEY_TYPE_INTEGER",
"OID_KEY_TYPE_FIXED_STRING","OID_KEY_TYPE_FIXED_BYTES","OID_KEY_TYPE_STRING",
"OID_KEY_TYPE_BYTES","OID_KEY_TYPE_NSAP","OID_KEY_TYPE_OID","OID_KEY_TYPE_IPADDR"};
proto_item* pi = proto_tree_add_text(tree,NULL,0,0,
"OidInfo: Name='%s' sub-id=%u kind=%s hfid=%d",
oid_info->name ? oid_info->name : "",
oid_info->subid,
oid_info->kind <= OID_KIND_CAPABILITIES ? oid_kinds[oid_info->kind] : "BROKEN",
oid_info->value_hfid);
proto_tree* pt = proto_item_add_subtree(pi,0);
oid_key_t* key;
for(key = oid_info->key; key; key = key->next) {
proto_tree_add_text(pt,NULL,0,0,
"Key: name='%s' num_subids=%d type=%s",
key->name,
key->key_type <= OID_KEY_TYPE_IPADDR ? key_types[key->key_type] : "BROKEN"
);
};
if (oid_info->parent) {
pi = proto_tree_add_text(pt,NULL,0,0,"Parent:");
pt = proto_item_add_subtree(pi,0);
add_oid_debug_subtree(oid_info->parent, pt);
}
}
#endif
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: tabs
* End:
*
* ex: set shiftwidth=8 tabstop=8 noexpandtab
* :indentSize=8:tabSize=8:noTabs=false:
*/