2 * Object IDentifier Support
4 * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include <wsutil/report_err.h>
37 #include "wmem/wmem.h"
42 #include "filesystem.h"
43 #include "dissectors/packet-ber.h"
48 static gboolean oids_init_done
= FALSE
;
49 static gboolean load_smi_modules
= FALSE
;
50 static gboolean suppress_smi_errors
= FALSE
;
53 #define D(level,args) do if (debuglevel >= level) { printf args; printf("\n"); fflush(stdout); } while(0)
57 static int debuglevel
= 0;
60 * From SNMPv2-SMI and X.690
62 * Counter32 ::= [APPLICATION 1] IMPLICIT INTEGER (0..4294967295)
63 * Gauge32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
64 * Unsigned32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) (alias of Gauge32)
65 * TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
67 * If the BER encoding should not have the top bit set as to not become a negative number
68 * the BER encoding may take 5 octets to encode.
71 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};
72 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};
73 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};
74 static const oid_value_type_t ipv4_type
= { FT_IPv4
, BASE_NONE
, BER_CLASS_APP
, 0, 4, 4, OID_KEY_TYPE_IPADDR
, 4};
75 static const oid_value_type_t counter32_type
= { FT_UINT64
, BASE_DEC
, BER_CLASS_APP
, 1, 1, 5, OID_KEY_TYPE_INTEGER
, 1};
76 static const oid_value_type_t unsigned32_type
= { FT_UINT64
, BASE_DEC
, BER_CLASS_APP
, 2, 1, 5, OID_KEY_TYPE_INTEGER
, 1};
77 static const oid_value_type_t timeticks_type
= { FT_UINT64
, BASE_DEC
, BER_CLASS_APP
, 3, 1, 5, OID_KEY_TYPE_INTEGER
, 1};
79 static const oid_value_type_t opaque_type
= { FT_BYTES
, BASE_NONE
, BER_CLASS_APP
, 4, 1, 4, OID_KEY_TYPE_BYTES
, 0};
81 static const oid_value_type_t nsap_type
= { FT_BYTES
, BASE_NONE
, BER_CLASS_APP
, 5, 0, -1, OID_KEY_TYPE_NSAP
, 0};
82 static const oid_value_type_t counter64_type
= { FT_UINT64
, BASE_DEC
, BER_CLASS_APP
, 6, 1, 8, OID_KEY_TYPE_INTEGER
, 1};
83 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};
84 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};
85 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};
86 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};
87 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};
88 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};
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 D(3,("\tOid (from subids): %s %s ",name
?name
:"NULL", oid_subid2string(subids
,oid_len
)));
175 add_oid(name
,OID_KIND_UNKNOWN
,NULL
,NULL
,oid_len
,subids
);
177 D(1,("Failed to add Oid: %s (from subids)",name
?name
:"NULL"));
181 void oid_add_from_string(const char* name
, const gchar
*oid_str
) {
183 guint oid_len
= oid_string2subid(oid_str
, &subids
);
186 D(3,("\tOid (from string): %s %s ",name
?name
:"NULL", oid_subid2string(subids
,oid_len
)));
187 add_oid(name
,OID_KIND_UNKNOWN
,NULL
,NULL
,oid_len
,subids
);
189 D(1,("Failed to add Oid: %s %s ",name
?name
:"NULL", oid_str
?oid_str
:NULL
));
193 extern void oid_add_from_encoded(const char* name
, const guint8
*oid
, gint oid_len
) {
195 guint subids_len
= oid_encoded2subid(oid
, oid_len
, &subids
);
198 D(3,("\tOid (from encoded): %s %s ",name
, oid_subid2string(subids
,subids_len
)));
199 add_oid(name
,OID_KIND_UNKNOWN
,NULL
,NULL
,subids_len
,subids
);
201 D(1,("Failed to add Oid: %s [%d]%s ",name
?name
:"NULL", oid_len
,bytestring_to_str(oid
, oid_len
, ':')));
206 /* de-allocate storage mallocated by libsmi */
208 /* XXX: libsmi provides access to smiFree as of libsmi v 0.4.8. */
209 /* On Windows: Wireshark 1.01 and later is built and distributed */
210 /* with libsmi 0.4.8 (or newer). */
211 /* On non-Windows systems, free() should be OK for libsmi */
212 /* versions older than 0.4.8. */
214 static void smi_free(void *ptr
) {
216 #if (SMI_VERSION_MAJOR >= 0) && (SMI_VERSION_MINOR >= 4) && (SMI_VERSION_PATCHLEVEL >= 8)
220 #error Invalid Windows libsmi version ?? !!
222 #define xx_free free /* hack so checkAPIs.pl doesn't complain */
228 typedef struct smi_module_t
{
232 static smi_module_t
* smi_paths
= NULL
;
233 static guint num_smi_paths
= 0;
234 static uat_t
* smi_paths_uat
= NULL
;
236 static smi_module_t
* smi_modules
= NULL
;
237 static guint num_smi_modules
= 0;
238 static uat_t
* smi_modules_uat
= NULL
;
240 static GString
* smi_errors
;
242 UAT_DIRECTORYNAME_CB_DEF(smi_mod
,name
,smi_module_t
)
244 static void smi_error_handler(char *path
, int line
, int severity
, char *msg
, char *tag
) {
245 g_string_append_printf(smi_errors
,"%s:%d %d %s %s\n",
253 static void* smi_mod_copy_cb(void* dest
, const void* orig
, size_t len _U_
) {
254 const smi_module_t
* m
= (const smi_module_t
*)orig
;
255 smi_module_t
* d
= (smi_module_t
*)dest
;
257 d
->name
= g_strdup(m
->name
);
262 static void smi_mod_free_cb(void* p
) {
263 smi_module_t
* m
= (smi_module_t
*)p
;
268 static char* alnumerize(const char* name
) {
269 char* s
= g_strdup(name
);
274 for (;(c
= *r
); r
++) {
275 if (isalnum(c
) || c
== '_' || c
== '-' || c
== '.') {
277 } else if (c
== ':' && r
[1] == ':') {
287 static const oid_value_type_t
* get_typedata(SmiType
* smiType
) {
289 * There has to be a better way to know if a given
290 * OCTETSTRING type is actually human readable text,
291 * an address of some type or some moe specific FT_
292 * Until that is found, this is the mappping between
293 * SNMP Types and our FT_s
295 static const struct _type_mapping_t
{
298 const oid_value_type_t
* type
;
300 {"IpAddress", SMI_BASETYPE_UNKNOWN
, &ipv4_type
},
301 {"InetAddressIPv4",SMI_BASETYPE_UNKNOWN
,&ipv4_type
},
302 {"InetAddressIPv6",SMI_BASETYPE_UNKNOWN
,&ipv6_type
},
303 {"NetworkAddress",SMI_BASETYPE_UNKNOWN
,&ipv4_type
},
304 {"MacAddress",SMI_BASETYPE_UNKNOWN
,ðer_type
},
305 {"TimeTicks",SMI_BASETYPE_UNKNOWN
,&timeticks_type
},
306 {"Ipv6Address",SMI_BASETYPE_UNKNOWN
,&ipv6_type
},
307 {"TimeStamp",SMI_BASETYPE_UNKNOWN
,&timeticks_type
},
308 {"DisplayString",SMI_BASETYPE_UNKNOWN
,&string_type
},
309 {"SnmpAdminString",SMI_BASETYPE_UNKNOWN
,&string_type
},
310 {"DateAndTime",SMI_BASETYPE_UNKNOWN
,&date_and_time_type
},
311 {"Counter",SMI_BASETYPE_UNKNOWN
,&counter32_type
},
312 {"Counter32",SMI_BASETYPE_UNKNOWN
,&counter32_type
},
313 {"Unsigned32",SMI_BASETYPE_UNKNOWN
,&unsigned32_type
},
314 {"Gauge",SMI_BASETYPE_UNKNOWN
,&unsigned32_type
},
315 {"Gauge32",SMI_BASETYPE_UNKNOWN
,&unsigned32_type
},
316 {"NsapAddress",SMI_BASETYPE_UNKNOWN
,&nsap_type
},
317 {"i32",SMI_BASETYPE_INTEGER32
,&integer_type
},
318 {"octets",SMI_BASETYPE_OCTETSTRING
,&bytes_type
},
319 {"oid",SMI_BASETYPE_OBJECTIDENTIFIER
,&oid_type
},
320 {"u32",SMI_BASETYPE_UNSIGNED32
,&unsigned32_type
},
321 {"u64",SMI_BASETYPE_UNSIGNED64
,&counter64_type
},
322 {"f32",SMI_BASETYPE_FLOAT32
,&float_type
},
323 {"f64",SMI_BASETYPE_FLOAT64
,&double_type
},
324 {"f128",SMI_BASETYPE_FLOAT128
,&bytes_type
},
325 {"enum",SMI_BASETYPE_ENUM
,&integer_type
},
326 {"bits",SMI_BASETYPE_BITS
,&bytes_type
},
327 {"unk",SMI_BASETYPE_UNKNOWN
,&unknown_type
},
328 {NULL
,SMI_BASETYPE_UNKNOWN
,NULL
} /* SMI_BASETYPE_UNKNOWN = 0 */
330 const struct _type_mapping_t
* t
;
331 SmiType
* sT
= smiType
;
333 if (!smiType
) return NULL
;
336 for (t
= types
; t
->type
; t
++ ) {
337 char* name
= smiRenderType(sT
, SMI_RENDER_NAME
);
338 if (name
&& t
->name
&& g_str_equal(name
, t
->name
)) {
346 } while(( sT
= smiGetParentType(sT
) ));
348 for (t
= types
; t
->type
; t
++ ) {
349 if(smiType
->basetype
== t
->base
) {
354 return &unknown_type
;
357 static guint
get_non_implicit_size(SmiType
* sT
) {
359 guint size
= 0xffffffff;
361 switch (sT
->basetype
) {
362 case SMI_BASETYPE_OCTETSTRING
:
363 case SMI_BASETYPE_OBJECTIDENTIFIER
:
369 for ( ; sT
; sT
= smiGetParentType(sT
) ) {
370 for (sR
= smiGetFirstRange(sT
); sR
; sR
= smiGetNextRange(sR
)) {
371 if (size
== 0xffffffff) {
372 if (sR
->minValue
.value
.unsigned32
== sR
->maxValue
.value
.unsigned32
) {
373 size
= (guint32
)sR
->minValue
.value
.unsigned32
;
378 if (sR
->minValue
.value
.unsigned32
!= size
|| sR
->maxValue
.value
.unsigned32
!= size
) {
385 return size
== 0xffffffff ? 0 : size
;
389 static inline oid_kind_t
smikind(SmiNode
* sN
, oid_key_t
** key_p
) {
392 switch(sN
->nodekind
) {
393 case SMI_NODEKIND_ROW
: {
395 oid_key_t
* kl
= NULL
;
396 const oid_value_type_t
* typedata
= NULL
;
399 switch (sN
->indexkind
) {
400 case SMI_INDEX_INDEX
:
402 case SMI_INDEX_AUGMENT
:
403 case SMI_INDEX_REORDER
:
404 case SMI_INDEX_SPARSE
:
405 case SMI_INDEX_EXPAND
:
406 sN
= smiGetRelatedNode(sN
);
408 case SMI_INDEX_UNKNOWN
:
409 return OID_KIND_UNKNOWN
;
412 implied
= sN
->implied
;
414 for (sE
= smiGetFirstElement(sN
); sE
; sE
= smiGetNextElement(sE
)) {
415 SmiNode
* elNode
= smiGetElementNode(sE
) ;
416 SmiType
* elType
= smiGetNodeType(elNode
);
418 guint non_implicit_size
= 0;
422 non_implicit_size
= get_non_implicit_size(elType
);
425 typedata
= get_typedata(elType
);
427 k
= g_new(oid_key_t
,1);
429 oid1
= smiRenderOID(sN
->oidlen
, sN
->oid
, SMI_RENDER_QUALIFIED
);
430 oid2
= smiRenderOID(elNode
->oidlen
, elNode
->oid
, SMI_RENDER_NAME
);
431 k
->name
= g_strdup_printf("%s.%s", oid1
, oid2
);
436 k
->ft_type
= typedata
? typedata
->ft_type
: FT_BYTES
;
437 k
->display
= typedata
? typedata
->display
: BASE_NONE
;
442 k
->key_type
= typedata
->keytype
;
443 k
->num_subids
= typedata
->keysize
;
446 switch (elType
->basetype
) {
447 case SMI_BASETYPE_BITS
:
448 case SMI_BASETYPE_OCTETSTRING
: {
449 k
->key_type
= OID_KEY_TYPE_BYTES
;
450 k
->num_subids
= non_implicit_size
;
453 case SMI_BASETYPE_ENUM
:
454 case SMI_BASETYPE_OBJECTIDENTIFIER
:
455 case SMI_BASETYPE_INTEGER32
:
456 case SMI_BASETYPE_UNSIGNED32
:
457 case SMI_BASETYPE_INTEGER64
:
458 case SMI_BASETYPE_UNSIGNED64
:
459 k
->key_type
= OID_KEY_TYPE_INTEGER
;
463 k
->key_type
= OID_KEY_TYPE_WRONG
;
468 k
->key_type
= OID_KEY_TYPE_WRONG
;
474 if (!*key_p
) *key_p
= k
;
475 if (kl
) kl
->next
= k
;
481 switch (kl
->key_type
) {
482 case OID_KEY_TYPE_BYTES
: kl
->key_type
= OID_KEY_TYPE_IMPLIED_BYTES
; break;
483 case OID_KEY_TYPE_STRING
: kl
->key_type
= OID_KEY_TYPE_IMPLIED_STRING
; break;
484 case OID_KEY_TYPE_OID
: kl
->key_type
= OID_KEY_TYPE_IMPLIED_OID
; break;
491 case SMI_NODEKIND_NODE
: return OID_KIND_NODE
;
492 case SMI_NODEKIND_SCALAR
: return OID_KIND_SCALAR
;
493 case SMI_NODEKIND_TABLE
: return OID_KIND_TABLE
;
494 case SMI_NODEKIND_COLUMN
: return OID_KIND_COLUMN
;
495 case SMI_NODEKIND_NOTIFICATION
: return OID_KIND_NOTIFICATION
;
496 case SMI_NODEKIND_GROUP
: return OID_KIND_GROUP
;
497 case SMI_NODEKIND_COMPLIANCE
: return OID_KIND_COMPLIANCE
;
498 case SMI_NODEKIND_CAPABILITIES
: return OID_KIND_CAPABILITIES
;
499 default: return OID_KIND_UNKNOWN
;
503 #define IS_ENUMABLE(ft) ( (ft == FT_UINT8) || (ft == FT_UINT16) || (ft == FT_UINT24) || (ft == FT_UINT32) \
504 || (ft == FT_INT8) || (ft == FT_INT16) || (ft == FT_INT24) || (ft == FT_INT32) \
505 || (ft == FT_UINT64) || (ft == FT_INT64) )
507 static void unregister_mibs(void) {
508 /* TODO: Unregister "MIBs" proto and clean up field array and subtree array.
509 * Wireshark does not support that yet. :-( */
514 static void restart_needed_warning(void) {
516 report_failure("Wireshark needs to be restarted for these changes to take effect");
519 static void register_mibs(void) {
520 SmiModule
*smiModule
;
528 if (!load_smi_modules
) {
529 D(1,("OID resolution not enabled"));
533 /* TODO: Remove this workaround when unregistration of "MIBs" proto is solved.
534 * Wireshark does not support that yet. :-( */
535 if (oids_init_done
) {
536 D(1,("Exiting register_mibs() to avoid double registration of MIBs proto."));
539 oids_init_done
= TRUE
;
542 hfa
= wmem_array_new(wmem_epan_scope(), sizeof(hf_register_info
));
543 etta
= g_array_new(FALSE
,TRUE
,sizeof(gint
*));
547 smi_errors
= g_string_new("");
548 smiSetErrorHandler(smi_error_handler
);
550 path_str
= oid_get_default_mib_path();
551 D(1,("SMI Path: '%s'",path_str
));
553 smiSetPath(path_str
);
555 for(i
=0;i
<num_smi_modules
;i
++) {
556 if (!smi_modules
[i
].name
) continue;
558 if (smiIsLoaded(smi_modules
[i
].name
)) {
561 char* mod_name
= smiLoadModule(smi_modules
[i
].name
);
563 D(2,("Loaded: '%s'[%d] as %s",smi_modules
[i
].name
,i
,mod_name
));
565 D(1,("Failed to load: '%s'[%d]",smi_modules
[i
].name
,i
));
569 if (smi_errors
->len
) {
570 if (!suppress_smi_errors
) {
571 report_failure("The following errors were found while loading the MIBS:\n%s\n\n"
572 "The Current Path is: %s\n\nYou can avoid this error message "
573 "by removing the missing MIB modules at Edit -> Preferences"
574 " -> Name Resolution -> SMI (MIB and PIB) modules or by "
575 "installing them.\n" , smi_errors
->str
, path_str
);
577 D(1,("Errors while loading:\n%s\n",smi_errors
->str
));
581 g_string_free(smi_errors
,TRUE
);
583 for (smiModule
= smiGetFirstModule();
585 smiModule
= smiGetNextModule(smiModule
)) {
587 D(3,("\tModule: %s", smiModule
->name
));
589 /* TODO: Check libsmi version at compile time and disable this
590 * workaround for libsmi versions where this problem is fixed.
591 * Currently there is no such version. :-(
593 if (smiModule
->conformance
== 1) {
594 if (!suppress_smi_errors
) {
595 report_failure("Stopped processing module %s due to "
596 "error(s) to prevent potential crash in libsmi.\n"
597 "Module's conformance level: %d.\n"
598 "See details at: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=560325\n",
599 smiModule
->name
, smiModule
->conformance
);
603 for (smiNode
= smiGetFirstNode(smiModule
, SMI_NODEKIND_ANY
);
605 smiNode
= smiGetNextNode(smiNode
, SMI_NODEKIND_ANY
)) {
607 SmiType
* smiType
= smiGetNodeType(smiNode
);
608 const oid_value_type_t
* typedata
= get_typedata(smiType
);
610 oid_kind_t kind
= smikind(smiNode
,&key
);
611 char *oid
= smiRenderOID(smiNode
->oidlen
, smiNode
->oid
, SMI_RENDER_QUALIFIED
);
612 oid_info_t
* oid_data
= add_oid(oid
,
620 D(4,("\t\tNode: kind=%d oid=%s name=%s ",
621 oid_data
->kind
, oid_subid2string(smiNode
->oid
, smiNode
->oidlen
), oid_data
->name
));
623 if ( typedata
&& oid_data
->value_hfid
== -2 ) {
624 SmiNamedNumber
* smiEnum
;
625 hf_register_info hf
= { &(oid_data
->value_hfid
), {
627 alnumerize(oid_data
->name
),
632 smiRenderOID(smiNode
->oidlen
, smiNode
->oid
, SMI_RENDER_ALL
),
635 /* Don't allow duplicate blurb/name */
636 if (strcmp(hf
.hfinfo
.blurb
, hf
.hfinfo
.name
) == 0) {
637 smi_free((void *) hf
.hfinfo
.blurb
);
638 hf
.hfinfo
.blurb
= NULL
;
641 oid_data
->value_hfid
= -1;
643 if ( IS_ENUMABLE(hf
.hfinfo
.type
) && (smiEnum
= smiGetFirstNamedNumber(smiType
))) {
644 GArray
* vals
= g_array_new(TRUE
,TRUE
,sizeof(value_string
));
646 for(;smiEnum
; smiEnum
= smiGetNextNamedNumber(smiEnum
)) {
648 value_string val
= {(guint32
)smiEnum
->value
.value
.integer32
,g_strdup(smiEnum
->name
)};
649 g_array_append_val(vals
,val
);
653 hf
.hfinfo
.strings
= vals
->data
;
654 g_array_free(vals
,FALSE
);
656 #if 0 /* packet-snmp does not handle bits yet */
657 } else if (smiType
->basetype
== SMI_BASETYPE_BITS
&& ( smiEnum
= smiGetFirstNamedNumber(smiType
) )) {
659 oid_bits_info_t
* bits
= g_malloc(sizeof(oid_bits_info_t
));
660 gint
* ettp
= &(bits
->ett
);
665 g_array_append_val(etta
,ettp
);
667 for(;smiEnum
; smiEnum
= smiGetNextNamedNumber(smiEnum
), bits
->num
++);
669 bits
->data
= g_malloc(sizeof(struct _oid_bit_t
)*bits
->num
);
671 for(smiEnum
= smiGetFirstNamedNumber(smiType
),n
=0;
673 smiEnum
= smiGetNextNamedNumber(smiEnum
),n
++) {
674 guint mask
= 1 << (smiEnum
->value
.value
.integer32
% 8);
675 char* base
= alnumerize(oid_data
->name
);
676 char* ext
= alnumerize(smiEnum
->name
);
677 hf_register_info hf2
= { &(bits
->data
[n
].hfid
), { NULL
, NULL
, FT_UINT8
, BASE_HEX
, NULL
, mask
, NULL
, HFILL
}};
679 bits
->data
[n
].hfid
= -1;
680 bits
->data
[n
].offset
= smiEnum
->value
.value
.integer32
/ 8;
682 hf2
.hfinfo
.name
= g_strdup_printf("%s:%s",oid_data
->name
,smiEnum
->name
);
683 hf2
.hfinfo
.abbrev
= g_strdup_printf("%s.%s",base
,ext
);
687 g_array_append_val(hfa
,hf2
);
689 #endif /* packet-snmp does not use this yet */
690 wmem_array_append_one(hfa
,hf
);
693 if ((key
= oid_data
->key
)) {
694 for(; key
; key
= key
->next
) {
695 hf_register_info hf
= { &(key
->hfid
), {
697 alnumerize(key
->name
),
705 D(5,("\t\t\tIndex: name=%s subids=%d key_type=%d",
706 key
->name
, key
->num_subids
, key
->key_type
));
708 if (key
->hfid
== -2) {
709 wmem_array_append_one(hfa
,hf
);
712 g_free((void*)hf
.hfinfo
.abbrev
);
719 proto_mibs
= proto_register_protocol("MIBs", "MIBS", "mibs");
721 proto_register_field_array(proto_mibs
, (hf_register_info
*)wmem_array_get_raw(hfa
), wmem_array_get_count(hfa
));
723 proto_register_subtree_array((gint
**)(void*)etta
->data
, etta
->len
);
725 g_array_free(etta
,TRUE
);
729 void oid_pref_init(module_t
*nameres
)
732 static uat_field_t smi_fields
[] = {
733 UAT_FLD_CSTRING(smi_mod
,name
,"Module name","The module's name"),
736 static uat_field_t smi_paths_fields
[] = {
737 UAT_FLD_DIRECTORYNAME(smi_mod
,name
,"Directory path","The directory name"),
741 prefs_register_bool_preference(nameres
, "load_smi_modules",
742 "Enable OID resolution",
743 "You must restart Wireshark for this change to take effect",
746 prefs_register_bool_preference(nameres
, "suppress_smi_errors",
747 "Suppress SMI errors",
748 "Some errors can be ignored. If unsure, set to false.",
749 &suppress_smi_errors
);
751 smi_paths_uat
= uat_new("SMI Paths",
752 sizeof(smi_module_t
),
757 /* affects dissection of packets (as the MIBs and PIBs affect the
758 interpretation of e.g. SNMP variable bindings), but not set of
761 XXX - if named fields are generated from the MIBs and PIBs
762 for particular variable bindings, this *does* affect the set
764 UAT_AFFECTS_DISSECTION
,
769 restart_needed_warning
,
772 prefs_register_uat_preference(nameres
,
774 "SMI (MIB and PIB) paths",
775 "Search paths for SMI (MIB and PIB) modules. You must\n"
776 "restart Wireshark for these changes to take effect.",
779 smi_modules_uat
= uat_new("SMI Modules",
780 sizeof(smi_module_t
),
783 (void**)&smi_modules
,
785 /* affects dissection of packets (as the MIBs and PIBs affect the
786 interpretation of e.g. SNMP variable bindings), but not set of
789 XXX - if named fields are generated from the MIBs and PIBs
790 for particular variable bindings, would this affect the set
792 UAT_AFFECTS_DISSECTION
,
797 restart_needed_warning
,
800 prefs_register_uat_preference(nameres
,
802 "SMI (MIB and PIB) modules",
803 "List of enabled SMI (MIB and PIB) modules. You must\n"
804 "restart Wireshark for these changes to take effect.",
808 prefs_register_static_text_preference(nameres
, "load_smi_modules_static",
809 "Enable OID resolution: N/A",
810 "Support for OID resolution was not compiled into this version of Wireshark");
812 prefs_register_static_text_preference(nameres
, "suppress_smi_errors_static",
813 "Suppress SMI errors: N/A",
814 "Support for OID resolution was not compiled into this version of Wireshark");
816 prefs_register_static_text_preference(nameres
, "smi_module_path",
817 "SMI (MIB and PIB) modules and paths: N/A",
818 "Support for OID resolution was not compiled into this version of Wireshark");
822 void oids_init(void) {
827 D(1,("libsmi disabled oid resolution not enabled"));
831 void oids_cleanup(void) {
835 D(1,("libsmi disabled oid resolution not enabled"));
839 const char* oid_subid2string(guint32
* subids
, guint len
) {
840 return rel_oid_subid2string(subids
, len
, TRUE
);
842 const char* rel_oid_subid2string(guint32
* subids
, guint len
, gboolean is_absolute
) {
845 if(!subids
|| len
== 0)
846 return "*** Empty OID ***";
848 s
= (char *)ep_alloc0(((len
)*11)+2);
855 w
+= g_snprintf(w
,12,"%u.",*subids
++);
858 if (w
!=s
) *(w
-1) = '\0'; else *(s
) = '\0';
863 static guint
check_num_oid(const char* str
) {
868 D(8,("check_num_oid: '%s'",str
));
872 D(9,("\tcheck_num_oid: '%c' %d",*r
,n
));
876 if (c
== '.') return 0;
878 case '1' : case '2' : case '3' : case '4' : case '5' :
879 case '6' : case '7' : case '8' : case '9' : case '0' :
889 guint
oid_string2subid(const char* str
, guint32
** subids_p
) {
892 guint32
* subids_overflow
;
893 guint n
= check_num_oid(str
);
895 * we cannot handle sub-ids greater than 32bytes
896 * keep a pilot subid of 64 bytes to check the limit
900 D(6,("oid_string2subid: str='%s'",str
));
907 *subids_p
= subids
= (guint32
*)ep_alloc0(sizeof(guint32
)*n
);
908 subids_overflow
= subids
+ n
;
914 case '1' : case '2' : case '3' : case '4' : case '5' :
915 case '6' : case '7' : case '8' : case '9' : case '0' :
919 if( subids
>= subids_overflow
|| subid
> 0xffffffff) {
925 *(subids
) += *r
- '0';
937 guint
oid_encoded2subid(const guint8
*oid_bytes
, gint oid_len
, guint32
** subids_p
) {
938 return oid_encoded2subid_sub(oid_bytes
, oid_len
, subids_p
, TRUE
);
940 guint
oid_encoded2subid_sub(const guint8
*oid_bytes
, gint oid_len
, guint32
** subids_p
,
943 guint n
= is_first
? 1 : 0;
945 guint32
* subid_overflow
;
947 * we cannot handle sub-ids greater than 32bytes
948 * have the subid in 64 bytes to be able to check the limit
952 for (i
=0; i
<oid_len
; i
++) { if (! (oid_bytes
[i
] & 0x80 )) n
++; }
954 *subids_p
= subids
= (guint32
*)ep_alloc(sizeof(guint32
)*n
);
955 subid_overflow
= subids
+n
;
957 /* If n is 0 or 1 (depending on how it was initialized) then we found
958 * no bytes in the OID with first bit cleared, so initialize our one
959 * byte (if any) to zero and return. This *seems* to be the right thing
960 * to do in this situation, and at the very least it avoids
961 * uninitialized memory errors that would otherwise occur. */
962 if (is_first
&& n
== 1) {
966 else if (!is_first
&& n
== 0) {
970 for (i
=0; i
<oid_len
; i
++){
971 guint8 byte
= oid_bytes
[i
];
974 subid
|= byte
& 0x7F;
983 if (subid
>= 40) { subid0
++; subid
-=40; }
984 if (subid
>= 40) { subid0
++; subid
-=40; }
991 if( subids
>= subid_overflow
|| subid
> 0xffffffff) {
996 *subids
++ = (guint32
)subid
;
1000 g_assert(subids
== subid_overflow
);
1005 oid_info_t
* oid_get(guint len
, guint32
* subids
, guint
* matched
, guint
* left
) {
1006 oid_info_t
* curr_oid
= &oid_root
;
1009 if(!(subids
&& *subids
<= 2)) {
1015 for( i
=0; i
< len
; i
++) {
1016 oid_info_t
* next_oid
= (oid_info_t
*)wmem_tree_lookup32(curr_oid
->children
,subids
[i
]);
1018 curr_oid
= next_oid
;
1030 oid_info_t
* oid_get_from_encoded(const guint8
*bytes
, gint byteslen
, guint32
** subids_p
, guint
* matched_p
, guint
* left_p
) {
1031 guint subids_len
= oid_encoded2subid(bytes
, byteslen
, subids_p
);
1032 return oid_get(subids_len
, *subids_p
, matched_p
, left_p
);
1035 oid_info_t
* oid_get_from_string(const gchar
*oid_str
, guint32
** subids_p
, guint
* matched
, guint
* left
) {
1036 guint subids_len
= oid_string2subid(oid_str
, subids_p
);
1037 return oid_get(subids_len
, *subids_p
, matched
, left
);
1040 const gchar
*oid_resolved_from_encoded(const guint8
*oid
, gint oid_len
) {
1042 guint subid_oid_length
= oid_encoded2subid(oid
, oid_len
, &subid_oid
);
1044 return oid_resolved(subid_oid_length
, subid_oid
);
1047 const gchar
*rel_oid_resolved_from_encoded(const guint8
*oid
, gint oid_len
) {
1049 guint subid_oid_length
= oid_encoded2subid_sub(oid
, oid_len
, &subid_oid
, FALSE
);
1051 return rel_oid_subid2string(subid_oid
, subid_oid_length
, FALSE
);
1055 guint
oid_subid2encoded(guint subids_len
, guint32
* subids
, guint8
** bytes_p
) {
1061 if ( !subids
|| subids_len
<= 1) {
1066 for (subid
=subids
[0] * 40, i
= 1; i
<subids_len
; i
++, subid
=0) {
1068 if (subid
<= 0x0000007F) {
1070 } else if (subid
<= 0x00003FFF ) {
1072 } else if (subid
<= 0x001FFFFF ) {
1074 } else if (subid
<= 0x0FFFFFFF ) {
1081 *bytes_p
= b
= (guint8
*)ep_alloc(bytelen
);
1083 for (subid
=subids
[0] * 40, i
= 1; i
<subids_len
; i
++, subid
=0) {
1087 if ((subid
<= 0x0000007F )) len
= 1;
1088 else if ((subid
<= 0x00003FFF )) len
= 2;
1089 else if ((subid
<= 0x001FFFFF )) len
= 3;
1090 else if ((subid
<= 0x0FFFFFFF )) len
= 4;
1094 default: *bytes_p
=NULL
; return 0;
1095 case 5: *(b
++) = ((subid
& 0xF0000000) >> 28) | 0x80;
1096 case 4: *(b
++) = ((subid
& 0x0FE00000) >> 21) | 0x80;
1097 case 3: *(b
++) = ((subid
& 0x001FC000) >> 14) | 0x80;
1098 case 2: *(b
++) = ((subid
& 0x00003F80) >> 7) | 0x80;
1099 case 1: *(b
++) = subid
& 0x0000007F ; break;
1106 const gchar
* oid_encoded2string(const guint8
* encoded
, guint len
) {
1108 guint subids_len
= oid_encoded2subid(encoded
, len
, &subids
);
1111 return oid_subid2string(subids
,subids_len
);
1117 const gchar
* rel_oid_encoded2string(const guint8
* encoded
, guint len
) {
1119 guint subids_len
= oid_encoded2subid_sub(encoded
, len
, &subids
, FALSE
);
1122 return rel_oid_subid2string(subids
,subids_len
, FALSE
);
1128 guint
oid_string2encoded(const char *oid_str
, guint8
**bytes
) {
1133 if ( ( subids_len
= oid_string2subid(oid_str
, &subids
) )
1135 ( byteslen
= oid_subid2encoded(subids_len
, subids
, bytes
) ) ) {
1141 const gchar
*oid_resolved_from_string(const gchar
*oid_str
) {
1143 guint subid_oid_length
= oid_string2subid(oid_str
, &subid_oid
);
1145 return oid_resolved(subid_oid_length
, subid_oid
);
1148 const gchar
*oid_resolved(guint32 num_subids
, guint32
* subids
) {
1153 if(! (subids
&& *subids
<= 2 ))
1154 return "*** Malformed OID ***";
1156 oid
= oid_get(num_subids
, subids
, &matched
, &left
);
1158 while (! oid
->name
) {
1159 if (!(oid
= oid
->parent
)) {
1160 return oid_subid2string(subids
,num_subids
);
1167 return ep_strdup_printf("%s.%s",
1168 oid
->name
? oid
->name
: oid_subid2string(subids
,matched
),
1169 oid_subid2string(&(subids
[matched
]),left
));
1171 return oid
->name
? oid
->name
: oid_subid2string(subids
,matched
);
1175 extern void oid_both(guint oid_len
, guint32
*subids
, char** resolved_p
, char** numeric_p
) {
1176 *resolved_p
= (char *)oid_resolved(oid_len
,subids
);
1177 *numeric_p
= (char *)oid_subid2string(subids
,oid_len
);
1180 extern void oid_both_from_encoded(const guint8
*oid
, gint oid_len
, char** resolved_p
, char** numeric_p
) {
1182 guint subids_len
= oid_encoded2subid(oid
, oid_len
, &subids
);
1183 *resolved_p
= (char *)oid_resolved(subids_len
,subids
);
1184 *numeric_p
= (char *)oid_subid2string(subids
,subids_len
);
1187 extern void oid_both_from_string(const gchar
*oid_str
, char** resolved_p
, char** numeric_p
) {
1189 guint subids_len
= oid_string2subid(oid_str
, &subids
);
1190 *resolved_p
= (char *)oid_resolved(subids_len
,subids
);
1191 *numeric_p
= (char *)oid_subid2string(subids
,subids_len
);
1195 * Fetch the default OID path.
1198 oid_get_default_mib_path(void) {
1205 path_str
= g_string_new("");
1207 if (!load_smi_modules
) {
1208 D(1,("OID resolution not enabled"));
1209 return path_str
->str
;
1212 #define PATH_SEPARATOR ";"
1213 path
= get_datafile_path("snmp\\mibs");
1214 g_string_append_printf(path_str
, "%s;", path
);
1217 path
= get_persconffile_path("snmp\\mibs", FALSE
);
1218 g_string_append_printf(path_str
, "%s", path
);
1221 #define PATH_SEPARATOR ":"
1222 path
= smiGetPath();
1223 g_string_append(path_str
, "/usr/share/snmp/mibs");
1224 if (strlen(path
) > 0 ) {
1225 g_string_append(path_str
, PATH_SEPARATOR
);
1227 g_string_append_printf(path_str
, "%s", path
);
1231 for(i
=0;i
<num_smi_paths
;i
++) {
1232 if (!( smi_paths
[i
].name
&& *smi_paths
[i
].name
))
1235 g_string_append_printf(path_str
,PATH_SEPARATOR
"%s",smi_paths
[i
].name
);
1238 path_ret
= path_str
->str
;
1239 g_string_free(path_str
, FALSE
);
1241 #else /* HAVE_LIBSMI */
1242 return g_strdup("");
1247 char* oid_test_a2b(guint32 num_subids
, guint32
* subids
) {
1252 const char* sub2str
= oid_subid2string(subids
, num_subids
);
1253 guint sub2enc_len
= oid_subid2encoded(num_subids
, subids
,&sub2enc
);
1254 guint enc2sub_len
= oid_encoded2subid(sub2enc
, sub2enc_len
, &enc2sub
);
1255 const char* enc2str
= oid_encoded2string(sub2enc
, sub2enc_len
);
1256 guint str2enc_len
= oid_string2encoded(sub2str
,&str2enc
);
1257 guint str2sub_len
= oid_string2subid(sub2str
,&str2sub
);
1259 return ep_strdup_printf(
1260 "oid_subid2string=%s \n"
1261 "oid_subid2encoded=[%d]%s \n"
1262 "oid_encoded2subid=%s \n "
1263 "oid_encoded2string=%s \n"
1264 "oid_string2encoded=[%d]%s \n"
1265 "oid_string2subid=%s \n "
1267 ,sub2enc_len
,bytestring_to_str(sub2enc
, sub2enc_len
, ':')
1268 ,enc2sub
? oid_subid2string(enc2sub
,enc2sub_len
) : "-"
1270 ,str2enc_len
,bytestring_to_str(str2enc
, str2enc_len
, ':')
1271 ,str2sub
? oid_subid2string(str2sub
,str2sub_len
) : "-"
1275 void add_oid_debug_subtree(oid_info_t
* oid_info
, proto_tree
*tree
) {
1276 static const char* oid_kinds
[] = { "Unknown", "Node", "Scalar", "Table", "Row", "Column", "Notification", "Group", "Compliance", "Capabilities"};
1277 static const char* key_types
[] = {"OID_KEY_TYPE_WRONG","OID_KEY_TYPE_INTEGER",
1278 "OID_KEY_TYPE_FIXED_STRING","OID_KEY_TYPE_FIXED_BYTES","OID_KEY_TYPE_STRING",
1279 "OID_KEY_TYPE_BYTES","OID_KEY_TYPE_NSAP","OID_KEY_TYPE_OID","OID_KEY_TYPE_IPADDR"};
1280 proto_item
* pi
= proto_tree_add_text(tree
,NULL
,0,0,
1281 "OidInfo: Name='%s' sub-id=%u kind=%s hfid=%d",
1282 oid_info
->name
? oid_info
->name
: "",
1284 oid_info
->kind
<= OID_KIND_CAPABILITIES
? oid_kinds
[oid_info
->kind
] : "BROKEN",
1285 oid_info
->value_hfid
);
1286 proto_tree
* pt
= proto_item_add_subtree(pi
,0);
1289 for(key
= oid_info
->key
; key
; key
= key
->next
) {
1290 proto_tree_add_text(pt
,NULL
,0,0,
1291 "Key: name='%s' num_subids=%d type=%s",
1293 key
->key_type
<= OID_KEY_TYPE_IPADDR
? key_types
[key
->key_type
] : "BROKEN"
1297 if (oid_info
->parent
) {
1298 pi
= proto_tree_add_text(pt
,NULL
,0,0,"Parent:");
1299 pt
= proto_item_add_subtree(pi
,0);
1300 add_oid_debug_subtree(oid_info
->parent
, pt
);
1311 * indent-tabs-mode: t
1314 * ex: set shiftwidth=8 tabstop=8 noexpandtab:
1315 * :indentSize=8:tabSize=8:noTabs=false: