rerun pidl
[metze/wireshark/wip.git] / epan / oids.c
1 /* oids.c
2  * Object IDentifier Support
3  *
4  * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
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.
16  *
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.
21  *
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.
25  */
26
27 #include "config.h"
28
29 #include <glib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33
34 #include <wsutil/report_err.h>
35
36 #include "emem.h"
37 #include "wmem/wmem.h"
38 #include "uat.h"
39 #include "prefs.h"
40 #include "proto.h"
41 #include "packet.h"
42 #include "wsutil/filesystem.h"
43 #include "dissectors/packet-ber.h"
44
45 #ifdef HAVE_LIBSMI
46 #include <smi.h>
47
48 static gboolean oids_init_done = FALSE;
49 static gboolean load_smi_modules = FALSE;
50 static gboolean suppress_smi_errors = FALSE;
51 #endif
52
53 #define D(level,args) do if (debuglevel >= level) { printf args; printf("\n"); fflush(stdout); } while(0)
54
55 #include "oids.h"
56
57 static int debuglevel = 0;
58
59 /*
60  * From SNMPv2-SMI and X.690
61  *
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)
66  *
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.
69  */
70
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};
78 #if 0
79 static const oid_value_type_t opaque_type =     { FT_BYTES,  BASE_NONE, BER_CLASS_APP, 4,                       1,   4, OID_KEY_TYPE_BYTES,   0};
80 #endif
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};
90
91 static oid_info_t oid_root = { 0, NULL, OID_KIND_UNKNOWN, NULL, &unknown_type, -2, NULL, NULL, NULL};
92
93 static void prepopulate_oids(void) {
94         if (!oid_root.children) {
95                 char* debug_env = getenv("WIRESHARK_DEBUG_MIBS");
96                 guint32 subid;
97
98                 debuglevel = debug_env ? (int)strtoul(debug_env,NULL,10) : 0;
99
100                 oid_root.children = wmem_tree_new(wmem_epan_scope());
101
102                 /*
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
105                  */
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);
109         }
110 }
111
112         
113
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) {
115         guint i = 0;
116         oid_info_t* c = &oid_root;
117
118         prepopulate_oids();
119         oid_len--;
120
121         do {
122                 oid_info_t* n = (oid_info_t *)wmem_tree_lookup32(c->children,subids[i]);
123
124                 if(n) {
125                         if (i == oid_len) {
126                                 if (n->name) {
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));
129                                         }
130                                         wmem_free(wmem_epan_scope(), n->name);
131                                 }
132
133                                 n->name = wmem_strdup(wmem_epan_scope(), name);
134
135                                 if (! n->value_type) {
136                                         n->value_type = type;
137                                 }
138
139                                 return n;
140                         }
141                 } else {
142                         n = wmem_new(wmem_epan_scope(), oid_info_t);
143                         n->subid = subids[i];
144                         n->kind = kind;
145                         n->children = wmem_tree_new(wmem_epan_scope());
146                         n->value_hfid = -2;
147                         n->key = key;
148                         n->parent = c;
149                         n->bits = NULL;
150
151                         wmem_tree_insert32(c->children,n->subid,n);
152
153                         if (i == oid_len) {
154                                 n->name = wmem_strdup(wmem_epan_scope(), name);
155                                 n->value_type = type;
156                                 n->kind = kind;
157                                 return n;
158                         } else {
159                                 n->name = NULL;
160                                 n->value_type = NULL;
161                                 n->kind = OID_KIND_UNKNOWN;
162                         }
163                 }
164                 c = n;
165         } while(++i);
166
167         g_assert_not_reached();
168         return NULL;
169 }
170
171 void oid_add(const char* name, guint oid_len, guint32 *subids) {
172         g_assert(subids && *subids <= 2);
173         if (oid_len) {
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);
176         } else {
177                 D(1,("Failed to add Oid: %s (from subids)",name?name:"NULL"));
178         }
179 }
180
181 void oid_add_from_string(const char* name, const gchar *oid_str) {
182         guint32* subids;
183         guint oid_len = oid_string2subid(NULL, oid_str, &subids);
184
185         if (oid_len) {
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);
188         } else {
189                 D(1,("Failed to add Oid: %s %s ",name?name:"NULL", oid_str?oid_str:NULL));
190         }
191         wmem_free(NULL, subids);
192 }
193
194 extern void oid_add_from_encoded(const char* name, const guint8 *oid, gint oid_len) {
195         guint32* subids;
196         guint subids_len = oid_encoded2subid(oid, oid_len, &subids);
197
198         if (subids_len) {
199                 D(3,("\tOid (from encoded): %s %s ",name, oid_subid2string(subids,subids_len)));
200                 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,subids_len,subids);
201         } else {
202                 D(1,("Failed to add Oid: %s [%d]%s ",name?name:"NULL", oid_len,bytestring_to_ep_str(oid, oid_len, ':')));
203         }
204 }
205
206 #ifdef HAVE_LIBSMI
207 /* de-allocate storage mallocated by libsmi                            */
208 /*                                                                     */
209 /* XXX: libsmi provides access to smiFree as of libsmi v 0.4.8.        */
210 /*      On Windows: Wireshark 1.01 and later is built and distributed  */
211 /*      with libsmi 0.4.8 (or newer).                                  */
212 /*      On non-Windows systems, free() should be OK for libsmi         */
213 /*       versions older than 0.4.8.                                    */
214
215 static void smi_free(void *ptr) {
216
217 #if (SMI_VERSION_MAJOR >= 0) && (SMI_VERSION_MINOR >= 4) && (SMI_VERSION_PATCHLEVEL >= 8)
218        smiFree(ptr);
219 #else
220  #ifdef _WIN32
221  #error Invalid Windows libsmi version ?? !!
222  #endif
223 #define xx_free free  /* hack so checkAPIs.pl doesn't complain */
224        xx_free(ptr);
225 #endif
226 }
227
228
229 typedef struct smi_module_t {
230         char* name;
231 } smi_module_t;
232
233 static smi_module_t* smi_paths = NULL;
234 static guint num_smi_paths = 0;
235 static uat_t* smi_paths_uat = NULL;
236
237 static smi_module_t* smi_modules = NULL;
238 static guint num_smi_modules = 0;
239 static uat_t* smi_modules_uat = NULL;
240
241 static GString* smi_errors;
242
243 UAT_DIRECTORYNAME_CB_DEF(smi_mod,name,smi_module_t)
244
245 static void smi_error_handler(char *path, int line, int severity, char *msg, char *tag) {
246                 g_string_append_printf(smi_errors,"%s:%d %d %s %s\n",
247                                                   path ? path : "-",
248                                                   line, severity,
249                                                   tag ? tag : "-",
250                                                   msg ? msg : "");
251 }
252
253
254 static void* smi_mod_copy_cb(void* dest, const void* orig, size_t len _U_) {
255         const smi_module_t* m = (const smi_module_t*)orig;
256         smi_module_t* d = (smi_module_t*)dest;
257
258         d->name = g_strdup(m->name);
259
260         return d;
261 }
262
263 static void smi_mod_free_cb(void* p) {
264         smi_module_t* m = (smi_module_t*)p;
265         g_free(m->name);
266 }
267
268
269 static char* alnumerize(const char* name) {
270         char* s = g_strdup(name);
271         char* r = s;
272         char* w = r;
273         char c;
274
275         for (;(c = *r); r++) {
276                 if (isalnum(c) || c == '_' || c == '-' || c == '.') {
277                         *(w++) = c;
278                 } else if (c == ':' && r[1] == ':') {
279                         *(w++) = '.';
280                 }
281         }
282
283         *w = '\0';
284
285         return s;
286 }
287
288 static const oid_value_type_t* get_typedata(SmiType* smiType) {
289         /*
290          * There has to be a better way to know if a given
291          * OCTETSTRING type is actually human readable text,
292          * an address of some type or some moe specific FT_
293          * Until that is found, this is the mappping between
294          * SNMP Types and our FT_s
295          */
296         static const struct _type_mapping_t {
297                 const char* name;
298                 SmiBasetype base;
299                 const oid_value_type_t* type;
300         } types[] =  {
301                 {"IpAddress", SMI_BASETYPE_UNKNOWN, &ipv4_type},
302                 {"InetAddressIPv4",SMI_BASETYPE_UNKNOWN,&ipv4_type},
303                 {"InetAddressIPv6",SMI_BASETYPE_UNKNOWN,&ipv6_type},
304                 {"NetworkAddress",SMI_BASETYPE_UNKNOWN,&ipv4_type},
305                 {"MacAddress",SMI_BASETYPE_UNKNOWN,&ether_type},
306                 {"TimeTicks",SMI_BASETYPE_UNKNOWN,&timeticks_type},
307                 {"Ipv6Address",SMI_BASETYPE_UNKNOWN,&ipv6_type},
308                 {"TimeStamp",SMI_BASETYPE_UNKNOWN,&timeticks_type},
309                 {"DisplayString",SMI_BASETYPE_UNKNOWN,&string_type},
310                 {"SnmpAdminString",SMI_BASETYPE_UNKNOWN,&string_type},
311                 {"DateAndTime",SMI_BASETYPE_UNKNOWN,&date_and_time_type},
312                 {"Counter",SMI_BASETYPE_UNKNOWN,&counter32_type},
313                 {"Counter32",SMI_BASETYPE_UNKNOWN,&counter32_type},
314                 {"Unsigned32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
315                 {"Gauge",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
316                 {"Gauge32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
317                 {"NsapAddress",SMI_BASETYPE_UNKNOWN,&nsap_type},
318                 {"i32",SMI_BASETYPE_INTEGER32,&integer_type},
319                 {"octets",SMI_BASETYPE_OCTETSTRING,&bytes_type},
320                 {"oid",SMI_BASETYPE_OBJECTIDENTIFIER,&oid_type},
321                 {"u32",SMI_BASETYPE_UNSIGNED32,&unsigned32_type},
322                 {"u64",SMI_BASETYPE_UNSIGNED64,&counter64_type},
323                 {"f32",SMI_BASETYPE_FLOAT32,&float_type},
324                 {"f64",SMI_BASETYPE_FLOAT64,&double_type},
325                 {"f128",SMI_BASETYPE_FLOAT128,&bytes_type},
326                 {"enum",SMI_BASETYPE_ENUM,&integer_type},
327                 {"bits",SMI_BASETYPE_BITS,&bytes_type},
328                 {"unk",SMI_BASETYPE_UNKNOWN,&unknown_type},
329                 {NULL,SMI_BASETYPE_UNKNOWN,NULL} /* SMI_BASETYPE_UNKNOWN = 0 */
330         };
331         const struct _type_mapping_t* t;
332         SmiType* sT = smiType;
333
334         if (!smiType) return NULL;
335
336         do {
337                 for (t = types; t->type ; t++ ) {
338                         char* name = smiRenderType(sT, SMI_RENDER_NAME);
339                         if (name && t->name && g_str_equal(name, t->name )) {
340                                 smi_free(name);
341                                 return t->type;
342                         }
343                         if (name) {
344                                 smi_free (name);
345                         }
346                 }
347         } while(( sT  = smiGetParentType(sT) ));
348
349         for (t = types; t->type ; t++ ) {
350                 if(smiType->basetype == t->base) {
351                         return t->type;
352                 }
353         }
354
355         return &unknown_type;
356 }
357
358 static guint get_non_implicit_size(SmiType* sT) {
359         SmiRange *sR;
360         guint size = 0xffffffff;
361
362         switch (sT->basetype) {
363                 case SMI_BASETYPE_OCTETSTRING:
364                 case SMI_BASETYPE_OBJECTIDENTIFIER:
365                         break;
366                 default:
367                         return 0;
368         }
369
370         for ( ; sT; sT = smiGetParentType(sT) ) {
371                 for (sR = smiGetFirstRange(sT); sR ; sR = smiGetNextRange(sR)) {
372                         if (size == 0xffffffff) {
373                                 if (sR->minValue.value.unsigned32 == sR->maxValue.value.unsigned32) {
374                                         size = (guint32)sR->minValue.value.unsigned32;
375                                 } else {
376                                         return 0;
377                                 }
378                         } else {
379                                 if (sR->minValue.value.unsigned32 != size || sR->maxValue.value.unsigned32 != size) {
380                                         return 0;
381                                 }
382                         }
383                 }
384         }
385
386         return size == 0xffffffff ? 0 : size;
387 }
388
389
390 static inline oid_kind_t smikind(SmiNode* sN, oid_key_t** key_p) {
391         *key_p = NULL;
392
393         switch(sN->nodekind) {
394                 case SMI_NODEKIND_ROW: {
395                         SmiElement* sE;
396                         oid_key_t* kl = NULL;
397                         const oid_value_type_t* typedata = NULL;
398                         gboolean implied;
399
400                         switch (sN->indexkind) {
401                                 case SMI_INDEX_INDEX:
402                                         break;
403                                 case SMI_INDEX_AUGMENT:
404                                 case SMI_INDEX_REORDER:
405                                 case SMI_INDEX_SPARSE:
406                                 case SMI_INDEX_EXPAND:
407                                         sN = smiGetRelatedNode(sN);
408                                         break;
409                                 case SMI_INDEX_UNKNOWN:
410                                         return OID_KIND_UNKNOWN;
411                         };
412
413                         implied = sN->implied;
414
415                         for (sE = smiGetFirstElement(sN); sE; sE = smiGetNextElement(sE)) {
416                                 SmiNode* elNode =  smiGetElementNode(sE) ;
417                                 SmiType* elType = smiGetNodeType(elNode);
418                                 oid_key_t* k;
419                                 guint non_implicit_size = 0;
420                                 char *oid1, *oid2;
421
422                                 if (elType) {
423                                         non_implicit_size = get_non_implicit_size(elType);
424                                 }
425
426                                 typedata =  get_typedata(elType);
427
428                                 k = g_new(oid_key_t,1);
429
430                                 oid1 = smiRenderOID(sN->oidlen, sN->oid, SMI_RENDER_QUALIFIED);
431                                 oid2 = smiRenderOID(elNode->oidlen, elNode->oid, SMI_RENDER_NAME);
432                                 k->name = g_strdup_printf("%s.%s", oid1, oid2);
433                                 smi_free (oid1);
434                                 smi_free (oid2);
435
436                                 k->hfid = -2;
437                                 k->ft_type = typedata ? typedata->ft_type : FT_BYTES;
438                                 k->display = typedata ? typedata->display : BASE_NONE;
439                                 k->next = NULL;
440
441
442                                 if (typedata) {
443                                         k->key_type = typedata->keytype;
444                                         k->num_subids = typedata->keysize;
445                                 } else {
446                                         if (elType) {
447                                                 switch (elType->basetype) {
448                                                         case SMI_BASETYPE_BITS:
449                                                         case SMI_BASETYPE_OCTETSTRING: {
450                                                                 k->key_type = OID_KEY_TYPE_BYTES;
451                                                                 k->num_subids = non_implicit_size;
452                                                                 break;
453                                                         }
454                                                         case SMI_BASETYPE_ENUM:
455                                                         case SMI_BASETYPE_OBJECTIDENTIFIER:
456                                                         case SMI_BASETYPE_INTEGER32:
457                                                         case SMI_BASETYPE_UNSIGNED32:
458                                                         case SMI_BASETYPE_INTEGER64:
459                                                         case SMI_BASETYPE_UNSIGNED64:
460                                                                 k->key_type = OID_KEY_TYPE_INTEGER;
461                                                                 k->num_subids = 1;
462                                                                 break;
463                                                         default:
464                                                                 k->key_type = OID_KEY_TYPE_WRONG;
465                                                                 k->num_subids = 0;
466                                                                 break;
467                                                 }
468                                         } else {
469                                                 k->key_type = OID_KEY_TYPE_WRONG;
470                                                 k->num_subids = 0;
471                                                 break;
472                                         }
473                                 }
474
475                                 if (!*key_p) *key_p = k;
476                                 if (kl) kl->next = k;
477
478                                 kl = k;
479                         }
480
481                         if (implied && kl) {
482                                 switch (kl->key_type) {
483                                         case OID_KEY_TYPE_BYTES:  kl->key_type = OID_KEY_TYPE_IMPLIED_BYTES; break;
484                                         case OID_KEY_TYPE_STRING: kl->key_type = OID_KEY_TYPE_IMPLIED_STRING; break;
485                                         case OID_KEY_TYPE_OID:    kl->key_type = OID_KEY_TYPE_IMPLIED_OID; break;
486                                         default: break;
487                                 }
488                         }
489
490                         return OID_KIND_ROW;
491                 }
492                 case SMI_NODEKIND_NODE: return OID_KIND_NODE;
493                 case SMI_NODEKIND_SCALAR: return OID_KIND_SCALAR;
494                 case SMI_NODEKIND_TABLE: return OID_KIND_TABLE;
495                 case SMI_NODEKIND_COLUMN: return OID_KIND_COLUMN;
496                 case SMI_NODEKIND_NOTIFICATION: return OID_KIND_NOTIFICATION;
497                 case SMI_NODEKIND_GROUP: return OID_KIND_GROUP;
498                 case SMI_NODEKIND_COMPLIANCE: return OID_KIND_COMPLIANCE;
499                 case SMI_NODEKIND_CAPABILITIES: return OID_KIND_CAPABILITIES;
500                 default: return OID_KIND_UNKNOWN;
501         }
502 }
503
504 #define IS_ENUMABLE(ft) ( (ft == FT_UINT8) || (ft == FT_UINT16) || (ft == FT_UINT24) || (ft == FT_UINT32) \
505                                                    || (ft == FT_INT8) || (ft == FT_INT16) || (ft == FT_INT24) || (ft == FT_INT32) \
506                                                    || (ft == FT_UINT64) || (ft == FT_INT64) )
507
508 static void unregister_mibs(void) {
509         /* TODO: Unregister "MIBs" proto and clean up field array and subtree array.
510          * Wireshark does not support that yet. :-( */
511
512         /* smiExit(); */
513 }
514
515 static void restart_needed_warning(void) {
516         if (oids_init_done)
517                 report_failure("Wireshark needs to be restarted for these changes to take effect");
518 }
519
520 static void register_mibs(void) {
521         SmiModule *smiModule;
522         SmiNode *smiNode;
523         guint i;
524         int proto_mibs = -1;
525         wmem_array_t* hfa;
526         GArray* etta;
527         gchar* path_str;
528
529         if (!load_smi_modules) {
530                 D(1,("OID resolution not enabled"));
531                 return;
532         }
533
534         /* TODO: Remove this workaround when unregistration of "MIBs" proto is solved.
535          * Wireshark does not support that yet. :-( */
536         if (oids_init_done) {
537                 D(1,("Exiting register_mibs() to avoid double registration of MIBs proto."));
538                 return;
539         } else {
540                 oids_init_done = TRUE;
541         }
542
543         hfa = wmem_array_new(wmem_epan_scope(), sizeof(hf_register_info));
544         etta = g_array_new(FALSE,TRUE,sizeof(gint*));
545
546         smiInit(NULL);
547
548         smi_errors = g_string_new("");
549         smiSetErrorHandler(smi_error_handler);
550
551         path_str = oid_get_default_mib_path();
552         D(1,("SMI Path: '%s'",path_str));
553
554         smiSetPath(path_str);
555
556         for(i=0;i<num_smi_modules;i++) {
557                 if (!smi_modules[i].name) continue;
558
559                 if (smiIsLoaded(smi_modules[i].name)) {
560                         continue;
561                 } else {
562                         char* mod_name =  smiLoadModule(smi_modules[i].name);
563                         if (mod_name)
564                                 D(2,("Loaded: '%s'[%d] as %s",smi_modules[i].name,i,mod_name ));
565                         else
566                                 D(1,("Failed to load: '%s'[%d]",smi_modules[i].name,i));
567                 }
568         }
569
570         if (smi_errors->len) {
571                 if (!suppress_smi_errors) {
572                         report_failure("The following errors were found while loading the MIBS:\n%s\n\n"
573                                            "The Current Path is: %s\n\nYou can avoid this error message "
574                                            "by removing the missing MIB modules at Edit -> Preferences"
575                                            " -> Name Resolution -> SMI (MIB and PIB) modules or by "
576                                            "installing them.\n" , smi_errors->str , path_str);
577                 }
578                 D(1,("Errors while loading:\n%s\n",smi_errors->str));
579         }
580
581         g_free(path_str);
582         g_string_free(smi_errors,TRUE);
583
584         for (smiModule = smiGetFirstModule();
585                  smiModule;
586                  smiModule = smiGetNextModule(smiModule)) {
587
588                 D(3,("\tModule: %s", smiModule->name));
589
590                 /* TODO: Check libsmi version at compile time and disable this
591                  * workaround for libsmi versions where this problem is fixed.
592                  * Currently there is no such version. :-(
593                  */
594                 if (smiModule->conformance == 1) {
595                         if (!suppress_smi_errors) {
596                                 report_failure("Stopped processing module %s due to "
597                                         "error(s) to prevent potential crash in libsmi.\n"
598                                         "Module's conformance level: %d.\n"
599                                         "See details at: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=560325\n",
600                                          smiModule->name, smiModule->conformance);
601                         }
602                         continue;
603                 }
604                 for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
605                          smiNode;
606                          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
607
608                         SmiType* smiType =  smiGetNodeType(smiNode);
609                         const oid_value_type_t* typedata =  get_typedata(smiType);
610                         oid_key_t* key;
611                         oid_kind_t kind = smikind(smiNode,&key);
612                         char *oid = smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_QUALIFIED);
613                         oid_info_t* oid_data = add_oid(oid,
614                                                        kind,
615                                                        typedata,
616                                                        key,
617                                                        smiNode->oidlen,
618                                                        smiNode->oid);
619                         smi_free (oid);
620
621                         D(4,("\t\tNode: kind=%d oid=%s name=%s ",
622                                  oid_data->kind, oid_subid2string(smiNode->oid, smiNode->oidlen), oid_data->name ));
623
624                         if ( typedata && oid_data->value_hfid == -2 ) {
625                                 SmiNamedNumber* smiEnum;
626                                 hf_register_info hf;
627
628                 hf.p_id                     = &(oid_data->value_hfid);
629                 hf.hfinfo.name              = oid_data->name;
630                 hf.hfinfo.abbrev            = alnumerize(oid_data->name);
631                 hf.hfinfo.type              = typedata->ft_type;
632                 hf.hfinfo.display           = typedata->display;
633                 hf.hfinfo.strings           = NULL;
634                 hf.hfinfo.bitmask           = 0;
635                 hf.hfinfo.blurb             = smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_ALL);
636                 /* HFILL */
637                 HFILL_INIT(hf);
638
639                                 /* Don't allow duplicate blurb/name */
640                                 if (strcmp(hf.hfinfo.blurb, hf.hfinfo.name) == 0) {
641                                         smi_free((void *) hf.hfinfo.blurb);
642                                         hf.hfinfo.blurb = NULL;
643                                 }
644
645                                 oid_data->value_hfid = -1;
646
647                                 if ( IS_ENUMABLE(hf.hfinfo.type) && (smiEnum = smiGetFirstNamedNumber(smiType))) {
648                                         GArray* vals = g_array_new(TRUE,TRUE,sizeof(value_string));
649
650                                         for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum)) {
651                                                 if (smiEnum->name) {
652                             value_string val;
653                             val.value  = (guint32)smiEnum->value.value.integer32;
654                             val.strptr = g_strdup(smiEnum->name);
655                                                         g_array_append_val(vals,val);
656                                                 }
657                                         }
658
659                                         hf.hfinfo.strings = vals->data;
660                                         g_array_free(vals,FALSE);
661                                 }
662 #if 0 /* packet-snmp does not handle bits yet */
663                         } else if (smiType->basetype == SMI_BASETYPE_BITS && ( smiEnum = smiGetFirstNamedNumber(smiType) )) {
664                                 guint n = 0;
665                                 oid_bits_info_t* bits = g_malloc(sizeof(oid_bits_info_t));
666                                 gint* ettp = &(bits->ett);
667
668                                 bits->num = 0;
669                                 bits->ett = -1;
670
671                                 g_array_append_val(etta,ettp);
672
673                                 for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum), bits->num++);
674
675                                 bits->data = g_malloc(sizeof(struct _oid_bit_t)*bits->num);
676
677                                 for(smiEnum = smiGetFirstNamedNumber(smiType),n=0;
678                                         smiEnum;
679                                         smiEnum = smiGetNextNamedNumber(smiEnum),n++) {
680                                         guint mask = 1 << (smiEnum->value.value.integer32 % 8);
681                                         char* base = alnumerize(oid_data->name);
682                                         char* ext = alnumerize(smiEnum->name);
683                                         hf_register_info hf2 = { &(bits->data[n].hfid), { NULL, NULL, FT_UINT8, BASE_HEX, NULL, mask, NULL, HFILL }};
684
685                                         bits->data[n].hfid = -1;
686                                         bits->data[n].offset = smiEnum->value.value.integer32 / 8;
687
688                                         hf2.hfinfo.name = g_strdup_printf("%s:%s",oid_data->name,smiEnum->name);
689                                         hf2.hfinfo.abbrev = g_strdup_printf("%s.%s",base,ext);
690
691                                         g_free(base);
692                                         g_free(ext);
693                                         g_array_append_val(hfa,hf2);
694                                 }
695 #endif /* packet-snmp does not use this yet */
696                                 wmem_array_append_one(hfa,hf);
697                         }
698
699                         if ((key = oid_data->key)) {
700                                 for(; key; key = key->next) {
701                                         hf_register_info hf;
702
703                                         hf.p_id                     = &(key->hfid);
704                                         hf.hfinfo.name              = key->name;
705                                         hf.hfinfo.abbrev            = alnumerize(key->name);
706                                         hf.hfinfo.type              = key->ft_type;
707                                         hf.hfinfo.display           = key->display;
708                                         hf.hfinfo.strings           = NULL;
709                                         hf.hfinfo.bitmask           = 0;
710                                         hf.hfinfo.blurb             = NULL;
711                     /* HFILL */
712                     HFILL_INIT(hf);
713
714                                         D(5,("\t\t\tIndex: name=%s subids=%d key_type=%d",
715                                                  key->name, key->num_subids, key->key_type ));
716
717                                         if (key->hfid == -2) {
718                                                 wmem_array_append_one(hfa,hf);
719                                                 key->hfid = -1;
720                                         } else {
721                                                 g_free((void*)hf.hfinfo.abbrev);
722                                         }
723                                 }
724                         }
725                 }
726         }
727
728         proto_mibs = proto_register_protocol("MIBs", "MIBS", "mibs");
729
730         proto_register_field_array(proto_mibs, (hf_register_info*)wmem_array_get_raw(hfa), wmem_array_get_count(hfa));
731
732         proto_register_subtree_array((gint**)(void*)etta->data, etta->len);
733
734         g_array_free(etta,TRUE);
735 }
736 #endif
737
738 void oid_pref_init(module_t *nameres)
739 {
740 #ifdef HAVE_LIBSMI
741         static uat_field_t smi_fields[] = {
742                 UAT_FLD_CSTRING(smi_mod,name,"Module name","The module's name"),
743                 UAT_END_FIELDS
744         };
745         static uat_field_t smi_paths_fields[] = {
746                 UAT_FLD_DIRECTORYNAME(smi_mod,name,"Directory path","The directory name"),
747                 UAT_END_FIELDS
748         };
749
750     prefs_register_bool_preference(nameres, "load_smi_modules",
751                                   "Enable OID resolution",
752                                   "You must restart Wireshark for this change to take effect",
753                                   &load_smi_modules);
754
755     prefs_register_bool_preference(nameres, "suppress_smi_errors",
756                                   "Suppress SMI errors",
757                                   "Some errors can be ignored. If unsure, set to false.",
758                                   &suppress_smi_errors);
759
760     smi_paths_uat = uat_new("SMI Paths",
761                             sizeof(smi_module_t),
762                             "smi_paths",
763                             FALSE,
764                             (void**)&smi_paths,
765                             &num_smi_paths,
766     /* affects dissection of packets (as the MIBs and PIBs affect the
767        interpretation of e.g. SNMP variable bindings), but not set of
768        named fields
769
770        XXX - if named fields are generated from the MIBs and PIBs
771        for particular variable bindings, this *does* affect the set
772        of named fields! */
773                             UAT_AFFECTS_DISSECTION,
774                             "ChSNMPSMIPaths",
775                             smi_mod_copy_cb,
776                             NULL,
777                             smi_mod_free_cb,
778                             restart_needed_warning,
779                             smi_paths_fields);
780
781     prefs_register_uat_preference(nameres,
782                                   "smi_paths",
783                                   "SMI (MIB and PIB) paths",
784                                   "Search paths for SMI (MIB and PIB) modules. You must\n"
785                                   "restart Wireshark for these changes to take effect.",
786                                   smi_paths_uat);
787
788     smi_modules_uat = uat_new("SMI Modules",
789                               sizeof(smi_module_t),
790                               "smi_modules",
791                               FALSE,
792                               (void**)&smi_modules,
793                               &num_smi_modules,
794     /* affects dissection of packets (as the MIBs and PIBs affect the
795        interpretation of e.g. SNMP variable bindings), but not set of
796        named fields
797
798        XXX - if named fields are generated from the MIBs and PIBs
799        for particular variable bindings, would this affect the set
800        of named fields? */
801                               UAT_AFFECTS_DISSECTION,
802                               "ChSNMPSMIModules",
803                               smi_mod_copy_cb,
804                               NULL,
805                               smi_mod_free_cb,
806                               restart_needed_warning,
807                               smi_fields);
808
809     prefs_register_uat_preference(nameres,
810                                   "smi_modules",
811                                   "SMI (MIB and PIB) modules",
812                                   "List of enabled SMI (MIB and PIB) modules. You must\n"
813                                   "restart Wireshark for these changes to take effect.",
814                                   smi_modules_uat);
815
816 #else
817     prefs_register_static_text_preference(nameres, "load_smi_modules_static",
818                             "Enable OID resolution: N/A",
819                             "Support for OID resolution was not compiled into this version of Wireshark");
820
821     prefs_register_static_text_preference(nameres, "suppress_smi_errors_static",
822                             "Suppress SMI errors: N/A",
823                             "Support for OID resolution was not compiled into this version of Wireshark");
824
825     prefs_register_static_text_preference(nameres, "smi_module_path",
826                             "SMI (MIB and PIB) modules and paths: N/A",
827                             "Support for OID resolution was not compiled into this version of Wireshark");
828 #endif
829 }
830
831 void oids_init(void) {
832         prepopulate_oids();
833 #ifdef HAVE_LIBSMI
834         register_mibs();
835 #else
836         D(1,("libsmi disabled oid resolution not enabled"));
837 #endif
838 }
839
840 void oids_cleanup(void) {
841 #ifdef HAVE_LIBSMI
842         unregister_mibs();
843 #else
844         D(1,("libsmi disabled oid resolution not enabled"));
845 #endif
846 }
847
848 const char* oid_subid2string(guint32* subids, guint len) {
849     return rel_oid_subid2string(subids, len, TRUE);
850 }
851 const char* rel_oid_subid2string(guint32* subids, guint len, gboolean is_absolute) {
852         char *s, *w;
853
854         if(!subids || len == 0)
855                 return "*** Empty OID ***";
856
857         s = (char *)ep_alloc0(((len)*11)+2);
858         w = s;
859
860         if (!is_absolute)
861                 *w++ = '.';
862
863         do {
864                 w += g_snprintf(w,12,"%u.",*subids++);
865         } while(--len);
866
867         if (w!=s) *(w-1) = '\0'; else *(s) = '\0';
868
869         return s;
870 }
871
872 static guint check_num_oid(const char* str) {
873         const char* r = str;
874         char c = '.';
875         guint n = 0;
876
877         D(8,("check_num_oid: '%s'",str));
878         if (!r) return 0;
879
880         do {
881                 D(9,("\tcheck_num_oid: '%c' %d",*r,n));
882                 switch(*r) {
883             case '.': case '\0':
884                                 n++;
885                                 if (c == '.') return 0;
886                                 break;
887                         case '1' : case '2' : case '3' : case '4' : case '5' :
888                         case '6' : case '7' : case '8' : case '9' : case '0' :
889                                 continue;
890                         default:
891                                 return 0;
892                 }
893         } while((c = *r++));
894
895         return n;
896 }
897
898 guint oid_string2subid(wmem_allocator_t *scope, const char* str, guint32** subids_p) {
899         const char* r = str;
900         guint32* subids;
901         guint32* subids_overflow;
902         guint n = check_num_oid(str);
903         /*
904          * we cannot handle sub-ids greater than 32bytes
905          * keep a pilot subid of 64 bytes to check the limit
906          */
907         guint64 subid = 0;
908
909         D(6,("oid_string2subid: str='%s'",str));
910
911         if (!n) {
912                 *subids_p = NULL;
913                 return 0;
914         }
915
916         *subids_p = subids = wmem_alloc0_array(scope, guint32, n);
917         subids_overflow = subids + n;
918         do switch(*r) {
919                 case '.':
920                         subid = 0;
921                         subids++;
922                         continue;
923                 case '1' : case '2' : case '3' : case '4' : case '5' :
924                 case '6' : case '7' : case '8' : case '9' : case '0' :
925                         subid *= 10;
926                         subid += *r - '0';
927
928                         if( subids >= subids_overflow ||  subid > 0xffffffff) {
929                                 *subids_p=NULL;
930                                 return 0;
931                         }
932
933                         *(subids) *= 10;
934                         *(subids) += *r - '0';
935                         continue;
936                 case '\0':
937                         break;
938                 default:
939                         return 0;
940         } while(*r++);
941
942         return n;
943 }
944
945
946 guint oid_encoded2subid(const guint8 *oid_bytes, gint oid_len, guint32** subids_p) {
947         return oid_encoded2subid_sub(oid_bytes, oid_len, subids_p, TRUE);
948 }
949 guint oid_encoded2subid_sub(const guint8 *oid_bytes, gint oid_len, guint32** subids_p,
950                 gboolean is_first) {
951         gint i;
952         guint n = is_first ? 1 : 0;
953         guint32* subids;
954         guint32* subid_overflow;
955         /*
956          * we cannot handle sub-ids greater than 32bytes
957          * have the subid in 64 bytes to be able to check the limit
958          */
959         guint64 subid = 0;
960
961         for (i=0; i<oid_len; i++) { if (! (oid_bytes[i] & 0x80 )) n++; }
962
963         *subids_p = subids = (guint32 *)ep_alloc(sizeof(guint32)*n);
964         subid_overflow = subids+n;
965
966         /* If n is 0 or 1 (depending on how it was initialized) then we found
967          * no bytes in the OID with first bit cleared, so initialize our one
968          * byte (if any) to zero and return. This *seems* to be the right thing
969          * to do in this situation, and at the very least it avoids
970          * uninitialized memory errors that would otherwise occur. */
971         if (is_first && n == 1) {
972                 *subids = 0;
973                 return n;
974         }
975         else if (!is_first && n == 0) {
976                 return n;
977         }
978
979         for (i=0; i<oid_len; i++){
980                 guint8 byte = oid_bytes[i];
981
982                 subid <<= 7;
983                 subid |= byte & 0x7F;
984
985                 if (byte & 0x80) {
986                         continue;
987                 }
988
989                 if (is_first) {
990                         guint32 subid0 = 0;
991
992                         if (subid >= 40) { subid0++; subid-=40; }
993                         if (subid >= 40) { subid0++; subid-=40; }
994
995                         *subids++ = subid0;
996
997                         is_first = FALSE;
998                 }
999
1000                 if( subids >= subid_overflow || subid > 0xffffffff) {
1001                         *subids_p=NULL;
1002                         return 0;
1003                 }
1004
1005                 *subids++ = (guint32)subid;
1006                 subid = 0;
1007         }
1008
1009         g_assert(subids == subid_overflow);
1010
1011         return n;
1012 }
1013
1014 oid_info_t* oid_get(guint len, guint32* subids, guint* matched, guint* left) {
1015         oid_info_t* curr_oid = &oid_root;
1016         guint i;
1017
1018         if(!(subids && *subids <= 2)) {
1019                 *matched = 0;
1020                 *left = len;
1021                 return curr_oid;
1022         }
1023
1024         for( i=0; i < len; i++) {
1025                 oid_info_t* next_oid = (oid_info_t *)wmem_tree_lookup32(curr_oid->children,subids[i]);
1026                 if (next_oid) {
1027                         curr_oid = next_oid;
1028                 } else {
1029                         goto done;
1030                 }
1031         }
1032 done:
1033         *matched = i;
1034         *left = len - i;
1035         return curr_oid;
1036 }
1037
1038
1039 oid_info_t* oid_get_from_encoded(const guint8 *bytes, gint byteslen, guint32** subids_p, guint* matched_p, guint* left_p) {
1040         guint subids_len = oid_encoded2subid(bytes, byteslen, subids_p);
1041         return oid_get(subids_len, *subids_p, matched_p, left_p);
1042 }
1043
1044 oid_info_t* oid_get_from_string(wmem_allocator_t *scope, const gchar *oid_str, guint32** subids_p, guint* matched, guint* left) {
1045         guint subids_len = oid_string2subid(scope, oid_str, subids_p);
1046         return oid_get(subids_len, *subids_p, matched, left);
1047 }
1048
1049 const gchar *oid_resolved_from_encoded(const guint8 *oid, gint oid_len) {
1050         guint32 *subid_oid;
1051         guint subid_oid_length = oid_encoded2subid(oid, oid_len, &subid_oid);
1052
1053         return oid_resolved(subid_oid_length, subid_oid);
1054 }
1055
1056 const gchar *rel_oid_resolved_from_encoded(const guint8 *oid, gint oid_len) {
1057         guint32 *subid_oid;
1058         guint subid_oid_length = oid_encoded2subid_sub(oid, oid_len, &subid_oid, FALSE);
1059
1060         return rel_oid_subid2string(subid_oid, subid_oid_length, FALSE);
1061 }
1062
1063
1064 guint oid_subid2encoded(guint subids_len, guint32* subids, guint8** bytes_p) {
1065         guint bytelen = 0;
1066         guint i;
1067         guint32 subid;
1068         guint8* b;
1069
1070         if ( !subids || subids_len <= 1) {
1071                 *bytes_p = NULL;
1072                 return 0;
1073         }
1074
1075         for (subid=subids[0] * 40, i = 1; i<subids_len; i++, subid=0) {
1076                 subid += subids[i];
1077                 if (subid <= 0x0000007F) {
1078                         bytelen += 1;
1079                 } else if (subid <= 0x00003FFF ) {
1080                         bytelen += 2;
1081                 } else if (subid <= 0x001FFFFF ) {
1082                         bytelen += 3;
1083                 } else if (subid <= 0x0FFFFFFF ) {
1084                         bytelen += 4;
1085                 } else {
1086                         bytelen += 5;
1087                 }
1088         } 
1089
1090         *bytes_p = b = (guint8 *)ep_alloc(bytelen);
1091
1092         for (subid=subids[0] * 40, i = 1; i<subids_len; i++, subid=0) {
1093                 guint len;
1094
1095                 subid += subids[i];
1096                 if ((subid <= 0x0000007F )) len = 1;
1097                 else if ((subid <= 0x00003FFF )) len = 2;
1098                 else if ((subid <= 0x001FFFFF )) len = 3;
1099                 else if ((subid <= 0x0FFFFFFF )) len = 4;
1100                 else len = 5;
1101
1102                 switch(len) {
1103                         default: *bytes_p=NULL; return 0;
1104                         case 5: *(b++) = ((subid & 0xF0000000) >> 28) | 0x80;
1105                         case 4: *(b++) = ((subid & 0x0FE00000) >> 21) | 0x80;
1106                         case 3: *(b++) = ((subid & 0x001FC000) >> 14) | 0x80;
1107                         case 2: *(b++) = ((subid & 0x00003F80) >> 7)  | 0x80;
1108                         case 1: *(b++) =   subid & 0x0000007F ; break;
1109                 }
1110         } 
1111
1112         return bytelen;
1113 }
1114
1115 const gchar* oid_encoded2string(const guint8* encoded, guint len) {
1116         guint32* subids;
1117         guint subids_len = oid_encoded2subid(encoded, len, &subids);
1118
1119         if (subids_len) {
1120                 return oid_subid2string(subids,subids_len);
1121         } else {
1122                 return "";
1123         }
1124 }
1125
1126 const gchar* rel_oid_encoded2string(const guint8* encoded, guint len) {
1127         guint32* subids;
1128         guint subids_len = oid_encoded2subid_sub(encoded, len, &subids, FALSE);
1129
1130         if (subids_len) {
1131                 return rel_oid_subid2string(subids,subids_len, FALSE);
1132         } else {
1133                 return "";
1134         }
1135 }
1136
1137 guint oid_string2encoded(const char *oid_str, guint8 **bytes) {
1138         guint32* subids;
1139         guint32 subids_len;
1140         guint byteslen;
1141
1142         if ( (subids_len = oid_string2subid(NULL, oid_str, &subids)) &&
1143              (byteslen   = oid_subid2encoded(subids_len, subids, bytes)) ) {
1144                 wmem_free(NULL, subids);
1145                 return byteslen;
1146         }
1147         wmem_free(NULL, subids);
1148         return 0;
1149 }
1150
1151 const gchar *oid_resolved_from_string(const gchar *oid_str) {
1152         guint32     *subid_oid;
1153         guint        subid_oid_length;
1154         const gchar *resolved;
1155
1156         subid_oid_length = oid_string2subid(NULL, oid_str, &subid_oid);
1157         resolved         = oid_resolved(subid_oid_length, subid_oid);
1158
1159         wmem_free(NULL, subid_oid);
1160
1161         return resolved;
1162 }
1163
1164 const gchar *oid_resolved(guint32 num_subids, guint32* subids) {
1165         guint matched;
1166         guint left;
1167         oid_info_t* oid;
1168
1169         if(! (subids && *subids <= 2 ))
1170                 return "*** Malformed OID ***";
1171
1172         oid = oid_get(num_subids, subids, &matched, &left);
1173
1174         while (! oid->name ) {
1175                 if (!(oid = oid->parent)) {
1176                         return oid_subid2string(subids,num_subids);
1177                 }
1178                 left++;
1179                 matched--;
1180         }
1181
1182         if (left) {
1183                 return ep_strdup_printf("%s.%s",
1184                                         oid->name ? oid->name : oid_subid2string(subids,matched),
1185                                         oid_subid2string(&(subids[matched]),left));
1186         } else {
1187                 return oid->name ? oid->name : oid_subid2string(subids,matched);
1188         }
1189 }
1190
1191 extern void oid_both(guint oid_len, guint32 *subids, const char** resolved_p, const char** numeric_p) {
1192         *resolved_p = oid_resolved(oid_len,subids);
1193         *numeric_p = oid_subid2string(subids,oid_len);
1194 }
1195
1196 extern void oid_both_from_encoded(const guint8 *oid, gint oid_len, const char** resolved_p, const char** numeric_p) {
1197         guint32* subids;
1198         guint subids_len = oid_encoded2subid(oid, oid_len, &subids);
1199         *resolved_p = oid_resolved(subids_len,subids);
1200         *numeric_p = oid_subid2string(subids,subids_len);
1201 }
1202
1203 void oid_both_from_string(const gchar *oid_str, const char** resolved_p, const char** numeric_p) {
1204         guint32 *subids;
1205         guint    subids_len;
1206
1207         subids_len  = oid_string2subid(NULL, oid_str, &subids);
1208         *resolved_p = oid_resolved(subids_len,subids);
1209         *numeric_p  = oid_subid2string(subids,subids_len);
1210         wmem_free(NULL, subids);
1211 }
1212
1213 /**
1214  * Fetch the default OID path.
1215  */
1216 extern gchar *
1217 oid_get_default_mib_path(void) {
1218 #ifdef HAVE_LIBSMI
1219         GString* path_str;
1220         gchar *path_ret;
1221         char *path;
1222         guint i;
1223
1224         path_str = g_string_new("");
1225
1226         if (!load_smi_modules) {
1227                 D(1,("OID resolution not enabled"));
1228                 return path_str->str;
1229         }
1230 #ifdef _WIN32
1231 #define PATH_SEPARATOR ";"
1232         path = get_datafile_path("snmp\\mibs");
1233         g_string_append_printf(path_str, "%s;", path);
1234         g_free (path);
1235
1236         path = get_persconffile_path("snmp\\mibs", FALSE);
1237         g_string_append_printf(path_str, "%s", path);
1238         g_free (path);
1239 #else
1240 #define PATH_SEPARATOR ":"
1241         path = smiGetPath();
1242         g_string_append(path_str, "/usr/share/snmp/mibs");
1243         if (strlen(path) > 0 ) {
1244                 g_string_append(path_str, PATH_SEPARATOR);
1245         }
1246         g_string_append_printf(path_str, "%s", path);
1247         free (path);
1248 #endif
1249
1250         for(i=0;i<num_smi_paths;i++) {
1251                 if (!( smi_paths[i].name && *smi_paths[i].name))
1252                         continue;
1253
1254                 g_string_append_printf(path_str,PATH_SEPARATOR "%s",smi_paths[i].name);
1255         }
1256
1257         path_ret = path_str->str;
1258         g_string_free(path_str, FALSE);
1259         return path_ret;
1260 #else /* HAVE_LIBSMI */
1261         return g_strdup("");
1262 #endif
1263 }
1264
1265 #ifdef DEBUG_OIDS
1266 char* oid_test_a2b(guint32 num_subids, guint32* subids) {
1267         guint8* sub2enc;
1268         guint8* str2enc;
1269         guint32* enc2sub;
1270         guint32* str2sub;
1271         const char* sub2str = oid_subid2string(subids, num_subids);
1272         guint sub2enc_len = oid_subid2encoded(num_subids, subids,&sub2enc);
1273         guint enc2sub_len = oid_encoded2subid(sub2enc, sub2enc_len, &enc2sub);
1274         const char* enc2str = oid_encoded2string(sub2enc, sub2enc_len);
1275         guint str2enc_len = oid_string2encoded(sub2str,&str2enc);
1276         guint str2sub_len = oid_string2subid(sub2str,&str2sub);
1277
1278         return ep_strdup_printf(
1279                                                         "oid_subid2string=%s \n"
1280                                                         "oid_subid2encoded=[%d]%s \n"
1281                                                         "oid_encoded2subid=%s \n "
1282                                                         "oid_encoded2string=%s \n"
1283                                                         "oid_string2encoded=[%d]%s \n"
1284                                                         "oid_string2subid=%s \n "
1285                                                         ,sub2str
1286                                                         ,sub2enc_len,bytestring_to_ep_str(sub2enc, sub2enc_len, ':')
1287                                                         ,enc2sub ? oid_subid2string(enc2sub,enc2sub_len) : "-"
1288                                                         ,enc2str
1289                                                         ,str2enc_len,bytestring_to_ep_str(str2enc, str2enc_len, ':')
1290                                                         ,str2sub ? oid_subid2string(str2sub,str2sub_len) : "-"
1291                                                         );
1292 }
1293
1294 void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree) {
1295         static const char* oid_kinds[] = { "Unknown", "Node", "Scalar", "Table", "Row", "Column", "Notification", "Group", "Compliance", "Capabilities"};
1296         static const char* key_types[] = {"OID_KEY_TYPE_WRONG","OID_KEY_TYPE_INTEGER",
1297                                                                                 "OID_KEY_TYPE_FIXED_STRING","OID_KEY_TYPE_FIXED_BYTES","OID_KEY_TYPE_STRING",
1298                                                                                 "OID_KEY_TYPE_BYTES","OID_KEY_TYPE_NSAP","OID_KEY_TYPE_OID","OID_KEY_TYPE_IPADDR"};
1299         proto_item* pi = proto_tree_add_text(tree,NULL,0,0,
1300         "OidInfo: Name='%s' sub-id=%u  kind=%s  hfid=%d",
1301         oid_info->name ? oid_info->name : "",
1302         oid_info->subid,
1303         oid_info->kind <= OID_KIND_CAPABILITIES ? oid_kinds[oid_info->kind] : "BROKEN",
1304         oid_info->value_hfid);
1305         proto_tree* pt = proto_item_add_subtree(pi,0);
1306         oid_key_t* key;
1307
1308         for(key = oid_info->key; key; key = key->next) {
1309                 proto_tree_add_text(pt,NULL,0,0,
1310                 "Key: name='%s' num_subids=%d type=%s",
1311                 key->name,
1312                 key->key_type <= OID_KEY_TYPE_IPADDR ? key_types[key->key_type] : "BROKEN"
1313                 );
1314         };
1315
1316         if (oid_info->parent) {
1317                 pi = proto_tree_add_text(pt,NULL,0,0,"Parent:");
1318                 pt = proto_item_add_subtree(pi,0);
1319                 add_oid_debug_subtree(oid_info->parent, pt);
1320         }
1321 }
1322 #endif
1323
1324 /*
1325  * Editor modelines
1326  *
1327  * Local Variables:
1328  * c-basic-offset: 8
1329  * tab-width: 8
1330  * indent-tabs-mode: t
1331  * End:
1332  *
1333  * ex: set shiftwidth=8 tabstop=8 noexpandtab:
1334  * :indentSize=8:tabSize=8:noTabs=false:
1335  */