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