From Tyson Key:
[obnox/wireshark/wip.git] / epan / oids.c
index e2ef23fad98d605ca99160864b8ff49352583425..2f3f94aea5a5b1664358cf149258851931cc569a 100644 (file)
@@ -44,6 +44,8 @@
 
 #ifdef HAVE_LIBSMI
 #include <smi.h>
+
+static gboolean oids_init_done = FALSE;
 #endif
 
 #define D(level,args) do if (debuglevel >= level) { printf args; printf("\n"); fflush(stdout); } while(0)
 
 static int debuglevel = 0;
 
+/*
+ * From SNMPv2-SMI and X.690
+ *
+ * Counter32  ::= [APPLICATION 1] IMPLICIT INTEGER (0..4294967295)
+ * Gauge32    ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
+ * Unsigned32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) (alias of Gauge32)
+ * TimeTicks  ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
+ *
+ * If the BER encoding should not have the top bit set as to not become a negative number
+ * the BER encoding may take 5 octets to encode.
+ */
+
 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};
 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};
 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};
 static const oid_value_type_t ipv4_type =       { FT_IPv4,   BASE_NONE, BER_CLASS_APP, 0,                       4,   4, OID_KEY_TYPE_IPADDR,  4};
 static const oid_value_type_t counter32_type =  { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 1,                       1,   5, OID_KEY_TYPE_INTEGER, 1};
-static const oid_value_type_t unsigned32_type = { FT_UINT32, BASE_DEC,  BER_CLASS_APP, 2,                       1,   4, OID_KEY_TYPE_INTEGER, 1};
-/*static const oid_value_type_t timeticks_type =  { FT_UINT32, BASE_DEC,  BER_CLASS_APP, 3,                       1,   4, OID_KEY_TYPE_INTEGER, 1};
- * TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
- * If the BER encoding should not have the top bit set as to not become a negative number
- * the ber encoding may take 5 octets to encode.
- */
+static const oid_value_type_t unsigned32_type = { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 2,                       1,   5, OID_KEY_TYPE_INTEGER, 1};
 static const oid_value_type_t timeticks_type =  { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 3,                       1,   5, OID_KEY_TYPE_INTEGER, 1};
 static const oid_value_type_t opaque_type =     { FT_BYTES,  BASE_NONE, BER_CLASS_APP, 4,                       1,   4, OID_KEY_TYPE_BYTES,   0};
 static const oid_value_type_t nsap_type =       { FT_BYTES,  BASE_NONE, BER_CLASS_APP, 5,                       0,  -1, OID_KEY_TYPE_NSAP,    0};
@@ -221,7 +230,7 @@ static uat_t* smi_modules_uat = NULL;
 
 static GString* smi_errors;
 
-UAT_CSTRING_CB_DEF(smi_mod,name,smi_module_t)
+UAT_DIRECTORYNAME_CB_DEF(smi_mod,name,smi_module_t)
 
 static void smi_error_handler(char *path, int line, int severity, char *msg, char *tag) {
                g_string_append_printf(smi_errors,"%s:%d %d %s %s\n",
@@ -232,7 +241,7 @@ static void smi_error_handler(char *path, int line, int severity, char *msg, cha
 }
 
 
-static void* smi_mod_copy_cb(void* dest, const void* orig, unsigned len _U_) {
+static void* smi_mod_copy_cb(void* dest, const void* orig, size_t len _U_) {
        const smi_module_t* m = orig;
        smi_module_t* d = dest;
 
@@ -275,7 +284,7 @@ static const oid_value_type_t* get_typedata(SmiType* smiType) {
         * SNMP Types and our FT_s
         */
        static const struct _type_mapping_t {
-               char* name;
+               const char* name;
                SmiBasetype base;
                const oid_value_type_t* type;
        } types[] =  {
@@ -486,6 +495,18 @@ static inline oid_kind_t smikind(SmiNode* sN, oid_key_t** key_p) {
                                                   || (ft == FT_INT8) || (ft == FT_INT16) || (ft == FT_INT24) || (ft == FT_INT32) \
                                                   || (ft == FT_UINT64) || (ft == FT_INT64) )
 
+static void unregister_mibs(void) {
+       /* TODO: Unregister "MIBs" proto and clean up field array and subtree array.
+        * Wireshark does not support that yet. :-( */
+
+       /* smiExit(); */
+}
+
+static void restart_needed_warning(void) {
+       if (oids_init_done)
+               report_failure("Wireshark needs to be restarted for these changes to take effect");
+}
+
 static void register_mibs(void) {
        SmiModule *smiModule;
        SmiNode *smiNode;
@@ -498,7 +519,7 @@ static void register_mibs(void) {
                UAT_END_FIELDS
        };
        static uat_field_t smi_paths_fields[] = {
-               UAT_FLD_PATHNAME(smi_mod,name,"Directory path","The directory name"),
+               UAT_FLD_DIRECTORYNAME(smi_mod,name,"Directory path","The directory name"),
                UAT_END_FIELDS
        };
        char* smi_load_error = NULL;
@@ -515,6 +536,7 @@ static void register_mibs(void) {
                                                          smi_mod_copy_cb,
                                                          NULL,
                                                          smi_mod_free_cb,
+                                                         restart_needed_warning,
                                                          smi_fields);
 
        smi_paths_uat = uat_new("SMI Paths",
@@ -528,11 +550,10 @@ static void register_mibs(void) {
                                                          smi_mod_copy_cb,
                                                          NULL,
                                                          smi_mod_free_cb,
+                                                         restart_needed_warning,
                                                          smi_paths_fields);
 
 
-       smiInit(NULL);
-
        uat_load(smi_modules_uat, &smi_load_error);
 
        if (smi_load_error) {
@@ -547,20 +568,33 @@ static void register_mibs(void) {
                return;
        }
 
-       path_str = oid_get_default_mib_path();
-       D(1,("SMI Path: '%s'",path_str));
-
-       smiSetPath(path_str);
+       if (!prefs.load_smi_modules) {
+               D(1,("OID resolution not enabled"));
+               return;
+       }
 
+       /* TODO: Remove this workaround when unregistration of "MIBs" proto is solved.
+        * Wireshark does not support that yet. :-( */
+       if (oids_init_done) {
+               D(1,("Exiting register_mibs() to avoid double registration of MIBs proto."));
+               return;
+       } else {
+               oids_init_done = TRUE;
+       }
 
+       smiInit(NULL);
 
        smi_errors = g_string_new("");
        smiSetErrorHandler(smi_error_handler);
 
+       path_str = oid_get_default_mib_path();
+       D(1,("SMI Path: '%s'",path_str));
+
+       smiSetPath(path_str);
+
        for(i=0;i<num_smi_modules;i++) {
                if (!smi_modules[i].name) continue;
 
-
                if (smiIsLoaded(smi_modules[i].name)) {
                        continue;
                } else {
@@ -573,8 +607,13 @@ static void register_mibs(void) {
        }
 
        if (smi_errors->len) {
-               report_failure("The following errors were found while loading the MIBS:\n%s\n\n"
-                                          "The Current Path is: %s\n" , smi_errors->str , path_str);
+               if (!prefs.suppress_smi_errors) {
+                       report_failure("The following errors were found while loading the MIBS:\n%s\n\n"
+                                          "The Current Path is: %s\n\nYou can avoid this error message "
+                                          "by removing the missing MIB modules at Edit -> Preferences"
+                                          " -> Name Resolution -> SMI (MIB and PIB) modules or by "
+                                          "installing them.\n" , smi_errors->str , path_str);
+               }
                D(1,("Errors while loading:\n%s\n",smi_errors->str));
        }
 
@@ -587,6 +626,20 @@ static void register_mibs(void) {
 
                D(3,("\tModule: %s", smiModule->name));
 
+               /* TODO: Check libsmi version at compile time and disable this
+                * workaround for libsmi versions where this problem is fixed.
+                * Currently there is no such version. :-(
+                */
+               if (smiModule->conformance == 1) {
+                       if (!prefs.suppress_smi_errors) {
+                               report_failure("Stopped processing module %s due to "
+                                       "error(s) to prevent potential crash in libsmi.\n"
+                                       "Module's conformance level: %d.\n"
+                                       "See details at: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=560325\n",
+                                        smiModule->name, smiModule->conformance);
+                       }
+                       continue;
+               }
                for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
                         smiNode;
                         smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
@@ -637,7 +690,7 @@ static void register_mibs(void) {
                                                }
                                        }
 
-                                       hf.hfinfo.strings = VALS(vals->data);
+                                       hf.hfinfo.strings = vals->data;
                                        g_array_free(vals,FALSE);
                                }
 #if 0 /* packet-snmp does not handle bits yet */
@@ -705,9 +758,9 @@ static void register_mibs(void) {
 
        proto_mibs = proto_register_protocol("MIBs", "MIBS", "mibs");
 
-       proto_register_field_array(proto_mibs, (hf_register_info*)hfa->data, hfa->len);
+       proto_register_field_array(proto_mibs, (hf_register_info*)(void*)hfa->data, hfa->len);
 
-       proto_register_subtree_array((gint**)etta->data, etta->len);
+       proto_register_subtree_array((gint**)(void*)etta->data, etta->len);
 
 
        g_array_free(etta,TRUE);
@@ -724,6 +777,14 @@ void oids_init(void) {
 #endif
 }
 
+void oids_cleanup(void) {
+#ifdef HAVE_LIBSMI
+       unregister_mibs();
+#else
+       D(1,("libsmi disabled oid resolution not enabled"));
+#endif
+}
+
 const char* oid_subid2string(guint32* subids, guint len) {
        char* s = ep_alloc0(((len)*11)+1);
        char* w = s;
@@ -740,13 +801,13 @@ const char* oid_subid2string(guint32* subids, guint len) {
        return s;
 }
 
-guint check_num_oid(const char* str) {
+static guint check_num_oid(const char* str) {
        const char* r = str;
        char c = '\0';
        guint n = 0;
 
        D(8,("check_num_oid: '%s'",str));
-       if (*r == '.' || *r == '\0') return 0;
+       if (!r || *r == '.' || *r == '\0') return 0;
 
        do {
                D(9,("\tcheck_num_oid: '%c' %d",*r,n));
@@ -957,11 +1018,11 @@ guint oid_subid2encoded(guint subids_len, guint32* subids, guint8** bytes_p) {
 
                switch(len) {
                        default: *bytes_p=NULL; return 0;
-                       case 5: *(b++) = ((subid & 0xF0000000) << 28) | 0x80;
-                       case 4: *(b++) = ((subid & 0x0FE00000 ) >> 21)  | 0x80;
-                       case 3: *(b++) = ((subid & 0x001FC000 ) >> 14)  | 0x80;
-                       case 2: *(b++) = ((subid & 0x00003F10 ) >> 7)  | 0x80;
-                       case 1: *(b++) =  subid & 0x0000007F ; break;
+                       case 5: *(b++) = ((subid & 0xF0000000) >> 28) | 0x80;
+                       case 4: *(b++) = ((subid & 0x0FE00000) >> 21) | 0x80;
+                       case 3: *(b++) = ((subid & 0x001FC000) >> 14) | 0x80;
+                       case 2: *(b++) = ((subid & 0x00003F10) >> 7)  | 0x80;
+                       case 1: *(b++) =   subid & 0x0000007F ; break;
                }
 
                subid = subids[i];
@@ -996,14 +1057,6 @@ guint oid_string2encoded(const char *oid_str, guint8 **bytes) {
        return 0;
 }
 
-char* oid2str(oid_info_t* oid, guint32* subids, guint len, guint left) {
-       if (left == 0) {
-               return oid->name;
-       } else {
-               return ep_strdup_printf("%s.%s",oid->name,oid_subid2string(subids+(len-left),left));
-       }
-}
-
 const gchar *oid_resolved_from_string(const gchar *oid_str) {
        guint32 *subid_oid;
        guint subid_oid_length = oid_string2subid(oid_str, &subid_oid);
@@ -1069,6 +1122,11 @@ oid_get_default_mib_path(void) {
        guint i;
 
        path_str = g_string_new("");
+       
+       if (!prefs.load_smi_modules) {
+               D(1,("OID resolution not enabled"));
+               return path_str->str;
+       }
 #ifdef _WIN32
 #define PATH_SEPARATOR ";"
        path = get_datafile_path("snmp\\mibs");
@@ -1081,6 +1139,10 @@ oid_get_default_mib_path(void) {
 #else
 #define PATH_SEPARATOR ":"
        path = smiGetPath();
+       g_string_append(path_str, "/usr/share/snmp/mibs");
+       if (strlen(path) > 0 ) {
+               g_string_append(path_str, PATH_SEPARATOR);
+       }
        g_string_append_printf(path_str, "%s", path);
        free (path);
 #endif
@@ -1168,7 +1230,7 @@ void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree) {
  * indent-tabs-mode: t
  * End:
  *
- * ex: set shiftwidth=8 tabstop=8 noexpandtab
+ * ex: set shiftwidth=8 tabstop=8 noexpandtab:
  * :indentSize=8:tabSize=8:noTabs=false:
  */