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