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