2 * Object IDentifier Support
4 * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <wsutil/report_message.h>
33 #include "wmem/wmem.h"
38 #include "wsutil/filesystem.h"
39 #include "dissectors/packet-ber.h"
40 #include <wsutil/ws_printf.h> /* ws_debug_printf */
45 static gboolean oids_init_done = FALSE;
46 static gboolean load_smi_modules = FALSE;
47 static gboolean suppress_smi_errors = FALSE;
50 #define D(level,args) do if (debuglevel >= level) { ws_debug_printf args; ws_debug_printf("\n"); fflush(stdout); } while(0)
54 static int debuglevel = 0;
57 * From SNMPv2-SMI and X.690
59 * Counter32 ::= [APPLICATION 1] IMPLICIT INTEGER (0..4294967295)
60 * Gauge32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
61 * Unsigned32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) (alias of Gauge32)
62 * TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
64 * If the BER encoding should not have the top bit set as to not become a negative number
65 * the BER encoding may take 5 octets to encode.
69 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};
70 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};
71 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};
72 static const oid_value_type_t ipv4_type = { FT_IPv4, BASE_NONE, BER_CLASS_APP, 0, 4, 4, OID_KEY_TYPE_IPADDR, 4};
73 static const oid_value_type_t counter32_type = { FT_UINT64, BASE_DEC, BER_CLASS_APP, 1, 1, 5, OID_KEY_TYPE_INTEGER, 1};
74 static const oid_value_type_t unsigned32_type = { FT_UINT64, BASE_DEC, BER_CLASS_APP, 2, 1, 5, OID_KEY_TYPE_INTEGER, 1};
75 static const oid_value_type_t timeticks_type = { FT_UINT64, BASE_DEC, BER_CLASS_APP, 3, 1, 5, OID_KEY_TYPE_INTEGER, 1};
77 static const oid_value_type_t opaque_type = { FT_BYTES, BASE_NONE, BER_CLASS_APP, 4, 1, 4, OID_KEY_TYPE_BYTES, 0};
79 static const oid_value_type_t nsap_type = { FT_BYTES, BASE_NONE, BER_CLASS_APP, 5, 0, -1, OID_KEY_TYPE_NSAP, 0};
80 static const oid_value_type_t counter64_type = { FT_UINT64, BASE_DEC, BER_CLASS_APP, 6, 1, 8, OID_KEY_TYPE_INTEGER, 1};
81 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};
82 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};
83 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};
84 static const oid_value_type_t ether_type = { FT_ETHER, BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 6, 6, OID_KEY_TYPE_ETHER, 6};
85 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};
86 static const oid_value_type_t date_and_time_type = { FT_STRING, BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 8, 11, OID_KEY_TYPE_DATE_AND_TIME, 0};
87 #endif /* HAVE_LIBSMI */
89 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};
91 static oid_info_t oid_root = { 0, NULL, OID_KIND_UNKNOWN, NULL, &unknown_type, -2, NULL, NULL, NULL};
93 static void prepopulate_oids(void) {
94 if (!oid_root.children) {
95 char* debug_env = getenv("WIRESHARK_DEBUG_MIBS");
98 debuglevel = debug_env ? (int)strtoul(debug_env,NULL,10) : 0;
100 oid_root.children = wmem_tree_new(wmem_epan_scope());
103 * make sure we got strings at least in the three root-children oids
104 * that way oid_resolved() will always have a string to print
106 subid = 0; oid_add("itu-t",1,&subid);
107 subid = 1; oid_add("iso",1,&subid);
108 subid = 2; oid_add("joint-iso-itu-t",1,&subid);
114 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) {
116 oid_info_t* c = &oid_root;
122 oid_info_t* n = (oid_info_t *)wmem_tree_lookup32(c->children,subids[i]);
127 if (!g_str_equal(n->name,name)) {
128 D(2,("Renaming Oid from: %s -> %s, this means the same oid is registered more than once",n->name,name));
130 wmem_free(wmem_epan_scope(), n->name);
133 n->name = wmem_strdup(wmem_epan_scope(), name);
135 if (! n->value_type) {
136 n->value_type = type;
142 n = wmem_new(wmem_epan_scope(), oid_info_t);
143 n->subid = subids[i];
145 n->children = wmem_tree_new(wmem_epan_scope());
151 wmem_tree_insert32(c->children,n->subid,n);
154 n->name = wmem_strdup(wmem_epan_scope(), name);
155 n->value_type = type;
160 n->value_type = NULL;
161 n->kind = OID_KIND_UNKNOWN;
167 g_assert_not_reached();
171 void oid_add(const char* name, guint oid_len, guint32 *subids) {
172 g_assert(subids && *subids <= 2);
174 gchar* sub = oid_subid2string(NULL, subids,oid_len);
175 D(3,("\tOid (from subids): %s %s ",name?name:"NULL", sub));
176 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
177 wmem_free(NULL, sub);
179 D(1,("Failed to add Oid: %s (from subids)",name?name:"NULL"));
183 void oid_add_from_string(const char* name, const gchar *oid_str) {
185 guint oid_len = oid_string2subid(NULL, oid_str, &subids);
188 gchar* sub = oid_subid2string(NULL, subids,oid_len);
189 D(3,("\tOid (from string): %s %s ",name?name:"NULL", sub));
190 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
191 wmem_free(NULL, sub);
193 D(1,("Failed to add Oid: %s %s ",name?name:"NULL", oid_str?oid_str:NULL));
195 wmem_free(NULL, subids);
198 extern void oid_add_from_encoded(const char* name, const guint8 *oid, gint oid_len) {
199 guint32* subids = NULL;
200 guint subids_len = oid_encoded2subid(NULL, oid, oid_len, &subids);
203 gchar* sub = oid_subid2string(NULL, subids,subids_len);
204 D(3,("\tOid (from encoded): %s %s ",name, sub));
205 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,subids_len,subids);
206 wmem_free(NULL, sub);
208 gchar* bytestr = bytestring_to_str(NULL, oid, oid_len, ':');
209 D(1,("Failed to add Oid: %s [%d]%s ",name?name:"NULL", oid_len, bytestr));
210 wmem_free(NULL, bytestr);
212 wmem_free(NULL, subids);
216 /* de-allocate storage mallocated by libsmi */
218 /* XXX: libsmi provides access to smiFree as of libsmi v 0.4.8. */
219 /* On Windows: Wireshark 1.01 and later is built and distributed */
220 /* with libsmi 0.4.8 (or newer). */
221 /* On non-Windows systems, free() should be OK for libsmi */
222 /* versions older than 0.4.8. */
224 static void smi_free(void *ptr) {
226 #if (SMI_VERSION_MAJOR >= 0) && (SMI_VERSION_MINOR >= 4) && (SMI_VERSION_PATCHLEVEL >= 8)
230 #error Invalid Windows libsmi version ?? !!
232 #define xx_free free /* hack so checkAPIs.pl doesn't complain */
238 typedef struct smi_module_t {
242 static smi_module_t* smi_paths = NULL;
243 static guint num_smi_paths = 0;
244 static uat_t* smi_paths_uat = NULL;
246 static smi_module_t* smi_modules = NULL;
247 static guint num_smi_modules = 0;
248 static uat_t* smi_modules_uat = NULL;
250 static GString* smi_errors;
252 UAT_DIRECTORYNAME_CB_DEF(smi_mod,name,smi_module_t)
254 static void smi_error_handler(char *path, int line, int severity, char *msg, char *tag) {
255 g_string_append_printf(smi_errors,"%s:%d %d %s %s\n",
263 static void* smi_mod_copy_cb(void* dest, const void* orig, size_t len _U_) {
264 const smi_module_t* m = (const smi_module_t*)orig;
265 smi_module_t* d = (smi_module_t*)dest;
267 d->name = g_strdup(m->name);
272 static void smi_mod_free_cb(void* p) {
273 smi_module_t* m = (smi_module_t*)p;
278 static char* alnumerize(const char* name) {
279 char* s = g_strdup(name);
284 for (;(c = *r); r++) {
285 if (g_ascii_isalnum(c) || c == '_' || c == '-' || c == '.') {
287 } else if (c == ':' && r[1] == ':') {
297 static const oid_value_type_t* get_typedata(SmiType* smiType) {
299 * There has to be a better way to know if a given
300 * OCTETSTRING type is actually human readable text,
301 * an address of some type or some moe specific FT_
302 * Until that is found, this is the mappping between
303 * SNMP Types and our FT_s
305 static const struct _type_mapping_t {
308 const oid_value_type_t* type;
310 {"IpAddress", SMI_BASETYPE_UNKNOWN, &ipv4_type},
311 {"InetAddressIPv4",SMI_BASETYPE_UNKNOWN,&ipv4_type},
312 {"InetAddressIPv6",SMI_BASETYPE_UNKNOWN,&ipv6_type},
313 {"NetworkAddress",SMI_BASETYPE_UNKNOWN,&ipv4_type},
314 {"MacAddress",SMI_BASETYPE_UNKNOWN,ðer_type},
315 {"TimeTicks",SMI_BASETYPE_UNKNOWN,&timeticks_type},
316 {"Ipv6Address",SMI_BASETYPE_UNKNOWN,&ipv6_type},
317 {"TimeStamp",SMI_BASETYPE_UNKNOWN,&timeticks_type},
318 {"DisplayString",SMI_BASETYPE_UNKNOWN,&string_type},
319 {"SnmpAdminString",SMI_BASETYPE_UNKNOWN,&string_type},
320 {"DateAndTime",SMI_BASETYPE_UNKNOWN,&date_and_time_type},
321 {"Counter",SMI_BASETYPE_UNKNOWN,&counter32_type},
322 {"Counter32",SMI_BASETYPE_UNKNOWN,&counter32_type},
323 {"Unsigned32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
324 {"Gauge",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
325 {"Gauge32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
326 {"NsapAddress",SMI_BASETYPE_UNKNOWN,&nsap_type},
327 {"i32",SMI_BASETYPE_INTEGER32,&integer_type},
328 {"octets",SMI_BASETYPE_OCTETSTRING,&bytes_type},
329 {"oid",SMI_BASETYPE_OBJECTIDENTIFIER,&oid_type},
330 {"u32",SMI_BASETYPE_UNSIGNED32,&unsigned32_type},
331 {"u64",SMI_BASETYPE_UNSIGNED64,&counter64_type},
332 {"f32",SMI_BASETYPE_FLOAT32,&float_type},
333 {"f64",SMI_BASETYPE_FLOAT64,&double_type},
334 {"f128",SMI_BASETYPE_FLOAT128,&bytes_type},
335 {"enum",SMI_BASETYPE_ENUM,&integer_type},
336 {"bits",SMI_BASETYPE_BITS,&bytes_type},
337 {"unk",SMI_BASETYPE_UNKNOWN,&unknown_type},
338 {NULL,SMI_BASETYPE_UNKNOWN,NULL} /* SMI_BASETYPE_UNKNOWN = 0 */
340 const struct _type_mapping_t* t;
341 SmiType* sT = smiType;
343 if (!smiType) return NULL;
346 for (t = types; t->type ; t++ ) {
347 char* name = smiRenderType(sT, SMI_RENDER_NAME);
348 if (name && t->name && g_str_equal(name, t->name )) {
356 } while(( sT = smiGetParentType(sT) ));
358 for (t = types; t->type ; t++ ) {
359 if(smiType->basetype == t->base) {
364 return &unknown_type;
367 static guint get_non_implicit_size(SmiType* sT) {
369 guint size = 0xffffffff;
371 switch (sT->basetype) {
372 case SMI_BASETYPE_OCTETSTRING:
373 case SMI_BASETYPE_OBJECTIDENTIFIER:
379 for ( ; sT; sT = smiGetParentType(sT) ) {
380 for (sR = smiGetFirstRange(sT); sR ; sR = smiGetNextRange(sR)) {
381 if (size == 0xffffffff) {
382 if (sR->minValue.value.unsigned32 == sR->maxValue.value.unsigned32) {
383 size = (guint32)sR->minValue.value.unsigned32;
388 if (sR->minValue.value.unsigned32 != size || sR->maxValue.value.unsigned32 != size) {
395 return size == 0xffffffff ? 0 : size;
399 static inline oid_kind_t smikind(SmiNode* sN, oid_key_t** key_p) {
402 switch(sN->nodekind) {
403 case SMI_NODEKIND_ROW: {
405 oid_key_t* kl = NULL;
406 const oid_value_type_t* typedata = NULL;
409 switch (sN->indexkind) {
410 case SMI_INDEX_INDEX:
412 case SMI_INDEX_AUGMENT:
413 case SMI_INDEX_REORDER:
414 case SMI_INDEX_SPARSE:
415 case SMI_INDEX_EXPAND:
416 sN = smiGetRelatedNode(sN);
418 case SMI_INDEX_UNKNOWN:
419 return OID_KIND_UNKNOWN;
422 implied = sN->implied;
424 for (sE = smiGetFirstElement(sN); sE; sE = smiGetNextElement(sE)) {
425 SmiNode* elNode = smiGetElementNode(sE) ;
426 SmiType* elType = smiGetNodeType(elNode);
428 guint non_implicit_size = 0;
432 non_implicit_size = get_non_implicit_size(elType);
435 typedata = get_typedata(elType);
437 k = g_new(oid_key_t,1);
439 oid1 = smiRenderOID(sN->oidlen, sN->oid, SMI_RENDER_QUALIFIED);
440 oid2 = smiRenderOID(elNode->oidlen, elNode->oid, SMI_RENDER_NAME);
441 k->name = g_strconcat(oid1, ".", oid2, NULL);
446 k->ft_type = typedata ? typedata->ft_type : FT_BYTES;
447 k->display = typedata ? typedata->display : BASE_NONE;
452 k->key_type = typedata->keytype;
453 k->num_subids = typedata->keysize;
456 switch (elType->basetype) {
457 case SMI_BASETYPE_BITS:
458 case SMI_BASETYPE_OCTETSTRING: {
459 k->key_type = OID_KEY_TYPE_BYTES;
460 k->num_subids = non_implicit_size;
463 case SMI_BASETYPE_ENUM:
464 case SMI_BASETYPE_OBJECTIDENTIFIER:
465 case SMI_BASETYPE_INTEGER32:
466 case SMI_BASETYPE_UNSIGNED32:
467 case SMI_BASETYPE_INTEGER64:
468 case SMI_BASETYPE_UNSIGNED64:
469 k->key_type = OID_KEY_TYPE_INTEGER;
473 k->key_type = OID_KEY_TYPE_WRONG;
478 k->key_type = OID_KEY_TYPE_WRONG;
484 if (!*key_p) *key_p = k;
485 if (kl) kl->next = k;
491 switch (kl->key_type) {
492 case OID_KEY_TYPE_BYTES: kl->key_type = OID_KEY_TYPE_IMPLIED_BYTES; break;
493 case OID_KEY_TYPE_STRING: kl->key_type = OID_KEY_TYPE_IMPLIED_STRING; break;
494 case OID_KEY_TYPE_OID: kl->key_type = OID_KEY_TYPE_IMPLIED_OID; break;
501 case SMI_NODEKIND_NODE: return OID_KIND_NODE;
502 case SMI_NODEKIND_SCALAR: return OID_KIND_SCALAR;
503 case SMI_NODEKIND_TABLE: return OID_KIND_TABLE;
504 case SMI_NODEKIND_COLUMN: return OID_KIND_COLUMN;
505 case SMI_NODEKIND_NOTIFICATION: return OID_KIND_NOTIFICATION;
506 case SMI_NODEKIND_GROUP: return OID_KIND_GROUP;
507 case SMI_NODEKIND_COMPLIANCE: return OID_KIND_COMPLIANCE;
508 case SMI_NODEKIND_CAPABILITIES: return OID_KIND_CAPABILITIES;
509 default: return OID_KIND_UNKNOWN;
513 #define IS_ENUMABLE(ft) ( (ft == FT_UINT8) || (ft == FT_UINT16) || (ft == FT_UINT24) || (ft == FT_UINT32) \
514 || (ft == FT_INT8) || (ft == FT_INT16) || (ft == FT_INT24) || (ft == FT_INT32) \
515 || (ft == FT_UINT64) || (ft == FT_INT64) )
517 static void unregister_mibs(void) {
518 /* TODO: Unregister "MIBs" proto and clean up field array and subtree array.
519 * Wireshark does not support that yet. :-( */
524 static void restart_needed_warning(void) {
526 report_failure("Wireshark needs to be restarted for these changes to take effect");
529 static void register_mibs(void) {
530 SmiModule *smiModule;
538 if (!load_smi_modules) {
539 D(1,("OID resolution not enabled"));
543 /* TODO: Remove this workaround when unregistration of "MIBs" proto is solved.
544 * Wireshark does not support that yet. :-( */
545 if (oids_init_done) {
546 D(1,("Exiting register_mibs() to avoid double registration of MIBs proto."));
549 oids_init_done = TRUE;
552 hfa = wmem_array_new(wmem_epan_scope(), sizeof(hf_register_info));
553 etta = g_array_new(FALSE,TRUE,sizeof(gint*));
557 smi_errors = g_string_new("");
558 smiSetErrorHandler(smi_error_handler);
560 path_str = oid_get_default_mib_path();
561 D(1,("SMI Path: '%s'",path_str));
563 smiSetPath(path_str);
565 for(i=0;i<num_smi_modules;i++) {
566 if (!smi_modules[i].name) continue;
568 if (smiIsLoaded(smi_modules[i].name)) {
571 char* mod_name = smiLoadModule(smi_modules[i].name);
573 D(2,("Loaded: '%s'[%u] as %s",smi_modules[i].name,i,mod_name ));
575 D(1,("Failed to load: '%s'[%u]",smi_modules[i].name,i));
579 if (smi_errors->len) {
580 if (!suppress_smi_errors) {
581 report_failure("The following errors were found while loading the MIBS:\n%s\n\n"
582 "The Current Path is: %s\n\nYou can avoid this error message "
583 "by removing the missing MIB modules at Edit -> Preferences"
584 " -> Name Resolution -> SMI (MIB and PIB) modules or by "
585 "installing them.\n" , smi_errors->str , path_str);
587 D(1,("Errors while loading:\n%s\n",smi_errors->str));
591 g_string_free(smi_errors,TRUE);
593 for (smiModule = smiGetFirstModule();
595 smiModule = smiGetNextModule(smiModule)) {
597 D(3,("\tModule: %s", smiModule->name));
599 /* TODO: Check libsmi version at compile time and disable this
600 * workaround for libsmi versions where this problem is fixed.
601 * Currently there is no such version. :-(
603 if (smiModule->conformance == 1) {
604 if (!suppress_smi_errors) {
605 report_failure("Stopped processing module %s due to "
606 "error(s) to prevent potential crash in libsmi.\n"
607 "Module's conformance level: %d.\n"
608 "See details at: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=560325\n",
609 smiModule->name, smiModule->conformance);
613 for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
615 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
617 SmiType* smiType = smiGetNodeType(smiNode);
618 const oid_value_type_t* typedata = get_typedata(smiType);
620 oid_kind_t kind = smikind(smiNode,&key);
622 char *oid = smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_QUALIFIED);
623 oid_info_t* oid_data = add_oid(oid,
631 sub = oid_subid2string(NULL, smiNode->oid, smiNode->oidlen);
632 D(4,("\t\tNode: kind=%d oid=%s name=%s ",
633 oid_data->kind, sub, oid_data->name));
634 wmem_free(NULL, sub);
636 if ( typedata && oid_data->value_hfid == -2 ) {
637 SmiNamedNumber* smiEnum;
640 hf.p_id = &(oid_data->value_hfid);
641 hf.hfinfo.name = g_strdup(oid_data->name);
642 hf.hfinfo.abbrev = alnumerize(oid_data->name);
643 hf.hfinfo.type = typedata->ft_type;
644 hf.hfinfo.display = typedata->display;
645 hf.hfinfo.strings = NULL;
646 hf.hfinfo.bitmask = 0;
647 hf.hfinfo.blurb = smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_ALL);
651 /* Don't allow duplicate blurb/name */
652 if (strcmp(hf.hfinfo.blurb, hf.hfinfo.name) == 0) {
653 smi_free((void *) hf.hfinfo.blurb);
654 hf.hfinfo.blurb = NULL;
657 oid_data->value_hfid = -1;
659 if ( IS_ENUMABLE(hf.hfinfo.type) && (smiEnum = smiGetFirstNamedNumber(smiType))) {
660 GArray* vals = g_array_new(TRUE,TRUE,sizeof(value_string));
662 for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum)) {
665 val.value = (guint32)smiEnum->value.value.integer32;
666 val.strptr = g_strdup(smiEnum->name);
667 g_array_append_val(vals,val);
671 hf.hfinfo.strings = vals->data;
672 g_array_free(vals,FALSE);
674 #if 0 /* packet-snmp does not handle bits yet */
675 } else if (smiType->basetype == SMI_BASETYPE_BITS && ( smiEnum = smiGetFirstNamedNumber(smiType) )) {
677 oid_bits_info_t* bits = g_malloc(sizeof(oid_bits_info_t));
678 gint* ettp = &(bits->ett);
683 g_array_append_val(etta,ettp);
685 for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum), bits->num++);
687 bits->data = g_malloc(sizeof(struct _oid_bit_t)*bits->num);
689 for(smiEnum = smiGetFirstNamedNumber(smiType),n=0;
691 smiEnum = smiGetNextNamedNumber(smiEnum),n++) {
692 guint mask = 1 << (smiEnum->value.value.integer32 % 8);
693 char* base = alnumerize(oid_data->name);
694 char* ext = alnumerize(smiEnum->name);
695 hf_register_info hf2 = { &(bits->data[n].hfid), { NULL, NULL, FT_UINT8, BASE_HEX, NULL, mask, NULL, HFILL }};
697 bits->data[n].hfid = -1;
698 bits->data[n].offset = smiEnum->value.value.integer32 / 8;
700 hf2.hfinfo.name = g_strconcat("%s:%s",oid_data->name, ":", smiEnum->name, NULL);
701 hf2.hfinfo.abbrev = g_strconcat(base, ".", ext, NULL);
705 g_array_append_val(hfa,hf2);
707 #endif /* packet-snmp does not use this yet */
708 wmem_array_append_one(hfa,hf);
711 if ((key = oid_data->key)) {
712 for(; key; key = key->next) {
715 hf.p_id = &(key->hfid);
716 hf.hfinfo.name = key->name;
717 hf.hfinfo.abbrev = alnumerize(key->name);
718 hf.hfinfo.type = key->ft_type;
719 hf.hfinfo.display = key->display;
720 hf.hfinfo.strings = NULL;
721 hf.hfinfo.bitmask = 0;
722 hf.hfinfo.blurb = NULL;
726 D(5,("\t\t\tIndex: name=%s subids=%u key_type=%d",
727 key->name, key->num_subids, key->key_type ));
729 if (key->hfid == -2) {
730 wmem_array_append_one(hfa,hf);
733 g_free((void*)hf.hfinfo.abbrev);
740 proto_mibs = proto_register_protocol("MIBs", "MIBS", "mibs");
742 proto_register_field_array(proto_mibs, (hf_register_info*)wmem_array_get_raw(hfa), wmem_array_get_count(hfa));
744 proto_register_subtree_array((gint**)(void*)etta->data, etta->len);
746 g_array_free(etta,TRUE);
750 void oid_pref_init(module_t *nameres)
753 static uat_field_t smi_fields[] = {
754 UAT_FLD_CSTRING(smi_mod,name,"Module name","The module's name"),
757 static uat_field_t smi_paths_fields[] = {
758 UAT_FLD_DIRECTORYNAME(smi_mod,name,"Directory path","The directory name"),
762 prefs_register_bool_preference(nameres, "load_smi_modules",
763 "Enable OID resolution",
764 "Resolve Object IDs to object names from the MIB and PIB"
765 " modules defined below."
766 " You must restart Wireshark for this change to take effect",
769 prefs_register_bool_preference(nameres, "suppress_smi_errors",
770 "Suppress SMI errors",
771 "While loading MIB or PIB modules errors may be detected,"
772 " which are reported. Some errors can be ignored."
773 " If unsure, set to false.",
774 &suppress_smi_errors);
776 smi_paths_uat = uat_new("SMI Paths",
777 sizeof(smi_module_t),
782 /* affects dissection of packets (as the MIBs and PIBs affect the
783 interpretation of e.g. SNMP variable bindings), but not set of
786 XXX - if named fields are generated from the MIBs and PIBs
787 for particular variable bindings, this *does* affect the set
789 UAT_AFFECTS_DISSECTION,
794 restart_needed_warning,
798 prefs_register_uat_preference(nameres,
800 "SMI (MIB and PIB) paths",
801 "Search paths for SMI (MIB and PIB) modules. You must"
802 " restart Wireshark for these changes to take effect.",
805 smi_modules_uat = uat_new("SMI Modules",
806 sizeof(smi_module_t),
809 (void**)&smi_modules,
811 /* affects dissection of packets (as the MIBs and PIBs affect the
812 interpretation of e.g. SNMP variable bindings), but not set of
815 XXX - if named fields are generated from the MIBs and PIBs
816 for particular variable bindings, would this affect the set
818 UAT_AFFECTS_DISSECTION,
823 restart_needed_warning,
827 prefs_register_uat_preference(nameres,
829 "SMI (MIB and PIB) modules",
830 "List of SMI (MIB and PIB) modules to load. You must"
831 " restart Wireshark for these changes to take effect.",
835 prefs_register_static_text_preference(nameres, "load_smi_modules_static",
836 "Enable OID resolution: N/A",
837 "Support for OID resolution was not compiled into this version of Wireshark");
839 prefs_register_static_text_preference(nameres, "suppress_smi_errors_static",
840 "Suppress SMI errors: N/A",
841 "Support for OID resolution was not compiled into this version of Wireshark");
843 prefs_register_static_text_preference(nameres, "smi_module_path",
844 "SMI (MIB and PIB) modules and paths: N/A",
845 "Support for OID resolution was not compiled into this version of Wireshark");
849 void oids_init(void) {
854 D(1,("libsmi disabled oid resolution not enabled"));
858 void oids_cleanup(void) {
862 D(1,("libsmi disabled oid resolution not enabled"));
866 char* oid_subid2string(wmem_allocator_t *scope, guint32* subids, guint len) {
867 return rel_oid_subid2string(scope, subids, len, TRUE);
869 char* rel_oid_subid2string(wmem_allocator_t *scope, guint32* subids, guint len, gboolean is_absolute) {
871 wmem_strbuf_t *oid_str;
874 if(!subids || len == 0)
875 return wmem_strdup(scope, "*** Empty OID ***");
877 oid_str = wmem_strbuf_new(scope, "");
880 wmem_strbuf_append_c(oid_str, '.');
883 wmem_strbuf_append_printf(oid_str, "%u.",*subids++);
886 /* Remove trailing "." (which is guaranteed to be there) */
887 oid_str_len = wmem_strbuf_get_len(oid_str);
888 wmem_strbuf_truncate(oid_str, oid_str_len - 1);
890 return wmem_strbuf_finalize(oid_str);
893 static guint check_num_oid(const char* str) {
898 D(8,("check_num_oid: '%s'",str));
902 D(9,("\tcheck_num_oid: '%c' %u",*r,n));
906 if (c == '.') return 0;
908 case '1' : case '2' : case '3' : case '4' : case '5' :
909 case '6' : case '7' : case '8' : case '9' : case '0' :
919 guint oid_string2subid(wmem_allocator_t *scope, const char* str, guint32** subids_p) {
922 guint32* subids_overflow;
923 guint n = check_num_oid(str);
925 * we cannot handle sub-ids greater than 32bytes
926 * keep a pilot subid of 64 bytes to check the limit
930 D(6,("oid_string2subid: str='%s'",str));
937 *subids_p = subids = wmem_alloc0_array(scope, guint32, n);
938 subids_overflow = subids + n;
944 case '1' : case '2' : case '3' : case '4' : case '5' :
945 case '6' : case '7' : case '8' : case '9' : case '0' :
949 if( subids >= subids_overflow || subid > 0xffffffff) {
955 *(subids) += *r - '0';
967 guint oid_encoded2subid(wmem_allocator_t *scope, const guint8 *oid_bytes, gint oid_len, guint32** subids_p) {
968 return oid_encoded2subid_sub(scope, oid_bytes, oid_len, subids_p, TRUE);
970 guint oid_encoded2subid_sub(wmem_allocator_t *scope, const guint8 *oid_bytes, gint oid_len, guint32** subids_p,
973 guint n = is_first ? 1 : 0;
975 guint32* subid_overflow;
977 * we cannot handle sub-ids greater than 32bytes
978 * have the subid in 64 bytes to be able to check the limit
982 for (i=0; i<oid_len; i++) { if (! (oid_bytes[i] & 0x80 )) n++; }
984 *subids_p = subids = (guint32 *)wmem_alloc(scope, sizeof(guint32)*n);
985 subid_overflow = subids+n;
987 /* If n is 0 or 1 (depending on how it was initialized) then we found
988 * no bytes in the OID with first bit cleared, so initialize our one
989 * byte (if any) to zero and return. This *seems* to be the right thing
990 * to do in this situation, and at the very least it avoids
991 * uninitialized memory errors that would otherwise occur. */
992 if (is_first && n == 1) {
996 else if (!is_first && n == 0) {
1000 for (i=0; i<oid_len; i++){
1001 guint8 byte = oid_bytes[i];
1004 subid |= byte & 0x7F;
1013 if (subid >= 40) { subid0++; subid-=40; }
1014 if (subid >= 40) { subid0++; subid-=40; }
1021 if( subids >= subid_overflow || subid > 0xffffffff) {
1022 /* scope may be NULL in which case we must free our
1023 * useless buffer before returning */
1024 wmem_free(scope, *subids_p);
1029 *subids++ = (guint32)subid;
1033 g_assert(subids == subid_overflow);
1038 oid_info_t* oid_get(guint len, guint32* subids, guint* matched, guint* left) {
1039 oid_info_t* curr_oid = &oid_root;
1042 if(!(subids && *subids <= 2)) {
1048 for( i=0; i < len; i++) {
1049 oid_info_t* next_oid = (oid_info_t *)wmem_tree_lookup32(curr_oid->children,subids[i]);
1051 curr_oid = next_oid;
1063 oid_info_t* oid_get_from_encoded(wmem_allocator_t *scope, const guint8 *bytes, gint byteslen, guint32** subids_p, guint* matched_p, guint* left_p) {
1064 guint subids_len = oid_encoded2subid(scope, bytes, byteslen, subids_p);
1065 return oid_get(subids_len, *subids_p, matched_p, left_p);
1068 oid_info_t* oid_get_from_string(wmem_allocator_t *scope, const gchar *oid_str, guint32** subids_p, guint* matched, guint* left) {
1069 guint subids_len = oid_string2subid(scope, oid_str, subids_p);
1070 return oid_get(subids_len, *subids_p, matched, left);
1073 gchar *oid_resolved_from_encoded(wmem_allocator_t *scope, const guint8 *oid, gint oid_len) {
1074 guint32 *subid_oid = NULL;
1076 guint subid_oid_length = oid_encoded2subid(NULL, oid, oid_len, &subid_oid);
1078 ret = oid_resolved(scope, subid_oid_length, subid_oid);
1079 wmem_free(NULL, subid_oid);
1083 gchar *rel_oid_resolved_from_encoded(wmem_allocator_t *scope, const guint8 *oid, gint oid_len) {
1084 guint32 *subid_oid = NULL;
1086 guint subid_oid_length = oid_encoded2subid_sub(NULL, oid, oid_len, &subid_oid, FALSE);
1088 ret = rel_oid_subid2string(scope, subid_oid, subid_oid_length, FALSE);
1089 wmem_free(NULL, subid_oid);
1094 guint oid_subid2encoded(wmem_allocator_t *scope, guint subids_len, guint32* subids, guint8** bytes_p) {
1100 if ( !subids || subids_len <= 1) {
1105 for (subid=subids[0] * 40, i = 1; i<subids_len; i++, subid=0) {
1107 if (subid <= 0x0000007F) {
1109 } else if (subid <= 0x00003FFF ) {
1111 } else if (subid <= 0x001FFFFF ) {
1113 } else if (subid <= 0x0FFFFFFF ) {
1120 *bytes_p = b = (guint8 *)wmem_alloc(scope, bytelen);
1122 for (subid=subids[0] * 40, i = 1; i<subids_len; i++, subid=0) {
1126 if ((subid <= 0x0000007F )) len = 1;
1127 else if ((subid <= 0x00003FFF )) len = 2;
1128 else if ((subid <= 0x001FFFFF )) len = 3;
1129 else if ((subid <= 0x0FFFFFFF )) len = 4;
1133 default: *bytes_p=NULL; return 0;
1134 case 5: *(b++) = ((subid & 0xF0000000) >> 28) | 0x80;
1136 case 4: *(b++) = ((subid & 0x0FE00000) >> 21) | 0x80;
1138 case 3: *(b++) = ((subid & 0x001FC000) >> 14) | 0x80;
1140 case 2: *(b++) = ((subid & 0x00003F80) >> 7) | 0x80;
1142 case 1: *(b++) = subid & 0x0000007F ; break;
1149 gchar* oid_encoded2string(wmem_allocator_t *scope, const guint8* encoded, guint len) {
1150 guint32* subids = NULL;
1152 guint subids_len = oid_encoded2subid(NULL, encoded, len, &subids);
1155 ret = oid_subid2string(scope, subids,subids_len);
1157 ret = wmem_strdup(scope, "");
1160 wmem_free(NULL, subids);
1164 gchar* rel_oid_encoded2string(wmem_allocator_t *scope, const guint8* encoded, guint len) {
1165 guint32* subids = NULL;
1167 guint subids_len = oid_encoded2subid_sub(NULL, encoded, len, &subids, FALSE);
1170 ret = rel_oid_subid2string(scope, subids,subids_len, FALSE);
1172 ret = wmem_strdup(scope, "");
1175 wmem_free(NULL, subids);
1179 guint oid_string2encoded(wmem_allocator_t *scope, const char *oid_str, guint8 **bytes) {
1184 if ( (subids_len = oid_string2subid(NULL, oid_str, &subids)) &&
1185 (byteslen = oid_subid2encoded(scope, subids_len, subids, bytes)) ) {
1186 wmem_free(NULL, subids);
1189 wmem_free(NULL, subids);
1193 gchar *oid_resolved_from_string(wmem_allocator_t *scope, const gchar *oid_str) {
1195 guint subid_oid_length;
1198 subid_oid_length = oid_string2subid(NULL, oid_str, &subid_oid);
1199 resolved = oid_resolved(scope, subid_oid_length, subid_oid);
1201 wmem_free(NULL, subid_oid);
1206 gchar *oid_resolved(wmem_allocator_t *scope, guint32 num_subids, guint32* subids) {
1211 if(! (subids && *subids <= 2 ))
1212 return wmem_strdup(scope, "*** Malformed OID ***");
1214 oid = oid_get(num_subids, subids, &matched, &left);
1216 while (! oid->name ) {
1217 if (!(oid = oid->parent)) {
1218 return oid_subid2string(scope, subids,num_subids);
1226 *str1 = oid_subid2string(NULL, subids,matched),
1227 *str2 = oid_subid2string(NULL, &(subids[matched]),left);
1229 ret = wmem_strconcat(scope, oid->name ? oid->name : str1, ".", str2, NULL);
1230 wmem_free(NULL, str1);
1231 wmem_free(NULL, str2);
1234 return oid->name ? wmem_strdup(scope, oid->name) : oid_subid2string(scope, subids,matched);
1238 extern void oid_both(wmem_allocator_t *scope, guint oid_len, guint32 *subids, gchar** resolved_p, gchar** numeric_p) {
1239 *resolved_p = oid_resolved(scope, oid_len,subids);
1240 *numeric_p = oid_subid2string(scope, subids,oid_len);
1243 extern void oid_both_from_encoded(wmem_allocator_t *scope, const guint8 *oid, gint oid_len, gchar** resolved_p, gchar** numeric_p) {
1244 guint32* subids = NULL;
1245 guint subids_len = oid_encoded2subid(NULL, oid, oid_len, &subids);
1246 *resolved_p = oid_resolved(scope, subids_len,subids);
1247 *numeric_p = oid_subid2string(scope, subids,subids_len);
1248 wmem_free(NULL, subids);
1251 void oid_both_from_string(wmem_allocator_t *scope, const gchar *oid_str, gchar** resolved_p, gchar** numeric_p) {
1255 subids_len = oid_string2subid(NULL, oid_str, &subids);
1256 *resolved_p = oid_resolved(scope, subids_len,subids);
1257 *numeric_p = oid_subid2string(scope, subids,subids_len);
1258 wmem_free(NULL, subids);
1262 * Fetch the default OID path.
1265 oid_get_default_mib_path(void) {
1271 path_str = g_string_new("");
1273 if (!load_smi_modules) {
1274 D(1,("OID resolution not enabled"));
1275 return path_str->str;
1278 #define PATH_SEPARATOR ";"
1279 path = get_datafile_path("snmp\\mibs");
1280 g_string_append_printf(path_str, "%s;", path);
1283 path = get_persconffile_path("snmp\\mibs", FALSE);
1284 g_string_append_printf(path_str, "%s", path);
1287 #define PATH_SEPARATOR ":"
1288 path = smiGetPath();
1289 g_string_append(path_str, "/usr/share/snmp/mibs");
1290 if (strlen(path) > 0 ) {
1291 g_string_append(path_str, PATH_SEPARATOR);
1293 g_string_append_printf(path_str, "%s", path);
1297 for(i=0;i<num_smi_paths;i++) {
1298 if (!( smi_paths[i].name && *smi_paths[i].name))
1301 g_string_append_printf(path_str,PATH_SEPARATOR "%s",smi_paths[i].name);
1304 return g_string_free(path_str, FALSE);
1305 #else /* HAVE_LIBSMI */
1306 return g_strdup("");
1311 char* oid_test_a2b(guint32 num_subids, guint32* subids) {
1312 guint8* sub2enc = NULL;
1313 guint8* str2enc = NULL;
1314 guint32* enc2sub = NULL;
1317 char* sub2str = oid_subid2string(NULL, subids, num_subids);
1318 guint sub2enc_len = oid_subid2encoded(NULL, num_subids, subids,&sub2enc);
1319 guint enc2sub_len = oid_encoded2subid(NULL, sub2enc, sub2enc_len, &enc2sub);
1320 char* enc2str = oid_encoded2string(NULL, sub2enc, sub2enc_len);
1321 guint str2enc_len = oid_string2encoded(NULL, sub2str,&str2enc);
1322 guint str2sub_len = oid_string2subid(sub2str,&str2sub);
1324 ret = wmem_strdup_printf(wmem_packet_scope(),
1325 "oid_subid2string=%s \n"
1326 "oid_subid2encoded=[%d]%s \n"
1327 "oid_encoded2subid=%s \n "
1328 "oid_encoded2string=%s \n"
1329 "oid_string2encoded=[%d]%s \n"
1330 "oid_string2subid=%s \n "
1332 ,sub2enc_len,bytestring_to_str(wmem_packet_scope(), sub2enc, sub2enc_len, ':')
1333 ,enc2sub ? oid_subid2string(wmem_packet_scope(), enc2sub,enc2sub_len) : "-"
1335 ,str2enc_len,bytestring_to_str(wmem_packet_scope(), str2enc, str2enc_len, ':')
1336 ,str2sub ? oid_subid2string(wmem_packet_scope(), str2sub,str2sub_len) : "-"
1339 wmem_free(NULL, sub2str);
1340 wmem_free(NULL, enc2sub);
1341 wmem_free(NULL, sub2enc);
1342 wmem_free(NULL, str2enc);
1343 wmem_free(NULL, enc2str);
1347 void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree) {
1348 static const char* oid_kinds[] = { "Unknown", "Node", "Scalar", "Table", "Row", "Column", "Notification", "Group", "Compliance", "Capabilities"};
1349 static const char* key_types[] = {"OID_KEY_TYPE_WRONG","OID_KEY_TYPE_INTEGER",
1350 "OID_KEY_TYPE_FIXED_STRING","OID_KEY_TYPE_FIXED_BYTES","OID_KEY_TYPE_STRING",
1351 "OID_KEY_TYPE_BYTES","OID_KEY_TYPE_NSAP","OID_KEY_TYPE_OID","OID_KEY_TYPE_IPADDR"};
1352 proto_item* pi = proto_tree_add_debug_text(tree,NULL,0,0,
1353 "OidInfo: Name='%s' sub-id=%u kind=%s hfid=%d",
1354 oid_info->name ? oid_info->name : "",
1356 oid_info->kind <= OID_KIND_CAPABILITIES ? oid_kinds[oid_info->kind] : "BROKEN",
1357 oid_info->value_hfid);
1358 proto_tree* pt = proto_item_add_subtree(pi,0);
1361 for(key = oid_info->key; key; key = key->next) {
1362 proto_tree_add_debug_text(pt,NULL,0,0,
1363 "Key: name='%s' num_subids=%d type=%s",
1365 key->key_type <= OID_KEY_TYPE_IPADDR ? key_types[key->key_type] : "BROKEN"
1369 if (oid_info->parent) {
1370 pi = proto_tree_add_debug_text(pt,NULL,0,0,"Parent:");
1371 pt = proto_item_add_subtree(pi,0);
1372 add_oid_debug_subtree(oid_info->parent, pt);
1383 * indent-tabs-mode: t
1386 * ex: set shiftwidth=8 tabstop=8 noexpandtab:
1387 * :indentSize=8:tabSize=8:noTabs=false: