oid_get_default_mib_path() is present in libwireshark.def. Make sure it's
[metze/wireshark/wip.git] / epan / oids.c
1 /* oids.c
2  * Object IDentifier Support
3  *
4  * (c) 2007, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <glib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35
36 #include "emem.h"
37 #include "uat.h"
38 #include "prefs.h"
39 #include "proto.h"
40 #include "packet.h"
41 #include "report_err.h"
42 #include "filesystem.h"
43 #include "dissectors/packet-ber.h"
44
45 #ifdef HAVE_LIBSMI
46 #include <smi.h>
47 #endif
48
49 #define D(level,args) do if (debuglevel >= level) { printf args; printf("\n"); fflush(stdout); } while(0)
50
51 #include "oids.h"
52
53 static int debuglevel = 0;
54
55 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};
56 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};
57 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};
58 static const oid_value_type_t ipv4_type =       { FT_IPv4,   BASE_NONE, BER_CLASS_APP, 0,                       4,   4, OID_KEY_TYPE_IPADDR,  4};
59 static const oid_value_type_t counter32_type =  { FT_UINT32, BASE_DEC,  BER_CLASS_APP, 1,                       1,   4, OID_KEY_TYPE_INTEGER, 1};
60 static const oid_value_type_t unsigned32_type = { FT_UINT32, BASE_DEC,  BER_CLASS_APP, 2,                       1,   4, OID_KEY_TYPE_INTEGER, 1};
61 static const oid_value_type_t timeticks_type =  { FT_UINT32, BASE_DEC,  BER_CLASS_APP, 3,                       1,   4, OID_KEY_TYPE_INTEGER, 1};
62 static const oid_value_type_t opaque_type =     { FT_BYTES,  BASE_NONE, BER_CLASS_APP, 4,                       1,   4, OID_KEY_TYPE_BYTES,   0};
63 static const oid_value_type_t nsap_type =       { FT_BYTES,  BASE_NONE, BER_CLASS_APP, 5,                       0,  -1, OID_KEY_TYPE_NSAP,    0};
64 static const oid_value_type_t counter64_type =  { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 6,                       1,   8, OID_KEY_TYPE_INTEGER, 1};
65 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};
66 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};
67 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};
68 static const oid_value_type_t ether_type =      { FT_ETHER,  BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 6,   6, OID_KEY_TYPE_BYTES,   6};
69 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};
70 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};
71
72 static oid_info_t oid_root = { 0, NULL, OID_KIND_UNKNOWN, NULL, &unknown_type, -2, NULL, NULL, NULL};
73
74 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) {
75         guint i = 0;
76         oid_info_t* c = &oid_root;
77
78         if (!oid_root.children) {
79                 char* debug_env = getenv("WIRESHARK_DEBUG_MIBS");
80                 guint32 subid;
81
82                 debuglevel = debug_env ? strtoul(debug_env,NULL,10) : 0;
83
84                 oid_root.children = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"oid_root");
85
86                 /*
87                  * make sure we got strings at least in the three root-children oids
88                  * that way oid_resolved() will always have a string to print
89                  */
90                 subid = 0; oid_add("itu-t",1,&subid);
91                 subid = 1; oid_add("iso",1,&subid);
92                 subid = 2; oid_add("joint-iso-itu-t",1,&subid);
93         }
94
95         oid_len--;
96
97         do {
98                 oid_info_t* n = emem_tree_lookup32(c->children,subids[i]);
99
100                 if(n) {
101                         if (i == oid_len) {
102                                 if (n->name) {
103                                         if (!g_str_equal(n->name,name)) {
104                                                 D(2,("Renaming Oid from: %s -> %s, this means the same oid is registered more than once",n->name,name));
105                                         }
106                                         /* XXX - Don't free n->name here. It may be part of an hf_register_info
107                                          * struct that has been appended to the hfa GArray. */
108                                 }
109
110                                 n->name = g_strdup(name);
111
112                                 if (! n->value_type) {
113                                         n->value_type = type;
114                                 }
115
116                                 return n;
117                         }
118                 } else {
119                         n = g_malloc(sizeof(oid_info_t));
120                         n->subid = subids[i];
121                         n->kind = kind;
122                         n->children = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"oid_children");
123                         n->value_hfid = -2;
124                         n->key = key;
125                         n->parent = c;
126                         n->bits = NULL;
127
128                         emem_tree_insert32(c->children,n->subid,n);
129
130                         if (i == oid_len) {
131                                 n->name = g_strdup(name);
132                                 n->value_type = type;
133                                 n->kind = kind;
134                                 return n;
135                         } else {
136                                 n->name = NULL;
137                                 n->value_type = NULL;
138                                 n->kind = OID_KIND_UNKNOWN;
139                         }
140                 }
141                 c = n;
142         } while(++i);
143
144         g_assert_not_reached();
145         return NULL;
146 }
147
148 void oid_add(const char* name, guint oid_len, guint32 *subids) {
149         g_assert(subids && *subids <= 2);
150         if (oid_len) {
151                 D(3,("\tOid (from subids): %s %s ",name?name:"NULL", oid_subid2string(subids,oid_len)));
152                 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
153         } else {
154                 D(1,("Failed to add Oid: %s (from subids)",name?name:"NULL"));
155         }
156 }
157
158 void oid_add_from_string(const char* name, const gchar *oid_str) {
159         guint32* subids;
160         guint oid_len = oid_string2subid(oid_str, &subids);
161
162         if (oid_len) {
163                 D(3,("\tOid (from string): %s %s ",name?name:"NULL", oid_subid2string(subids,oid_len)));
164                 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
165         } else {
166                 D(1,("Failed to add Oid: %s %s ",name?name:"NULL", oid_str?oid_str:NULL));
167         }
168 }
169
170 extern void oid_add_from_encoded(const char* name, const guint8 *oid, gint oid_len) {
171         guint32* subids;
172         guint subids_len = oid_encoded2subid(oid, oid_len, &subids);
173
174         if (subids_len) {
175                 D(3,("\tOid (from encoded): %s %s ",name, oid_subid2string(subids,subids_len)));
176                 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,subids_len,subids);
177         } else {
178                 D(1,("Failed to add Oid: %s [%d]%s ",name?name:"NULL", oid_len,bytestring_to_str(oid, oid_len, ':')));
179         }
180 }
181
182 #ifdef HAVE_LIBSMI
183 typedef struct smi_module_t {
184         char* name;
185 } smi_module_t;
186
187 static smi_module_t* smi_paths = NULL;
188 static guint num_smi_paths = 0;
189 static uat_t* smi_paths_uat = NULL;
190
191 static smi_module_t* smi_modules = NULL;
192 static guint num_smi_modules = 0;
193 static uat_t* smi_modules_uat = NULL;
194
195 static GString* smi_errors;
196
197 UAT_CSTRING_CB_DEF(smi_mod,name,smi_module_t)
198
199 static void smi_error_handler(char *path, int line, int severity, char *msg, char *tag) {
200                 g_string_sprintfa(smi_errors,"%s:%d %d %s %s\n",
201                                                   path ? path : "-",
202                                                   line, severity,
203                                                   tag ? tag : "-",
204                                                   msg ? msg : "");
205 }
206
207
208 static void* smi_mod_copy_cb(void* dest, const void* orig, unsigned len _U_) {
209         const smi_module_t* m = orig;
210         smi_module_t* d = dest;
211
212         d->name = g_strdup(m->name);
213
214         return d;
215 }
216
217 static void smi_mod_free_cb(void* p) {
218         smi_module_t* m = p;
219         if (m->name) g_free(m->name);
220 }
221
222
223 static char* alnumerize(const char* name) {
224         char* s = g_strdup(name);
225         char* r = s;
226         char* w = r;
227         char c;
228
229         for (;(c = *r); r++) {
230                 if (isalnum(c) || c == '_' || c == '-' || c == '.') {
231                         *(w++) = c;
232                 } else if (c == ':' && r[1] == ':') {
233                         *(w++) = '.';
234                 }
235         }
236
237         *w = '\0';
238
239         return s;
240 }
241
242 const oid_value_type_t* get_typedata(SmiType* smiType) {
243         /*
244          * There has to be a better way to know if a given
245          * OCTETSTRING type is actually human readable text,
246          * an address of some type or some moe specific FT_
247          * Until that is found, this is the mappping between
248          * SNMP Types and our FT_s
249          */
250         static const struct _type_mapping_t {
251                 char* name;
252                 SmiBasetype base;
253                 const oid_value_type_t* type;
254         } types[] =  {
255                 {"IpAddress", SMI_BASETYPE_UNKNOWN, &ipv4_type},
256                 {"InetAddressIPv4",SMI_BASETYPE_UNKNOWN,&ipv4_type},
257                 {"InetAddressIPv6",SMI_BASETYPE_UNKNOWN,&ipv6_type},
258                 {"NetworkAddress",SMI_BASETYPE_UNKNOWN,&ipv4_type},
259                 {"MacAddress",SMI_BASETYPE_UNKNOWN,&ether_type},
260                 {"TimeTicks",SMI_BASETYPE_UNKNOWN,&timeticks_type},
261                 {"Ipv6Address",SMI_BASETYPE_UNKNOWN,&ipv6_type},
262                 {"TimeStamp",SMI_BASETYPE_UNKNOWN,&integer_type},
263                 {"DisplayString",SMI_BASETYPE_UNKNOWN,&string_type},
264                 {"SnmpAdminString",SMI_BASETYPE_UNKNOWN,&string_type},
265                 {"DateAndTime",SMI_BASETYPE_UNKNOWN,&string_type},
266                 {"Counter",SMI_BASETYPE_UNKNOWN,&counter32_type},
267                 {"Counter32",SMI_BASETYPE_UNKNOWN,&counter32_type},
268                 {"Unsigned32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
269                 {"Gauge",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
270                 {"Gauge32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
271                 {"NsapAddress",SMI_BASETYPE_UNKNOWN,&nsap_type},
272                 {"i32",SMI_BASETYPE_INTEGER32,&integer_type},
273                 {"octets",SMI_BASETYPE_OCTETSTRING,&bytes_type},
274                 {"oid",SMI_BASETYPE_OBJECTIDENTIFIER,&oid_type},
275                 {"u32",SMI_BASETYPE_UNSIGNED32,&unsigned32_type},
276                 {"u64",SMI_BASETYPE_UNSIGNED64,&counter64_type},
277                 {"f32",SMI_BASETYPE_FLOAT32,&float_type},
278                 {"f64",SMI_BASETYPE_FLOAT64,&double_type},
279                 {"f128",SMI_BASETYPE_FLOAT128,&bytes_type},
280                 {"enum",SMI_BASETYPE_ENUM,&integer_type},
281                 {"bits",SMI_BASETYPE_BITS,&bytes_type},
282                 {"unk",SMI_BASETYPE_UNKNOWN,&unknown_type},
283                 {NULL,0,NULL}
284         };
285         const struct _type_mapping_t* t;
286         SmiType* sT = smiType;
287
288         if (!smiType) return NULL;
289
290         do {
291                 for (t = types; t->type ; t++ ) {
292                         char* name = smiRenderType(sT, SMI_RENDER_NAME);
293                         if (name && t->name && g_str_equal(name, t->name )) {
294                                 free (name);
295                                 return t->type;
296                         }
297                         if (name) {
298                                 free (name);
299                         }
300                 }
301         } while(( sT  = smiGetParentType(sT) ));
302
303         for (t = types; t->type ; t++ ) {
304                 if(smiType->basetype == t->base) {
305                         return t->type;
306                 }
307         }
308
309         return &unknown_type;
310 }
311
312 static guint get_non_implicit_size(SmiType* sT) {
313         SmiRange *sR;
314         guint size = 0xffffffff;
315
316         switch (sT->basetype) {
317                 case SMI_BASETYPE_OCTETSTRING:
318                 case SMI_BASETYPE_OBJECTIDENTIFIER:
319                         break;
320                 default:
321                         return 0;
322         }
323
324         for ( ; sT; sT = smiGetParentType(sT) ) {
325                 for (sR = smiGetFirstRange(sT); sR ; sR = smiGetNextRange(sR)) {
326                         if (size == 0xffffffff) {
327                                 if (sR->minValue.value.unsigned32 == sR->maxValue.value.unsigned32) {
328                                         size = sR->minValue.value.unsigned32;
329                                 } else {
330                                         return 0;
331                                 }
332                         } else {
333                                 if (sR->minValue.value.unsigned32 != size || sR->maxValue.value.unsigned32 != size) {
334                                         return 0;
335                                 }
336                         }
337                 }
338         }
339
340         return size == 0xffffffff ? 0 : size;
341 }
342
343
344 static inline oid_kind_t smikind(SmiNode* sN, oid_key_t** key_p) {
345         *key_p = NULL;
346
347         switch(sN->nodekind) {
348                 case SMI_NODEKIND_ROW: {
349                         SmiElement* sE;
350                         oid_key_t* kl = NULL;
351                         const oid_value_type_t* typedata = NULL;
352                         gboolean implied;
353
354                         switch (sN->indexkind) {
355                                 case SMI_INDEX_INDEX:
356                                         break;
357                                 case SMI_INDEX_AUGMENT:
358                                 case SMI_INDEX_REORDER:
359                                 case SMI_INDEX_SPARSE:
360                                 case SMI_INDEX_EXPAND:
361                                         sN = smiGetRelatedNode(sN);
362                                         break;
363                                 case SMI_INDEX_UNKNOWN:
364                                         return OID_KIND_UNKNOWN;
365                         };
366
367                         implied = sN->implied;
368
369                         for (sE = smiGetFirstElement(sN); sE; sE = smiGetNextElement(sE)) {
370                                 SmiNode* elNode =  smiGetElementNode(sE) ;
371                                 SmiType* elType = smiGetNodeType(elNode);
372                                 oid_key_t* k;
373                                 guint non_implicit_size = 0;
374                                 char *oid1, *oid2;
375
376                                 if (elType) {
377                                         non_implicit_size = get_non_implicit_size(elType);
378                                 }
379
380                                 typedata =  get_typedata(elType);
381
382                                 k = g_malloc(sizeof(oid_key_t));
383
384                                 oid1 = smiRenderOID(sN->oidlen, sN->oid, SMI_RENDER_QUALIFIED);
385                                 oid2 = smiRenderOID(elNode->oidlen, elNode->oid, SMI_RENDER_NAME);
386                                 k->name = g_strdup_printf("%s.%s", oid1, oid2);
387                                 free (oid1);
388                                 free (oid2);
389
390                                 k->hfid = -2;
391                                 k->ft_type = typedata ? typedata->ft_type : FT_BYTES;
392                                 k->display = typedata ? typedata->display : BASE_NONE;
393                                 k->next = NULL;
394
395
396                                 if (typedata) {
397                                         k->key_type = typedata->keytype;
398                                         k->num_subids = typedata->keysize;
399                                 } else {
400                                         if (elType) {
401                                                 switch (elType->basetype) {
402                                                         case SMI_BASETYPE_BITS:
403                                                         case SMI_BASETYPE_OCTETSTRING: {
404                                                                 k->key_type = OID_KEY_TYPE_BYTES;
405                                                                 k->num_subids = non_implicit_size;
406                                                                 break;
407                                                         }
408                                                         case SMI_BASETYPE_ENUM:
409                                                         case SMI_BASETYPE_OBJECTIDENTIFIER:
410                                                         case SMI_BASETYPE_INTEGER32:
411                                                         case SMI_BASETYPE_UNSIGNED32:
412                                                         case SMI_BASETYPE_INTEGER64:
413                                                         case SMI_BASETYPE_UNSIGNED64:
414                                                                 k->key_type = OID_KEY_TYPE_INTEGER;
415                                                                 k->num_subids = 1;
416                                                                 break;
417                                                         default:
418                                                                 k->key_type = OID_KEY_TYPE_WRONG;
419                                                                 k->num_subids = 0;
420                                                                 break;
421                                                 }
422                                         } else {
423                                                 k->key_type = OID_KEY_TYPE_WRONG;
424                                                 k->num_subids = 0;
425                                                 break;
426                                         }
427                                 }
428
429                                 if (!*key_p) *key_p = k;
430                                 if (kl) kl->next = k;
431
432                                 kl = k;
433                         }
434
435                         if (implied) {
436                                 switch (kl->key_type) {
437                                         case OID_KEY_TYPE_BYTES:  kl->key_type = OID_KEY_TYPE_IMPLIED_BYTES; break;
438                                         case OID_KEY_TYPE_STRING: kl->key_type = OID_KEY_TYPE_IMPLIED_STRING; break;
439                                         case OID_KEY_TYPE_OID:    kl->key_type = OID_KEY_TYPE_IMPLIED_OID; break;
440                                         default: break;
441                                 }
442                         }
443
444                         return OID_KIND_ROW;
445                 }
446                 case SMI_NODEKIND_NODE: return OID_KIND_NODE;
447                 case SMI_NODEKIND_SCALAR: return OID_KIND_SCALAR;
448                 case SMI_NODEKIND_TABLE: return OID_KIND_TABLE;
449                 case SMI_NODEKIND_COLUMN: return OID_KIND_COLUMN;
450                 case SMI_NODEKIND_NOTIFICATION: return OID_KIND_NOTIFICATION;
451                 case SMI_NODEKIND_GROUP: return OID_KIND_GROUP;
452                 case SMI_NODEKIND_COMPLIANCE: return OID_KIND_COMPLIANCE;
453                 case SMI_NODEKIND_CAPABILITIES: return OID_KIND_CAPABILITIES;
454                 default: return OID_KIND_UNKNOWN;
455         }
456 }
457
458 #define IS_ENUMABLE(ft) ( (ft == FT_UINT8) || (ft == FT_UINT16) || (ft == FT_UINT24) || (ft == FT_UINT32) \
459                                                    || (ft == FT_INT8) || (ft == FT_INT16) || (ft == FT_INT24) || (ft == FT_INT32) \
460                                                    || (ft == FT_UINT64) || (ft == FT_INT64) )
461
462 void register_mibs(void) {
463         SmiModule *smiModule;
464         SmiNode *smiNode;
465         guint i;
466         int proto_mibs = -1;
467         GArray* hfa = g_array_new(FALSE,TRUE,sizeof(hf_register_info));
468         GArray* etta = g_array_new(FALSE,TRUE,sizeof(gint*));
469         static uat_field_t smi_fields[] = {
470                 UAT_FLD_CSTRING(smi_mod,name,"The module's name"),
471                 UAT_END_FIELDS
472         };
473         static uat_field_t smi_paths_fields[] = {
474                 UAT_FLD_CSTRING(smi_mod,name,"The directory name"),
475                 UAT_END_FIELDS
476         };
477         char* smi_load_error = NULL;
478         gchar* path_str;
479
480         smi_modules_uat = uat_new("SMI Modules",
481                                                           sizeof(smi_module_t),
482                                                           "smi_modules",
483                                                           FALSE,
484                                                           (void*)&smi_modules,
485                                                           &num_smi_modules,
486                                                           UAT_CAT_GENERAL,
487                                                           "ChSNMPSMIModules",
488                                                           smi_mod_copy_cb,
489                                                           NULL,
490                                                           smi_mod_free_cb,
491                                                           smi_fields);
492
493         smi_paths_uat = uat_new("SMI Paths",
494                                                           sizeof(smi_module_t),
495                                                           "smi_paths",
496                                                           FALSE,
497                                                           (void*)&smi_paths,
498                                                           &num_smi_paths,
499                                                           UAT_CAT_GENERAL,
500                                                           "ChSNMPSMIPaths",
501                                                           smi_mod_copy_cb,
502                                                           NULL,
503                                                           smi_mod_free_cb,
504                                                           smi_paths_fields);
505
506
507         smiInit(NULL);
508
509         uat_load(smi_modules_uat, &smi_load_error);
510
511         if (smi_load_error) {
512                 report_failure("Error Loading SMI Modules Table: %s",smi_load_error);
513                 return;
514         }
515
516         uat_load(smi_paths_uat, &smi_load_error);
517
518         if (smi_load_error) {
519                 report_failure("Error Loading SMI Paths Table: %s",smi_load_error);
520                 return;
521         }
522
523         path_str = oid_get_default_mib_path();
524         D(1,("SMI Path: '%s'",path_str));
525
526         smiSetPath(path_str);
527
528
529
530         smi_errors = g_string_new("");
531         smiSetErrorHandler(smi_error_handler);
532
533         for(i=0;i<num_smi_modules;i++) {
534                 if (!smi_modules[i].name) continue;
535
536
537                 if (smiIsLoaded(smi_modules[i].name)) {
538                         continue;
539                 } else {
540                         char* mod_name =  smiLoadModule(smi_modules[i].name);
541                         if (mod_name)
542                                 D(2,("Loaded: '%s'[%d] as %s",smi_modules[i].name,i,mod_name ));
543                         else
544                                 D(1,("Failed to load: '%s'[%d]",smi_modules[i].name,i));
545                 }
546         }
547
548         if (smi_errors->len) {
549                 report_failure("The following errors were found while loading the MIBS:\n%s\n\n"
550                                            "The Current Path is: %s\n" , smi_errors->str , path_str);
551                 D(1,("Errors while loading:\n%s\n",smi_errors->str));
552         }
553
554         g_free(path_str);
555         g_string_free(smi_errors,TRUE);
556
557         for (smiModule = smiGetFirstModule();
558                  smiModule;
559                  smiModule = smiGetNextModule(smiModule)) {
560
561                 D(3,("\tModule: %s", smiModule->name));
562
563                 for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
564                          smiNode;
565                          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
566
567                         SmiType* smiType =  smiGetNodeType(smiNode);
568                         const oid_value_type_t* typedata =  get_typedata(smiType);
569                         oid_key_t* key;
570                         oid_kind_t kind = smikind(smiNode,&key);
571                         char *oid = smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_QUALIFIED);
572                         oid_info_t* oid_data = add_oid(oid,
573                                                        kind,
574                                                        typedata,
575                                                        key,
576                                                        smiNode->oidlen,
577                                                        smiNode->oid);
578                         free (oid);
579
580                         D(4,("\t\tNode: kind=%d oid=%s name=%s ",
581                                  oid_data->kind, oid_subid2string(smiNode->oid, smiNode->oidlen), oid_data->name ));
582
583                         if ( typedata && oid_data->value_hfid == -2 ) {
584                                 SmiNamedNumber* smiEnum;
585                                 hf_register_info hf = { &(oid_data->value_hfid), {
586                                         oid_data->name,
587                                         alnumerize(oid_data->name),
588                                         typedata->ft_type,
589                                         typedata->display,
590                                         NULL,
591                                         0,
592                                         smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_ALL),
593                                         HFILL }};
594
595                                 oid_data->value_hfid = -1;
596
597                                 if ( IS_ENUMABLE(hf.hfinfo.type) && (smiEnum = smiGetFirstNamedNumber(smiType))) {
598                                         GArray* vals = g_array_new(TRUE,TRUE,sizeof(value_string));
599
600                                         for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum)) {
601                                                 if (smiEnum->name) {
602                                                         value_string val = {smiEnum->value.value.integer32,g_strdup(smiEnum->name)};
603                                                         g_array_append_val(vals,val);
604                                                 }
605                                         }
606
607                                         hf.hfinfo.strings = VALS(vals->data);
608                                         g_array_free(vals,FALSE);
609                                 }
610 #if 0 /* packet-snmp does not hanldle bits yet */
611                         } else if (smiType->basetype == SMI_BASETYPE_BITS && ( smiEnum = smiGetFirstNamedNumber(smiType) )) {
612                                 guint n = 0;
613                                 oid_bits_info_t* bits = g_malloc(sizeof(oid_bits_info_t));
614                                 gint* ettp = &(bits->ett);
615
616                                 bits->num = 0;
617                                 bits->ett = -1;
618
619                                 g_array_append_val(etta,ettp);
620
621                                 for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum), bits->num++);
622
623                                 bits->data = g_malloc(sizeof(struct _oid_bit_t)*bits->num);
624
625                                 for(smiEnum = smiGetFirstNamedNumber(smiType),n=0;
626                                         smiEnum;
627                                         smiEnum = smiGetNextNamedNumber(smiEnum),n++) {
628                                         guint mask = 1 << (smiEnum->value.value.integer32 % 8);
629                                         char* base = alnumerize(oid_data->name);
630                                         char* ext = alnumerize(smiEnum->name);
631                                         hf_register_info hf2 = { &(bits->data[n].hfid), { NULL, NULL, FT_UINT8, BASE_HEX, NULL, mask, "", HFILL }};
632
633                                         bits->data[n].hfid = -1;
634                                         bits->data[n].offset = smiEnum->value.value.integer32 / 8;
635
636                                         hf2.hfinfo.name = g_strdup_printf("%s:%s",oid_data->name,smiEnum->name);
637                                         hf2.hfinfo.abbrev = g_strdup_printf("%s.%s",base,ext);
638
639                                         g_free(base);
640                                         g_free(ext);
641                                         g_array_append_val(hfa,hf2);
642                                 }
643 #endif /* packet-snmp does not use this yet */
644                                 g_array_append_val(hfa,hf);
645                         }
646
647                         if ((key = oid_data->key)) {
648                                 for(; key; key = key->next) {
649                                         hf_register_info hf = { &(key->hfid), {
650                                                 key->name,
651                                                 alnumerize(key->name),
652                                                 key->ft_type,
653                                                 key->display,
654                                                 NULL,
655                                                 0,
656                                                 "",
657                                                 HFILL }};
658
659                                         D(5,("\t\t\tIndex: name=%s subids=%d key_type=%d",
660                                                  key->name, key->num_subids, key->key_type ));
661
662                                         if (key->hfid == -2) {
663                                                 g_array_append_val(hfa,hf);
664                                                 key->hfid = -1;
665                                         } else {
666                                                 g_free((void*)hf.hfinfo.abbrev);
667                                         }
668                                 }
669                         }
670                 }
671         }
672
673         proto_mibs = proto_register_protocol("MIBs", "MIBS", "mibs");
674
675         proto_register_field_array(proto_mibs, (hf_register_info*)hfa->data, hfa->len);
676
677         proto_register_subtree_array((gint**)etta->data, etta->len);
678
679
680         g_array_free(etta,TRUE);
681         g_array_free(hfa,FALSE);
682 }
683 #endif
684
685
686 void oids_init(void) {
687 #ifdef HAVE_LIBSMI
688         register_mibs();
689 #else
690         D(1,("libsmi disabled oid resolution not enabled"));
691 #endif
692 }
693
694 const char* oid_subid2string(guint32* subids, guint len) {
695         char* s = ep_alloc0(((len)*11)+1);
696         char* w = s;
697
698         if(!subids)
699                 return "*** Empty OID ***";
700
701         do {
702                 w += sprintf(w,"%u.",*subids++);
703         } while(--len);
704
705         if (w!=s) *(w-1) = '\0'; else *(s) = '\0';
706
707         return s;
708 }
709
710 guint check_num_oid(const char* str) {
711         const char* r = str;
712         char c = '\0';
713         guint n = 0;
714
715         D(8,("check_num_oid: '%s'",str));
716         if (*r == '.' || *r == '\0') return 0;
717
718         do {
719                 D(9,("\tcheck_num_oid: '%c' %d",*r,n));
720                 switch(*r) {
721                         case '.':
722                                 n++;
723                                 if (c == '.') return 0;
724                         case '1' : case '2' : case '3' : case '4' : case '5' :
725                         case '6' : case '7' : case '8' : case '9' : case '0' :
726                                 continue;
727                         case '\0':
728                                 n++;
729                                 break;
730                         default:
731                                 return 0;
732                 }
733         } while((c = *r++));
734
735         if (c == '.') return 0;
736
737         return n;
738 }
739
740 guint oid_string2subid(const char* str, guint32** subids_p) {
741         const char* r = str;
742         guint32* subids;
743         guint32* subids_overflow;
744         guint n = check_num_oid(str);
745         /*
746          * we cannot handle sub-ids greater than 32bytes
747          * keep a pilot subid of 64 bytes to check the limit
748          */
749         guint64 subid = 0;
750
751         D(6,("oid_string2subid: str='%s'",str));
752
753         if (!n) {
754                 *subids_p = NULL;
755                 return 0;
756         }
757
758         *subids_p = subids = ep_alloc0(sizeof(guint32)*n);
759         subids_overflow = subids + n;
760         do switch(*r) {
761                 case '.':
762                         subid = 0;
763                         subids++;
764                         continue;
765                 case '1' : case '2' : case '3' : case '4' : case '5' :
766                 case '6' : case '7' : case '8' : case '9' : case '0' :
767                         subid *= 10;
768                         subid += *r - '0';
769
770                         if( subids >= subids_overflow ||  subid > 0xffffffff) {
771                                 *subids_p=NULL;
772                                 return 0;
773                         }
774
775                         *(subids) *= 10;
776                         *(subids) += *r - '0';
777                         continue;
778                 case '\0':
779                         break;
780                 default:
781                         return 0;
782         } while(*r++);
783
784         return n;
785 }
786
787
788 guint oid_encoded2subid(const guint8 *oid_bytes, gint oid_len, guint32** subids_p) {
789         gint i;
790         guint n = 1;
791         gboolean is_first = TRUE;
792         guint32* subids;
793         guint32* subid_overflow;
794         /*
795          * we cannot handle sub-ids greater than 32bytes
796          * have the subid in 64 bytes to be able to check the limit
797          */
798         guint64 subid = 0;
799
800         for (i=0; i<oid_len; i++) { if (! (oid_bytes[i] & 0x80 )) n++; }
801
802         *subids_p = subids = ep_alloc(sizeof(guint32)*n);
803         subid_overflow = subids+n;
804
805         for (i=0; i<oid_len; i++){
806                 guint8 byte = oid_bytes[i];
807
808                 subid <<= 7;
809                 subid |= byte & 0x7F;
810
811                 if (byte & 0x80) {
812                         continue;
813                 }
814
815                 if (is_first) {
816                         guint32 subid0 = 0;
817
818                         if (subid >= 40) { subid0++; subid-=40; }
819                         if (subid >= 40) { subid0++; subid-=40; }
820
821                         *subids++ = subid0;
822
823                         is_first = FALSE;
824                 }
825
826                 if( subids >= subid_overflow || subid > 0xffffffff) {
827                         *subids_p=NULL;
828                         return 0;
829                 }
830
831                 *subids++ = (guint32)subid;
832                 subid = 0;
833         }
834
835         return n;
836 }
837
838 oid_info_t* oid_get(guint len, guint32* subids, guint* matched, guint* left) {
839         oid_info_t* curr_oid = &oid_root;
840         guint i;
841
842         if(!(subids && *subids <= 2)) {
843                 *matched = 0;
844                 *left = len;
845                 return curr_oid;
846         }
847
848         for( i=0; i < len; i++) {
849                 oid_info_t* next_oid = emem_tree_lookup32(curr_oid->children,subids[i]);
850                 if (next_oid) {
851                         curr_oid = next_oid;
852                 } else {
853                         goto done;
854                 }
855         }
856 done:
857         *matched = i;
858         *left = len - i;
859         return curr_oid;
860 }
861
862
863 oid_info_t* oid_get_from_encoded(const guint8 *bytes, gint byteslen, guint32** subids_p, guint* matched_p, guint* left_p) {
864         guint subids_len = oid_encoded2subid(bytes, byteslen, subids_p);
865         return oid_get(subids_len, *subids_p, matched_p, left_p);
866 }
867
868 oid_info_t* oid_get_from_string(const gchar *oid_str, guint32** subids_p, guint* matched, guint* left) {
869         guint subids_len = oid_string2subid(oid_str, subids_p);
870         return oid_get(subids_len, *subids_p, matched, left);
871 }
872
873 const gchar *oid_resolved_from_encoded(const guint8 *oid, gint oid_len) {
874         guint32 *subid_oid;
875         guint subid_oid_length = oid_encoded2subid(oid, oid_len, &subid_oid);
876
877         return oid_resolved(subid_oid_length, subid_oid);
878 }
879
880
881 guint oid_subid2encoded(guint subids_len, guint32* subids, guint8** bytes_p) {
882         guint bytelen = 0;
883         guint i;
884         guint32 subid;
885         guint8* bytes;
886         guint8* b;
887
888         if ( !subids || subids_len <= 0) {
889                 *bytes_p = NULL;
890                 return 0;
891         }
892
893         subid = (subids[0] * 40) + subids[1];
894         i = 2;
895
896         do {
897                 if (subid <= 0x0000007F) {
898                         bytelen += 1;
899                 } else if (subid <= 0x00003FFF ) {
900                         bytelen += 2;
901                 } else if (subid <= 0x001FFFFF ) {
902                         bytelen += 3;
903                 } else if (subid <= 0x0FFFFFFF ) {
904                         bytelen += 4;
905                 } else {
906                         bytelen += 5;
907                 }
908
909                         subid = subids[i];
910         } while ( i++ < subids_len );
911
912         *bytes_p = b = bytes = ep_alloc(bytelen);
913
914         subid = (subids[0] * 40) + subids[1];
915         i = 2;
916
917         do {
918                 guint len;
919
920                 if ((subid <= 0x0000007F )) len = 1;
921                 else if ((subid <= 0x00003FFF )) len = 2;
922                 else if ((subid <= 0x001FFFFF )) len = 3;
923                 else if ((subid <= 0x0FFFFFFF )) len = 4;
924                 else len = 5;
925
926                 switch(len) {
927                         default: *bytes_p=NULL; return 0;
928                         case 5: *(b++) = ((subid & 0xF0000000) << 28) | 0x80;
929                         case 4: *(b++) = ((subid & 0x0FE00000 ) >> 21)  | 0x80;
930                         case 3: *(b++) = ((subid & 0x001FC000 ) >> 14)  | 0x80;
931                         case 2: *(b++) = ((subid & 0x00003F10 ) >> 7)  | 0x80;
932                         case 1: *(b++) =  subid & 0x0000007F ; break;
933                 }
934
935                 subid = subids[i];
936         } while ( i++ < subids_len);
937
938         return bytelen;
939 }
940
941 const gchar* oid_encoded2string(const guint8* encoded, guint len) {
942         guint32* subids;
943         guint subids_len = oid_encoded2subid(encoded, len, &subids);
944
945         if (subids_len) {
946                 return oid_subid2string(subids,subids_len);
947         } else {
948                 return "";
949         }
950 }
951
952
953
954 guint oid_string2encoded(const char *oid_str, guint8 **bytes) {
955         guint32* subids;
956         guint32 subids_len;
957         guint byteslen;
958
959                 if ( ( subids_len = oid_string2subid(oid_str, &subids) )
960                          &&
961                          ( byteslen = oid_subid2encoded(subids_len, subids, bytes) )  ) {
962                         return byteslen;
963                 }
964         return 0;
965 }
966
967 char* oid2str(oid_info_t* oid, guint32* subids, guint len, guint left) {
968         if (left == 0) {
969                 return oid->name;
970         } else {
971                 return ep_strdup_printf("%s.%s",oid->name,oid_subid2string(subids+(len-left),left));
972         }
973 }
974
975 const gchar *oid_resolved_from_string(const gchar *oid_str) {
976         guint32 *subid_oid;
977         guint subid_oid_length = oid_string2subid(oid_str, &subid_oid);
978
979         return oid_resolved(subid_oid_length, subid_oid);
980 }
981
982 const gchar *oid_resolved(guint32 num_subids, guint32* subids) {
983         guint matched;
984         guint left;
985         oid_info_t* oid;
986
987         if(! (subids && *subids <= 2 ))
988                 return "*** Malformed OID ***";
989
990         oid = oid_get(num_subids, subids, &matched, &left);
991
992         while (! oid->name ) {
993                 if (!(oid = oid->parent)) {
994                         return oid_subid2string(subids,num_subids);
995                 }
996                 left++;
997                 matched--;
998         }
999
1000         if (left) {
1001                 return ep_strdup_printf("%s.%s",
1002                                         oid->name ? oid->name : oid_subid2string(subids,matched),
1003                                         oid_subid2string(&(subids[matched]),left));
1004         } else {
1005                 return oid->name ? oid->name : oid_subid2string(subids,matched);
1006         }
1007 }
1008
1009 extern void oid_both(guint oid_len, guint32 *subids, char** resolved_p, char** numeric_p) {
1010         *resolved_p = (void*)oid_resolved(oid_len,subids);
1011         *numeric_p = (void*)oid_subid2string(subids,oid_len);
1012 }
1013
1014 extern void oid_both_from_encoded(const guint8 *oid, gint oid_len, char** resolved_p, char** numeric_p) {
1015         guint32* subids;
1016         guint subids_len = oid_encoded2subid(oid, oid_len, &subids);
1017         *resolved_p = (void*)oid_resolved(subids_len,subids);
1018         *numeric_p = (void*)oid_subid2string(subids,subids_len);
1019 }
1020
1021 extern void oid_both_from_string(const gchar *oid_str, char** resolved_p, char** numeric_p) {
1022         guint32* subids;
1023         guint subids_len = oid_string2subid(oid_str, &subids);
1024         *resolved_p = (void*)oid_resolved(subids_len,subids);
1025         *numeric_p = (void*)oid_subid2string(subids,subids_len);
1026 }
1027
1028 /**
1029  * Fetch the default OID path.
1030  */
1031 extern gchar *
1032 oid_get_default_mib_path(void) {
1033 #ifdef HAVE_LIBSMI
1034         GString* path_str;
1035         gchar *path_ret;
1036         char *path;
1037         guint i;
1038
1039         path_str = g_string_new("");
1040 #ifdef WIN32
1041 #define PATH_SEPARATOR ";"
1042         path = get_datafile_path("snmp\\mibs");
1043         g_string_sprintfa(path_str, "%s;", path);
1044         g_free (path);
1045
1046         path = get_persconffile_path("snmp\\mibs", FALSE, FALSE);
1047         g_string_sprintfa(path_str, "%s", path);
1048         g_free (path);
1049 #else
1050 #define PATH_SEPARATOR ":"
1051         path = smiGetPath();
1052         g_string_sprintfa(path_str, "%s", path);
1053         free (path);
1054 #endif
1055
1056         for(i=0;i<num_smi_paths;i++) {
1057                 if (!( smi_paths[i].name && *smi_paths[i].name))
1058                         continue;
1059
1060                 g_string_sprintfa(path_str,PATH_SEPARATOR "%s",smi_paths[i].name);
1061         }
1062
1063         path_ret = path_str->str;
1064         g_string_free(path_str, FALSE);
1065         return path_ret;
1066 #else /* HAVE_LIBSMI */
1067         return g_strdup("");
1068 #endif
1069 }
1070
1071 #ifdef DEBUG_OIDS
1072 char* oid_test_a2b(guint32 num_subids, guint32* subids) {
1073         guint8* sub2enc;
1074         guint8* str2enc;
1075         guint32* enc2sub;
1076         guint32* str2sub;
1077         const char* sub2str = oid_subid2string(subids, num_subids);
1078         guint sub2enc_len = oid_subid2encoded(num_subids, subids,&sub2enc);
1079         guint enc2sub_len = oid_encoded2subid(sub2enc, sub2enc_len, &enc2sub);
1080         const char* enc2str = oid_encoded2string(sub2enc, sub2enc_len);
1081         guint str2enc_len = oid_string2encoded(sub2str,&str2enc);
1082         guint str2sub_len = oid_string2subid(sub2str,&str2sub);
1083
1084         return ep_strdup_printf(
1085                                                         "oid_subid2string=%s \n"
1086                                                         "oid_subid2encoded=[%d]%s \n"
1087                                                         "oid_encoded2subid=%s \n "
1088                                                         "oid_encoded2string=%s \n"
1089                                                         "oid_string2encoded=[%d]%s \n"
1090                                                         "oid_string2subid=%s \n "
1091                                                         ,sub2str
1092                                                         ,sub2enc_len,bytestring_to_str(sub2enc, sub2enc_len, ':')
1093                                                         ,enc2sub ? oid_subid2string(enc2sub,enc2sub_len) : "-"
1094                                                         ,enc2str
1095                                                         ,str2enc_len,bytestring_to_str(str2enc, str2enc_len, ':')
1096                                                         ,str2sub ? oid_subid2string(str2sub,str2sub_len) : "-"
1097                                                         );
1098 }
1099
1100 void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree) {
1101         static const char* oid_kinds[] = { "Unknown", "Node", "Scalar", "Table", "Row", "Column", "Notification", "Group", "Compliance", "Capabilities"};
1102         static const char* key_types[] = {"OID_KEY_TYPE_WRONG","OID_KEY_TYPE_INTEGER",
1103                                                                                 "OID_KEY_TYPE_FIXED_STRING","OID_KEY_TYPE_FIXED_BYTES","OID_KEY_TYPE_STRING",
1104                                                                                 "OID_KEY_TYPE_BYTES","OID_KEY_TYPE_NSAP","OID_KEY_TYPE_OID","OID_KEY_TYPE_IPADDR"};
1105         proto_item* pi = proto_tree_add_text(tree,NULL,0,0,
1106         "OidInfo: Name='%s' sub-id=%u  kind=%s  hfid=%d",
1107         oid_info->name ? oid_info->name : "",
1108         oid_info->subid,
1109         oid_info->kind <= OID_KIND_CAPABILITIES ? oid_kinds[oid_info->kind] : "BROKEN",
1110         oid_info->value_hfid);
1111         proto_tree* pt = proto_item_add_subtree(pi,0);
1112         oid_key_t* key;
1113
1114         for(key = oid_info->key; key; key = key->next) {
1115                 proto_tree_add_text(pt,NULL,0,0,
1116                 "Key: name='%s' num_subids=%d type=%s",
1117                 key->name,
1118                 key->key_type <= OID_KEY_TYPE_IPADDR ? key_types[key->key_type] : "BROKEN"
1119                 );
1120         };
1121
1122         if (oid_info->parent) {
1123                 pi = proto_tree_add_text(pt,NULL,0,0,"Parent:");
1124                 pt = proto_item_add_subtree(pi,0);
1125                 add_oid_debug_subtree(oid_info->parent, pt);
1126         }
1127 }
1128 #endif
1129
1130 /*
1131  * Editor modelines
1132  *
1133  * Local Variables:
1134  * c-basic-offset: 8
1135  * tab-width: 8
1136  * indent-tabs-mode: tabs
1137  * End:
1138  *
1139  * ex: set shiftwidth=8 tabstop=8 noexpandtab
1140  * :indentSize=8:tabSize=8:noTabs=false:
1141  */
1142