Document the new Copy Profile button.
[obnox/wireshark/wip.git] / epan / packet.c
index 45b073f1fb5d6b579186dc0db897d9b02fe567e6..551cf9bd885d2980ece43273848a6112056f566c 100644 (file)
@@ -3,8 +3,8 @@
  *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
@@ -19,7 +19,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
 #include "tvbuff.h"
 #include "plugins.h"
 #include "epan_dissect.h"
+
 #include "emem.h"
 
 #include <epan/reassemble.h>
+#include <epan/stream.h>
+#include <epan/expert.h>
 
 static gint proto_malformed = -1;
 static dissector_handle_t frame_handle = NULL;
 static dissector_handle_t data_handle = NULL;
 
-const true_false_string flags_set_truth = {
-  "Set",
-  "Not set"
-};
-
 void
 packet_init(void)
 {
@@ -85,15 +83,15 @@ packet_cleanup(void)
 void
 set_actual_length(tvbuff_t *tvb, guint specified_len)
 {
-  if (specified_len < tvb_reported_length(tvb)) {
-    /* Adjust the length of this tvbuff to include only the specified
-       payload length.
+       if (specified_len < tvb_reported_length(tvb)) {
+               /* Adjust the length of this tvbuff to include only the specified
+                  payload length.
 
-       The dissector above the one calling us (the dissector above is
-       probably us) may use that to determine how much of its packet
-       was padding. */
-    tvb_set_reported_length(tvb, specified_len);
-  }
+                  The dissector above the one calling us (the dissector above is
+                  probably us) may use that to determine how much of its packet
+                  was padding. */
+               tvb_set_reported_length(tvb, specified_len);
+       }
 }
 
 /* Allow protocols to register "init" routines, which are called before
@@ -144,14 +142,43 @@ init_dissection(void)
        /* Initialize the common data structures for fragment reassembly.
           Must be done *after* calling init routines, as those routines
           may free up space for fragments, which they find by using the
-          data structures that "reassemble_init()" frees. */
+          data structures that "reassemble_cleanup()" frees. */
        reassemble_init();
+
+       /* Initialize the stream-handling tables */
+       stream_init();
+
+       /* Initialize the expert infos */
+       expert_init();
 }
 
 void
 cleanup_dissection(void)
 {
-       init_dissection();
+       /* Reclaim all memory of seasonal scope */
+       se_free_all();
+
+       /* Cleanup the table of conversations. */
+       epan_conversation_cleanup();
+
+       /* Cleanup the table of circuits. */
+       epan_circuit_cleanup();
+
+       /* TODO: Introduce cleanup_routines */
+       /* Cleanup protocol-specific variables. */
+       g_slist_foreach(init_routines, &call_init_routine, NULL);
+
+       /* Cleanup the common data structures for fragment reassembly.
+          Must be done *after* calling init routines, as those routines
+          may free up space for fragments, which they find by using the
+          data structures that "reassemble_cleanup()" frees. */
+       reassemble_cleanup();
+
+       /* Cleanup the stream-handling tables */
+       stream_cleanup();
+
+       /* Initialize the expert infos */
+       expert_cleanup();
 }
 
 /* Allow protocols to register a "cleanup" routine to be
@@ -193,32 +220,55 @@ add_new_data_source(packet_info *pinfo, tvbuff_t *tvb, const char *name)
 
        src = ep_alloc(sizeof (data_source));
        src->tvb = tvb;
-       /*
-        * XXX - if we require this argument to be a string constant,
-        * we don't need to allocate a buffer for a copy and make a
-        * copy, and wouldn't need to free the buffer, either.
-        */
-       src->name = ep_strdup_printf("%s (%u bytes)", name, tvb_length(tvb));
+       src->name_initialized = FALSE;
+       src->name = name;
        pinfo->data_src = g_slist_append(pinfo->data_src, src);
 }
 
+/*
+ * This should only add a data source to the list of data sources for
+ * a frame if the data sources are being used.  Note that they can
+ * be used even if the protocol tree isn't being built or isn't visible,
+ * e.g. if you run tshark with -x but without -V or anything else to
+ * cause the protocol tree to be built.
+ */
+void
+packet_add_new_data_source(packet_info *pinfo, proto_tree *tree _U_,
+                          tvbuff_t *tvb, const char *name)
+{
+       add_new_data_source(pinfo, tvb, name);
+}
+
+const char*
+get_data_source_name(data_source *src)
+{
+       if (!src->name_initialized) {
+               src->name = ep_strdup_printf("%s (%u bytes)", src->name, tvb_length(src->tvb));
+               src->name_initialized = TRUE;
+       }
+
+       return src->name;
+}
+
 /*
  * Free up a frame's list of data sources.
  */
 void
 free_data_sources(packet_info *pinfo)
 {
-       g_slist_free(pinfo->data_src);
-       pinfo->data_src = NULL;
+       if (pinfo->data_src) {
+               g_slist_free(pinfo->data_src);
+               pinfo->data_src = NULL;
+       }
 }
 
 /* Allow dissectors to register a "final_registration" routine
- * that is run like the proto_register_XXX() routine, but the end
+ * that is run like the proto_register_XXX() routine, but at the
  * end of the epan_init() function; that is, *after* all other
  * subsystems, like dfilters, have finished initializing. This is
  * useful for dissector registration routines which need to compile
  * display filters. dfilters can't initialize itself until all protocols
- * have registereed themselves. */
+ * have registered themselves. */
 static GSList *final_registration_routines;
 
 void
@@ -252,66 +302,32 @@ dissect_packet(epan_dissect_t *edt, union wtap_pseudo_header *pseudo_header,
 {
        if (cinfo != NULL)
                col_init(cinfo);
+       memset(&edt->pi, 0, sizeof(edt->pi));
        edt->pi.current_proto = "<Missing Protocol Name>";
        edt->pi.cinfo = cinfo;
        edt->pi.fd = fd;
        edt->pi.pseudo_header = pseudo_header;
-       edt->pi.data_src = NULL;
        edt->pi.dl_src.type = AT_NONE;
-       edt->pi.dl_src.len = 0;
-       edt->pi.dl_src.data = NULL;
        edt->pi.dl_dst.type = AT_NONE;
-       edt->pi.dl_dst.len = 0;
-       edt->pi.dl_dst.data = NULL;
        edt->pi.net_src.type = AT_NONE;
-       edt->pi.net_src.len = 0;
-       edt->pi.net_src.data = NULL;
        edt->pi.net_dst.type = AT_NONE;
-       edt->pi.net_dst.len = 0;
-       edt->pi.net_dst.data = NULL;
        edt->pi.src.type = AT_NONE;
-       edt->pi.src.len = 0;
-       edt->pi.src.data = NULL;
        edt->pi.dst.type = AT_NONE;
-       edt->pi.dst.len = 0;
-       edt->pi.dst.data = NULL;
-       edt->pi.ethertype = 0;
-       edt->pi.ipproto  = 0;
-       edt->pi.ipxptype = 0;
        edt->pi.ctype = CT_NONE;
-       edt->pi.circuit_id = 0;
        edt->pi.noreassembly_reason = "";
-       edt->pi.fragmented = FALSE;
-       edt->pi.in_error_pkt = FALSE;
        edt->pi.ptype = PT_NONE;
-       edt->pi.srcport  = 0;
-       edt->pi.destport = 0;
-       edt->pi.match_port = 0;
-       edt->pi.match_string = NULL;
-       edt->pi.can_desegment = 0;
-       edt->pi.want_pdu_tracking = 0;
        edt->pi.p2p_dir = P2P_DIR_UNKNOWN;
-       edt->pi.private_data = NULL;
-       edt->pi.oxid = 0;
-       edt->pi.rxid = 0;
-       edt->pi.r_ctl = 0;
-       edt->pi.src_idx = 0;
-       edt->pi.dst_idx = 0;
-       edt->pi.vsan = 0;
-       edt->pi.dcectxid = 0;
        edt->pi.dcetransporttype = -1;
-       edt->pi.decrypt_gssapi_tvb = 0;
-       edt->pi.gssapi_wrap_tvb = NULL;
-       edt->pi.gssapi_encrypted_tvb = NULL;
-       edt->pi.gssapi_decrypted_tvb = NULL;
-       edt->pi.layer_names = NULL;
-       edt->pi.link_number = 0;
        edt->pi.annex_a_used = MTP2_ANNEX_A_USED_UNKNOWN;
+       edt->pi.dcerpc_procedure_name="";
+       edt->pi.link_dir = LINK_DIR_UNKNOWN;
+
+       EP_CHECK_CANARY(("before dissecting frame %d",fd->num));
 
        TRY {
                edt->tvb = tvb_new_real_data(pd, fd->cap_len, fd->pkt_len);
                /* Add this tvbuffer into the data_src list */
-               add_new_data_source(&edt->pi, edt->tvb, "Frame");
+               packet_add_new_data_source(&edt->pi, edt->tree, edt->tvb, "Frame");
 
                /* Even though dissect_frame() catches all the exceptions a
                 * sub-dissector can throw, dissect_frame() itself may throw
@@ -327,13 +343,18 @@ dissect_packet(epan_dissect_t *edt, union wtap_pseudo_header *pseudo_header,
        CATCH(ReportedBoundsError) {
                if(proto_malformed != -1){
                        proto_tree_add_protocol_format(edt->tree, proto_malformed, edt->tvb, 0, 0,
-                                                      "[Malformed Frame: Packet Length]" );
+                                                      "[Malformed Frame: Packet Length]" );
                } else {
                        g_assert_not_reached();
                }
        }
+       CATCH(OutOfMemoryError) {
+               RETHROW;
+       }
        ENDTRY;
 
+       EP_CHECK_CANARY(("after dissecting frame %d",fd->num));
+
        fd->flags.visited = 1;
 }
 
@@ -361,10 +382,10 @@ struct dissector_handle {
  *
  * The only time this function will return 0 is if it is a new style dissector
  * and if the dissector rejected the packet.
- */ 
+ */
 static int
 call_dissector_through_handle(dissector_handle_t handle, tvbuff_t *tvb,
-    packet_info *pinfo, proto_tree *tree)
+                             packet_info *pinfo, proto_tree *tree)
 {
        const char *saved_proto;
        int ret;
@@ -373,13 +394,17 @@ call_dissector_through_handle(dissector_handle_t handle, tvbuff_t *tvb,
 
        if (handle->protocol != NULL) {
                pinfo->current_proto =
-                   proto_get_protocol_short_name(handle->protocol);
+                       proto_get_protocol_short_name(handle->protocol);
        }
 
        if (handle->is_new) {
+               EP_CHECK_CANARY(("before calling handle->dissector.new for %s",handle->name));
                ret = (*handle->dissector.new)(tvb, pinfo, tree);
+               EP_CHECK_CANARY(("after calling handle->dissector.new for %s",handle->name));
        } else {
+               EP_CHECK_CANARY(("before calling handle->dissector.old for %s",handle->name));
                (*handle->dissector.old)(tvb, pinfo, tree);
+               EP_CHECK_CANARY(("after calling handle->dissector.old for %s",handle->name));
                ret = tvb_length(tvb);
                if (ret == 0) {
                        /*
@@ -404,22 +429,20 @@ call_dissector_through_handle(dissector_handle_t handle, tvbuff_t *tvb,
  * dissector and return its return value, otherwise call it and return
  * the length of the tvbuff pointed to by the argument.
  */
+
+static int
+call_dissector_work_error(dissector_handle_t handle, tvbuff_t *tvb,
+                         packet_info *pinfo_arg, proto_tree *tree);
+
 static int
 call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb,
-    packet_info *pinfo_arg, proto_tree *tree)
+                                       packet_info *pinfo_arg, proto_tree *tree, gboolean add_proto_name)
 {
-       packet_info *volatile pinfo = pinfo_arg;
+       packet_info *pinfo = pinfo_arg;
        const char *saved_proto;
        guint16 saved_can_desegment;
-       volatile int ret;
-       gboolean save_writable;
-       volatile address save_dl_src;
-       volatile address save_dl_dst;
-       volatile address save_net_src;
-       volatile address save_net_dst;
-       volatile address save_src;
-       volatile address save_dst;
-       volatile gint saved_layer_names_len = 0;
+       int ret;
+       gint saved_layer_names_len = 0;
 
        if (handle->protocol != NULL &&
            !proto_is_protocol_enabled(handle->protocol)) {
@@ -433,7 +456,7 @@ call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb,
        saved_can_desegment = pinfo->can_desegment;
 
        if (pinfo->layer_names != NULL)
-               saved_layer_names_len = pinfo->layer_names->len;
+               saved_layer_names_len = (gint) pinfo->layer_names->len;
 
        /*
         * can_desegment is set to 2 by anyone which offers the
@@ -451,97 +474,97 @@ call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb,
        pinfo->can_desegment = saved_can_desegment-(saved_can_desegment>0);
        if (handle->protocol != NULL) {
                pinfo->current_proto =
-                   proto_get_protocol_short_name(handle->protocol);
+                       proto_get_protocol_short_name(handle->protocol);
 
                /*
                 * Add the protocol name to the layers
+                * if not told not to. Asn2wrs generated dissectors may be added multiple times otherwise.
                 */
-               if (pinfo->layer_names) {
+               if ((pinfo->layer_names)&&(add_proto_name)) {
                        if (pinfo->layer_names->len > 0)
                                g_string_append(pinfo->layer_names, ":");
-                       g_string_append(pinfo->layer_names, 
-                           proto_get_protocol_filter_name(proto_get_id(handle->protocol)));
+                               g_string_append(pinfo->layer_names,
+                               proto_get_protocol_filter_name(proto_get_id(handle->protocol)));
                }
        }
 
        if (pinfo->in_error_pkt) {
+               ret = call_dissector_work_error(handle, tvb, pinfo, tree);
+       } else {
                /*
-                * This isn't a packet being transported inside
-                * the protocol whose dissector is calling us,
-                * it's a copy of a packet that caused an error
-                * in some protocol included in a packet that
-                * reports the error (e.g., an ICMP Unreachable
-                * packet).
-                */
-
+                * Just call the subdissector.
+                */
+               ret = call_dissector_through_handle(handle, tvb, pinfo, tree);
+       }
+       if (ret == 0) {
                /*
-                * Save the current state of the writability of
-                * the columns, and restore them after the
-                * dissector returns, so that the columns
-                * don't reflect the packet that got the error,
-                * they reflect the packet that reported the
-                * error.
+                * That dissector didn't accept the packet, so
+                * remove its protocol's name from the list
+                * of protocols.
                 */
-               save_writable = col_get_writable(pinfo->cinfo);
-               col_set_writable(pinfo->cinfo, FALSE);
-               save_dl_src = pinfo->dl_src;
-               save_dl_dst = pinfo->dl_dst;
-               save_net_src = pinfo->net_src;
-               save_net_dst = pinfo->net_dst;
-               save_src = pinfo->src;
-               save_dst = pinfo->dst;
-
-               /* Dissect the contained packet. */
-               TRY {
-                       ret = call_dissector_through_handle(handle, tvb,
-                           pinfo, tree);
+               if ((pinfo->layer_names != NULL)&&(add_proto_name)) {
+                       g_string_truncate(pinfo->layer_names, saved_layer_names_len);
                }
-               CATCH(BoundsError) {
-                       /*
-                        * Restore the column writability and addresses.
-                        */
-                       col_set_writable(pinfo->cinfo, save_writable);
-                       pinfo->dl_src = save_dl_src;
-                       pinfo->dl_dst = save_dl_dst;
-                       pinfo->net_src = save_net_src;
-                       pinfo->net_dst = save_net_dst;
-                       pinfo->src = save_src;
-                       pinfo->dst = save_dst;
+       }
+       pinfo->current_proto = saved_proto;
+       pinfo->can_desegment = saved_can_desegment;
+       return ret;
+}
 
-                       /*
-                        * Restore the current protocol, so any
-                        * "Short Frame" indication reflects that
-                        * protocol, not the protocol for the
-                        * packet that got the error.
-                        */
-                       pinfo->current_proto = saved_proto;
 
-                       /*
-                        * Restore the desegmentability state.
-                        */
-                       pinfo->can_desegment = saved_can_desegment;
+static int
+call_dissector_work_error(dissector_handle_t handle, tvbuff_t *tvb,
+                         packet_info *pinfo_arg, proto_tree *tree)
+{
+       packet_info *pinfo = pinfo_arg;
+       const char *saved_proto;
+       guint16 saved_can_desegment;
+       volatile int ret = 0;
+       gboolean save_writable;
+       address save_dl_src;
+       address save_dl_dst;
+       address save_net_src;
+       address save_net_dst;
+       address save_src;
+       address save_dst;
 
-                       /*
-                        * Rethrow the exception, so this will be
-                        * reported as a short frame.
-                        */
-                       RETHROW;
-               }
-               CATCH(ReportedBoundsError) {
-                       /*
-                        * "ret" wasn't set because an exception was thrown
-                        * before "call_dissector_through_handle()" returned.
-                        * As it called something, at least one dissector
-                        * accepted the packet, and, as an exception was
-                        * thrown, not only was all the tvbuff dissected,
-                        * a dissector tried dissecting past the end of
-                        * the data in some tvbuff, so we'll assume that
-                        * the entire tvbuff was dissected.
-                        */
-                       ret = tvb_length(tvb);
-               }
-               ENDTRY;
+       /*
+       * This isn't a packet being transported inside
+       * the protocol whose dissector is calling us,
+       * it's a copy of a packet that caused an error
+       * in some protocol included in a packet that
+       * reports the error (e.g., an ICMP Unreachable
+       * packet).
+       */
+
+       /*
+       * Save the current state of the writability of
+       * the columns, and restore them after the
+       * dissector returns, so that the columns
+       * don't reflect the packet that got the error,
+       * they reflect the packet that reported the
+       * error.
+       */
+       saved_proto = pinfo->current_proto;
+       saved_can_desegment = pinfo->can_desegment;
 
+       save_writable = col_get_writable(pinfo->cinfo);
+       col_set_writable(pinfo->cinfo, FALSE);
+       save_dl_src = pinfo->dl_src;
+       save_dl_dst = pinfo->dl_dst;
+       save_net_src = pinfo->net_src;
+       save_net_dst = pinfo->net_dst;
+       save_src = pinfo->src;
+       save_dst = pinfo->dst;
+
+       /* Dissect the contained packet. */
+       TRY {
+               ret = call_dissector_through_handle(handle, tvb,pinfo, tree);
+       }
+       CATCH(BoundsError) {
+               /*
+               * Restore the column writability and addresses.
+               */
                col_set_writable(pinfo->cinfo, save_writable);
                pinfo->dl_src = save_dl_src;
                pinfo->dl_dst = save_dl_dst;
@@ -549,27 +572,52 @@ call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb,
                pinfo->net_dst = save_net_dst;
                pinfo->src = save_src;
                pinfo->dst = save_dst;
-               pinfo->want_pdu_tracking = 0;
-       } else {
+
                /*
-                * Just call the subdissector.
-                */
-               ret = call_dissector_through_handle(handle, tvb, pinfo, tree);
-       }
+               * Restore the current protocol, so any
+               * "Short Frame" indication reflects that
+               * protocol, not the protocol for the
+               * packet that got the error.
+               */
+               pinfo->current_proto = saved_proto;
 
-       if (ret == 0) {
                /*
-                * That dissector didn't accept the packet, so
-                * remove its protocol's name from the list
-                * of protocols.
-                */
-               if (pinfo->layer_names != NULL) {
-                       g_string_truncate(pinfo->layer_names,
-                           saved_layer_names_len);
-               }
+               * Restore the desegmentability state.
+               */
+               pinfo->can_desegment = saved_can_desegment;
+
+               /*
+               * Rethrow the exception, so this will be
+               * reported as a short frame.
+               */
+               RETHROW;
        }
-       pinfo->current_proto = saved_proto;
-       pinfo->can_desegment = saved_can_desegment;
+       CATCH(ReportedBoundsError) {
+               /*
+               * "ret" wasn't set because an exception was thrown
+               * before "call_dissector_through_handle()" returned.
+               * As it called something, at least one dissector
+               * accepted the packet, and, as an exception was
+               * thrown, not only was all the tvbuff dissected,
+               * a dissector tried dissecting past the end of
+               * the data in some tvbuff, so we'll assume that
+               * the entire tvbuff was dissected.
+               */
+               ret = tvb_length(tvb);
+       }
+       CATCH(OutOfMemoryError) {
+               RETHROW;
+       }
+       ENDTRY;
+
+       col_set_writable(pinfo->cinfo, save_writable);
+       pinfo->dl_src = save_dl_src;
+       pinfo->dl_dst = save_dl_dst;
+       pinfo->net_src = save_net_src;
+       pinfo->net_dst = save_net_dst;
+       pinfo->src = save_src;
+       pinfo->dst = save_dst;
+       pinfo->want_pdu_tracking = 0;
        return ret;
 }
 
@@ -645,18 +693,40 @@ find_uint_dtbl_entry(dissector_table_t sub_dissectors, guint32 pattern)
         * Find the entry.
         */
        return g_hash_table_lookup(sub_dissectors->hash_table,
-           GUINT_TO_POINTER(pattern));
+                                  GUINT_TO_POINTER(pattern));
 }
 
+#if 0
+static void
+dissector_add_sanity_check(const char *name, guint32 pattern, dissector_handle_t handle, dissector_table_t sub_dissectors)
+{
+       dtbl_entry_t *dtbl_entry;
+
+       if (pattern == 0) {
+               g_warning("%s: %s registering using a pattern of 0",
+                         name, proto_get_protocol_filter_name(proto_get_id(handle->protocol)));
+       }
+
+       dtbl_entry = g_hash_table_lookup(sub_dissectors->hash_table, GUINT_TO_POINTER(pattern));
+       if (dtbl_entry != NULL) {
+               g_warning("%s: %s registering using pattern %d already registered by %s",
+                         name, proto_get_protocol_filter_name(proto_get_id(handle->protocol)),
+                                                 pattern, proto_get_protocol_filter_name(proto_get_id(dtbl_entry->initial->protocol)));
+       }
+}
+#endif
+
 /* Add an entry to a uint dissector table. */
 void
 dissector_add(const char *name, guint32 pattern, dissector_handle_t handle)
 {
-       dissector_table_t sub_dissectors = find_dissector_table( name);
+       dissector_table_t sub_dissectors;
        dtbl_entry_t *dtbl_entry;
 
-/* sanity checks */
-       g_assert( sub_dissectors);
+       sub_dissectors = find_dissector_table(name);
+       /* sanity checks */
+       g_assert(sub_dissectors);
+       g_assert(handle!=NULL);
        switch (sub_dissectors->type) {
 
        case FT_UINT8:
@@ -676,13 +746,17 @@ dissector_add(const char *name, guint32 pattern, dissector_handle_t handle)
                g_assert_not_reached();
        }
 
+#if 0
+       dissector_add_sanity_check(name, pattern, handle, sub_dissectors);
+#endif
+
        dtbl_entry = g_malloc(sizeof (dtbl_entry_t));
        dtbl_entry->current = handle;
        dtbl_entry->initial = dtbl_entry->current;
 
 /* do the table insertion */
-       g_hash_table_insert( sub_dissectors->hash_table,
-           GUINT_TO_POINTER( pattern), (gpointer)dtbl_entry);
+       g_hash_table_insert( sub_dissectors->hash_table,
+                            GUINT_TO_POINTER( pattern), (gpointer)dtbl_entry);
 
        /*
         * Now add it to the list of handles that could be used with this
@@ -719,7 +793,7 @@ dissector_delete(const char *name, guint32 pattern,
                 * Found - remove it.
                 */
                g_hash_table_remove(sub_dissectors->hash_table,
-                   GUINT_TO_POINTER(pattern));
+                                   GUINT_TO_POINTER(pattern));
 
                /*
                 * Now free up the entry.
@@ -761,8 +835,8 @@ dissector_change(const char *name, guint32 pattern, dissector_handle_t handle)
        dtbl_entry->current = handle;
 
 /* do the table insertion */
-       g_hash_table_insert( sub_dissectors->hash_table,
-           GUINT_TO_POINTER( pattern), (gpointer)dtbl_entry);
+       g_hash_table_insert( sub_dissectors->hash_table,
+                            GUINT_TO_POINTER( pattern), (gpointer)dtbl_entry);
 }
 
 /* Reset an entry in a uint dissector table to its initial value. */
@@ -790,7 +864,7 @@ dissector_reset(const char *name, guint32 pattern)
                dtbl_entry->current = dtbl_entry->initial;
        } else {
                g_hash_table_remove(sub_dissectors->hash_table,
-                   GUINT_TO_POINTER(pattern));
+                                   GUINT_TO_POINTER(pattern));
                g_free(dtbl_entry);
        }
 }
@@ -798,9 +872,10 @@ dissector_reset(const char *name, guint32 pattern)
 /* Look for a given value in a given uint dissector table and, if found,
    call the dissector with the arguments supplied, and return TRUE,
    otherwise return FALSE. */
+
 gboolean
-dissector_try_port(dissector_table_t sub_dissectors, guint32 port,
-    tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissector_try_port_new(dissector_table_t sub_dissectors, guint32 port,
+                      tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean add_proto_name)
 {
        dtbl_entry_t *dtbl_entry;
        struct dissector_handle *handle;
@@ -829,7 +904,7 @@ dissector_try_port(dissector_table_t sub_dissectors, guint32 port,
                 */
                saved_match_port = pinfo->match_port;
                pinfo->match_port = port;
-               ret = call_dissector_work(handle, tvb, pinfo, tree);
+               ret = call_dissector_work(handle, tvb, pinfo, tree, add_proto_name);
                pinfo->match_port = saved_match_port;
 
                /*
@@ -850,6 +925,13 @@ dissector_try_port(dissector_table_t sub_dissectors, guint32 port,
        return FALSE;
 }
 
+gboolean
+dissector_try_port(dissector_table_t sub_dissectors, guint32 port,
+                  tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+
+       return dissector_try_port_new(sub_dissectors, port, tvb, pinfo, tree, TRUE);
+}
 /* Look for a given value in a given uint dissector table and, if found,
    return the dissector handle for that value. */
 dissector_handle_t
@@ -894,7 +976,7 @@ find_string_dtbl_entry(dissector_table_t sub_dissectors, const gchar *pattern)
 /* Add an entry to a string dissector table. */
 void
 dissector_add_string(const char *name, const gchar *pattern,
-    dissector_handle_t handle)
+                    dissector_handle_t handle)
 {
        dissector_table_t sub_dissectors = find_dissector_table( name);
        dtbl_entry_t *dtbl_entry;
@@ -924,8 +1006,8 @@ dissector_add_string(const char *name, const gchar *pattern,
        dtbl_entry->initial = dtbl_entry->current;
 
 /* do the table insertion */
-       g_hash_table_insert( sub_dissectors->hash_table, (gpointer)pattern,
-           (gpointer)dtbl_entry);
+       g_hash_table_insert( sub_dissectors->hash_table, (gpointer)pattern,
+                            (gpointer)dtbl_entry);
 
        /*
         * Now add it to the list of handles that could be used with this
@@ -975,7 +1057,7 @@ dissector_delete_string(const char *name, const gchar *pattern,
    with a particular pattern to use a new dissector handle. */
 void
 dissector_change_string(const char *name, gchar *pattern,
-    dissector_handle_t handle)
+                       dissector_handle_t handle)
 {
        dissector_table_t sub_dissectors = find_dissector_table( name);
        dtbl_entry_t *dtbl_entry;
@@ -1005,8 +1087,8 @@ dissector_change_string(const char *name, gchar *pattern,
        dtbl_entry->current = handle;
 
 /* do the table insertion */
-       g_hash_table_insert( sub_dissectors->hash_table, pattern,
-           (gpointer)dtbl_entry);
+       g_hash_table_insert( sub_dissectors->hash_table, pattern,
+                            (gpointer)dtbl_entry);
 }
 
 /* Reset an entry in a string sub-dissector table to its initial value. */
@@ -1043,13 +1125,15 @@ dissector_reset_string(const char *name, const gchar *pattern)
    return FALSE. */
 gboolean
 dissector_try_string(dissector_table_t sub_dissectors, const gchar *string,
-    tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+                    tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
        dtbl_entry_t *dtbl_entry;
        struct dissector_handle *handle;
        int ret;
        const gchar *saved_match_string;
 
+       /* XXX ASSERT instead ? */
+       if (!string) return FALSE;
        dtbl_entry = find_string_dtbl_entry(sub_dissectors, string);
        if (dtbl_entry != NULL) {
                /*
@@ -1072,7 +1156,7 @@ dissector_try_string(dissector_table_t sub_dissectors, const gchar *string,
                 */
                saved_match_string = pinfo->match_string;
                pinfo->match_string = string;
-               ret = call_dissector_work(handle, tvb, pinfo, tree);
+               ret = call_dissector_work(handle, tvb, pinfo, tree, TRUE);
                pinfo->match_string = saved_match_string;
 
                /*
@@ -1097,7 +1181,7 @@ dissector_try_string(dissector_table_t sub_dissectors, const gchar *string,
    return the dissector handle for that value. */
 dissector_handle_t
 dissector_get_string_handle(dissector_table_t sub_dissectors,
-    const gchar *string)
+                           const gchar *string)
 {
        dtbl_entry_t *dtbl_entry;
 
@@ -1136,7 +1220,7 @@ dissector_add_handle(const char *name, dissector_handle_t handle)
 
        /* Add it to the list. */
        sub_dissectors->dissector_handles =
-           g_slist_append(sub_dissectors->dissector_handles, (gpointer)handle);
+               g_slist_append(sub_dissectors->dissector_handles, (gpointer)handle);
 }
 
 dissector_handle_t
@@ -1155,7 +1239,7 @@ typedef struct dissector_foreach_info {
   gpointer     caller_data;
   DATFunc      caller_func;
   GHFunc       next_func;
-  gchar       *table_name;
+  const gchar  *table_name;
   ftenum_t     selector_type;
 } dissector_foreach_info_t;
 
@@ -1186,7 +1270,7 @@ dissector_table_foreach_func (gpointer key, gpointer value, gpointer user_data)
 
        info = user_data;
        info->caller_func(info->table_name, info->selector_type, key, value,
-           info->caller_data);
+                         info->caller_data);
 }
 
 /*
@@ -1229,7 +1313,7 @@ dissector_all_tables_foreach (DATFunc func,
  * on each entry.
  */
 void
-dissector_table_foreach (char *name,
+dissector_table_foreach (const char *name,
                         DATFunc func,
                         gpointer user_data)
 {
@@ -1256,7 +1340,7 @@ dissector_table_foreach_handle(const char *name,
        GSList *tmp;
 
        for (tmp = sub_dissectors->dissector_handles; tmp != NULL;
-           tmp = g_slist_next(tmp))
+            tmp = g_slist_next(tmp))
                func(name, tmp->data, user_data);
 }
 
@@ -1282,7 +1366,7 @@ dissector_table_foreach_changed_func (gpointer key, gpointer value, gpointer use
 
        info = user_data;
        info->caller_func(info->table_name, info->selector_type, key, value,
-           info->caller_data);
+                         info->caller_data);
 }
 
 /*
@@ -1306,7 +1390,7 @@ dissector_all_tables_foreach_changed (DATFunc func,
  * any entry that has been changed from its original state.
  */
 void
-dissector_table_foreach_changed (char *name,
+dissector_table_foreach_changed (const char *name,
                                 DATFunc func,
                                 gpointer user_data)
 {
@@ -1318,12 +1402,12 @@ dissector_table_foreach_changed (char *name,
        info.caller_func = func;
        info.caller_data = user_data;
        g_hash_table_foreach(sub_dissectors->hash_table,
-           dissector_table_foreach_changed_func, &info);
+                            dissector_table_foreach_changed_func, &info);
 }
 
 typedef struct dissector_foreach_table_info {
-  gpointer      caller_data;
-  DATFunc_table caller_func;
+       gpointer      caller_data;
+       DATFunc_table caller_func;
 } dissector_foreach_table_info_t;
 
 /*
@@ -1357,7 +1441,7 @@ dissector_all_tables_foreach_table (DATFunc_table func,
 
 dissector_table_t
 register_dissector_table(const char *name, const char *ui_name, ftenum_t type,
-    int base)
+                        int base)
 {
        dissector_table_t       sub_dissectors;
 
@@ -1368,7 +1452,9 @@ register_dissector_table(const char *name, const char *ui_name, ftenum_t type,
        }
 
        /* Make sure the registration is unique */
-       g_assert(!g_hash_table_lookup( dissector_tables, name ));
+       if(g_hash_table_lookup( dissector_tables, name )) {
+               g_error("The filter name %s (%s) is already registered - do you use a buggy plugin?", name, ui_name);
+       }
 
        /* Create and register the dissector table for this name; returns */
        /* a pointer to the dissector table. */
@@ -1384,13 +1470,13 @@ register_dissector_table(const char *name, const char *ui_name, ftenum_t type,
                 * so we use "g_direct_hash()" and "g_direct_equal()".
                 */
                sub_dissectors->hash_table = g_hash_table_new( g_direct_hash,
-                   g_direct_equal );
+                                                              g_direct_equal );
                break;
 
        case FT_STRING:
        case FT_STRINGZ:
                sub_dissectors->hash_table = g_hash_table_new( g_str_hash,
-                   g_str_equal );
+                                                              g_str_equal );
                break;
 
        default:
@@ -1460,9 +1546,40 @@ heur_dissector_add(const char *name, heur_dissector_t dissector, int proto)
        *sub_dissectors = g_slist_append(*sub_dissectors, (gpointer)dtbl_entry);
 }
 
+
+
+static int find_matching_heur_dissector( gconstpointer a, gconstpointer b) {
+       const heur_dtbl_entry_t *dtbl_entry_a = (const heur_dtbl_entry_t *) a;
+       const heur_dtbl_entry_t *dtbl_entry_b = (const heur_dtbl_entry_t *) b;
+       return (dtbl_entry_a->dissector == dtbl_entry_b->dissector) &&
+               (dtbl_entry_a->protocol == dtbl_entry_b->protocol) ? 0 : 1;
+}
+
+void heur_dissector_delete(const char *name, heur_dissector_t dissector, int proto) {
+       heur_dissector_list_t *sub_dissectors = find_heur_dissector_list(name);
+       heur_dtbl_entry_t dtbl_entry;
+       GSList* found_entry;
+
+       /* sanity check */
+       g_assert(sub_dissectors != NULL);
+
+       dtbl_entry.dissector = dissector;
+
+       dtbl_entry.protocol = find_protocol_by_id(proto);
+
+       found_entry = g_slist_find_custom(*sub_dissectors, (gpointer) &dtbl_entry, find_matching_heur_dissector);
+
+       if (found_entry) {
+               *sub_dissectors = g_slist_remove_link(*sub_dissectors, found_entry);
+               g_free(g_slist_nth_data(found_entry, 1));
+               g_slist_free_1(found_entry);
+       }
+}
+
+
 gboolean
 dissector_try_heuristic(heur_dissector_list_t sub_dissectors,
-    tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+                       tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
        gboolean status;
        const char *saved_proto;
@@ -1488,7 +1605,7 @@ dissector_try_heuristic(heur_dissector_list_t sub_dissectors,
        saved_proto = pinfo->current_proto;
 
        if (pinfo->layer_names != NULL)
-               saved_layer_names_len = pinfo->layer_names->len;
+               saved_layer_names_len = (gint) pinfo->layer_names->len;
 
        for (entry = sub_dissectors; entry != NULL; entry = g_slist_next(entry)) {
                /* XXX - why set this now and above? */
@@ -1505,32 +1622,37 @@ dissector_try_heuristic(heur_dissector_list_t sub_dissectors,
 
                if (dtbl_entry->protocol != NULL) {
                        pinfo->current_proto =
-                           proto_get_protocol_short_name(dtbl_entry->protocol);
-               }
+                               proto_get_protocol_short_name(dtbl_entry->protocol);
 
-               /*
-                * Add the protocol name to the layers; we'll remove it
-                * if the dissector fails.
-                */
-               if (pinfo->layer_names) {
-                       if (pinfo->layer_names->len > 0)
-                               g_string_append(pinfo->layer_names, ":");
-                       g_string_append(pinfo->layer_names,
-                           proto_get_protocol_filter_name(proto_get_id(dtbl_entry->protocol)));
+                       /*
+                        * Add the protocol name to the layers; we'll remove it
+                        * if the dissector fails.
+                        */
+                       if (pinfo->layer_names) {
+                               if (pinfo->layer_names->len > 0)
+                                       g_string_append(pinfo->layer_names, ":");
+                                       g_string_append(pinfo->layer_names,
+                                       proto_get_protocol_filter_name(proto_get_id(dtbl_entry->protocol)));
+                       }
                }
-
+               EP_CHECK_CANARY(("before calling heuristic dissector for protocol: %s",
+                                proto_get_protocol_filter_name(proto_get_id(dtbl_entry->protocol))));
                if ((*dtbl_entry->dissector)(tvb, pinfo, tree)) {
+                       EP_CHECK_CANARY(("after heuristic dissector for protocol: %s has accepted and dissected packet",
+                                        proto_get_protocol_filter_name(proto_get_id(dtbl_entry->protocol))));
                        status = TRUE;
                        break;
                } else {
+                       EP_CHECK_CANARY(("after heuristic dissector for protocol: %s has returned true",
+                                        proto_get_protocol_filter_name(proto_get_id(dtbl_entry->protocol))));
+
                        /*
                         * That dissector didn't accept the packet, so
                         * remove its protocol's name from the list
                         * of protocols.
                         */
                        if (pinfo->layer_names != NULL) {
-                               g_string_truncate(pinfo->layer_names,
-                                   saved_layer_names_len);
+                               g_string_truncate(pinfo->layer_names, saved_layer_names_len);
                        }
                }
        }
@@ -1553,7 +1675,7 @@ register_heur_dissector_list(const char *name, heur_dissector_list_t *sub_dissec
 
        *sub_dissectors = NULL; /* initially empty */
        g_hash_table_insert(heur_dissector_lists, (gpointer)name,
-           (gpointer) sub_dissectors);
+                           (gpointer) sub_dissectors);
 }
 
 /*
@@ -1661,7 +1783,7 @@ register_dissector(const char *name, dissector_t dissector, int proto)
        handle->protocol = find_protocol_by_id(proto);
 
        g_hash_table_insert(registered_dissectors, (gpointer)name,
-           (gpointer) handle);
+                           (gpointer) handle);
 }
 
 void
@@ -1685,7 +1807,21 @@ new_register_dissector(const char *name, new_dissector_t dissector, int proto)
        handle->protocol = find_protocol_by_id(proto);
 
        g_hash_table_insert(registered_dissectors, (gpointer)name,
-           (gpointer) handle);
+                           (gpointer) handle);
+}
+
+/* Call a dissector through a handle but if the dissector rejected it
+ * return 0.
+ */
+int
+call_dissector_only(dissector_handle_t handle, tvbuff_t *tvb,
+                   packet_info *pinfo, proto_tree *tree)
+{
+       int ret;
+
+       g_assert(handle != NULL);
+       ret = call_dissector_work(handle, tvb, pinfo, tree, TRUE);
+       return ret;
 }
 
 /* Call a dissector through a handle and if this fails call the "data"
@@ -1693,37 +1829,24 @@ new_register_dissector(const char *name, new_dissector_t dissector, int proto)
  */
 int
 call_dissector(dissector_handle_t handle, tvbuff_t *tvb,
-    packet_info *pinfo, proto_tree *tree)
+              packet_info *pinfo, proto_tree *tree)
 {
        int ret;
 
-       ret = call_dissector_work(handle, tvb, pinfo, tree);
+       ret = call_dissector_only(handle, tvb, pinfo, tree);
        if (ret == 0) {
                /*
                 * The protocol was disabled, or the dissector rejected
                 * it.  Just dissect this packet as data.
                 */
-               g_assert(data_handle != NULL);
+               g_assert(data_handle != NULL);
                g_assert(data_handle->protocol != NULL);
-               call_dissector(data_handle, tvb, pinfo, tree);
+               call_dissector_work(data_handle, tvb, pinfo, tree, TRUE);
                return tvb_length(tvb);
        }
        return ret;
 }
 
-/* Call a dissector through a handle but if the dissector rejected it
- * return 0 instead of using the default "data" dissector.
- */
-int
-call_dissector_only(dissector_handle_t handle, tvbuff_t *tvb,
-    packet_info *pinfo, proto_tree *tree)
-{
-       int ret;
-
-       ret = call_dissector_work(handle, tvb, pinfo, tree);
-       return ret;
-}
-
 /*
  * Dumps the "layer type"/"decode as" associations to stdout, similar
  * to the proto_registrar_dump_*() routines.
@@ -1737,10 +1860,11 @@ call_dissector_only(dissector_handle_t handle, tvbuff_t *tvb,
 
 
 static void
-dissector_dump_decodes_display(gchar *table_name, ftenum_t selector_type _U_,
-    gpointer key, gpointer value, gpointer user_data _U_)
+dissector_dump_decodes_display(const gchar *table_name,
+                              ftenum_t selector_type _U_, gpointer key, gpointer value,
+                              gpointer user_data _U_)
 {
-       guint32 selector = (guint32) key;
+       guint32 selector = (guint32)(unsigned long) key;
        dissector_table_t sub_dissectors = find_dissector_table(table_name);
        dtbl_entry_t *dtbl_entry;
        dissector_handle_t handle;
@@ -1775,6 +1899,49 @@ dissector_dump_decodes_display(gchar *table_name, ftenum_t selector_type _U_,
 }
 
 void
-dissector_dump_decodes() {
+dissector_dump_decodes()
+{
        dissector_all_tables_foreach(dissector_dump_decodes_display, NULL);
 }
+
+static GPtrArray* post_dissectors = NULL;
+static guint num_of_postdissectors = 0;
+
+void
+register_postdissector(dissector_handle_t handle)
+{
+       if (!post_dissectors)
+               post_dissectors = g_ptr_array_new();
+
+       g_ptr_array_add(post_dissectors, handle);
+       num_of_postdissectors++;
+}
+
+gboolean
+have_postdissector()
+{
+       guint i;
+       dissector_handle_t handle;
+
+       for(i = 0; i < num_of_postdissectors; i++) {
+               handle = (dissector_handle_t) g_ptr_array_index(post_dissectors,i);
+
+               if (handle->protocol != NULL
+                   && proto_is_protocol_enabled(handle->protocol)) {
+                       /* We have at least one enabled postdissector */
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+void
+call_all_postdissectors(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       guint i;
+
+       for(i = 0; i < num_of_postdissectors; i++) {
+               call_dissector_only((dissector_handle_t) g_ptr_array_index(post_dissectors,i),
+                                   tvb,pinfo,tree);
+       }
+}