attr_dissector_fn_t
[wireshark-sm.git] / epan / oids.c
blobb999057da6b54415ed0030811389e9e271a04a0b
1 /* oids.c
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 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "config.h"
15 #include <glib.h>
16 #include <stdio.h>
17 #include <string.h>
19 #include <wsutil/report_message.h>
21 #include <epan/strutil.h>
22 #include <epan/wmem_scopes.h>
23 #include "uat.h"
24 #include "prefs.h"
25 #include "proto.h"
26 #include "packet.h"
27 #include "wsutil/filesystem.h"
28 #include "dissectors/packet-ber.h"
29 #include <wsutil/ws_assert.h>
31 #ifdef HAVE_LIBSMI
32 #include <smi.h>
34 static bool smi_init_done;
35 static bool oids_init_done;
36 static bool load_smi_modules;
37 static bool suppress_smi_errors;
38 #endif
40 #define D(level,args) do if (debuglevel >= level) { printf args; printf("\n"); fflush(stdout); } while(0)
42 #include "oids.h"
44 static int debuglevel;
47 * From SNMPv2-SMI and X.690
49 * Counter32 ::= [APPLICATION 1] IMPLICIT INTEGER (0..4294967295)
50 * Gauge32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
51 * Unsigned32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) (alias of Gauge32)
52 * TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
54 * If the BER encoding should not have the top bit set as to not become a negative number
55 * the BER encoding may take 5 octets to encode.
58 #ifdef HAVE_LIBSMI
59 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};
60 static const oid_value_type_t bytes_type = { FT_BYTES, BASE_SHOW_ASCII_PRINTABLE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 0, -1, OID_KEY_TYPE_BYTES, 0};
61 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};
62 static const oid_value_type_t ipv4_type = { FT_IPv4, BASE_NONE, BER_CLASS_APP, 0, 4, 4, OID_KEY_TYPE_IPADDR, 4};
63 static const oid_value_type_t counter32_type = { FT_UINT64, BASE_DEC, BER_CLASS_APP, 1, 1, 5, OID_KEY_TYPE_INTEGER, 1};
64 static const oid_value_type_t unsigned32_type = { FT_UINT64, BASE_DEC, BER_CLASS_APP, 2, 1, 5, OID_KEY_TYPE_INTEGER, 1};
65 static const oid_value_type_t timeticks_type = { FT_UINT64, BASE_DEC, BER_CLASS_APP, 3, 1, 5, OID_KEY_TYPE_INTEGER, 1};
66 #if 0
67 static const oid_value_type_t opaque_type = { FT_BYTES, BASE_NONE, BER_CLASS_APP, 4, 1, 4, OID_KEY_TYPE_BYTES, 0};
68 #endif
69 static const oid_value_type_t nsap_type = { FT_BYTES, BASE_NONE, BER_CLASS_APP, 5, 0, -1, OID_KEY_TYPE_NSAP, 0};
70 static const oid_value_type_t counter64_type = { FT_UINT64, BASE_DEC, BER_CLASS_APP, 6, 1, 8, OID_KEY_TYPE_INTEGER, 1};
71 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};
72 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};
73 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};
74 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};
75 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};
76 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};
77 #endif /* HAVE_LIBSMI */
79 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};
81 static oid_info_t oid_root = { 0, NULL, OID_KIND_UNKNOWN, NULL, &unknown_type, -2, NULL, NULL, NULL};
83 // NOLINTNEXTLINE(misc-no-recursion)
84 static void prepopulate_oids(void) {
85 if (!oid_root.children) {
86 char* debug_env = getenv("WIRESHARK_DEBUG_MIBS");
87 uint32_t subid;
89 debuglevel = debug_env ? (int)strtoul(debug_env,NULL,10) : 0;
91 oid_root.children = wmem_tree_new(wmem_epan_scope());
94 * make sure we got strings at least in the three root-children oids
95 * that way oid_resolved() will always have a string to print
97 // We recurse here once.
98 subid = 0; oid_add("itu-t",1,&subid);
99 subid = 1; oid_add("iso",1,&subid);
100 subid = 2; oid_add("joint-iso-itu-t",1,&subid);
104 // NOLINTNEXTLINE(misc-no-recursion)
105 static oid_info_t* add_oid(const char* name, oid_kind_t kind, const oid_value_type_t* type, oid_key_t* key, unsigned oid_len, uint32_t *subids) {
106 unsigned i = 0;
107 oid_info_t* c = &oid_root;
109 prepopulate_oids();
110 oid_len--;
112 do {
113 oid_info_t* n = (oid_info_t *)wmem_tree_lookup32(c->children,subids[i]);
115 if(n) {
116 if (i == oid_len) {
117 if (n->name) {
118 if (!g_str_equal(n->name,name)) {
119 D(2,("Renaming Oid from: %s -> %s, this means the same oid is registered more than once",n->name,name));
121 wmem_free(wmem_epan_scope(), n->name);
124 n->name = wmem_strdup(wmem_epan_scope(), name);
126 if (! n->value_type) {
127 n->value_type = type;
130 return n;
132 } else {
133 n = wmem_new(wmem_epan_scope(), oid_info_t);
134 n->subid = subids[i];
135 n->kind = kind;
136 n->children = wmem_tree_new(wmem_epan_scope());
137 n->value_hfid = -2;
138 n->key = key;
139 n->parent = c;
140 n->bits = NULL;
142 wmem_tree_insert32(c->children,n->subid,n);
144 if (i == oid_len) {
145 n->name = wmem_strdup(wmem_epan_scope(), name);
146 n->value_type = type;
147 n->kind = kind;
148 return n;
149 } else {
150 n->name = NULL;
151 n->value_type = NULL;
152 n->kind = OID_KIND_UNKNOWN;
155 c = n;
156 } while(++i);
158 ws_assert_not_reached();
159 return NULL;
162 // NOLINTNEXTLINE(misc-no-recursion)
163 void oid_add(const char* name, unsigned oid_len, uint32_t *subids) {
164 ws_assert(subids && *subids <= 2);
165 if (oid_len) {
166 char* sub = oid_subid2string(NULL, subids,oid_len);
167 D(3,("\tOid (from subids): %s %s ",name?name:"NULL", sub));
168 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
169 wmem_free(NULL, sub);
170 } else {
171 D(1,("Failed to add Oid: %s (from subids)",name?name:"NULL"));
175 void oid_add_from_string(const char* name, const char *oid_str) {
176 uint32_t* subids;
177 unsigned oid_len = oid_string2subid(NULL, oid_str, &subids);
179 if (oid_len) {
180 char* sub = oid_subid2string(NULL, subids,oid_len);
181 D(3,("\tOid (from string): %s %s ",name?name:"NULL", sub));
182 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
183 wmem_free(NULL, sub);
184 } else {
185 D(1,("Failed to add Oid: %s %s ",name?name:"NULL", oid_str?oid_str:NULL));
187 wmem_free(NULL, subids);
190 extern void oid_add_from_encoded(const char* name, const uint8_t *oid, int oid_len) {
191 uint32_t* subids = NULL;
192 unsigned subids_len = oid_encoded2subid(NULL, oid, oid_len, &subids);
194 if (subids_len) {
195 char* sub = oid_subid2string(NULL, subids,subids_len);
196 D(3,("\tOid (from encoded): %s %s ",name, sub));
197 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,subids_len,subids);
198 wmem_free(NULL, sub);
199 } else {
200 char* bytestr = bytes_to_str_punct(NULL, oid, oid_len, ':');
201 D(1,("Failed to add Oid: %s [%d]%s ",name?name:"NULL", oid_len, bytestr));
202 wmem_free(NULL, bytestr);
204 wmem_free(NULL, subids);
207 #ifdef HAVE_LIBSMI
208 /* de-allocate storage mallocated by libsmi */
209 /* */
210 /* XXX: libsmi provides access to smiFree as of libsmi v 0.4.8. */
211 /* On Windows: Wireshark 1.01 and later is built and distributed */
212 /* with libsmi 0.4.8 (or newer). */
213 /* On non-Windows systems, free() should be OK for libsmi */
214 /* versions older than 0.4.8. */
216 static void smi_free(void *ptr) {
218 #if (SMI_VERSION_MAJOR > 0) || (SMI_VERSION_MINOR > 4) || (SMI_VERSION_PATCHLEVEL >= 8)
219 smiFree(ptr);
220 #else
221 #ifdef _WIN32
222 #error Unsupported Windows libsmi version < 0.4.8
223 #endif
224 #define xx_free free /* hack so checkAPIs.pl doesn't complain */
225 xx_free(ptr);
226 #endif
230 typedef struct smi_module_t {
231 char* name;
232 } smi_module_t;
234 static smi_module_t* smi_paths;
235 static unsigned num_smi_paths;
236 static uat_t* smi_paths_uat;
238 static smi_module_t* smi_modules;
239 static unsigned num_smi_modules;
240 static uat_t* smi_modules_uat;
242 static GString* smi_errors;
244 UAT_DIRECTORYNAME_CB_DEF(smi_mod,name,smi_module_t)
246 static void smi_error_handler(char *path, int line, int severity, char *msg, char *tag) {
247 g_string_append_printf(smi_errors,"%s:%d %d %s %s\n",
248 path ? path : "-",
249 line, severity,
250 tag ? tag : "-",
251 msg ? msg : "");
255 static void* smi_mod_copy_cb(void* dest, const void* orig, size_t len _U_) {
256 const smi_module_t* m = (const smi_module_t*)orig;
257 smi_module_t* d = (smi_module_t*)dest;
259 d->name = g_strdup(m->name);
261 return d;
264 static void smi_mod_free_cb(void* p) {
265 smi_module_t* m = (smi_module_t*)p;
266 g_free(m->name);
270 static char* alnumerize(const char* name) {
271 char* s = g_strdup(name);
272 char* r = s;
273 char* w = r;
274 char c;
276 for (;(c = *r); r++) {
277 if (g_ascii_isalnum(c) || c == '_' || c == '-' || c == '.') {
278 *(w++) = c;
279 } else if (c == ':' && r[1] == ':') {
280 *(w++) = '.';
284 *w = '\0';
286 return s;
289 static const oid_value_type_t* get_typedata(SmiType* smiType) {
291 * There has to be a better way to know if a given
292 * OCTETSTRING type is actually human readable text,
293 * an address of some type or some moe specific FT_
294 * Until that is found, this is the mappping between
295 * SNMP Types and our FT_s
297 static const struct _type_mapping_t {
298 const char* name;
299 SmiBasetype base;
300 const oid_value_type_t* type;
301 } types[] = {
302 {"IpAddress", SMI_BASETYPE_UNKNOWN, &ipv4_type},
303 {"InetAddressIPv4",SMI_BASETYPE_UNKNOWN,&ipv4_type},
304 {"InetAddressIPv6",SMI_BASETYPE_UNKNOWN,&ipv6_type},
305 {"NetworkAddress",SMI_BASETYPE_UNKNOWN,&ipv4_type},
306 {"MacAddress",SMI_BASETYPE_UNKNOWN,&ether_type},
307 {"TimeTicks",SMI_BASETYPE_UNKNOWN,&timeticks_type},
308 {"Ipv6Address",SMI_BASETYPE_UNKNOWN,&ipv6_type},
309 {"TimeStamp",SMI_BASETYPE_UNKNOWN,&timeticks_type},
310 {"DisplayString",SMI_BASETYPE_UNKNOWN,&string_type},
311 {"SnmpAdminString",SMI_BASETYPE_UNKNOWN,&string_type},
312 {"DateAndTime",SMI_BASETYPE_UNKNOWN,&date_and_time_type},
313 {"Counter",SMI_BASETYPE_UNKNOWN,&counter32_type},
314 {"Counter32",SMI_BASETYPE_UNKNOWN,&counter32_type},
315 {"Unsigned32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
316 {"Gauge",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
317 {"Gauge32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
318 {"NsapAddress",SMI_BASETYPE_UNKNOWN,&nsap_type},
319 {"i32",SMI_BASETYPE_INTEGER32,&integer_type},
320 {"octets",SMI_BASETYPE_OCTETSTRING,&bytes_type},
321 {"oid",SMI_BASETYPE_OBJECTIDENTIFIER,&oid_type},
322 {"u32",SMI_BASETYPE_UNSIGNED32,&unsigned32_type},
323 {"u64",SMI_BASETYPE_UNSIGNED64,&counter64_type},
324 {"f32",SMI_BASETYPE_FLOAT32,&float_type},
325 {"f64",SMI_BASETYPE_FLOAT64,&double_type},
326 {"f128",SMI_BASETYPE_FLOAT128,&bytes_type},
327 {"enum",SMI_BASETYPE_ENUM,&integer_type},
328 {"bits",SMI_BASETYPE_BITS,&bytes_type},
329 {"unk",SMI_BASETYPE_UNKNOWN,&unknown_type},
330 {NULL,SMI_BASETYPE_UNKNOWN,NULL} /* SMI_BASETYPE_UNKNOWN = 0 */
332 const struct _type_mapping_t* t;
333 SmiType* sT = smiType;
335 if (!smiType) return NULL;
337 do {
338 for (t = types; t->type ; t++ ) {
339 char* name = smiRenderType(sT, SMI_RENDER_NAME);
340 if (name && t->name && g_str_equal(name, t->name )) {
341 smi_free(name);
342 return t->type;
344 if (name) {
345 smi_free (name);
348 } while(( sT = smiGetParentType(sT) ));
350 for (t = types; t->type ; t++ ) {
351 if(smiType->basetype == t->base) {
352 return t->type;
356 return &unknown_type;
359 static unsigned get_non_implicit_size(SmiType* sT) {
360 SmiRange *sR;
361 unsigned size = 0xffffffff;
363 switch (sT->basetype) {
364 case SMI_BASETYPE_OCTETSTRING:
365 case SMI_BASETYPE_OBJECTIDENTIFIER:
366 break;
367 default:
368 return 0;
371 for ( ; sT; sT = smiGetParentType(sT) ) {
372 for (sR = smiGetFirstRange(sT); sR ; sR = smiGetNextRange(sR)) {
373 if (size == 0xffffffff) {
374 if (sR->minValue.value.unsigned32 == sR->maxValue.value.unsigned32) {
375 size = (uint32_t)sR->minValue.value.unsigned32;
376 } else {
377 return 0;
379 } else {
380 if (sR->minValue.value.unsigned32 != size || sR->maxValue.value.unsigned32 != size) {
381 return 0;
387 return size == 0xffffffff ? 0 : size;
391 static inline oid_kind_t smikind(SmiNode* sN, oid_key_t** key_p) {
392 *key_p = NULL;
394 switch(sN->nodekind) {
395 case SMI_NODEKIND_ROW: {
396 SmiElement* sE;
397 oid_key_t* kl = NULL; /* points to last element in the list of oid_key_t's */
398 const oid_value_type_t* typedata = NULL;
399 bool implied;
401 switch (sN->indexkind) {
402 case SMI_INDEX_INDEX:
403 break;
404 case SMI_INDEX_AUGMENT:
405 case SMI_INDEX_REORDER:
406 case SMI_INDEX_SPARSE:
407 case SMI_INDEX_EXPAND:
408 sN = smiGetRelatedNode(sN);
409 break;
410 case SMI_INDEX_UNKNOWN:
411 return OID_KIND_UNKNOWN;
414 implied = sN->implied;
416 for (sE = smiGetFirstElement(sN); sE; sE = smiGetNextElement(sE)) {
417 SmiNode* elNode = smiGetElementNode(sE) ;
418 SmiType* elType = smiGetNodeType(elNode);
419 oid_key_t* k;
420 unsigned non_implicit_size = 0;
421 char *oid1, *oid2;
423 if (elType) {
424 non_implicit_size = get_non_implicit_size(elType);
427 typedata = get_typedata(elType);
429 k = g_new(oid_key_t,1);
431 oid1 = smiRenderOID(sN->oidlen, sN->oid, SMI_RENDER_QUALIFIED);
432 oid2 = smiRenderOID(elNode->oidlen, elNode->oid, SMI_RENDER_NAME);
433 k->name = g_strconcat(oid1, ".", oid2, NULL);
434 smi_free (oid1);
435 smi_free (oid2);
437 k->hfid = -2;
438 k->ft_type = typedata ? typedata->ft_type : FT_BYTES;
439 k->display = typedata ? typedata->display : BASE_NONE;
440 k->next = NULL;
443 if (typedata) {
444 k->key_type = typedata->keytype;
445 k->num_subids = typedata->keysize;
446 } else {
447 if (elType) {
448 switch (elType->basetype) {
449 case SMI_BASETYPE_BITS:
450 case SMI_BASETYPE_OCTETSTRING: {
451 k->key_type = OID_KEY_TYPE_BYTES;
452 k->num_subids = non_implicit_size;
453 break;
455 case SMI_BASETYPE_ENUM:
456 case SMI_BASETYPE_OBJECTIDENTIFIER:
457 case SMI_BASETYPE_INTEGER32:
458 case SMI_BASETYPE_UNSIGNED32:
459 case SMI_BASETYPE_INTEGER64:
460 case SMI_BASETYPE_UNSIGNED64:
461 k->key_type = OID_KEY_TYPE_INTEGER;
462 k->num_subids = 1;
463 break;
464 default:
465 k->key_type = OID_KEY_TYPE_WRONG;
466 k->num_subids = 0;
467 break;
469 } else {
470 k->key_type = OID_KEY_TYPE_WRONG;
471 k->num_subids = 0;
475 if (!kl) {
477 * The list is empty, so set the
478 * pointer to the head of the list
479 * to point to this entry.
481 *key_p = k;
482 } else {
484 * The list is non-empty, and kl
485 * points to its last element.
486 * Make the last element point to
487 * this entry as its successor.
489 kl->next = k;
493 * This entry is now the last entry in
494 * the list.
496 kl = k;
499 if (implied && kl) {
500 switch (kl->key_type) {
501 case OID_KEY_TYPE_BYTES: kl->key_type = OID_KEY_TYPE_IMPLIED_BYTES; break;
502 case OID_KEY_TYPE_STRING: kl->key_type = OID_KEY_TYPE_IMPLIED_STRING; break;
503 case OID_KEY_TYPE_OID: kl->key_type = OID_KEY_TYPE_IMPLIED_OID; break;
504 default: break;
508 return OID_KIND_ROW;
510 case SMI_NODEKIND_NODE: return OID_KIND_NODE;
511 case SMI_NODEKIND_SCALAR: return OID_KIND_SCALAR;
512 case SMI_NODEKIND_TABLE: return OID_KIND_TABLE;
513 case SMI_NODEKIND_COLUMN: return OID_KIND_COLUMN;
514 case SMI_NODEKIND_NOTIFICATION: return OID_KIND_NOTIFICATION;
515 case SMI_NODEKIND_GROUP: return OID_KIND_GROUP;
516 case SMI_NODEKIND_COMPLIANCE: return OID_KIND_COMPLIANCE;
517 case SMI_NODEKIND_CAPABILITIES: return OID_KIND_CAPABILITIES;
518 default: return OID_KIND_UNKNOWN;
522 #define IS_ENUMABLE(ft) ( (ft == FT_UINT8) || (ft == FT_UINT16) || (ft == FT_UINT24) || (ft == FT_UINT32) \
523 || (ft == FT_INT8) || (ft == FT_INT16) || (ft == FT_INT24) || (ft == FT_INT32) \
524 || (ft == FT_UINT64) || (ft == FT_INT64) )
526 static void unregister_mibs(void) {
527 /* TODO: Unregister "MIBs" proto and clean up field array and subtree array.
528 * Wireshark does not support that yet. :-( */
530 /* smiExit(); */
533 static void restart_needed_warning(void) {
534 if (oids_init_done)
535 report_failure("Wireshark needs to be restarted for these changes to take effect");
538 static void register_mibs(void) {
539 SmiModule *smiModule;
540 SmiNode *smiNode;
541 unsigned i;
542 int proto_mibs = -1;
543 wmem_array_t* hfa;
544 GArray* etta;
545 char* path_str;
547 if (!load_smi_modules) {
548 D(1,("OID resolution not enabled"));
549 return;
552 /* TODO: Remove this workaround when unregistration of "MIBs" proto is solved.
553 * Wireshark does not support that yet. :-( */
554 if (oids_init_done) {
555 D(1,("Exiting register_mibs() to avoid double registration of MIBs proto."));
556 return;
559 hfa = wmem_array_new(wmem_epan_scope(), sizeof(hf_register_info));
560 etta = g_array_new(false,true,sizeof(int*));
562 smiInit("wireshark");
563 smi_init_done = true;
565 smi_errors = g_string_new("");
566 smiSetErrorHandler(smi_error_handler);
568 path_str = oid_get_default_mib_path();
569 D(1,("SMI Path: '%s'",path_str));
571 smiSetPath(path_str);
573 for(i=0;i<num_smi_modules;i++) {
574 if (!smi_modules[i].name) continue;
576 if (smiIsLoaded(smi_modules[i].name)) {
577 continue;
578 } else {
579 char* mod_name = smiLoadModule(smi_modules[i].name);
580 if (mod_name)
581 D(2,("Loaded: '%s'[%u] as %s",smi_modules[i].name,i,mod_name ));
582 else
583 D(1,("Failed to load: '%s'[%u]",smi_modules[i].name,i));
587 if (smi_errors->len) {
588 if (!suppress_smi_errors) {
589 report_failure("The following errors were found while loading the MIBS:\n%s\n\n"
590 "The Current Path is: %s\n\nYou can avoid this error message "
591 "by removing the missing MIB modules at Edit -> Preferences"
592 " -> Name Resolution -> SMI (MIB and PIB) modules or by "
593 "installing them.\n" , smi_errors->str , path_str);
595 D(1,("Errors while loading:\n%s\n",smi_errors->str));
598 g_free(path_str);
599 g_string_free(smi_errors,TRUE);
601 for (smiModule = smiGetFirstModule();
602 smiModule;
603 smiModule = smiGetNextModule(smiModule)) {
605 D(3,("\tModule: %s", smiModule->name));
607 /* TODO: Check libsmi version at compile time and disable this
608 * workaround for libsmi versions where this problem is fixed.
609 * Currently there is no such version. :-(
611 if (smiModule->conformance == 1) {
612 if (!suppress_smi_errors) {
613 report_failure("Stopped processing module %s due to "
614 "error(s) to prevent potential crash in libsmi.\n"
615 "Module's conformance level: %d.\n"
616 "See details at: https://bugs.debian.org/560325\n",
617 smiModule->name, smiModule->conformance);
619 continue;
621 for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
622 smiNode;
623 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
625 SmiType* smiType = smiGetNodeType(smiNode);
626 const oid_value_type_t* typedata = get_typedata(smiType);
627 oid_key_t* key;
628 oid_kind_t kind = smikind(smiNode,&key);
629 char *sub;
630 char *oid = smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_QUALIFIED);
631 oid_info_t* oid_data = add_oid(oid,
632 kind,
633 typedata,
634 key,
635 smiNode->oidlen,
636 smiNode->oid);
637 smi_free (oid);
639 sub = oid_subid2string(NULL, smiNode->oid, smiNode->oidlen);
640 D(4,("\t\tNode: kind=%d oid=%s name=%s ",
641 oid_data->kind, sub, oid_data->name));
642 wmem_free(NULL, sub);
644 if ( typedata && oid_data->value_hfid == -2 ) {
645 SmiNamedNumber* smiEnum;
646 hf_register_info hf;
647 char *name;
648 char *blurb;
650 name = g_strdup(oid_data->name);
651 blurb = smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_ALL);
652 /* Don't allow duplicate blurb/name */
653 if (strcmp(blurb, name) == 0) {
654 smi_free(blurb);
655 blurb = NULL;
658 hf.p_id = &(oid_data->value_hfid);
659 hf.hfinfo.name = name;
660 hf.hfinfo.abbrev = alnumerize(oid_data->name);
661 hf.hfinfo.type = typedata->ft_type;
662 hf.hfinfo.display = typedata->display;
663 hf.hfinfo.strings = NULL;
664 hf.hfinfo.bitmask = 0;
665 hf.hfinfo.blurb = blurb;
666 /* HFILL */
667 HFILL_INIT(hf);
669 oid_data->value_hfid = -1;
671 if ( IS_ENUMABLE(hf.hfinfo.type) && (smiEnum = smiGetFirstNamedNumber(smiType))) {
672 GArray* vals = g_array_new(true,true,sizeof(value_string));
674 for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum)) {
675 if (smiEnum->name) {
676 value_string val;
677 val.value = (uint32_t)smiEnum->value.value.integer32;
678 val.strptr = g_strdup(smiEnum->name);
679 g_array_append_val(vals,val);
683 hf.hfinfo.strings = g_array_free(vals, false);
685 #if 0 /* packet-snmp does not handle bits yet */
686 } else if (smiType->basetype == SMI_BASETYPE_BITS && ( smiEnum = smiGetFirstNamedNumber(smiType) )) {
687 unsigned n = 0;
688 oid_bits_info_t* bits = g_new(oid_bits_info_t, 1);
689 int* ettp = &(bits->ett);
691 bits->num = 0;
692 bits->ett = -1;
694 g_array_append_val(etta,ettp);
696 for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum), bits->num++);
698 bits->data = g_malloc(sizeof(struct _oid_bit_t)*bits->num);
700 for(smiEnum = smiGetFirstNamedNumber(smiType),n=0;
701 smiEnum;
702 smiEnum = smiGetNextNamedNumber(smiEnum),n++) {
703 unsigned mask = 1 << (smiEnum->value.value.integer32 % 8);
704 char* base = alnumerize(oid_data->name);
705 char* ext = alnumerize(smiEnum->name);
706 hf_register_info hf2 = { &(bits->data[n].hfid), { NULL, NULL, FT_UINT8, BASE_HEX, NULL, mask, NULL, HFILL }};
708 bits->data[n].hfid = -1;
709 bits->data[n].offset = smiEnum->value.value.integer32 / 8;
711 hf2.hfinfo.name = g_strconcat("%s:%s",oid_data->name, ":", smiEnum->name, NULL);
712 hf2.hfinfo.abbrev = g_strconcat(base, ".", ext, NULL);
714 g_free(base);
715 g_free(ext);
716 g_array_append_val(hfa,hf2);
718 #endif /* packet-snmp does not use this yet */
719 wmem_array_append_one(hfa,hf);
722 if ((key = oid_data->key)) {
723 for(; key; key = key->next) {
724 D(5,("\t\t\tIndex: name=%s subids=%u key_type=%d",
725 key->name, key->num_subids, key->key_type ));
727 if (key->hfid == -2) {
728 hf_register_info hf;
730 hf.p_id = &(key->hfid);
731 hf.hfinfo.name = key->name;
732 hf.hfinfo.abbrev = alnumerize(key->name);
733 hf.hfinfo.type = key->ft_type;
734 hf.hfinfo.display = key->display;
735 hf.hfinfo.strings = NULL;
736 hf.hfinfo.bitmask = 0;
737 hf.hfinfo.blurb = NULL;
738 /* HFILL */
739 HFILL_INIT(hf);
741 wmem_array_append_one(hfa,hf);
742 key->hfid = -1;
749 proto_mibs = proto_register_protocol("MIBs", "MIBS", "mibs");
751 proto_register_field_array(proto_mibs, (hf_register_info*)wmem_array_get_raw(hfa), wmem_array_get_count(hfa));
753 proto_register_subtree_array((int**)(void*)etta->data, etta->len);
755 g_array_free(etta,true);
757 oids_init_done = true;
759 #endif
761 void oid_pref_init(module_t *nameres)
763 #ifdef HAVE_LIBSMI
764 static uat_field_t smi_fields[] = {
765 UAT_FLD_CSTRING(smi_mod,name,"Module name","The module's name"),
766 UAT_END_FIELDS
768 static uat_field_t smi_paths_fields[] = {
769 UAT_FLD_DIRECTORYNAME(smi_mod,name,"Directory path","The directory name"),
770 UAT_END_FIELDS
773 prefs_register_bool_preference(nameres, "load_smi_modules",
774 "Enable OID resolution",
775 "Resolve Object IDs to object names from the MIB and PIB"
776 " modules defined below."
777 " You must restart Wireshark for this change to take effect",
778 &load_smi_modules);
780 prefs_register_bool_preference(nameres, "suppress_smi_errors",
781 "Suppress SMI errors",
782 "While loading MIB or PIB modules errors may be detected,"
783 " which are reported. Some errors can be ignored."
784 " If unsure, set to false.",
785 &suppress_smi_errors);
787 smi_paths_uat = uat_new("SMI Paths",
788 sizeof(smi_module_t),
789 "smi_paths",
790 false,
791 (void**)&smi_paths,
792 &num_smi_paths,
793 /* affects dissection of packets (as the MIBs and PIBs affect the
794 interpretation of e.g. SNMP variable bindings), but not set of
795 named fields
797 XXX - if named fields are generated from the MIBs and PIBs
798 for particular variable bindings, this *does* affect the set
799 of named fields! */
800 UAT_AFFECTS_DISSECTION,
801 "ChSNMPSMIPaths",
802 smi_mod_copy_cb,
803 NULL,
804 smi_mod_free_cb,
805 restart_needed_warning,
806 NULL,
807 smi_paths_fields);
809 prefs_register_uat_preference(nameres,
810 "smi_paths",
811 "SMI (MIB and PIB) paths",
812 "Search paths for SMI (MIB and PIB) modules. You must"
813 " restart Wireshark for these changes to take effect.",
814 smi_paths_uat);
816 smi_modules_uat = uat_new("SMI Modules",
817 sizeof(smi_module_t),
818 "smi_modules",
819 false,
820 (void**)&smi_modules,
821 &num_smi_modules,
822 /* affects dissection of packets (as the MIBs and PIBs affect the
823 interpretation of e.g. SNMP variable bindings), but not set of
824 named fields
826 XXX - if named fields are generated from the MIBs and PIBs
827 for particular variable bindings, would this affect the set
828 of named fields? */
829 UAT_AFFECTS_DISSECTION,
830 "ChSNMPSMIModules",
831 smi_mod_copy_cb,
832 NULL,
833 smi_mod_free_cb,
834 restart_needed_warning,
835 NULL,
836 smi_fields);
838 prefs_register_uat_preference(nameres,
839 "smi_modules",
840 "SMI (MIB and PIB) modules",
841 "List of SMI (MIB and PIB) modules to load. You must"
842 " restart Wireshark for these changes to take effect.",
843 smi_modules_uat);
845 #else
846 prefs_register_static_text_preference(nameres, "load_smi_modules_static",
847 "Enable OID resolution: N/A",
848 "Support for OID resolution was not compiled into this version of Wireshark");
850 prefs_register_static_text_preference(nameres, "suppress_smi_errors_static",
851 "Suppress SMI errors: N/A",
852 "Support for OID resolution was not compiled into this version of Wireshark");
854 prefs_register_static_text_preference(nameres, "smi_module_path",
855 "SMI (MIB and PIB) modules and paths: N/A",
856 "Support for OID resolution was not compiled into this version of Wireshark");
857 #endif
860 void oids_init(void) {
861 prepopulate_oids();
862 #ifdef HAVE_LIBSMI
863 register_mibs();
864 #else
865 D(1,("libsmi disabled oid resolution not enabled"));
866 #endif
869 void oids_cleanup(void) {
870 #ifdef HAVE_LIBSMI
871 unregister_mibs();
872 #else
873 D(1,("libsmi disabled oid resolution not enabled"));
874 #endif
877 char* oid_subid2string(wmem_allocator_t *scope, uint32_t* subids, unsigned len) {
878 return rel_oid_subid2string(scope, subids, len, true);
880 char* rel_oid_subid2string(wmem_allocator_t *scope, uint32_t* subids, unsigned len, bool is_absolute) {
882 wmem_strbuf_t *oid_str;
883 size_t oid_str_len;
885 if(!subids || len == 0)
886 return wmem_strdup(scope, "*** Empty OID ***");
888 oid_str = wmem_strbuf_new(scope, "");
890 if (!is_absolute)
891 wmem_strbuf_append_c(oid_str, '.');
893 do {
894 wmem_strbuf_append_printf(oid_str, "%u.",*subids++);
895 } while(--len);
897 /* Remove trailing "." (which is guaranteed to be there) */
898 oid_str_len = wmem_strbuf_get_len(oid_str);
899 wmem_strbuf_truncate(oid_str, oid_str_len - 1);
901 return wmem_strbuf_finalize(oid_str);
904 /* If a valid OID string, return number of numbers */
905 static unsigned check_num_oid(const char* str) {
906 const char* r = str;
907 char c = '.';
908 unsigned n = 0;
910 D(8,("check_num_oid: '%s'",str));
911 if (!r) return 0;
913 do {
914 D(9,("\tcheck_num_oid: '%c' %u",*r,n));
915 switch(*r) {
916 case '.': case '\0':
917 n++;
918 if (c == '.') return 0;
919 break;
920 case '1' : case '2' : case '3' : case '4' : case '5' :
921 case '6' : case '7' : case '8' : case '9' : case '0' :
922 continue;
923 default:
924 return 0;
926 } while((c = *r++));
928 return n;
931 /* Set subids_p to an array of found numbers, return number of numbers */
932 unsigned oid_string2subid(wmem_allocator_t *scope, const char* str, uint32_t** subids_p) {
933 const char* r = str;
934 uint32_t* subids;
935 uint32_t* subids_overflow;
936 unsigned n = check_num_oid(str);
938 * we cannot handle sub-ids greater than 32bytes
939 * keep a pilot subid of 64 bytes to check the limit
941 uint64_t subid = 0;
943 D(6,("oid_string2subid: str='%s'",str));
945 if (!n) {
946 *subids_p = NULL;
947 return 0;
950 *subids_p = subids = wmem_alloc0_array(scope, uint32_t, n);
951 subids_overflow = subids + n;
952 do switch(*r) {
953 case '.':
954 subid = 0;
955 subids++;
956 continue;
957 case '1' : case '2' : case '3' : case '4' : case '5' :
958 case '6' : case '7' : case '8' : case '9' : case '0' :
959 subid *= 10;
960 subid += *r - '0';
962 if( subids >= subids_overflow || subid > 0xffffffff) {
963 wmem_free(scope, *subids_p);
964 *subids_p=NULL;
965 return 0;
968 *(subids) *= 10;
969 *(subids) += *r - '0';
970 continue;
971 case '\0':
972 break;
973 default:
974 return 0;
975 } while(*r++);
977 return n;
981 unsigned oid_encoded2subid(wmem_allocator_t *scope, const uint8_t *oid_bytes, int oid_len, uint32_t** subids_p) {
982 return oid_encoded2subid_sub(scope, oid_bytes, oid_len, subids_p, true);
984 unsigned oid_encoded2subid_sub(wmem_allocator_t *scope, const uint8_t *oid_bytes, int oid_len, uint32_t** subids_p,
985 bool is_first) {
986 int i;
987 unsigned n = is_first ? 1 : 0;
988 uint32_t* subids;
989 uint32_t* subid_overflow;
991 * we cannot handle sub-ids greater than 32bytes
992 * have the subid in 64 bytes to be able to check the limit
994 uint64_t subid = 0;
996 for (i=0; i<oid_len; i++) { if (! (oid_bytes[i] & 0x80 )) n++; }
998 *subids_p = subids = (uint32_t *)wmem_alloc(scope, sizeof(uint32_t)*n);
999 subid_overflow = subids+n;
1001 /* If n is 0 or 1 (depending on how it was initialized) then we found
1002 * no bytes in the OID with first bit cleared, so initialize our one
1003 * byte (if any) to zero and return. This *seems* to be the right thing
1004 * to do in this situation, and at the very least it avoids
1005 * uninitialized memory errors that would otherwise occur. */
1006 if (is_first && n == 1) {
1007 *subids = 0;
1008 return n;
1010 else if (!is_first && n == 0) {
1011 return n;
1014 for (i=0; i<oid_len; i++){
1015 uint8_t byte = oid_bytes[i];
1017 subid <<= 7;
1018 subid |= byte & 0x7F;
1020 if (byte & 0x80) {
1021 continue;
1024 if (is_first) {
1025 uint32_t subid0 = 0;
1027 if (subid >= 40) { subid0++; subid-=40; }
1028 if (subid >= 40) { subid0++; subid-=40; }
1030 *subids++ = subid0;
1032 is_first = false;
1035 if( subids >= subid_overflow || subid > 0xffffffff) {
1036 /* scope may be NULL in which case we must free our
1037 * useless buffer before returning */
1038 wmem_free(scope, *subids_p);
1039 *subids_p = NULL;
1040 return 0;
1043 *subids++ = (uint32_t)subid;
1044 subid = 0;
1047 ws_assert(subids == subid_overflow);
1049 return n;
1052 oid_info_t* oid_get(unsigned len, uint32_t* subids, unsigned* matched, unsigned* left) {
1053 oid_info_t* curr_oid = &oid_root;
1054 unsigned i;
1056 if(!(subids && *subids <= 2)) {
1057 *matched = 0;
1058 *left = len;
1059 return curr_oid;
1062 for( i=0; i < len; i++) {
1063 oid_info_t* next_oid = (oid_info_t *)wmem_tree_lookup32(curr_oid->children,subids[i]);
1064 if (next_oid) {
1065 curr_oid = next_oid;
1066 } else {
1067 goto done;
1070 done:
1071 *matched = i;
1072 *left = len - i;
1073 return curr_oid;
1077 oid_info_t* oid_get_from_encoded(wmem_allocator_t *scope, const uint8_t *bytes, int byteslen, uint32_t** subids_p, unsigned* matched_p, unsigned* left_p) {
1078 unsigned subids_len = oid_encoded2subid(scope, bytes, byteslen, subids_p);
1079 return oid_get(subids_len, *subids_p, matched_p, left_p);
1082 oid_info_t* oid_get_from_string(wmem_allocator_t *scope, const char *oid_str, uint32_t** subids_p, unsigned* matched, unsigned* left) {
1083 unsigned subids_len = oid_string2subid(scope, oid_str, subids_p);
1084 return oid_get(subids_len, *subids_p, matched, left);
1087 char *oid_resolved_from_encoded(wmem_allocator_t *scope, const uint8_t *oid, int oid_len) {
1088 uint32_t *subid_oid = NULL;
1089 char * ret;
1090 unsigned subid_oid_length = oid_encoded2subid(NULL, oid, oid_len, &subid_oid);
1092 ret = oid_resolved(scope, subid_oid_length, subid_oid);
1093 wmem_free(NULL, subid_oid);
1094 return ret;
1097 char *rel_oid_resolved_from_encoded(wmem_allocator_t *scope, const uint8_t *oid, int oid_len) {
1098 uint32_t *subid_oid = NULL;
1099 char* ret;
1100 unsigned subid_oid_length = oid_encoded2subid_sub(NULL, oid, oid_len, &subid_oid, false);
1102 ret = rel_oid_subid2string(scope, subid_oid, subid_oid_length, false);
1103 wmem_free(NULL, subid_oid);
1104 return ret;
1108 unsigned oid_subid2encoded(wmem_allocator_t *scope, unsigned subids_len, uint32_t* subids, uint8_t** bytes_p) {
1109 unsigned bytelen = 0;
1110 unsigned i;
1111 uint32_t subid;
1112 uint8_t* b;
1114 if ( !subids || subids_len <= 1) {
1115 *bytes_p = NULL;
1116 return 0;
1119 for (subid=subids[0] * 40, i = 1; i<subids_len; i++, subid=0) {
1120 subid += subids[i];
1121 if (subid <= 0x0000007F) {
1122 bytelen += 1;
1123 } else if (subid <= 0x00003FFF ) {
1124 bytelen += 2;
1125 } else if (subid <= 0x001FFFFF ) {
1126 bytelen += 3;
1127 } else if (subid <= 0x0FFFFFFF ) {
1128 bytelen += 4;
1129 } else {
1130 bytelen += 5;
1134 *bytes_p = b = (uint8_t *)wmem_alloc(scope, bytelen);
1136 for (subid=subids[0] * 40, i = 1; i<subids_len; i++, subid=0) {
1137 unsigned len;
1139 subid += subids[i];
1140 if ((subid <= 0x0000007F )) len = 1;
1141 else if ((subid <= 0x00003FFF )) len = 2;
1142 else if ((subid <= 0x001FFFFF )) len = 3;
1143 else if ((subid <= 0x0FFFFFFF )) len = 4;
1144 else len = 5;
1146 switch(len) {
1147 default: *bytes_p=NULL; return 0;
1148 case 5: *(b++) = ((subid & 0xF0000000) >> 28) | 0x80;
1149 /* FALL THROUGH */
1150 case 4: *(b++) = ((subid & 0x0FE00000) >> 21) | 0x80;
1151 /* FALL THROUGH */
1152 case 3: *(b++) = ((subid & 0x001FC000) >> 14) | 0x80;
1153 /* FALL THROUGH */
1154 case 2: *(b++) = ((subid & 0x00003F80) >> 7) | 0x80;
1155 /* FALL THROUGH */
1156 case 1: *(b++) = subid & 0x0000007F ; break;
1160 return bytelen;
1163 char* oid_encoded2string(wmem_allocator_t *scope, const uint8_t* encoded, unsigned len) {
1164 uint32_t* subids = NULL;
1165 char* ret;
1166 unsigned subids_len = oid_encoded2subid(NULL, encoded, len, &subids);
1168 if (subids_len) {
1169 ret = oid_subid2string(scope, subids,subids_len);
1170 } else {
1171 ret = wmem_strdup(scope, "");
1174 wmem_free(NULL, subids);
1175 return ret;
1178 char* rel_oid_encoded2string(wmem_allocator_t *scope, const uint8_t* encoded, unsigned len) {
1179 uint32_t* subids = NULL;
1180 char* ret;
1181 unsigned subids_len = oid_encoded2subid_sub(NULL, encoded, len, &subids, false);
1183 if (subids_len) {
1184 ret = rel_oid_subid2string(scope, subids,subids_len, false);
1185 } else {
1186 ret = wmem_strdup(scope, "");
1189 wmem_free(NULL, subids);
1190 return ret;
1193 unsigned oid_string2encoded(wmem_allocator_t *scope, const char *oid_str, uint8_t **bytes) {
1194 uint32_t* subids;
1195 uint32_t subids_len;
1196 unsigned byteslen;
1198 if ( (subids_len = oid_string2subid(NULL, oid_str, &subids)) &&
1199 (byteslen = oid_subid2encoded(scope, subids_len, subids, bytes)) ) {
1200 wmem_free(NULL, subids);
1201 return byteslen;
1203 wmem_free(NULL, subids);
1204 return 0;
1207 char *oid_resolved_from_string(wmem_allocator_t *scope, const char *oid_str) {
1208 uint32_t *subid_oid;
1209 unsigned subid_oid_length;
1210 char *resolved;
1212 subid_oid_length = oid_string2subid(NULL, oid_str, &subid_oid);
1213 resolved = oid_resolved(scope, subid_oid_length, subid_oid);
1215 wmem_free(NULL, subid_oid);
1217 return resolved;
1220 char *oid_resolved(wmem_allocator_t *scope, uint32_t num_subids, uint32_t* subids) {
1221 unsigned matched;
1222 unsigned left;
1223 oid_info_t* oid;
1225 if(! (subids && *subids <= 2 ))
1226 return wmem_strdup(scope, "*** Malformed OID ***");
1228 oid = oid_get(num_subids, subids, &matched, &left);
1230 while (! oid->name ) {
1231 if (!(oid = oid->parent)) {
1232 return oid_subid2string(scope, subids,num_subids);
1234 left++;
1235 matched--;
1238 if (left) {
1239 char *ret,
1240 *str1 = oid_subid2string(NULL, subids,matched),
1241 *str2 = oid_subid2string(NULL, &(subids[matched]),left);
1243 ret = wmem_strconcat(scope, oid->name ? oid->name : str1, ".", str2, NULL);
1244 wmem_free(NULL, str1);
1245 wmem_free(NULL, str2);
1246 return ret;
1247 } else {
1248 return oid->name ? wmem_strdup(scope, oid->name) : oid_subid2string(scope, subids,matched);
1252 extern void oid_both(wmem_allocator_t *scope, unsigned oid_len, uint32_t *subids, char** resolved_p, char** numeric_p) {
1253 *resolved_p = oid_resolved(scope, oid_len,subids);
1254 *numeric_p = oid_subid2string(scope, subids,oid_len);
1257 extern void oid_both_from_encoded(wmem_allocator_t *scope, const uint8_t *oid, int oid_len, char** resolved_p, char** numeric_p) {
1258 uint32_t* subids = NULL;
1259 unsigned subids_len = oid_encoded2subid(NULL, oid, oid_len, &subids);
1260 *resolved_p = oid_resolved(scope, subids_len,subids);
1261 *numeric_p = oid_subid2string(scope, subids,subids_len);
1262 wmem_free(NULL, subids);
1265 void oid_both_from_string(wmem_allocator_t *scope, const char *oid_str, char** resolved_p, char** numeric_p) {
1266 uint32_t *subids;
1267 unsigned subids_len;
1269 subids_len = oid_string2subid(NULL, oid_str, &subids);
1270 *resolved_p = oid_resolved(scope, subids_len,subids);
1271 *numeric_p = oid_subid2string(scope, subids,subids_len);
1272 wmem_free(NULL, subids);
1276 * Fetch the default OID path.
1278 extern char *
1279 oid_get_default_mib_path(void) {
1280 #ifdef HAVE_LIBSMI
1281 GString* path_str;
1282 char *path;
1283 unsigned i;
1285 path_str = g_string_new("");
1287 if (!load_smi_modules) {
1288 D(1,("OID resolution not enabled"));
1289 return g_string_free(path_str, FALSE);
1291 #ifdef _WIN32
1292 path = get_datafile_path("snmp\\mibs");
1293 g_string_append_printf(path_str, "%s;", path);
1294 g_free (path);
1296 path = get_persconffile_path("snmp\\mibs", false);
1297 g_string_append_printf(path_str, "%s", path);
1298 g_free (path);
1299 #else
1300 g_string_append(path_str, "/usr/share/snmp/mibs");
1301 if (!smi_init_done)
1302 smiInit("wireshark");
1303 path = smiGetPath();
1304 if (strlen(path) > 0 ) {
1305 g_string_append(path_str, G_SEARCHPATH_SEPARATOR_S);
1306 g_string_append_printf(path_str, "%s", path);
1308 smi_free(path);
1310 if (oids_init_done == false)
1312 #endif
1313 for (i = 0; i < num_smi_paths; i++) {
1314 if (!(smi_paths[i].name && *smi_paths[i].name))
1315 continue;
1317 g_string_append_printf(path_str, G_SEARCHPATH_SEPARATOR_S "%s", smi_paths[i].name);
1319 #ifndef _WIN32
1321 #endif
1322 return g_string_free(path_str, FALSE);
1323 #else /* HAVE_LIBSMI */
1324 return g_strdup("");
1325 #endif
1328 #ifdef DEBUG_OIDS
1329 char* oid_test_a2b(uint32_t num_subids, uint32_t* subids) {
1330 uint8_t* sub2enc = NULL;
1331 uint8_t* str2enc = NULL;
1332 uint32_t* enc2sub = NULL;
1333 uint32_t* str2sub;
1334 char* ret;
1335 char* sub2str = oid_subid2string(NULL, subids, num_subids);
1336 unsigned sub2enc_len = oid_subid2encoded(NULL, num_subids, subids,&sub2enc);
1337 unsigned enc2sub_len = oid_encoded2subid(NULL, sub2enc, sub2enc_len, &enc2sub);
1338 char* enc2str = oid_encoded2string(NULL, sub2enc, sub2enc_len);
1339 unsigned str2enc_len = oid_string2encoded(NULL, sub2str,&str2enc);
1340 unsigned str2sub_len = oid_string2subid(sub2str,&str2sub);
1342 char* sub2enc_str = bytes_to_str_punct(NULL, sub2enc, sub2enc_len, ':');
1343 char* enc2sub_str = enc2sub ? oid_subid2string(NULL, enc2sub,enc2sub_len) : wmem_strdup(NULL, "-");
1344 char* str2enc_str = bytes_to_str_punct(NULL, str2enc, str2enc_len, ':');
1345 char* str2sub_str = str2sub ? oid_subid2string(NULL, str2sub,str2sub_len) : wmem_strdup(NULL, "-");
1347 ret = wmem_strdup_printf(NULL,
1348 "oid_subid2string=%s \n"
1349 "oid_subid2encoded=[%d]%s \n"
1350 "oid_encoded2subid=%s \n "
1351 "oid_encoded2string=%s \n"
1352 "oid_string2encoded=[%d]%s \n"
1353 "oid_string2subid=%s \n "
1354 ,sub2str
1355 ,sub2enc_len,sub2enc_str
1356 ,enc2sub_str
1357 ,enc2str
1358 ,str2enc_len,str2enc_str,
1359 ,str2sub_str
1362 wmem_free(NULL, sub2enc_str);
1363 wmem_free(NULL, enc2sub_str);
1364 wmem_free(NULL, str2enc_str);
1365 wmem_free(NULL, str2sub_str);
1367 wmem_free(NULL, sub2str);
1368 wmem_free(NULL, enc2sub);
1369 wmem_free(NULL, sub2enc);
1370 wmem_free(NULL, str2enc);
1371 wmem_free(NULL, enc2str);
1372 return ret;
1375 void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree) {
1376 static const char* oid_kinds[] = { "Unknown", "Node", "Scalar", "Table", "Row", "Column", "Notification", "Group", "Compliance", "Capabilities"};
1377 static const char* key_types[] = {"OID_KEY_TYPE_WRONG","OID_KEY_TYPE_INTEGER",
1378 "OID_KEY_TYPE_FIXED_STRING","OID_KEY_TYPE_FIXED_BYTES","OID_KEY_TYPE_STRING",
1379 "OID_KEY_TYPE_BYTES","OID_KEY_TYPE_NSAP","OID_KEY_TYPE_OID","OID_KEY_TYPE_IPADDR"};
1380 proto_item* pi = proto_tree_add_debug_text(tree,NULL,0,0,
1381 "OidInfo: Name='%s' sub-id=%u kind=%s hfid=%d",
1382 oid_info->name ? oid_info->name : "",
1383 oid_info->subid,
1384 oid_info->kind <= OID_KIND_CAPABILITIES ? oid_kinds[oid_info->kind] : "BROKEN",
1385 oid_info->value_hfid);
1386 proto_tree* pt = proto_item_add_subtree(pi,0);
1387 oid_key_t* key;
1389 for(key = oid_info->key; key; key = key->next) {
1390 proto_tree_add_debug_text(pt,NULL,0,0,
1391 "Key: name='%s' num_subids=%d type=%s",
1392 key->name,
1393 key->key_type <= OID_KEY_TYPE_IPADDR ? key_types[key->key_type] : "BROKEN"
1397 if (oid_info->parent) {
1398 pi = proto_tree_add_debug_text(pt,NULL,0,0,"Parent:");
1399 pt = proto_item_add_subtree(pi,0);
1400 add_oid_debug_subtree(oid_info->parent, pt);
1403 #endif
1406 * Editor modelines
1408 * Local Variables:
1409 * c-basic-offset: 8
1410 * tab-width: 8
1411 * indent-tabs-mode: t
1412 * End:
1414 * ex: set shiftwidth=8 tabstop=8 noexpandtab:
1415 * :indentSize=8:tabSize=8:noTabs=false: