packet-dcerpc: let dissect_dcerpc_cn_auth() always dissect the whole auth_info
[metze/wireshark/wip.git] / epan / dissectors / packet-dcerpc.c
index 1c3255635068c69b1985561fcd99be33d1aabd31..a9f931fbfc3a3871b82d939f55deb8e779e82819 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright 2003, Tim Potter <tpot[AT]samba.org>
  * Copyright 2010, Julien Kerihuel <j.kerihuel[AT]openchange.org>
  *
- * $Id$
- *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
 
 #include "config.h"
 
-#include <string.h>
-
-#include <glib.h>
-
+#include <stdio.h>
 #include <epan/packet.h>
 #include <epan/exceptions.h>
-#include <epan/conversation.h>
 #include <epan/prefs.h>
 #include <epan/reassemble.h>
 #include <epan/tap.h>
-#include <epan/wmem/wmem.h>
+#include <epan/srt_table.h>
 #include <epan/expert.h>
-#include <epan/strutil.h>
 #include <epan/addr_resolv.h>
 #include <epan/show_exception.h>
-#include <epan/dissectors/packet-dcerpc.h>
-#include <epan/dissectors/packet-dcerpc-nt.h>
+#include <epan/decode_as.h>
+#include <epan/proto_data.h>
+
+#include <wsutil/str_util.h>
+#include "packet-tcp.h"
+#include "packet-dcerpc.h"
+#include "packet-dcerpc-nt.h"
+
+void proto_register_dcerpc(void);
+void proto_reg_handoff_dcerpc(void);
 
 static int dcerpc_tap = -1;
 
 /* 32bit Network Data Representation, see DCE/RPC Appendix I */
-static e_uuid_t uuid_data_repr_proto        = { 0x8a885d04, 0x1ceb, 0x11c9,
+static e_guid_t uuid_data_repr_proto        = { 0x8a885d04, 0x1ceb, 0x11c9,
                                                 { 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
 
 /* 64bit Network Data Representation, introduced in Windows Server 2008 */
-static e_uuid_t uuid_ndr64                  = { 0x71710533, 0xbeba, 0x4937,
+static e_guid_t uuid_ndr64                  = { 0x71710533, 0xbeba, 0x4937,
                                                 { 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
 
-/* Bind Time Feature Negotiation, see [MS-RPCE] 3.3.1.5.3 */
-static e_uuid_t uuid_bind_time_feature_nego_00 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
-static e_uuid_t uuid_bind_time_feature_nego_01 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
-static e_uuid_t uuid_bind_time_feature_nego_02 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
-static e_uuid_t uuid_bind_time_feature_nego_03 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
-
 /* see [MS-OXRPC] Appendix A: Full IDL, http://msdn.microsoft.com/en-us/library/ee217991%28v=exchg.80%29.aspx */
-static e_uuid_t uuid_asyncemsmdb            = { 0x5261574a, 0x4572, 0x206e,
+static e_guid_t uuid_asyncemsmdb            = { 0x5261574a, 0x4572, 0x206e,
                                                 { 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
 
 static const value_string pckt_vals[] = {
@@ -269,6 +264,7 @@ static const value_string reject_status_vals[] = {
     { 0x00000005, "nca_s_fault_access_denied" },
     { 0x000006f7, "nca_s_fault_ndr" },
     { 0x000006d8, "nca_s_fault_cant_perform" },
+    { 0x00000721, "nca_s_fault_sec_pkg_error" },
     { 0x1c000001, "nca_s_fault_int_div_by_zero" },
     { 0x1c000002, "nca_s_fault_addr_error" },
     { 0x1c000003, "nca_s_fault_fp_div_zero" },
@@ -452,6 +448,7 @@ static int hf_dcerpc_cn_flags_maybe = -1;
 static int hf_dcerpc_cn_flags_object = -1;
 static int hf_dcerpc_drep = -1;
        int hf_dcerpc_drep_byteorder = -1;
+       int hf_dcerpc_ndr_padding = -1;
 static int hf_dcerpc_drep_character = -1;
 static int hf_dcerpc_drep_fp = -1;
 static int hf_dcerpc_cn_frag_len = -1;
@@ -471,6 +468,7 @@ static int hf_dcerpc_cn_bind_if_ver_minor = -1;
 static int hf_dcerpc_cn_bind_trans_syntax = -1;
 static int hf_dcerpc_cn_bind_trans_id = -1;
 static int hf_dcerpc_cn_bind_trans_ver = -1;
+static int hf_dcerpc_cn_bind_trans_btfn = -1;
 static int hf_dcerpc_cn_bind_trans_btfn_01 = -1;
 static int hf_dcerpc_cn_bind_trans_btfn_02 = -1;
 static int hf_dcerpc_cn_alloc_hint = -1;
@@ -481,7 +479,6 @@ static int hf_dcerpc_cn_ack_result = -1;
 static int hf_dcerpc_cn_ack_reason = -1;
 static int hf_dcerpc_cn_ack_trans_id = -1;
 static int hf_dcerpc_cn_ack_trans_ver = -1;
-static int hf_dcerpc_cn_ack_btfn = -1;
 static int hf_dcerpc_cn_reject_reason = -1;
 static int hf_dcerpc_cn_num_protocols = -1;
 static int hf_dcerpc_cn_protocol_ver_major = -1;
@@ -568,9 +565,10 @@ static int hf_dcerpc_dg_status = -1;
 static int hf_dcerpc_array_max_count = -1;
 static int hf_dcerpc_array_offset = -1;
 static int hf_dcerpc_array_actual_count = -1;
-static int hf_dcerpc_array_buffer = -1;
 static int hf_dcerpc_op = -1;
-static int hf_dcerpc_referent_id = -1;
+static int hf_dcerpc_referent_id32 = -1;
+static int hf_dcerpc_referent_id64 = -1;
+static int hf_dcerpc_null_pointer = -1;
 static int hf_dcerpc_fragments = -1;
 static int hf_dcerpc_fragment = -1;
 static int hf_dcerpc_fragment_overlap = -1;
@@ -582,6 +580,61 @@ static int hf_dcerpc_fragment_count = -1;
 static int hf_dcerpc_reassembled_in = -1;
 static int hf_dcerpc_reassembled_length = -1;
 static int hf_dcerpc_unknown_if_id = -1;
+static int hf_dcerpc_sec_vt_signature = -1;
+static int hf_dcerpc_sec_vt_command = -1;
+static int hf_dcerpc_sec_vt_command_cmd = -1;
+static int hf_dcerpc_sec_vt_command_end = -1;
+static int hf_dcerpc_sec_vt_command_must = -1;
+static int hf_dcerpc_sec_vt_command_length = -1;
+static int hf_dcerpc_sec_vt_bitmask = -1;
+static int hf_dcerpc_sec_vt_bitmask_sign = -1;
+static int hf_dcerpc_sec_vt_pcontext_uuid = -1;
+static int hf_dcerpc_sec_vt_pcontext_ver = -1;
+
+static const int *sec_vt_command_fields[] = {
+    &hf_dcerpc_sec_vt_command_cmd,
+    &hf_dcerpc_sec_vt_command_end,
+    &hf_dcerpc_sec_vt_command_must,
+    NULL
+};
+static int hf_dcerpc_reserved = -1;
+static int hf_dcerpc_unknown = -1;
+static int hf_dcerpc_missalign = -1;
+
+/* Generated from convert_proto_tree_add_text.pl */
+static int hf_dcerpc_duplicate_ptr = -1;
+static int hf_dcerpc_encrypted_stub_data = -1;
+static int hf_dcerpc_decrypted_stub_data = -1;
+static int hf_dcerpc_payload_stub_data = -1;
+static int hf_dcerpc_stub_data_with_sec_vt = -1;
+static int hf_dcerpc_stub_data = -1;
+static int hf_dcerpc_auth_padding = -1;
+static int hf_dcerpc_auth_verifier = -1;
+static int hf_dcerpc_auth_info = -1;
+static int hf_dcerpc_auth_credentials = -1;
+static int hf_dcerpc_fault_stub_data = -1;
+static int hf_dcerpc_fragment_data = -1;
+static int hf_dcerpc_cmd_client_ipv4 = -1;
+static int hf_dcerpc_cmd_client_ipv6 = -1;
+static int hf_dcerpc_authentication_verifier = -1;
+
+static const int *dcerpc_cn_bind_trans_btfn_fields[] = {
+        &hf_dcerpc_cn_bind_trans_btfn_01,
+        &hf_dcerpc_cn_bind_trans_btfn_02,
+        NULL
+};
+
+static const int *sec_vt_bitmask_fields[] = {
+    &hf_dcerpc_sec_vt_bitmask_sign,
+    NULL
+};
+
+static const value_string sec_vt_command_cmd_vals[] = {
+    {1, "BITMASK_1"},
+    {2, "PCONTEXT"},
+    {3, "HEADER2"},
+    {0, NULL}
+};
 
 static gint ett_dcerpc = -1;
 static gint ett_dcerpc_cn_flags = -1;
@@ -589,6 +642,7 @@ static gint ett_dcerpc_cn_ctx = -1;
 static gint ett_dcerpc_cn_iface = -1;
 static gint ett_dcerpc_cn_trans_syntax = -1;
 static gint ett_dcerpc_cn_trans_btfn = -1;
+static gint ett_dcerpc_cn_bind_trans_btfn = -1;
 static gint ett_dcerpc_cn_rts_flags = -1;
 static gint ett_dcerpc_cn_rts_command = -1;
 static gint ett_dcerpc_cn_rts_pdu = -1;
@@ -600,6 +654,13 @@ static gint ett_dcerpc_string = -1;
 static gint ett_dcerpc_fragments = -1;
 static gint ett_dcerpc_fragment = -1;
 static gint ett_dcerpc_krb5_auth_verf = -1;
+static gint ett_dcerpc_auth_info = -1;
+static gint ett_dcerpc_verification_trailer = -1;
+static gint ett_dcerpc_sec_vt_command = -1;
+static gint ett_dcerpc_sec_vt_bitmask = -1;
+static gint ett_dcerpc_sec_vt_pcontext = -1;
+static gint ett_dcerpc_sec_vt_header = -1;
+static gint ett_dcerpc_complete_stub_data = -1;
 
 static expert_field ei_dcerpc_fragment_multiple = EI_INIT;
 static expert_field ei_dcerpc_cn_status = EI_INIT;
@@ -609,6 +670,334 @@ static expert_field ei_dcerpc_no_request_found = EI_INIT;
 static expert_field ei_dcerpc_context_change = EI_INIT;
 static expert_field ei_dcerpc_cn_ctx_id_no_bind = EI_INIT;
 static expert_field ei_dcerpc_bind_not_acknowledged = EI_INIT;
+static expert_field ei_dcerpc_verifier_unavailable = EI_INIT;
+static expert_field ei_dcerpc_invalid_pdu_authentication_attempt = EI_INIT;
+/* Generated from convert_proto_tree_add_text.pl */
+static expert_field ei_dcerpc_long_frame = EI_INIT;
+static expert_field ei_dcerpc_cn_rts_command = EI_INIT;
+
+static const guint8 TRAILER_SIGNATURE[] = {0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71};
+static tvbuff_t *tvb_trailer_signature = NULL;
+
+static GSList *decode_dcerpc_bindings = NULL;
+/*
+ * To keep track of ctx_id mappings.
+ *
+ * Every time we see a bind call we update this table.
+ * Note that we always specify a SMB FID. For non-SMB transports this
+ * value is 0.
+ */
+static GHashTable *dcerpc_binds = NULL;
+
+typedef struct _dcerpc_bind_key {
+    conversation_t *conv;
+    guint16         ctx_id;
+    guint64         transport_salt;
+} dcerpc_bind_key;
+
+typedef struct _dcerpc_bind_value {
+    e_guid_t uuid;
+    guint16  ver;
+    e_guid_t transport;
+} dcerpc_bind_value;
+
+/* Extra data for DCERPC handling and tracking of context ids */
+typedef struct _dcerpc_decode_as_data {
+    guint16 dcectxid;             /**< Context ID (DCERPC-specific) */
+    int     dcetransporttype;     /**< Transport type
+                                    * Value -1 means "not a DCERPC packet"
+                                    */
+    guint64 dcetransportsalt;     /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
+} dcerpc_decode_as_data;
+
+static dcerpc_decode_as_data*
+dcerpc_get_decode_data(packet_info* pinfo)
+{
+    dcerpc_decode_as_data* data = (dcerpc_decode_as_data*)p_get_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0);
+    if (data == NULL)
+    {
+        data = wmem_new0(pinfo->pool, dcerpc_decode_as_data);
+        data->dcetransporttype = -1;
+        p_add_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0, data);
+    }
+
+    return data;
+}
+
+/**
+ *  Registers a conversation/UUID binding association, so that
+ *  we can invoke the proper sub-dissector for a given DCERPC
+ *  conversation.
+ *
+ *  @param binding all values needed to create and bind a new conversation
+ *
+ *  @return Pointer to newly-added UUID/conversation binding.
+ */
+static struct _dcerpc_bind_value *
+dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
+{
+    dcerpc_bind_value *bind_value;
+    dcerpc_bind_key   *key;
+    conversation_t    *conv;
+
+    conv = find_conversation(
+        0,
+        &binding->addr_a,
+        &binding->addr_b,
+        binding->ptype,
+        binding->port_a,
+        binding->port_b,
+        0);
+
+    if (!conv) {
+        conv = conversation_new(
+            0,
+            &binding->addr_a,
+            &binding->addr_b,
+            binding->ptype,
+            binding->port_a,
+            binding->port_b,
+            0);
+    }
+
+    bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
+    bind_value->uuid = binding->uuid;
+    bind_value->ver = binding->ver;
+    /* For now, assume all DCE/RPC we pick from "decode as" is using
+       standard ndr and not ndr64.
+       We should make this selectable from the dialog in the future
+    */
+    bind_value->transport = uuid_data_repr_proto;
+
+    key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
+    key->conv = conv;
+    key->ctx_id = binding->ctx_id;
+    key->transport_salt = binding->transport_salt;
+
+    /* add this entry to the bind table */
+    g_hash_table_insert(dcerpc_binds, key, bind_value);
+
+    return bind_value;
+
+}
+
+/* inject one of our bindings into the dcerpc binding table */
+static void
+decode_dcerpc_inject_binding(gpointer data, gpointer user_data _U_)
+{
+    dcerpc_add_conv_to_bind_table((decode_dcerpc_bind_values_t *) data);
+}
+
+/* inject all of our bindings into the dcerpc binding table */
+static void
+decode_dcerpc_inject_bindings(void) {
+    g_slist_foreach(decode_dcerpc_bindings, decode_dcerpc_inject_binding, NULL /* user_data */);
+}
+
+/* free a binding */
+static void
+decode_dcerpc_binding_free(void *binding_in)
+{
+    decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)binding_in;
+
+    free_address(&binding->addr_a);
+    free_address(&binding->addr_b);
+    if (binding->ifname)
+        g_string_free(binding->ifname, TRUE);
+    g_free(binding);
+}
+
+static void
+dcerpc_decode_as_free(gpointer value)
+{
+    decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)value;
+    if (binding != NULL)
+        decode_dcerpc_binding_free(binding);
+}
+
+/* removes all bindings */
+void
+decode_dcerpc_reset_all(void)
+{
+    decode_dcerpc_bind_values_t *binding;
+
+    while (decode_dcerpc_bindings) {
+        binding = (decode_dcerpc_bind_values_t *)decode_dcerpc_bindings->data;
+
+        decode_dcerpc_binding_free(binding);
+        decode_dcerpc_bindings = g_slist_remove(
+            decode_dcerpc_bindings,
+            decode_dcerpc_bindings->data);
+    }
+}
+
+
+void
+decode_dcerpc_add_show_list(decode_add_show_list_func func, gpointer user_data)
+{
+    g_slist_foreach(decode_dcerpc_bindings, func, user_data);
+}
+
+static void
+dcerpc_prompt(packet_info *pinfo, gchar* result)
+{
+    GString *str = g_string_new("Replace binding between:\r\n"),
+            *address_str = g_string_new("");
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+    switch (pinfo->ptype) {
+    case(PT_TCP):
+        g_string_append(address_str, "Address: ToBeDone TCP port");
+        break;
+    case(PT_UDP):
+        g_string_append(address_str, "Address: ToBeDone UDP port");
+        break;
+    default:
+        g_string_append(address_str, "Address: ToBeDone Unknown port type");
+    }
+
+    g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->srcport);
+    g_string_append(str, "&\r\n");
+    g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->destport);
+    g_string_append_printf(str, "&\r\nContext ID: %u\r\n", decode_data->dcectxid);
+    g_string_append_printf(str, "&\r\nSMB FID: %"G_GINT64_MODIFIER"u\r\n",
+                           dcerpc_get_transport_salt(pinfo));
+    g_string_append(str, "with:\r\n");
+
+    g_strlcpy(result, str->str, MAX_DECODE_AS_PROMPT_LEN);
+    g_string_free(str, TRUE);
+    g_string_free(address_str, TRUE);
+}
+
+static gpointer
+dcerpc_value(packet_info *pinfo)
+{
+    decode_dcerpc_bind_values_t *binding;
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+    /* clone binding */
+    binding = g_new(decode_dcerpc_bind_values_t,1);
+    copy_address(&binding->addr_a, &pinfo->src);
+    copy_address(&binding->addr_b, &pinfo->dst);
+    binding->ptype = pinfo->ptype;
+    binding->port_a = pinfo->srcport;
+    binding->port_b = pinfo->destport;
+    binding->ctx_id = decode_data->dcectxid;
+    binding->transport_salt = dcerpc_get_transport_salt(pinfo);
+    binding->ifname = NULL;
+    /*binding->uuid = NULL;*/
+    binding->ver = 0;
+
+    return binding;
+}
+
+struct dcerpc_decode_as_populate
+{
+    decode_as_add_to_list_func add_to_list;
+    gpointer ui_element;
+};
+
+static void
+decode_dcerpc_add_to_list(gpointer key, gpointer value, gpointer user_data)
+{
+    struct dcerpc_decode_as_populate* populate = (struct dcerpc_decode_as_populate*)user_data;
+
+    /*guid_key *k = key;*/
+    dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
+
+    if (strcmp(v->name, "(none)"))
+        populate->add_to_list("DCE-RPC", v->name, key, populate->ui_element);
+}
+
+static void
+dcerpc_populate_list(const gchar *table_name _U_, decode_as_add_to_list_func add_to_list, gpointer ui_element)
+{
+    struct dcerpc_decode_as_populate populate;
+
+    populate.add_to_list = add_to_list;
+    populate.ui_element = ui_element;
+
+    g_hash_table_foreach(dcerpc_uuids, decode_dcerpc_add_to_list, &populate);
+}
+
+/* compare two bindings (except the interface related things, e.g. uuid) */
+static gint
+decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b)
+{
+    const decode_dcerpc_bind_values_t *binding_a = (const decode_dcerpc_bind_values_t *)a;
+    const decode_dcerpc_bind_values_t *binding_b = (const decode_dcerpc_bind_values_t *)b;
+
+
+    /* don't compare uuid and ver! */
+    if (
+        addresses_equal(&binding_a->addr_a, &binding_b->addr_a) &&
+        addresses_equal(&binding_a->addr_b, &binding_b->addr_b) &&
+        binding_a->ptype == binding_b->ptype &&
+        binding_a->port_a == binding_b->port_a &&
+        binding_a->port_b == binding_b->port_b &&
+        binding_a->ctx_id == binding_b->ctx_id &&
+        binding_a->transport_salt == binding_b->transport_salt)
+    {
+        /* equal */
+        return 0;
+    }
+
+    /* unequal */
+    return 1;
+}
+
+/* remove a binding (looking the same way as the given one) */
+static gboolean
+decode_dcerpc_binding_reset(const char *name _U_, gconstpointer pattern)
+{
+    const decode_dcerpc_bind_values_t *binding = (const decode_dcerpc_bind_values_t *)pattern;
+    GSList *le;
+    decode_dcerpc_bind_values_t *old_binding;
+
+    /* find the old binding (if it exists) */
+    le = g_slist_find_custom(decode_dcerpc_bindings,
+                                             binding,
+                                             decode_dcerpc_binding_cmp);
+    if (le == NULL)
+        return FALSE;
+
+    old_binding = (decode_dcerpc_bind_values_t *)le->data;
+
+    decode_dcerpc_bindings = g_slist_remove(decode_dcerpc_bindings, le->data);
+
+    free_address(&old_binding->addr_a);
+    free_address(&old_binding->addr_b);
+    g_string_free(old_binding->ifname, TRUE);
+    g_free(old_binding);
+    return FALSE;
+}
+
+static gboolean
+dcerpc_decode_as_change(const char *name, gconstpointer pattern, gpointer handle, gchar* list_name)
+{
+    decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
+    decode_dcerpc_bind_values_t *stored_binding;
+    guid_key     *key = *((guid_key**)handle);
+
+
+    binding->ifname = g_string_new(list_name);
+    binding->uuid = key->guid;
+    binding->ver = key->ver;
+
+    /* remove a probably existing old binding */
+    decode_dcerpc_binding_reset(name, binding);
+
+    /* clone the new binding and append it to the list */
+    stored_binding = g_new(decode_dcerpc_bind_values_t,1);
+    *stored_binding = *binding;
+    copy_address(&stored_binding->addr_a, &binding->addr_a);
+    copy_address(&stored_binding->addr_b, &binding->addr_b);
+    stored_binding->ifname = g_string_new(binding->ifname->str);
+
+    decode_dcerpc_bindings = g_slist_append (decode_dcerpc_bindings, stored_binding);
+
+    return FALSE;
+}
 
 static const fragment_items dcerpc_frag_items = {
     &ett_dcerpc_fragments,
@@ -632,22 +1021,6 @@ static const fragment_items dcerpc_frag_items = {
 /* list of hooks to be called when init_protocols is done */
 GHookList dcerpc_hooks_init_protos;
 
-static dcerpc_info *
-get_next_di(void)
-{
-    static dcerpc_info di[20];
-    static int         di_counter = 0;
-
-    di_counter++;
-    if (di_counter >= 20) {
-        di_counter = 0;
-    }
-
-    memset(&di[di_counter], 0, sizeof(dcerpc_info));
-
-    return &di[di_counter];
-}
-
 /* try to desegment big DCE/RPC packets over TCP? */
 static gboolean dcerpc_cn_desegment = TRUE;
 
@@ -665,43 +1038,43 @@ static reassembly_table dcerpc_co_reassembly_table;
 static reassembly_table dcerpc_cl_reassembly_table;
 
 typedef struct _dcerpc_fragment_key {
-       address src;
-       address dst;
-       guint32 id;
-       e_uuid_t act_id;
+    address src;
+    address dst;
+    guint32 id;
+    e_guid_t act_id;
 } dcerpc_fragment_key;
 
 static guint
 dcerpc_fragment_hash(gconstpointer k)
 {
-       const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
-       guint hash_val;
+    const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
+    guint hash_val;
 
-       hash_val = 0;
+    hash_val = 0;
 
-       hash_val += key->id;
-       hash_val += key->act_id.Data1;
-       hash_val += key->act_id.Data2 << 16;
-       hash_val += key->act_id.Data3;
+    hash_val += key->id;
+    hash_val += key->act_id.data1;
+    hash_val += key->act_id.data2 << 16;
+    hash_val += key->act_id.data3;
 
-       return hash_val;
+    return hash_val;
 }
 
 static gint
 dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
 {
-       const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
-       const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
-
-       /*key.id is the first item to compare since item is most
-         likely to differ between sessions, thus shortcircuiting
-         the comparison of addresses.
-       */
-       return (((key1->id == key2->id)
-                 && (ADDRESSES_EQUAL(&key1->src, &key2->src))
-                 && (ADDRESSES_EQUAL(&key1->dst, &key2->dst))
-                 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0))
-                ? TRUE : FALSE);
+    const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
+    const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
+
+    /*key.id is the first item to compare since item is most
+      likely to differ between sessions, thus shortcircuiting
+      the comparison of addresses.
+    */
+    return (((key1->id == key2->id)
+             && (addresses_equal(&key1->src, &key2->src))
+             && (addresses_equal(&key1->dst, &key2->dst))
+             && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_guid_t)) == 0))
+            ? TRUE : FALSE);
 }
 
 /* allocate a persistent dcerpc fragment key to insert in the hash */
@@ -709,15 +1082,15 @@ static void *
 dcerpc_fragment_temporary_key(const packet_info *pinfo, const guint32 id,
                               const void *data)
 {
-       dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
-       e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
+    dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
+    const e_dce_dg_common_hdr_t *hdr = (const e_dce_dg_common_hdr_t *)data;
 
-       key->src = pinfo->src;
-       key->dst = pinfo->dst;
-       key->id = id;
-       key->act_id = hdr->act_id;
+    copy_address_shallow(&key->src, &pinfo->src);
+    copy_address_shallow(&key->dst, &pinfo->dst);
+    key->id = id;
+    key->act_id = hdr->act_id;
 
-       return key;
+    return key;
 }
 
 /* allocate a persistent dcerpc fragment key to insert in the hash */
@@ -725,49 +1098,49 @@ static void *
 dcerpc_fragment_persistent_key(const packet_info *pinfo, const guint32 id,
                                const void *data)
 {
-       dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
-       e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
+    dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
+    const e_dce_dg_common_hdr_t *hdr = (const e_dce_dg_common_hdr_t *)data;
 
-       COPY_ADDRESS(&key->src, &pinfo->src);
-       COPY_ADDRESS(&key->dst, &pinfo->dst);
-       key->id = id;
-       key->act_id = hdr->act_id;
+    copy_address(&key->src, &pinfo->src);
+    copy_address(&key->dst, &pinfo->dst);
+    key->id = id;
+    key->act_id = hdr->act_id;
 
-       return key;
+    return key;
 }
 
 static void
 dcerpc_fragment_free_temporary_key(gpointer ptr)
 {
-       dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
+    dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
 
-       if(key)
-               g_slice_free(dcerpc_fragment_key, key);
+    if (key)
+        g_slice_free(dcerpc_fragment_key, key);
 }
 
 static void
 dcerpc_fragment_free_persistent_key(gpointer ptr)
 {
-       dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
+    dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
 
-       if(key){
-               /*
-                * Free up the copies of the addresses from the old key.
-                */
-               g_free((gpointer)key->src.data);
-               g_free((gpointer)key->dst.data);
+    if (key) {
+        /*
+         * Free up the copies of the addresses from the old key.
+         */
+        free_address(&key->src);
+        free_address(&key->dst);
 
-               g_slice_free(dcerpc_fragment_key, key);
-       }
+        g_slice_free(dcerpc_fragment_key, key);
+    }
 }
 
 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions = {
-       dcerpc_fragment_hash,
-       dcerpc_fragment_equal,
-       dcerpc_fragment_temporary_key,
-       dcerpc_fragment_persistent_key,
-       dcerpc_fragment_free_temporary_key,
-       dcerpc_fragment_free_persistent_key
+    dcerpc_fragment_hash,
+    dcerpc_fragment_equal,
+    dcerpc_fragment_temporary_key,
+    dcerpc_fragment_persistent_key,
+    dcerpc_fragment_free_temporary_key,
+    dcerpc_fragment_free_persistent_key
 };
 
 static void
@@ -833,117 +1206,466 @@ void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
 
 /* Hand off verifier data to a registered dissector */
 
-static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
-                              proto_tree *tree,
-                              dcerpc_auth_subdissector_fns *auth_fns,
+static void dissect_auth_verf(packet_info *pinfo,
                               e_dce_cn_common_hdr_t *hdr,
                               dcerpc_auth_info *auth_info)
 {
-    dcerpc_dissect_fnct_t *volatile fn = NULL;
+    dcerpc_dissect_fnct_t *fn = NULL;
     /* XXX - "stub" a fake DCERPC INFO STRUCTURE
        If a dcerpc_info is really needed, update
        the call stacks to include it
      */
     FAKE_DCERPC_INFO_STRUCTURE
 
+    if (auth_info == NULL) {
+        return;
+    }
+
+    if (auth_info->auth_fns == NULL) {
+        return;
+    }
+
     switch (hdr->ptype) {
     case PDU_BIND:
     case PDU_ALTER:
-        fn = auth_fns->bind_fn;
+        fn = auth_info->auth_fns->bind_fn;
         break;
     case PDU_BIND_ACK:
     case PDU_ALTER_ACK:
-        fn = auth_fns->bind_ack_fn;
+        fn = auth_info->auth_fns->bind_ack_fn;
         break;
     case PDU_AUTH3:
-        fn = auth_fns->auth3_fn;
+        fn = auth_info->auth_fns->auth3_fn;
         break;
     case PDU_REQ:
-        fn = auth_fns->req_verf_fn;
+    case PDU_CO_CANCEL:
+    case PDU_ORPHANED:
+        fn = auth_info->auth_fns->req_verf_fn;
         break;
     case PDU_RESP:
-        fn = auth_fns->resp_verf_fn;
+    case PDU_FAULT:
+        fn = auth_info->auth_fns->resp_verf_fn;
         break;
 
+    default:
         /* Don't know how to handle authentication data in this
            pdu type. */
-
-    default:
-        g_warning("attempt to dissect %s pdu authentication data",
-                  val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
+        proto_tree_add_expert_format(auth_info->auth_tree, pinfo,
+                                     &ei_dcerpc_invalid_pdu_authentication_attempt,
+                                     auth_info->auth_tvb, 0, 0,
+                                     "Don't know how to dissect authentication data for %s pdu type",
+                                     val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
+        return;
         break;
     }
 
     if (fn)
-        fn(auth_tvb, 0, pinfo, tree, &di, hdr->drep);
-    else {
-        tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
-        proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
-                            "%s Verifier",
-                            val_to_str(auth_info->auth_type,
-                                       authn_protocol_vals,
-                                       "Unknown (%u)"));
-    }
+        fn(auth_info->auth_tvb, 0, pinfo, auth_info->auth_tree, &di, hdr->drep);
+    else
+        proto_tree_add_expert_format(auth_info->auth_tree, pinfo,
+                                     &ei_dcerpc_verifier_unavailable,
+                                     auth_info->auth_tvb, 0, hdr->auth_len,
+                                     "%s Verifier unavailable",
+                                     val_to_str(auth_info->auth_type,
+                                                authn_protocol_vals,
+                                                "Unknown (%u)"));
+}
+
+static proto_item*
+proto_tree_add_dcerpc_drep(proto_tree *tree, tvbuff_t *tvb, int offset, guint8 drep[], int drep_len)
+{
+    const guint8 byteorder = drep[0] >> 4;
+    const guint8 character = drep[0] & 0x0f;
+    const guint8 fp = drep[1];
+    proto_item *ti = proto_tree_add_bytes(tree, hf_dcerpc_drep, tvb, offset, drep_len, drep);
+    proto_tree *tr = proto_item_add_subtree(ti, ett_dcerpc_drep);
+
+    proto_tree_add_uint(tr, hf_dcerpc_drep_byteorder, tvb, offset, 1, byteorder);
+    proto_tree_add_uint(tr, hf_dcerpc_drep_character, tvb, offset, 1, character);
+    proto_tree_add_uint(tr, hf_dcerpc_drep_fp, tvb, offset+1, 1, fp);
+
+    proto_item_append_text(ti, " (Order: %s, Char: %s, Float: %s)",
+                           val_to_str(byteorder, drep_byteorder_vals, "Unknown (%u)"),
+                           val_to_str(character, drep_character_vals, "Unknown (%u)"),
+                           val_to_str(fp, drep_fp_vals, "Unknown (%u)"));
+    return ti;
 }
 
 /* Hand off payload data to a registered dissector */
 
 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
-                                       tvbuff_t *auth_tvb,
                                        packet_info *pinfo,
-                                       dcerpc_auth_subdissector_fns *auth_fns,
-                                       gboolean is_request,
+                                       e_dce_cn_common_hdr_t *hdr,
                                        dcerpc_auth_info *auth_info)
 {
-    dcerpc_decode_data_fnct_t *fn;
+    dcerpc_decode_data_fnct_t *fn = NULL;
 
-    if (is_request)
-        fn = auth_fns->req_data_fn;
-    else
-        fn = auth_fns->resp_data_fn;
+    if (auth_info == NULL)
+        return NULL;
+
+    if (auth_info->auth_fns == NULL)
+        return NULL;
+
+    switch (hdr->ptype) {
+    case PDU_REQ:
+        fn = auth_info->auth_fns->req_data_fn;
+        break;
+    case PDU_RESP:
+    case PDU_FAULT:
+        fn = auth_info->auth_fns->resp_data_fn;
+        break;
+    }
 
     if (fn)
-        return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
+        return fn(data_tvb, auth_info->auth_tvb, 0, pinfo, auth_info);
 
     return NULL;
 }
 
+typedef struct _dcerpc_dissector_data
+{
+    dcerpc_uuid_value *sub_proto;
+    dcerpc_info *info;
+    gboolean decrypted;
+    dcerpc_auth_info *auth_info;
+    guint8 *drep;
+    proto_tree *dcerpc_tree;
+} dcerpc_dissector_data_t;
+
 /*
  * Subdissectors
  */
 
+dissector_table_t   uuid_dissector_table;
+
 /* the registered subdissectors */
 GHashTable *dcerpc_uuids = NULL;
 
 static gint
 dcerpc_uuid_equal(gconstpointer k1, gconstpointer k2)
 {
-    const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
-    const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
-    return ((memcmp(&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
+    const guid_key *key1 = (const guid_key *)k1;
+    const guid_key *key2 = (const guid_key *)k2;
+    return ((memcmp(&key1->guid, &key2->guid, sizeof (e_guid_t)) == 0)
             && (key1->ver == key2->ver));
 }
 
 static guint
 dcerpc_uuid_hash(gconstpointer k)
 {
-    const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
+    const guid_key *key = (const guid_key *)k;
     /* This isn't perfect, but the Data1 part of these is almost always
        unique. */
-    return key->uuid.Data1;
+    return key->guid.data1;
+}
+
+
+static int
+dissect_verification_trailer(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
+                             proto_tree *parent_tree, int *signature_offset);
+
+static void
+show_stub_data(packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
+               dcerpc_auth_info *auth_info, gboolean is_encrypted)
+{
+    int   length, plain_length, auth_pad_len;
+    guint auth_pad_offset;
+
+    /*
+     * We don't show stub data unless we have some in the tvbuff;
+     * however, in the protocol tree, we show, as the number of
+     * bytes, the reported number of bytes, not the number of bytes
+     * that happen to be in the tvbuff.
+     */
+    if (tvb_reported_length_remaining(tvb, offset) > 0) {
+        auth_pad_len = auth_info?auth_info->auth_pad_len:0;
+        length = tvb_reported_length_remaining(tvb, offset);
+
+        /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
+        plain_length = length - auth_pad_len;
+        if (plain_length < 1) {
+            plain_length = length;
+            auth_pad_len = 0;
+        }
+        auth_pad_offset = offset + plain_length;
+
+        if ((auth_info != NULL) &&
+            (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
+            if (is_encrypted) {
+                proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, tvb, offset, length, ENC_NA);
+                /* is the padding is still inside the encrypted blob, don't display it explicit */
+                auth_pad_len = 0;
+            } else {
+                proto_tree_add_item(dcerpc_tree, hf_dcerpc_decrypted_stub_data, tvb, offset, plain_length, ENC_NA);
+                dissect_verification_trailer(pinfo, tvb, offset, dcerpc_tree, NULL);
+            }
+        } else {
+            proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, plain_length, ENC_NA);
+            dissect_verification_trailer(pinfo, tvb, offset, dcerpc_tree, NULL);
+        }
+        /* If there is auth padding at the end of the stub, display it */
+        if (auth_pad_len != 0) {
+            proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_padding, tvb, auth_pad_offset, auth_pad_len, ENC_NA);
+        }
+    }
+}
+
+static int
+dissect_dcerpc_guid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+    dcerpc_dissector_data_t* dissector_data = (dcerpc_dissector_data_t*)data;
+    const gchar          *name     = NULL;
+    dcerpc_sub_dissector *proc;
+    int (*volatile sub_dissect)(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) = NULL;
+    proto_item           *pi, *sub_item;
+    proto_tree           *sub_tree;
+    volatile guint        length;
+    guint                 reported_length;
+    volatile gint         offset   = 0;
+    tvbuff_t *volatile    stub_tvb;
+    tvbuff_t *volatile    payload_tvb = NULL;
+    volatile guint        auth_pad_len;
+    volatile int          auth_pad_offset;
+    const char *volatile  saved_proto;
+
+    for (proc = dissector_data->sub_proto->procs; proc->name; proc++) {
+        if (proc->num == dissector_data->info->call_data->opnum) {
+            name = proc->name;
+            break;
+        }
+    }
+
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, dissector_data->sub_proto->name);
+
+    if (!name)
+        col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
+                     dissector_data->info->call_data->opnum,
+                     (dissector_data->info->ptype == PDU_REQ) ? "request" : "response");
+    else
+        col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
+                     name, (dissector_data->info->ptype == PDU_REQ) ? "request" : "response");
+
+    sub_dissect = (dissector_data->info->ptype == PDU_REQ) ?
+        proc->dissect_rqst : proc->dissect_resp;
+
+    sub_item = proto_tree_add_item(tree, dissector_data->sub_proto->proto_id,
+                                       tvb,//(decrypted_tvb != NULL)?decrypted_tvb:tvb,
+                                       0, -1, ENC_NA);
+    sub_tree = proto_item_add_subtree(sub_item, dissector_data->sub_proto->ett);
+    if (!name)
+        proto_item_append_text(sub_item, ", unknown operation %u",
+                                dissector_data->info->call_data->opnum);
+    else
+        proto_item_append_text(sub_item, ", %s", name);
+
+    if (tree) {
+        /*
+         * Put the operation number into the tree along with
+         * the operation's name.
+         */
+        if (dissector_data->sub_proto->opnum_hf != -1)
+            proto_tree_add_uint_format(sub_tree, dissector_data->sub_proto->opnum_hf,
+                                       tvb, 0, 0, dissector_data->info->call_data->opnum,
+                                       "Operation: %s (%u)",
+                                       name ? name : "Unknown operation",
+                                       dissector_data->info->call_data->opnum);
+        else
+            proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
+                                       0, 0, dissector_data->info->call_data->opnum,
+                                       "%s (%u)",
+                                       name ? name : "Unknown operation",
+                                       dissector_data->info->call_data->opnum);
+
+        if ((dissector_data->info->ptype == PDU_REQ) && (dissector_data->info->call_data->rep_frame != 0)) {
+            pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
+                                     tvb, 0, 0, dissector_data->info->call_data->rep_frame);
+            PROTO_ITEM_SET_GENERATED(pi);
+        }
+        if ((dissector_data->info->ptype == PDU_RESP) && (dissector_data->info->call_data->req_frame != 0)) {
+            pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
+                                     tvb, 0, 0, dissector_data->info->call_data->req_frame);
+            PROTO_ITEM_SET_GENERATED(pi);
+        }
+    } /* tree */
+
+    if (!dissector_data->decrypted || (sub_dissect == NULL))
+    {
+        show_stub_data(pinfo, tvb, 0, sub_tree, dissector_data->auth_info, !dissector_data->decrypted);
+        return tvb_captured_length(tvb);
+    }
+
+    /* Either there was no encryption or we successfully decrypted
+       the encrypted payload. */
+
+    /* We have a subdissector - call it. */
+    saved_proto          = pinfo->current_proto;
+    pinfo->current_proto = dissector_data->sub_proto->name;
+
+    init_ndr_pointer_list(dissector_data->info);
+
+    length = tvb_captured_length(tvb);
+    reported_length = tvb_reported_length(tvb);
+
+    /*
+     * Remove the authentication padding from the stub data.
+     */
+    if ((dissector_data->auth_info != NULL) && (dissector_data->auth_info->auth_pad_len != 0)) {
+        if (reported_length >= dissector_data->auth_info->auth_pad_len) {
+            /*
+             * OK, the padding length isn't so big that it
+             * exceeds the stub length.  Trim the reported
+             * length of the tvbuff.
+             */
+            reported_length -= dissector_data->auth_info->auth_pad_len;
+
+            /*
+             * If that exceeds the actual amount of data in
+             * the tvbuff (which means we have at least one
+             * byte of authentication padding in the tvbuff),
+             * trim the actual amount.
+             */
+            if (length > reported_length)
+                length = reported_length;
+
+            stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
+            auth_pad_len = dissector_data->auth_info->auth_pad_len;
+            auth_pad_offset = reported_length;
+        } else {
+            /*
+             * The padding length exceeds the stub length.
+             * Don't bother dissecting the stub, trim the padding
+             * length to what's in the stub data, and show the
+             * entire stub as authentication padding.
+             */
+            stub_tvb = NULL;
+            auth_pad_len = reported_length;
+            auth_pad_offset = 0;
+            length = 0;
+        }
+    } else {
+        /*
+         * No authentication padding.
+         */
+        stub_tvb = tvb;
+        auth_pad_len = 0;
+        auth_pad_offset = 0;
+    }
+
+    if (sub_item) {
+        proto_item_set_len(sub_item, length);
+    }
+
+    if (stub_tvb != NULL) {
+        /*
+         * Catch all exceptions other than BoundsError, so that even
+         * if the stub data is bad, we still show the authentication
+         * padding, if any.
+         *
+         * If we get BoundsError, it means the frame was cut short
+         * by a snapshot length, so there's nothing more to
+         * dissect; just re-throw that exception.
+         */
+        TRY {
+            proto_tree *stub_tree = NULL;
+            int remaining;
+            int trailer_start_offset = -1;
+            int trailer_end_offset = -1;
+
+            stub_tree = proto_tree_add_subtree_format(dissector_data->dcerpc_tree,
+                                stub_tvb, 0, length,
+                                ett_dcerpc_complete_stub_data, NULL,
+                                "Complete stub data (%d byte%s)", length,
+                                plurality(length, "", "s"));
+            trailer_end_offset = dissect_verification_trailer(pinfo,
+                                                    stub_tvb, 0,
+                                                    stub_tree,
+                                                    &trailer_start_offset);
+
+            if (trailer_end_offset != -1) {
+                remaining = tvb_captured_length_remaining(stub_tvb,
+                                                    trailer_start_offset);
+                length -= remaining;
+
+                if (sub_item) {
+                        proto_item_set_len(sub_item, length);
+                }
+            } else {
+                proto_item *payload_item;
+
+                payload_item = proto_tree_add_item(stub_tree,
+                                    hf_dcerpc_payload_stub_data,
+                                    stub_tvb, 0, length, ENC_NA);
+                proto_item_append_text(payload_item, " (%d byte%s)",
+                                        length, plurality(length, "", "s"));
+            }
+
+            payload_tvb = tvb_new_subset(stub_tvb, 0, length, length);
+            offset = sub_dissect(payload_tvb, 0, pinfo, sub_tree,
+                            dissector_data->info, dissector_data->drep);
+
+            /* If we have a subdissector and it didn't dissect all
+                data in the tvb, make a note of it. */
+            remaining = tvb_reported_length_remaining(stub_tvb, offset);
+
+            if (trailer_end_offset != -1) {
+                if (offset > trailer_start_offset) {
+                    remaining = offset - trailer_start_offset;
+                    proto_tree_add_item(sub_tree, hf_dcerpc_stub_data_with_sec_vt,
+                                        stub_tvb, trailer_start_offset, remaining, ENC_NA);
+                    col_append_fstr(pinfo->cinfo, COL_INFO,
+                                        "[Payload with Verification Trailer (%d byte%s)]",
+                                    remaining,
+                                    plurality(remaining, "", "s"));
+                    remaining = 0;
+                } else {
+                    remaining = trailer_start_offset - offset;
+                }
+            }
+
+            if (remaining > 0) {
+                proto_tree_add_expert(sub_tree, pinfo, &ei_dcerpc_long_frame, stub_tvb, offset, remaining);
+                col_append_fstr(pinfo->cinfo, COL_INFO,
+                                    "[Long frame (%d byte%s)]",
+                                    remaining,
+                                    plurality(remaining, "", "s"));
+            }
+        } CATCH_NONFATAL_ERRORS {
+            /*
+             * Somebody threw an exception that means that there
+             * was a problem dissecting the payload; that means
+             * that a dissector was found, so we don't need to
+             * dissect the payload as data or update the protocol
+             * or info columns.
+             *
+             * Just show the exception and then drive on to show
+             * the authentication padding.
+             */
+            show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
+        } ENDTRY;
+    }
+
+    /* If there is auth padding at the end of the stub, display it */
+    if (auth_pad_len != 0) {
+        proto_tree_add_item(sub_tree, hf_dcerpc_auth_padding, tvb, auth_pad_offset, auth_pad_len, ENC_NA);
+    }
+
+    pinfo->current_proto = saved_proto;
+
+    return tvb_captured_length(tvb);
 }
 
 void
-dcerpc_init_uuid(int proto, int ett, e_uuid_t *uuid, guint16 ver,
+dcerpc_init_uuid(int proto, int ett, e_guid_t *uuid, guint16 ver,
                  dcerpc_sub_dissector *procs, int opnum_hf)
 {
-    dcerpc_uuid_key   *key         = (dcerpc_uuid_key *)g_malloc(sizeof (*key));
+    guid_key   *key         = (guid_key *)g_malloc(sizeof (*key));
     dcerpc_uuid_value *value       = (dcerpc_uuid_value *)g_malloc(sizeof (*value));
     header_field_info *hf_info;
     module_t          *samr_module;
     const char        *filter_name = proto_get_protocol_filter_name(proto);
+    dissector_handle_t guid_handle;
 
-    key->uuid = *uuid;
+    key->guid = *uuid;
     key->ver = ver;
 
     value->proto    = find_protocol_by_id(proto);
@@ -958,6 +1680,10 @@ dcerpc_init_uuid(int proto, int ett, e_uuid_t *uuid, guint16 ver,
     hf_info = proto_registrar_get_nth(opnum_hf);
     hf_info->strings = value_string_from_subdissectors(procs);
 
+    /* Register the GUID with the dissector table */
+    guid_handle = create_dissector_handle( dissect_dcerpc_guid, proto);
+    dissector_add_guid( "dcerpc.uuid", key, guid_handle );
+
     /* add this GUID to the global name resolving */
     guids_add_uuid(uuid, proto_get_protocol_short_name(value->proto));
 
@@ -973,29 +1699,32 @@ dcerpc_init_uuid(int proto, int ett, e_uuid_t *uuid, guint16 ver,
  * or NULL if the protocol/version is not known to wireshark.
  */
 const char *
-dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
+dcerpc_get_proto_name(e_guid_t *uuid, guint16 ver)
 {
-    dcerpc_uuid_key    key;
-    dcerpc_uuid_value *sub_proto;
+    dissector_handle_t handle;
+    guid_key    key;
 
-    key.uuid = *uuid;
+    key.guid = *uuid;
     key.ver = ver;
-    if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
+
+    handle = dissector_get_guid_handle(uuid_dissector_table, &key);
+    if (handle == NULL) {
         return NULL;
     }
-    return sub_proto->name;
+
+    return dissector_handle_get_short_name(handle);
 }
 
 /* Function to find the opnum hf-field of a registered protocol
  * or -1 if the protocol/version is not known to wireshark.
  */
 int
-dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
+dcerpc_get_proto_hf_opnum(e_guid_t *uuid, guint16 ver)
 {
-    dcerpc_uuid_key    key;
+    guid_key    key;
     dcerpc_uuid_value *sub_proto;
 
-    key.uuid = *uuid;
+    key.guid = *uuid;
     key.ver = ver;
     if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
         return -1;
@@ -1036,40 +1765,20 @@ again:
  * or NULL if the protocol/version is not known to wireshark.
  */
 dcerpc_sub_dissector *
-dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
+dcerpc_get_proto_sub_dissector(e_guid_t *uuid, guint16 ver)
 {
-    dcerpc_uuid_key    key;
-    dcerpc_uuid_value *sub_proto;
-
-    key.uuid = *uuid;
-    key.ver = ver;
-    if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
-        return NULL;
-    }
-    return sub_proto->procs;
-}
-
-
-/*
- * To keep track of ctx_id mappings.
- *
- * Every time we see a bind call we update this table.
- * Note that we always specify a SMB FID. For non-SMB transports this
- * value is 0.
- */
-static GHashTable *dcerpc_binds = NULL;
+    guid_key    key;
+    dcerpc_uuid_value *sub_proto;
+
+    key.guid = *uuid;
+    key.ver = ver;
+    if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
+        return NULL;
+    }
+    return sub_proto->procs;
+}
 
-typedef struct _dcerpc_bind_key {
-    conversation_t *conv;
-    guint16         ctx_id;
-    guint16         smb_fid;
-} dcerpc_bind_key;
 
-typedef struct _dcerpc_bind_value {
-    e_uuid_t uuid;
-    guint16  ver;
-    e_uuid_t transport;
-} dcerpc_bind_value;
 
 static gint
 dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
@@ -1078,7 +1787,7 @@ dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
     const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
     return ((key1->conv == key2->conv)
             && (key1->ctx_id == key2->ctx_id)
-            && (key1->smb_fid == key2->smb_fid));
+            && (key1->transport_salt == key2->transport_salt));
 }
 
 static guint
@@ -1087,9 +1796,13 @@ dcerpc_bind_hash(gconstpointer k)
     const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
     guint hash;
 
-    hash = GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
-    return hash;
+    hash = GPOINTER_TO_UINT(key->conv);
+    hash += key->ctx_id;
+    /* sizeof(guint) might be smaller than sizeof(guint64) */
+    hash += (guint)key->transport_salt;
+    hash += (guint)(key->transport_salt << sizeof(guint));
 
+    return hash;
 }
 
 /*
@@ -1102,13 +1815,13 @@ static GHashTable *dcerpc_dg_calls = NULL;
 typedef struct _dcerpc_cn_call_key {
     conversation_t *conv;
     guint32 call_id;
-    guint16 smb_fid;
+    guint64 transport_salt;
 } dcerpc_cn_call_key;
 
 typedef struct _dcerpc_dg_call_key {
     conversation_t *conv;
     guint32         seqnum;
-    e_uuid_t        act_id ;
+    e_guid_t        act_id ;
 } dcerpc_dg_call_key;
 
 
@@ -1119,7 +1832,7 @@ dcerpc_cn_call_equal(gconstpointer k1, gconstpointer k2)
     const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
     return ((key1->conv == key2->conv)
             && (key1->call_id == key2->call_id)
-            && (key1->smb_fid == key2->smb_fid));
+            && (key1->transport_salt == key2->transport_salt));
 }
 
 static gint
@@ -1129,26 +1842,34 @@ dcerpc_dg_call_equal(gconstpointer k1, gconstpointer k2)
     const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
     return ((key1->conv == key2->conv)
             && (key1->seqnum == key2->seqnum)
-            && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0)));
+            && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_guid_t)) == 0)));
 }
 
 static guint
 dcerpc_cn_call_hash(gconstpointer k)
 {
     const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
-    return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
+    guint hash;
+
+    hash = GPOINTER_TO_UINT(key->conv);
+    hash += key->call_id;
+    /* sizeof(guint) might be smaller than sizeof(guint64) */
+    hash += (guint)key->transport_salt;
+    hash += (guint)(key->transport_salt << sizeof(guint));
+
+    return hash;
 }
 
 static guint
 dcerpc_dg_call_hash(gconstpointer k)
 {
     const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
-    return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
-            + (key->act_id.Data2 << 16)    + key->act_id.Data3
-            + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
-            + (key->act_id.Data4[2] << 8)  + (key->act_id.Data4[3] << 0)
-            + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
-            + (key->act_id.Data4[6] << 8)  + (key->act_id.Data4[7] << 0));
+    return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.data1
+            + (key->act_id.data2 << 16)    + key->act_id.data3
+            + (key->act_id.data4[0] << 24) + (key->act_id.data4[1] << 16)
+            + (key->act_id.data4[2] << 8)  + (key->act_id.data4[3] << 0)
+            + (key->act_id.data4[4] << 24) + (key->act_id.data4[5] << 16)
+            + (key->act_id.data4[6] << 8)  + (key->act_id.data4[7] << 0));
 }
 
 /* to keep track of matched calls/responses
@@ -1181,12 +1902,187 @@ dcerpc_matched_hash(gconstpointer k)
     return key->frame;
 }
 
+static gboolean
+uuid_equal(e_guid_t *uuid1, e_guid_t *uuid2)
+{
+    if( (uuid1->data1    != uuid2->data1)
+      ||(uuid1->data2    != uuid2->data2)
+      ||(uuid1->data3    != uuid2->data3)
+      ||(uuid1->data4[0] != uuid2->data4[0])
+      ||(uuid1->data4[1] != uuid2->data4[1])
+      ||(uuid1->data4[2] != uuid2->data4[2])
+      ||(uuid1->data4[3] != uuid2->data4[3])
+      ||(uuid1->data4[4] != uuid2->data4[4])
+      ||(uuid1->data4[5] != uuid2->data4[5])
+      ||(uuid1->data4[6] != uuid2->data4[6])
+      ||(uuid1->data4[7] != uuid2->data4[7]) ){
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static void
+dcerpcstat_init(struct register_srt* srt, GArray* srt_array, srt_gui_init_cb gui_callback, void* gui_data)
+{
+    dcerpcstat_tap_data_t* tap_data = (dcerpcstat_tap_data_t*)get_srt_table_param_data(srt);
+    srt_stat_table *dcerpc_srt_table;
+    int i, hf_opnum;
+    dcerpc_sub_dissector *procs;
+
+    DISSECTOR_ASSERT(tap_data);
+
+    hf_opnum = dcerpc_get_proto_hf_opnum(&tap_data->uuid, tap_data->ver);
+    procs    = dcerpc_get_proto_sub_dissector(&tap_data->uuid, tap_data->ver);
+
+    if(hf_opnum != -1){
+        dcerpc_srt_table = init_srt_table(tap_data->prog, NULL, srt_array, tap_data->num_procedures, NULL, proto_registrar_get_nth(hf_opnum)->abbrev, gui_callback, gui_data, tap_data);
+    } else {
+        dcerpc_srt_table = init_srt_table(tap_data->prog, NULL, srt_array, tap_data->num_procedures, NULL, NULL, gui_callback, gui_data, tap_data);
+    }
+
+    for(i=0;i<tap_data->num_procedures;i++){
+        int j;
+        const char *proc_name;
+
+        proc_name = "unknown";
+        for(j=0;procs[j].name;j++)
+        {
+            if (procs[j].num == i)
+            {
+                proc_name = procs[j].name;
+            }
+        }
+
+        init_srt_table_row(dcerpc_srt_table, i, proc_name);
+    }
+}
+
+static int
+dcerpcstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
+{
+    guint i = 0;
+    srt_stat_table *dcerpc_srt_table;
+    srt_data_t *data = (srt_data_t *)pss;
+    const dcerpc_info *ri = (const dcerpc_info *)prv;
+    dcerpcstat_tap_data_t* tap_data;
+
+    dcerpc_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
+    tap_data = (dcerpcstat_tap_data_t*)dcerpc_srt_table->table_specific_data;
+
+    if(!ri->call_data){
+        return 0;
+    }
+    if(!ri->call_data->req_frame){
+        /* we have not seen the request so we don't know the delta*/
+        return 0;
+    }
+    if(ri->call_data->opnum >= tap_data->num_procedures){
+        /* don't handle this since it's outside of known table */
+        return 0;
+    }
+
+    /* we are only interested in reply packets */
+    if(ri->ptype != PDU_RESP){
+        return 0;
+    }
+
+    /* we are only interested in certain program/versions */
+    if( (!uuid_equal( (&ri->call_data->uuid), (&tap_data->uuid)))
+        ||(ri->call_data->ver != tap_data->ver)){
+        return 0;
+    }
+
+    add_srt_table_data(dcerpc_srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
+
+    return 1;
+}
+
+static guint
+dcerpcstat_param(register_srt_t* srt, const char* opt_arg, char** err)
+{
+    int pos = 0;
+    guint32 i, max_procs;
+    dcerpcstat_tap_data_t* tap_data;
+    guint d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
+    int major, minor;
+    guint16 ver;
+    dcerpc_sub_dissector *procs;
+
+    if (sscanf(opt_arg, ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d%n",
+           &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos) == 13)
+    {
+        if ((major < 0) || (major > 65535)) {
+            *err = g_strdup_printf("dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535", major);
+            return pos;
+        }
+        if ((minor < 0) || (minor > 65535)) {
+            *err = g_strdup_printf("dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535", minor);
+            return pos;
+        }
+        ver = major;
+
+        tap_data = g_new0(dcerpcstat_tap_data_t, 1);
+
+        tap_data->uuid.data1    = d1;
+        tap_data->uuid.data2    = d2;
+        tap_data->uuid.data3    = d3;
+        tap_data->uuid.data4[0] = d40;
+        tap_data->uuid.data4[1] = d41;
+        tap_data->uuid.data4[2] = d42;
+        tap_data->uuid.data4[3] = d43;
+        tap_data->uuid.data4[4] = d44;
+        tap_data->uuid.data4[5] = d45;
+        tap_data->uuid.data4[6] = d46;
+        tap_data->uuid.data4[7] = d47;
+
+        procs             = dcerpc_get_proto_sub_dissector(&tap_data->uuid, ver);
+        tap_data->prog    = dcerpc_get_proto_name(&tap_data->uuid, ver);
+        tap_data->ver     = ver;
+
+        for(i=0,max_procs=0;procs[i].name;i++)
+        {
+            if(procs[i].num>max_procs)
+            {
+                max_procs = procs[i].num;
+            }
+        }
+        tap_data->num_procedures = max_procs+1;
+
+        set_srt_table_param_data(srt, tap_data);
+    }
+    else
+    {
+        *err = g_strdup_printf("<uuid>,<major version>.<minor version>[,<filter>]");
+    }
+
+    return pos;
+}
 
 
 /*
  * Utility functions.  Modeled after packet-rpc.c
  */
 
+int
+dissect_dcerpc_char(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
+                     proto_tree *tree, guint8 *drep,
+                     int hfindex, guint8 *pdata)
+{
+    guint8 data;
+
+    /*
+     * XXX - fix to handle EBCDIC if we ever support EBCDIC FT_CHAR.
+     */
+    data = tvb_get_guint8(tvb, offset);
+    if (hfindex != -1) {
+        proto_tree_add_item(tree, hfindex, tvb, offset, 1, ENC_ASCII|DREP_ENC_INTEGER(drep));
+    }
+    if (pdata)
+        *pdata = data;
+    tvb_ensure_bytes_exist(tvb, offset, 1);
+    return offset + 1;
+}
+
 int
 dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
                      proto_tree *tree, guint8 *drep,
@@ -1195,11 +2091,12 @@ dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
     guint8 data;
 
     data = tvb_get_guint8(tvb, offset);
-    if (tree) {
+    if (hfindex != -1) {
         proto_tree_add_item(tree, hfindex, tvb, offset, 1, DREP_ENC_INTEGER(drep));
     }
     if (pdata)
         *pdata = data;
+    tvb_ensure_bytes_exist(tvb, offset, 1);
     return offset + 1;
 }
 
@@ -1214,11 +2111,12 @@ dissect_dcerpc_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
             ? tvb_get_letohs(tvb, offset)
             : tvb_get_ntohs(tvb, offset));
 
-    if (tree) {
+    if (hfindex != -1) {
         proto_tree_add_item(tree, hfindex, tvb, offset, 2, DREP_ENC_INTEGER(drep));
     }
     if (pdata)
         *pdata = data;
+    tvb_ensure_bytes_exist(tvb, offset, 2);
     return offset + 2;
 }
 
@@ -1233,11 +2131,12 @@ dissect_dcerpc_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
             ? tvb_get_letohl(tvb, offset)
             : tvb_get_ntohl(tvb, offset));
 
-    if (tree) {
+    if (hfindex != -1) {
         proto_tree_add_item(tree, hfindex, tvb, offset, 4, DREP_ENC_INTEGER(drep));
     }
     if (pdata)
         *pdata = data;
+    tvb_ensure_bytes_exist(tvb, offset, 4);
     return offset+4;
 }
 
@@ -1256,7 +2155,7 @@ dissect_dcerpc_time_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
 
     tv.secs = data;
     tv.nsecs = 0;
-    if (tree) {
+    if (hfindex != -1) {
         if (data == 0xffffffff) {
             /* special case,   no time specified */
             proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
@@ -1267,12 +2166,13 @@ dissect_dcerpc_time_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
     if (pdata)
         *pdata = data;
 
+    tvb_ensure_bytes_exist(tvb, offset, 4);
     return offset+4;
 }
 
 int
 dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
-                      proto_tree *tree, guint8 *drep,
+                      proto_tree *tree, dcerpc_info *di, guint8 *drep,
                       int hfindex, guint64 *pdata)
 {
     guint64 data;
@@ -1281,7 +2181,7 @@ dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
             ? tvb_get_letoh64(tvb, offset)
             : tvb_get_ntoh64(tvb, offset));
 
-    if (tree) {
+    if (hfindex != -1) {
         header_field_info *hfinfo;
 
         /* This might be a field that is either 32bit, in NDR or
@@ -1298,12 +2198,15 @@ dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
             proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
             break;
         default:
-            DISSECTOR_ASSERT(data <= G_MAXUINT32);
+            /* The value is truncated to 32bits.  64bit values have only been
+               seen on fuzz-tested files */
+            DISSECTOR_ASSERT((di->call_data->flags & DCERPC_IS_NDR64) || (data <= G_MAXUINT32));
             proto_tree_add_uint(tree, hfindex, tvb, offset, 8, (guint32)data);
         }
     }
     if (pdata)
         *pdata = data;
+    tvb_ensure_bytes_exist(tvb, offset, 8);
     return offset+8;
 }
 
@@ -1321,7 +2224,7 @@ dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
         data = ((drep[0] & DREP_LITTLE_ENDIAN)
                 ? tvb_get_letohieee_float(tvb, offset)
                 : tvb_get_ntohieee_float(tvb, offset));
-        if (tree) {
+        if (tree && hfindex != -1) {
             proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
         }
         break;
@@ -1332,12 +2235,13 @@ dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
         /* ToBeDone: non IEEE floating formats */
         /* Set data to a negative infinity value */
         data = -G_MAXFLOAT;
-        if (tree) {
+        if (tree && hfindex != -1) {
             proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
         }
     }
     if (pdata)
         *pdata = data;
+    tvb_ensure_bytes_exist(tvb, offset, 4);
     return offset + 4;
 }
 
@@ -1355,7 +2259,7 @@ dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
         data = ((drep[0] & DREP_LITTLE_ENDIAN)
                 ? tvb_get_letohieee_double(tvb, offset)
                 : tvb_get_ntohieee_double(tvb, offset));
-        if (tree) {
+        if (tree && hfindex != -1) {
             proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
         }
         break;
@@ -1366,12 +2270,13 @@ dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
         /* ToBeDone: non IEEE double formats */
         /* Set data to a negative infinity value */
         data = -G_MAXDOUBLE;
-        if (tree) {
+        if (tree && hfindex != -1) {
             proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
         }
     }
     if (pdata)
         *pdata = data;
+    tvb_ensure_bytes_exist(tvb, offset, 8);
     return offset + 8;
 }
 
@@ -1379,9 +2284,9 @@ dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
 int
 dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
                       proto_tree *tree, guint8 *drep,
-                      int hfindex, e_uuid_t *pdata)
+                      int hfindex, e_guid_t *pdata)
 {
-    e_uuid_t uuid;
+    e_guid_t uuid;
 
 
     if (drep[0] & DREP_LITTLE_ENDIAN) {
@@ -1389,7 +2294,7 @@ dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
     } else {
         tvb_get_ntohguid(tvb, offset, (e_guid_t *) &uuid);
     }
-    if (tree) {
+    if (tree && hfindex != -1) {
         proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
     }
     if (pdata) {
@@ -1423,7 +2328,7 @@ dcerpc_tvb_get_ntohl(tvbuff_t *tvb, gint offset, guint8 *drep)
 }
 
 void
-dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
+dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_guid_t *uuid)
 {
     if (drep[0] & DREP_LITTLE_ENDIAN) {
         tvb_get_letohguid(tvb, offset, (e_guid_t *) uuid);
@@ -1435,15 +2340,19 @@ dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
 
 /* NDR arrays */
 /* function to dissect a unidimensional conformant array */
-int
-dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+static int
+dissect_ndr_ucarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                     proto_tree *tree, dcerpc_info *di, guint8 *drep,
-                    dcerpc_dissect_fnct_t *fnct)
+                    dcerpc_dissect_fnct_t *fnct_bytes,
+                    dcerpc_dissect_fnct_blk_t *fnct_block)
 {
     guint32      i;
     int          old_offset;
     int          conformance_size = 4;
 
+    /* ensure that just one pointer is set in the call */
+    DISSECTOR_ASSERT((fnct_bytes && !fnct_block) || (!fnct_bytes && fnct_block));
+
     if (di->call_data->flags & DCERPC_IS_NDR64) {
         conformance_size = 8;
     }
@@ -1465,14 +2374,35 @@ dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
 
         /* real run, dissect the elements */
-        for(i=0; i<di->array_max_count; i++) {
-            offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
+        if (fnct_block) {
+                offset = (*fnct_block)(tvb, offset, di->array_max_count,
+                                       pinfo, tree, di, drep);
+        } else {
+            for (i=0 ;i<di->array_max_count; i++) {
+                offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
+            }
         }
     }
 
     return offset;
 }
 
+int
+dissect_ndr_ucarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+                          proto_tree *tree, dcerpc_info *di, guint8 *drep,
+                          dcerpc_dissect_fnct_blk_t *fnct)
+{
+    return dissect_ndr_ucarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
+}
+
+int
+dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+                    proto_tree *tree, dcerpc_info *di, guint8 *drep,
+                    dcerpc_dissect_fnct_t *fnct)
+{
+    return dissect_ndr_ucarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
+}
+
 /* function to dissect a unidimensional conformant and varying array
  * depending on the dissection function passed as a parameter,
  * content of the array will be dissected as a block or byte by byte
@@ -1522,13 +2452,15 @@ dissect_ndr_ucvarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
         /* real run, dissect the elements */
         if (fnct_block) {
-                offset = (*fnct_block)(tvb, offset, di->array_actual_count, pinfo, tree, drep);
-        } else {
-            for(i=0 ;i<di->array_actual_count; i++) {
+                offset = (*fnct_block)(tvb, offset, di->array_actual_count,
+                                       pinfo, tree, di, drep);
+        } else if (fnct_bytes) {
+            for (i=0 ;i<di->array_actual_count; i++) {
                 old_offset = offset;
                 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
-                if (offset <= old_offset)
-                    THROW(ReportedBoundsError);
+                /* Make sure we're moving forward */
+                if (old_offset >= offset)
+                    break;
             }
         }
     }
@@ -1589,7 +2521,7 @@ dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
 
         /* real run, dissect the elements */
-        for(i=0; i<di->array_actual_count; i++) {
+        for (i=0; i<di->array_actual_count; i++) {
             offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
         }
     }
@@ -1635,10 +2567,9 @@ dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
                                   hf_dcerpc_array_actual_count, &len);
 
     DISSECTOR_ASSERT(len <= G_MAXUINT32);
-    if (tree && len) {
-        tvb_ensure_bytes_exist(tvb, offset, (guint32)len);
-        proto_tree_add_item(tree, hf_dcerpc_array_buffer,
-                            tvb, offset, (guint32)len, ENC_NA);
+    if (len) {
+        proto_tree_add_item(tree, di->hf_index, tvb, offset, (guint32)len,
+                            ENC_NA);
     }
 
     offset += (guint32)len;
@@ -1659,12 +2590,16 @@ dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
                      proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
                      int hfindex, gboolean add_subtree, char **data)
 {
+    header_field_info *hfinfo;
     proto_item        *string_item;
     proto_tree        *string_tree;
     guint64            len;
     guint32            buffer_len;
     char              *s;
-    header_field_info *hfinfo;
+
+    /* Make sure this really is a string field. */
+    hfinfo = proto_registrar_get_nth(hfindex);
+    DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
 
     if (di->conformant_run) {
         /* just a run to handle conformant arrays, no scalars to dissect */
@@ -1672,9 +2607,8 @@ dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
     }
 
     if (add_subtree) {
-        string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
+        string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
                                           proto_registrar_get_name(hfindex));
-        string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
     } else {
         string_item = NULL;
         string_tree = tree;
@@ -1691,51 +2625,43 @@ dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
     offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
                                   hf_dcerpc_array_actual_count, &len);
 
-    DISSECTOR_ASSERT(len <= G_MAXUINT32);
+    /* The value is truncated to 32bits.  64bit values have only been
+       seen on fuzztested files */
     buffer_len = size_is * (guint32)len;
 
     /* Adjust offset */
     if (!di->no_align && (offset % size_is))
         offset += size_is - (offset % size_is);
 
+    /*
+     * "tvb_get_string_enc()" throws an exception if the entire string
+     * isn't in the tvbuff.  If the length is bogus, this should
+     * keep us from trying to allocate an immensely large buffer.
+     * (It won't help if the length is *valid* but immensely large,
+     * but that's another matter; in any case, that would happen only
+     * if we had an immensely large tvbuff....)
+     *
+     * XXX - so why are we doing tvb_ensure_bytes_exist()?
+     */
+    tvb_ensure_bytes_exist(tvb, offset, buffer_len);
     if (size_is == sizeof(guint16)) {
-        /* XXX - use drep to determine the byte order? */
-        /* XXX - once we have an ENC_ value for UTF-16, just use
-           proto_tree_add_item() with the appropriate ENC_ value? */
-        /* XXX - should this ever be used with something that's *not*
-           an FT_STRING? */
-        s = tvb_get_unicode_string(wmem_packet_scope(), tvb, offset, buffer_len, ENC_LITTLE_ENDIAN);
-        if (tree && buffer_len) {
-            hfinfo = proto_registrar_get_nth(hfindex);
-            tvb_ensure_bytes_exist(tvb, offset, buffer_len);
-            if (hfinfo->type == FT_STRING) {
-                proto_tree_add_string(string_tree, hfindex, tvb, offset,
-                                      buffer_len, s);
-            } else {
-                proto_tree_add_item(string_tree, hfindex, tvb, offset,
-                                    buffer_len, DREP_ENC_INTEGER(drep));
-            }
-        }
-
-    } else {
         /*
-         * "tvb_get_string()" throws an exception if the entire string
-         * isn't in the tvbuff.  If the length is bogus, this should
-         * keep us from trying to allocate an immensely large buffer.
-         * (It won't help if the length is *valid* but immensely large,
-         * but that's another matter; in any case, that would happen only
-         * if we had an immensely large tvbuff....)
+         * Assume little-endian UTF-16.
          *
-         * XXX - if this is an octet string, does the byte order
-         * matter?  Will this ever be anything *other* than an
-         * octet string?  What if size_is is neither 1 nor 2?
+         * XXX - is this always little-endian?
+         */
+        s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
+                               ENC_UTF_16|ENC_LITTLE_ENDIAN);
+    } else {
+        /*
+         * XXX - what if size_is is neither 1 nor 2?
          */
-        tvb_ensure_bytes_exist(tvb, offset, buffer_len);
-        s = tvb_get_string(wmem_packet_scope(), tvb, offset, buffer_len);
-        if (tree && buffer_len)
-            proto_tree_add_item(string_tree, hfindex, tvb, offset,
-                                buffer_len, DREP_ENC_INTEGER(drep));
+        s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
+                               DREP_ENC_CHAR(drep));
     }
+    if (tree && buffer_len)
+        proto_tree_add_string(string_tree, hfindex, tvb, offset,
+                              buffer_len, s);
 
     if (string_item != NULL)
         proto_item_append_text(string_item, ": %s", s);
@@ -1849,12 +2775,16 @@ dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
                     proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
                     int hfindex, gboolean add_subtree, char **data)
 {
+    header_field_info *hfinfo;
     proto_item        *string_item;
     proto_tree        *string_tree;
     guint64            len;
     guint32            buffer_len;
     char              *s;
-    header_field_info *hfinfo;
+
+    /* Make sure this really is a string field. */
+    hfinfo = proto_registrar_get_nth(hfindex);
+    DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
 
     if (di->conformant_run) {
         /* just a run to handle conformant arrays, no scalars to dissect */
@@ -1862,9 +2792,8 @@ dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
     }
 
     if (add_subtree) {
-        string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
+        string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
                                           proto_registrar_get_name(hfindex));
-        string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
     } else {
         string_item = NULL;
         string_tree = tree;
@@ -1884,44 +2813,35 @@ dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
     if (!di->no_align && (offset % size_is))
         offset += size_is - (offset % size_is);
 
+    /*
+     * "tvb_get_string_enc()" throws an exception if the entire string
+     * isn't in the tvbuff.  If the length is bogus, this should
+     * keep us from trying to allocate an immensely large buffer.
+     * (It won't help if the length is *valid* but immensely large,
+     * but that's another matter; in any case, that would happen only
+     * if we had an immensely large tvbuff....)
+     *
+     * XXX - so why are we doing tvb_ensure_bytes_exist()?
+     */
+    tvb_ensure_bytes_exist(tvb, offset, buffer_len);
     if (size_is == sizeof(guint16)) {
-        /* XXX - use drep to determine the byte order? */
-        /* XXX - once we have an ENC_ value for UTF-16, just use
-           proto_tree_add_item() with the appropriate ENC_ value? */
-        /* XXX - should this ever be used with something that's *not*
-           an FT_STRING? */
-        s = tvb_get_unicode_string(wmem_packet_scope(), tvb, offset, buffer_len, ENC_LITTLE_ENDIAN);
-        if (tree && buffer_len) {
-            hfinfo = proto_registrar_get_nth(hfindex);
-            tvb_ensure_bytes_exist(tvb, offset, buffer_len);
-            if (hfinfo->type == FT_STRING) {
-                proto_tree_add_string(string_tree, hfindex, tvb, offset,
-                                      buffer_len, s);
-            } else {
-                proto_tree_add_item(string_tree, hfindex, tvb, offset,
-                                    buffer_len, DREP_ENC_INTEGER(drep));
-            }
-        }
-
-    } else {
         /*
-         * "tvb_get_string()" throws an exception if the entire string
-         * isn't in the tvbuff.  If the length is bogus, this should
-         * keep us from trying to allocate an immensely large buffer.
-         * (It won't help if the length is *valid* but immensely large,
-         * but that's another matter; in any case, that would happen only
-         * if we had an immensely large tvbuff....)
+         * Assume little-endian UTF-16.
          *
-         * XXX - if this is an octet string, does the byte order
-         * matter?  Will this ever be anything *other* than an
-         * octet string?  What if size_is is neither 1 nor 2?
+         * XXX - is this always little-endian?
          */
-        tvb_ensure_bytes_exist(tvb, offset, buffer_len);
-        s = tvb_get_string(wmem_packet_scope(), tvb, offset, buffer_len);
-        if (tree && buffer_len)
-            proto_tree_add_item(string_tree, hfindex, tvb, offset,
-                                buffer_len, DREP_ENC_INTEGER(drep));
+        s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
+                               ENC_UTF_16|ENC_LITTLE_ENDIAN);
+    } else {
+        /*
+         * XXX - what if size_is is neither 1 nor 2?
+         */
+        s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
+                               DREP_ENC_CHAR(drep));
     }
+    if (tree && buffer_len)
+        proto_tree_add_string(string_tree, hfindex, tvb, offset,
+                              buffer_len, s);
 
     if (string_item != NULL)
         proto_item_append_text(string_item, ": %s", s);
@@ -2025,7 +2945,7 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, dcerpc_
 
         found_new_pointer = 0;
         len = g_slist_length(ndr_pointer_list);
-        for(i=next_pointer; i<len; i++) {
+        for (i=next_pointer; i<len; i++) {
             ndr_pointer_data_t *tnpd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
             if (tnpd->fnct) {
                 dcerpc_dissect_fnct_t *fnct;
@@ -2125,7 +3045,7 @@ add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
                 }
             }
         } else {
-            /* if we haven't seen the request bail out since we cant
+            /* if we haven't seen the request bail out since we can't
                know whether this is the first non-NULL instance
                or not */
             if (value->req_frame == 0) {
@@ -2161,7 +3081,7 @@ find_pointer_index(guint32 id)
     int                 i,len;
 
     len = g_slist_length(ndr_pointer_list);
-    for(i=0; i<len; i++) {
+    for (i=0; i<len; i++) {
         npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
         if (npd) {
             if (npd->id == id) {
@@ -2220,9 +3140,8 @@ dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         proto_item *item;
 
         /* we must find out a nice way to do the length here */
-        item = proto_tree_add_text(tree, tvb, offset, 0,
-                                   "%s", text);
-        tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
+        tr = proto_tree_add_subtree(tree, tvb, offset, 0,
+                                   ett_dcerpc_pointer_data, &item, text);
 
         add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
                             hf_index, callback, callback_args);
@@ -2239,34 +3158,34 @@ dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         /* get the referent id */
         offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
 
-        tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
         /* we got a NULL pointer */
         if (id == 0) {
-            proto_tree_add_text(tree, tvb, offset-pointer_size,
-                                pointer_size,
-                                "(NULL pointer) %s",text);
+            proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
+                                pointer_size, NULL, "%s", text);
             goto after_ref_id;
         }
 
-        /* see if we have seen this pointer before */
-        DISSECTOR_ASSERT(id <= G_MAXUINT32);
+        /* see if we have seen this pointer before
+           The value is truncated to 32bits.  64bit values have only been
+           seen on fuzz-tested files */
         idx = find_pointer_index((guint32)id);
 
         /* we have seen this pointer before */
         if (idx >= 0) {
-            proto_tree_add_text(tree, tvb, offset-pointer_size,
-                                pointer_size,
-                                "(duplicate PTR) %s",text);
+            proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
             goto after_ref_id;
         }
 
         /* new pointer */
-        item = proto_tree_add_text(tree, tvb, offset-pointer_size,
-                                   pointer_size,
-                                   "%s", text);
-        tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
-        proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
-                            offset-pointer_size, pointer_size, (guint32)id);
+        tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
+                                   pointer_size, ett_dcerpc_pointer_data, &item, text);
+        if (di->call_data->flags & DCERPC_IS_NDR64) {
+            proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
+                                offset-pointer_size, pointer_size, id);
+        } else {
+            proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
+                                offset-pointer_size, pointer_size, (guint32)id);
+        }
         add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
                             callback, callback_args);
         goto after_ref_id;
@@ -2280,23 +3199,24 @@ dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         /* get the referent id */
         offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
 
-        tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
         /* we got a NULL pointer */
         if (id == 0) {
-            proto_tree_add_text(tree, tvb, offset-pointer_size,
-                                pointer_size,
-                                "(NULL pointer) %s",text);
+            proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
+                                pointer_size, NULL, "%s",text);
             goto after_ref_id;
         }
 
         /* new pointer */
-        DISSECTOR_ASSERT(id <= G_MAXUINT32);
-        item = proto_tree_add_text(tree, tvb, offset-pointer_size,
+        tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
                                    pointer_size,
-                                   "%s", text);
-        tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
-        proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
+                                   ett_dcerpc_pointer_data, &item, text);
+        if (di->call_data->flags & DCERPC_IS_NDR64) {
+            proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
+                            offset-pointer_size, pointer_size, id);
+        } else {
+            proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
                             offset-pointer_size, pointer_size, (guint32)id);
+        }
         add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
                             hf_index, callback, callback_args);
         goto after_ref_id;
@@ -2311,15 +3231,17 @@ dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         /* get the referent id */
         offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
 
-        tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
         /* new pointer */
-        item = proto_tree_add_text(tree, tvb, offset-pointer_size,
+        tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
                                  pointer_size,
-                                 "%s",text);
-        tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
-        DISSECTOR_ASSERT(id <= G_MAXUINT32);
-        proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
+                                 ett_dcerpc_pointer_data,&item,text);
+        if (di->call_data->flags & DCERPC_IS_NDR64) {
+            proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
+                            offset-pointer_size, pointer_size, id);
+        } else {
+            proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
                             offset-pointer_size, pointer_size, (guint32)id);
+        }
         add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
                             hf_index, callback, callback_args);
         goto after_ref_id;
@@ -2334,23 +3256,24 @@ dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         /* get the referent id */
         offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
 
-        tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
         /* we got a NULL pointer */
         if (id == 0) {
-            proto_tree_add_text(tree, tvb, offset-pointer_size,
-                                pointer_size,
-                                "(NULL pointer) %s", text);
+            proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
+                                pointer_size, NULL, "%s",text);
             goto after_ref_id;
         }
 
         /* new pointer */
-        item = proto_tree_add_text(tree, tvb, offset-pointer_size,
+        tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
                                    pointer_size,
-                                   "%s",text);
-        tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
-        DISSECTOR_ASSERT(id <= G_MAXUINT32);
-        proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
+                                   ett_dcerpc_pointer_data,&item,text);
+        if (di->call_data->flags & DCERPC_IS_NDR64) {
+            proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
+                            offset-pointer_size, pointer_size, id);
+        } else {
+            proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
                             offset-pointer_size, pointer_size, (guint32)id);
+        }
         add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
                             hf_index, callback, callback_args);
         goto after_ref_id;
@@ -2366,34 +3289,35 @@ dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         /* get the referent id */
         offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
 
-        tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
         /* we got a NULL pointer */
         if (id == 0) {
-            proto_tree_add_text(tree, tvb, offset-pointer_size,
-                                pointer_size,
-                                "(NULL pointer) %s",text);
+            proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
+                                pointer_size, NULL, "%s",text);
             goto after_ref_id;
         }
 
-        /* see if we have seen this pointer before */
-        DISSECTOR_ASSERT(id <= G_MAXUINT32);
+        /* see if we have seen this pointer before
+           The value is truncated to 32bits.  64bit values have only been
+           seen on fuzztested files */
         idx = find_pointer_index((guint32)id);
 
         /* we have seen this pointer before */
         if (idx >= 0) {
-            proto_tree_add_text(tree, tvb, offset-pointer_size,
-                                pointer_size,
-                                "(duplicate PTR) %s",text);
+            proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
             goto after_ref_id;
         }
 
         /* new pointer */
-        item = proto_tree_add_text(tree, tvb, offset-pointer_size,
+        tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
                                    pointer_size,
-                                   "%s", text);
-        tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
-        proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
+                                   ett_dcerpc_pointer_data, &item, text);
+        if (di->call_data->flags & DCERPC_IS_NDR64) {
+            proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
+                            offset-pointer_size, pointer_size, id);
+        } else {
+            proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
                             offset-pointer_size, pointer_size, (guint32)id);
+        }
         add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
                             callback, callback_args);
         goto after_ref_id;
@@ -2454,354 +3378,301 @@ dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 }
 
 static void
-show_stub_data(tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
-               dcerpc_auth_info *auth_info, gboolean is_encrypted)
+dissect_sec_vt_bitmask(proto_tree *tree, tvbuff_t *tvb)
 {
-    int   length, plain_length, auth_pad_len;
-    guint auth_pad_offset;
-
-    /*
-     * We don't show stub data unless we have some in the tvbuff;
-     * however, in the protocol tree, we show, as the number of
-     * bytes, the reported number of bytes, not the number of bytes
-     * that happen to be in the tvbuff.
-     */
-    if (tvb_length_remaining(tvb, offset) > 0) {
-        auth_pad_len = auth_info?auth_info->auth_pad_len:0;
-        length = tvb_reported_length_remaining(tvb, offset);
-
-        /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
-        plain_length = length - auth_pad_len;
-        if (plain_length < 1) {
-            plain_length = length;
-            auth_pad_len = 0;
-        }
-        auth_pad_offset = offset + plain_length;
-
-        if ((auth_info != NULL) &&
-            (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
-            if (is_encrypted) {
-                tvb_ensure_bytes_exist(tvb, offset, length);
-                proto_tree_add_text(dcerpc_tree, tvb, offset, length,
-                                    "Encrypted stub data (%d byte%s)",
-                                    length, plurality(length, "", "s"));
-                /* is the padding is still inside the encrypted blob, don't display it explicit */
-                auth_pad_len = 0;
-            } else {
-                tvb_ensure_bytes_exist(tvb, offset, plain_length);
-                proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
-                                    "Decrypted stub data (%d byte%s)",
-                                    plain_length, plurality(plain_length, "", "s"));
-            }
-        } else {
-            tvb_ensure_bytes_exist(tvb, offset, plain_length);
-            proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
-                                "Stub data (%d byte%s)", plain_length,
-                                plurality(plain_length, "", "s"));
-        }
-        /* If there is auth padding at the end of the stub, display it */
-        if (auth_pad_len != 0) {
-            tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
-            proto_tree_add_text(dcerpc_tree, tvb, auth_pad_offset,
-                                auth_pad_len,
-                                "Auth Padding (%u byte%s)",
-                                auth_pad_len,
-                                plurality(auth_pad_len, "", "s"));
-        }
-    }
+    proto_tree_add_bitmask(tree, tvb, 0,
+                           hf_dcerpc_sec_vt_bitmask,
+                           ett_dcerpc_sec_vt_bitmask,
+                           sec_vt_bitmask_fields,
+                           ENC_LITTLE_ENDIAN);
 }
 
-static int
-dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
-                   proto_tree *dcerpc_tree,
-                   tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
-                   guint8 *drep, dcerpc_info *info,
-                   dcerpc_auth_info *auth_info)
+static void
+dissect_sec_vt_pcontext(proto_tree *tree, tvbuff_t *tvb)
 {
-    volatile gint         offset   = 0;
-    dcerpc_uuid_key       key;
-    dcerpc_uuid_value    *sub_proto;
-    proto_tree *volatile  sub_tree = NULL;
-    dcerpc_sub_dissector *proc;
-    const gchar          *name     = NULL;
-    const char *volatile  saved_proto;
-    guint                 length   = 0, reported_length = 0;
-    tvbuff_t *volatile    stub_tvb;
-    volatile guint        auth_pad_len;
-    volatile int          auth_pad_offset;
-    proto_item           *sub_item = NULL;
-    proto_item           *pi, *hidden_item;
+    int offset = 0;
+    proto_item *ti = NULL;
+    proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
+                                            ett_dcerpc_sec_vt_pcontext,
+                                            &ti, "pcontext");
+    e_guid_t uuid;
+    const char *uuid_name;
+
+    tvb_get_letohguid(tvb, offset, &uuid);
+    uuid_name = guids_get_uuid_name(&uuid);
+    if (!uuid_name) {
+            uuid_name = guid_to_str(wmem_packet_scope(), &uuid);
+    }
 
-    dcerpc_dissect_fnct_t *volatile sub_dissect;
+    proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
+                               offset, 16, &uuid, "Abstract Syntax: %s", uuid_name);
+    offset += 16;
 
-    key.uuid = info->call_data->uuid;
-    key.ver = info->call_data->ver;
+    proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
+                        tvb, offset, 4, ENC_LITTLE_ENDIAN);
+    offset += 4;
 
-    if ((sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key)) == NULL
-        || !proto_is_protocol_enabled(sub_proto->proto)) {
-        /*
-         * We don't have a dissector for this UUID, or the protocol
-         * for that UUID is disabled.
-         */
+    tvb_get_letohguid(tvb, offset, &uuid);
+    uuid_name = guids_get_uuid_name(&uuid);
+    if (!uuid_name) {
+            uuid_name = guid_to_str(wmem_packet_scope(), &uuid);
+    }
 
-        hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
-                                             tvb, offset, 0, TRUE);
-        PROTO_ITEM_SET_HIDDEN(hidden_item);
-        col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
-        guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
+    proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
+                               offset, 16, &uuid, "Transfer Syntax: %s", uuid_name);
+    offset += 16;
 
-        if (decrypted_tvb != NULL) {
-            show_stub_data(decrypted_tvb, 0, dcerpc_tree, auth_info,
-                           FALSE);
-        } else
-            show_stub_data(tvb, 0, dcerpc_tree, auth_info, TRUE);
-        return -1;
-    }
+    proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
+                        tvb, offset, 4, ENC_LITTLE_ENDIAN);
+    offset += 4;
 
-    for (proc = sub_proto->procs; proc->name; proc++) {
-        if (proc->num == info->call_data->opnum) {
-            name = proc->name;
-            break;
-        }
-    }
+    proto_item_set_len(ti, offset);
+}
 
-    col_set_str(pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
+static void
+dissect_sec_vt_header(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
+{
+    int offset = 0;
+    proto_item *ti = NULL;
+    proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
+                                            ett_dcerpc_sec_vt_header,
+                                            &ti, "header2");
+    guint8 drep[4];
+    guint8 ptype = tvb_get_guint8(tvb, offset);
 
-    if (!name)
-        col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
-                     info->call_data->opnum,
-                     (info->ptype == PDU_REQ) ? "request" : "response");
-    else
-        col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
-                     name, (info->ptype == PDU_REQ) ? "request" : "response");
+    proto_tree_add_uint(tr, hf_dcerpc_packet_type, tvb, offset, 1, ptype);
+    offset += 1;
 
-    sub_dissect = (info->ptype == PDU_REQ) ?
-        proc->dissect_rqst : proc->dissect_resp;
+    proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 1, ENC_NA);
+    offset += 1;
 
-    if (tree) {
-        sub_item = proto_tree_add_item(tree, sub_proto->proto_id,
-                                       (decrypted_tvb != NULL)?decrypted_tvb:tvb,
-                                       0, -1, ENC_NA);
+    proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 2, ENC_NA);
+    offset += 2;
 
-        if (sub_item) {
-            sub_tree = proto_item_add_subtree(sub_item, sub_proto->ett);
-            if (!name)
-                proto_item_append_text(sub_item, ", unknown operation %u",
-                                       info->call_data->opnum);
-            else
-                proto_item_append_text(sub_item, ", %s", name);
-        }
+    tvb_memcpy(tvb, drep, offset, 4);
+    proto_tree_add_dcerpc_drep(tr, tvb, offset, drep, 4);
+    offset += 4;
 
-        /*
-         * Put the operation number into the tree along with
-         * the operation's name.
-         */
-        if (sub_proto->opnum_hf != -1)
-            proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
-                                       tvb, 0, 0, info->call_data->opnum,
-                                       "Operation: %s (%u)",
-                                       name ? name : "Unknown operation",
-                                       info->call_data->opnum);
-        else
-            proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
-                                       0, 0, info->call_data->opnum,
-                                       "%s (%u)",
-                                       name ? name : "Unknown operation",
-                                       info->call_data->opnum);
+    offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tr, drep,
+                                   hf_dcerpc_cn_call_id, NULL);
 
-        if ((info->ptype == PDU_REQ) && (info->call_data->rep_frame != 0)) {
-            pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
-                                     tvb, 0, 0, info->call_data->rep_frame);
-            PROTO_ITEM_SET_GENERATED(pi);
-        }
-        if ((info->ptype == PDU_RESP) && (info->call_data->req_frame != 0)) {
-            pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
-                                     tvb, 0, 0, info->call_data->req_frame);
-            PROTO_ITEM_SET_GENERATED(pi);
-        }
-    } /* tree */
+    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tr, drep,
+                                   hf_dcerpc_cn_ctx_id, NULL);
 
-    if (decrypted_tvb != NULL) {
-        /* Either there was no encryption or we successfully decrypted
-           the encrypted payload. */
-        if (sub_dissect) {
-            /* We have a subdissector - call it. */
-            saved_proto          = pinfo->current_proto;
-            pinfo->current_proto = sub_proto->name;
+    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tr, drep,
+                                   hf_dcerpc_opnum, NULL);
 
-            init_ndr_pointer_list(info);
+    proto_item_set_len(ti, offset);
+}
 
-            length = tvb_length(decrypted_tvb);
-            reported_length = tvb_reported_length(decrypted_tvb);
+static int
+dissect_verification_trailer_impl(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
+                                  proto_tree *parent_tree, int *signature_offset)
+{
+    int remaining = tvb_captured_length_remaining(tvb, stub_offset);
+    int offset;
+    gint signature_start;
+    gint payload_length;
+    typedef enum {
+        SEC_VT_COMMAND_BITMASK_1    = 0x0001,
+        SEC_VT_COMMAND_PCONTEXT     = 0x0002,
+        SEC_VT_COMMAND_HEADER2      = 0x0003,
+        SEC_VT_COMMAND_END          = 0x4000,
+        SEC_VT_MUST_PROCESS_COMMAND = 0x8000,
+        SEC_VT_COMMAND_MASK         = 0x3fff,
+    } sec_vt_command;
+    proto_item *payload_item;
+    proto_item *item;
+    proto_tree *tree;
+
+    if (signature_offset != NULL) {
+        *signature_offset = -1;
+    }
 
-            /*
-             * Remove the authentication padding from the stub data.
-             */
-            if ((auth_info != NULL) && (auth_info->auth_pad_len != 0)) {
-                if (reported_length >= auth_info->auth_pad_len) {
-                    /*
-                     * OK, the padding length isn't so big that it
-                     * exceeds the stub length.  Trim the reported
-                     * length of the tvbuff.
-                     */
-                    reported_length -= auth_info->auth_pad_len;
+    /* We need at least signature + the header of one command */
+    if (remaining < (int)(sizeof(TRAILER_SIGNATURE) + 4)) {
+         return -1;
+    }
 
-                    /*
-                     * If that exceeds the actual amount of data in
-                     * the tvbuff (which means we have at least one
-                     * byte of authentication padding in the tvbuff),
-                     * trim the actual amount.
-                     */
-                    if (length > reported_length)
-                        length = reported_length;
+    /* We only scan the last 512 bytes for a possible trailer */
+    if (remaining > 512) {
+         offset = remaining - 512;
+         remaining = 512;
+    } else {
+         offset = 0;
+    }
+    offset += stub_offset;
 
-                    stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
-                    auth_pad_len = auth_info->auth_pad_len;
-                    auth_pad_offset = reported_length;
-                } else {
-                    /*
-                     * The padding length exceeds the stub length.
-                     * Don't bother dissecting the stub, trim the padding
-                     * length to what's in the stub data, and show the
-                     * entire stub as authentication padding.
-                     */
-                    stub_tvb = NULL;
-                    auth_pad_len = reported_length;
-                    auth_pad_offset = 0;
-                    length = 0;
-                }
-            } else {
-                /*
-                 * No authentication padding.
-                 */
-                stub_tvb = decrypted_tvb;
-                auth_pad_len = 0;
-                auth_pad_offset = 0;
-            }
+    signature_start = tvb_find_tvb(tvb, tvb_trailer_signature, offset);
+    if (signature_start == -1) {
+        return -1;
+    }
+    payload_length = signature_start - stub_offset;
+    payload_item = proto_tree_add_item(parent_tree,
+                                       hf_dcerpc_payload_stub_data,
+                                       tvb, stub_offset, payload_length, ENC_NA);
+    proto_item_append_text(payload_item, " (%d byte%s)",
+                           payload_length, plurality(payload_length, "", "s"));
+
+    if (signature_offset != NULL) {
+        *signature_offset = signature_start;
+    }
+    remaining -= (signature_start - offset);
+    offset = signature_start;
+
+    tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1,
+                                  ett_dcerpc_verification_trailer,
+                                  &item, "Verification Trailer");
+
+    proto_tree_add_item(tree, hf_dcerpc_sec_vt_signature,
+                        tvb, offset, sizeof(TRAILER_SIGNATURE), ENC_NA);
+    offset += (int)sizeof(TRAILER_SIGNATURE);
+    remaining -= (int)sizeof(TRAILER_SIGNATURE);
+
+    while (remaining >= 4) {
+        sec_vt_command cmd;
+        guint16 len, len_missalign;
+        gboolean cmd_end, cmd_must;
+        proto_item *ti;
+        proto_tree *tr;
+        tvbuff_t *cmd_tvb = NULL;
+
+        cmd = (sec_vt_command)tvb_get_letohs(tvb, offset);
+        len = tvb_get_letohs(tvb, offset + 2);
+        cmd_end = cmd & SEC_VT_COMMAND_END;
+        cmd_must = cmd & SEC_VT_MUST_PROCESS_COMMAND;
+        cmd = (sec_vt_command)(cmd & SEC_VT_COMMAND_MASK);
+
+        tr = proto_tree_add_subtree_format(tree, tvb, offset, 4 + len,
+                                           ett_dcerpc_sec_vt_pcontext,
+                                           &ti, "Command: %s",
+                                             val_to_str(cmd, sec_vt_command_cmd_vals,
+                                                        "Unknown (0x%04x)"));
+
+        if (cmd_must) {
+            proto_item_append_text(ti, "!!!");
+        }
+        if (cmd_end) {
+            proto_item_append_text(ti, ", END");
+        }
 
-            if (sub_item) {
-                proto_item_set_len(sub_item, length);
-            }
+        proto_tree_add_bitmask(tr, tvb, offset,
+                               hf_dcerpc_sec_vt_command,
+                               ett_dcerpc_sec_vt_command,
+                               sec_vt_command_fields,
+                               ENC_LITTLE_ENDIAN);
+        offset += 2;
+
+        proto_tree_add_item(tr, hf_dcerpc_sec_vt_command_length, tvb,
+                            offset, 2, ENC_LITTLE_ENDIAN);
+        offset += 2;
+
+        cmd_tvb = tvb_new_subset_length(tvb, offset, len);
+        switch (cmd) {
+        case SEC_VT_COMMAND_BITMASK_1:
+            dissect_sec_vt_bitmask(tr, cmd_tvb);
+            break;
+        case SEC_VT_COMMAND_PCONTEXT:
+            dissect_sec_vt_pcontext(tr, cmd_tvb);
+            break;
+        case SEC_VT_COMMAND_HEADER2:
+            dissect_sec_vt_header(pinfo, tr, cmd_tvb);
+            break;
+        default:
+            proto_tree_add_item(tr, hf_dcerpc_unknown, cmd_tvb, 0, len, ENC_NA);
+            break;
+        }
 
-            if (stub_tvb != NULL) {
-                /*
-                 * Catch all exceptions other than BoundsError, so that even
-                 * if the stub data is bad, we still show the authentication
-                 * padding, if any.
-                 *
-                 * If we get BoundsError, it means the frame was cut short
-                 * by a snapshot length, so there's nothing more to
-                 * dissect; just re-throw that exception.
-                 */
-                TRY {
-                    int remaining;
-
-                    offset = sub_dissect(stub_tvb, 0, pinfo, sub_tree,
-                                          info, drep);
-
-                    /* If we have a subdissector and it didn't dissect all
-                       data in the tvb, make a note of it. */
-                    remaining = tvb_reported_length_remaining(stub_tvb, offset);
-                    if (remaining > 0) {
-                        proto_tree_add_text(sub_tree, stub_tvb, offset,
-                                            remaining,
-                                            "[Long frame (%d byte%s)]",
-                                            remaining,
-                                            plurality(remaining, "", "s"));
-                        col_append_fstr(pinfo->cinfo, COL_INFO,
-                                            "[Long frame (%d byte%s)]",
-                                            remaining,
-                                            plurality(remaining, "", "s"));
+        offset += len;
+        remaining -= (4 + len);
 
-                    }
-                } CATCH_NONFATAL_ERRORS {
-                    /*
-                     * Somebody threw an exception that means that there
-                     * was a problem dissecting the payload; that means
-                     * that a dissector was found, so we don't need to
-                     * dissect the payload as data or update the protocol
-                     * or info columns.
-                     *
-                     * Just show the exception and then drive on to show
-                     * the authentication padding.
-                     */
-                    show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
-                } ENDTRY;
-            }
+        len_missalign = len & 1;
 
-            /* If there is auth padding at the end of the stub, display it */
-            if (auth_pad_len != 0) {
-                tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
-                proto_tree_add_text(sub_tree, decrypted_tvb, auth_pad_offset,
-                                    auth_pad_len,
-                                    "Auth Padding (%u byte%s)",
-                                    auth_pad_len,
-                                    plurality(auth_pad_len, "", "s"));
-            }
+        if (len_missalign) {
+            int l = 2-len_missalign;
+            proto_tree_add_item(tr, hf_dcerpc_missalign, tvb, offset, l, ENC_NA);
+            offset += l;
+            remaining -= l;
+        }
 
-            pinfo->current_proto = saved_proto;
-        } else {
-            /* No subdissector - show it as stub data. */
-            if (decrypted_tvb) {
-                show_stub_data(decrypted_tvb, 0, sub_tree, auth_info, FALSE);
-            } else {
-                show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
-            }
+        if (cmd_end) {
+            break;
         }
-    } else
-        show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
+    }
 
-    tap_queue_packet(dcerpc_tap, pinfo, info);
-    return 0;
+    proto_item_set_end(item, tvb, offset);
+    return offset;
 }
 
 static int
-dissect_dcerpc_verifier(tvbuff_t *tvb, packet_info *pinfo,
-                        proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
-                        dcerpc_auth_info *auth_info)
+dissect_verification_trailer(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
+                             proto_tree *parent_tree, int *signature_offset)
 {
-    int auth_offset;
-
-    auth_info->auth_data = NULL;
+    volatile int ret = -1;
+    TRY {
+        /*
+         * Even if we found a signature we can't be sure to have a
+         * valid verification trailer, we're only relatively sure
+         * if we manage to dissect it completely, otherwise it
+         * may be part of the real payload. That's why we have
+         * a try/catch block here.
+         */
+        ret = dissect_verification_trailer_impl(pinfo, tvb, stub_offset, parent_tree, signature_offset);
+    } CATCH_NONFATAL_ERRORS {
+    } ENDTRY;
+    return ret;
+}
 
-    if (auth_info->auth_size != 0) {
-        dcerpc_auth_subdissector_fns *auth_fns;
-        tvbuff_t *auth_tvb;
+static int
+dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
+                   proto_tree *dcerpc_tree,
+                   tvbuff_t *volatile tvb, gboolean decrypted,
+                   guint8 *drep, dcerpc_info *info,
+                   dcerpc_auth_info *auth_info)
+{
+    volatile gint         offset   = 0;
+    guid_key              key;
+    dcerpc_dissector_data_t dissector_data;
+    proto_item           *hidden_item;
 
-        auth_offset = hdr->frag_len - hdr->auth_len;
+    /* GUID and UUID are same size, but compiler complains about structure "name" differences */
+    memcpy(&key.guid, &info->call_data->uuid, sizeof(key.guid));
+    key.ver = info->call_data->ver;
 
-        auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
-                                  hdr->auth_len);
+    dissector_data.sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key);
+    dissector_data.info = info;
+    dissector_data.decrypted = decrypted;
+    dissector_data.auth_info = auth_info;
+    dissector_data.drep = drep;
+    dissector_data.dcerpc_tree = dcerpc_tree;
+
+    /* Check the dissector table before the hash table.  Hopefully the hash table entries can
+       all be converted to use dissector table */
+    if ((dissector_data.sub_proto == NULL) ||
+        (!dissector_try_guid_new(uuid_dissector_table, &key, tvb, pinfo, tree, FALSE, &dissector_data))) {
+        /*
+         * We don't have a dissector for this UUID, or the protocol
+         * for that UUID is disabled.
+         */
 
-        auth_info->auth_data = auth_tvb;
+        hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
+                                             tvb, offset, 0, TRUE);
+        PROTO_ITEM_SET_HIDDEN(hidden_item);
+        col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
+        guids_resolve_guid_to_str(&info->call_data->uuid), info->call_data->ver);
 
-        if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
-                                                  auth_info->auth_type))) {
-            /*
-             * Catch all bounds-error exceptions, so that even if the
-             * verifier is bad or we don't have all of it, we still
-             * show the stub data.
-             */
-            TRY {
-                dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
-                                  hdr, auth_info);
-            } CATCH_BOUNDS_ERRORS {
-                show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
-            } ENDTRY;
-        } else {
-            tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
-            proto_tree_add_text(dcerpc_tree, auth_tvb, 0, hdr->auth_len,
-                                "Auth Verifier");
-        }
+        show_stub_data(pinfo, tvb, 0, dcerpc_tree, auth_info, !decrypted);
+        return -1;
     }
 
-    return hdr->auth_len;
+    tap_queue_packet(dcerpc_tap, pinfo, info);
+    return 0;
 }
 
 static void
 dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
                        proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
-                       gboolean are_credentials, dcerpc_auth_info *auth_info)
+                       dcerpc_auth_info *auth_info)
 {
     volatile int offset;
 
@@ -2809,10 +3680,15 @@ dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
      * Initially set auth_level and auth_type to zero to indicate that we
      * haven't yet seen any authentication level information.
      */
-    auth_info->auth_level   = 0;
-    auth_info->auth_type    = 0;
-    auth_info->auth_size    = 0;
-    auth_info->auth_pad_len = 0;
+    auth_info->auth_type       = 0;
+    auth_info->auth_level      = 0;
+    auth_info->auth_context_id = 0;
+    auth_info->auth_pad_len    = 0;
+    auth_info->auth_size       = 0;
+    auth_info->auth_fns        = NULL;
+    auth_info->auth_tvb        = NULL;
+    auth_info->auth_item       = NULL;
+    auth_info->auth_tree       = NULL;
 
     /*
      * The authentication information is at the *end* of the PDU; in
@@ -2838,6 +3714,15 @@ dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
          */
         offset = hdr->frag_len - (hdr->auth_len + 8);
         if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
+            /* Compute the size of the auth block.  Note that this should not
+               include auth padding, since when NTLMSSP encryption is used, the
+               padding is actually inside the encrypted stub */
+            auth_info->auth_size = hdr->auth_len + 8;
+
+            auth_info->auth_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_info,
+                                                       tvb, offset, auth_info->auth_size, ENC_NA);
+            auth_info->auth_tree = proto_item_add_subtree(auth_info->auth_item, ett_dcerpc_auth_info);
+
             /*
              * Either there's no stub data, or the last byte of the stub
              * data is present in the captured data, so we shouldn't
@@ -2849,45 +3734,49 @@ dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
              * dissect after this, such as stub data.
              */
             TRY {
-                offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+                offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
                                               hf_dcerpc_auth_type,
                                               &auth_info->auth_type);
-                offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+                offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
                                               hf_dcerpc_auth_level,
                                               &auth_info->auth_level);
 
-                offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+                offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
                                               hf_dcerpc_auth_pad_len,
                                               &auth_info->auth_pad_len);
-                offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+                offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
                                               hf_dcerpc_auth_rsrvd, NULL);
-                offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
-                                               hf_dcerpc_auth_ctx_id, NULL);
+                offset = dissect_dcerpc_uint32(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
+                                               hf_dcerpc_auth_ctx_id,
+                                               &auth_info->auth_context_id);
+
+                proto_item_append_text(auth_info->auth_item,
+                                       ": %s, %s, AuthContextId(%d)",
+                                       val_to_str(auth_info->auth_type,
+                                                  authn_protocol_vals,
+                                                  "AuthType(%u)"),
+                                       val_to_str(auth_info->auth_level,
+                                                  authn_level_vals,
+                                                  "AuthLevel(%u)"),
+                                       auth_info->auth_context_id);
 
                 /*
                  * Dissect the authentication data.
                  */
-                if (are_credentials) {
-                    tvbuff_t *auth_tvb;
-                    dcerpc_auth_subdissector_fns *auth_fns;
-
-                    auth_tvb = tvb_new_subset(tvb, offset,
-                                              MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
+                auth_info->auth_tvb = tvb_new_subset(tvb, offset,
+                                              MIN(hdr->auth_len,tvb_reported_length_remaining(tvb, offset)),
                                               hdr->auth_len);
 
-                    if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
-                                                              auth_info->auth_type)))
-                        dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
-                                          hdr, auth_info);
-                    else
-                        proto_tree_add_text(dcerpc_tree, tvb, offset, hdr->auth_len,
-                                             "Auth Credentials");
-                }
+                auth_info->auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
+                                                                auth_info->auth_type);
+                if (auth_info->auth_fns != NULL)
+                    dissect_auth_verf(pinfo, hdr, auth_info);
+                else
+                    proto_tree_add_item(auth_info->auth_tree,
+                                        hf_dcerpc_auth_credentials,
+                                        auth_info->auth_tvb, 0,
+                                        hdr->auth_len, ENC_NA);
 
-                /* Compute the size of the auth block.  Note that this should not
-                   include auth padding, since when NTLMSSP encryption is used, the
-                   padding is actually inside the encrypted stub */
-                auth_info->auth_size = hdr->auth_len + 8;
             } CATCH_BOUNDS_ERRORS {
                 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
             } ENDTRY;
@@ -2905,18 +3794,29 @@ dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
  * as well in the future.
  */
 
-guint16 dcerpc_get_transport_salt(packet_info *pinfo)
+guint64
+dcerpc_get_transport_salt(packet_info *pinfo)
 {
-    switch (pinfo->dcetransporttype) {
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+    switch (decode_data->dcetransporttype) {
     case DCE_CN_TRANSPORT_SMBPIPE:
         /* DCERPC over smb */
-        return pinfo->dcetransportsalt;
+        return decode_data->dcetransportsalt;
     }
 
     /* Some other transport... */
     return 0;
 }
 
+void
+dcerpc_set_transport_salt(guint64 dcetransportsalt, packet_info *pinfo)
+{
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+    decode_data->dcetransportsalt = dcetransportsalt;
+}
+
 /*
  * Connection oriented packet types
  */
@@ -2931,14 +3831,15 @@ dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
     guint16           ctx_id;
     guint8            num_trans_items;
     guint             j;
-    e_uuid_t          if_id;
-    e_uuid_t          trans_id;
+    e_guid_t          if_id;
+    e_guid_t          trans_id;
     guint32           trans_ver;
     guint16           if_ver, if_ver_minor;
     dcerpc_auth_info  auth_info;
     char             *uuid_str;
     const char       *uuid_name     = NULL;
     proto_item       *iface_item    = NULL;
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
 
     offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
                                    hf_dcerpc_cn_max_xmit, NULL);
@@ -2968,7 +3869,7 @@ dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         /* save context ID for use with dcerpc_add_conv_to_bind_table() */
         /* (if we have multiple contexts, this might cause "decode as"
          *  to behave unpredictably) */
-        pinfo->dcectxid = ctx_id;
+        decode_data->dcectxid = ctx_id;
 
         if (dcerpc_tree) {
             ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
@@ -2995,7 +3896,7 @@ dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
             iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
             iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
 
-            uuid_str = guid_to_str((e_guid_t*)&if_id);
+            uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t*)&if_id);
             uuid_name = guids_get_uuid_name(&if_id);
             if (uuid_name) {
                 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
@@ -3032,7 +3933,6 @@ dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         for (j = 0; j < num_trans_items; j++) {
             proto_tree *trans_tree = NULL;
             proto_item *trans_item = NULL;
-            proto_item *uuid_item = NULL;
 
             dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
             if (ctx_tree) {
@@ -3040,25 +3940,36 @@ dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
                 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
 
-                uuid_str = guid_to_str((e_guid_t *) &trans_id);
+                uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t *) &trans_id);
                 uuid_name = guids_get_uuid_name(&trans_id);
 
-                if (uuid_name) {
-                    uuid_item = proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id, tvb, offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s UUID:%s", uuid_name, uuid_str);
+                /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
+                if (trans_id.data1 == 0x6cb71c2c && trans_id.data2 == 0x9812 && trans_id.data3 == 0x4540) {
+                    proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
+                                               tvb, offset, 16, (e_guid_t *) &trans_id,
+                                               "Transfer Syntax: Bind Time Feature Negotiation UUID:%s",
+                                               uuid_str);
+                    proto_tree_add_bitmask(trans_tree, tvb, offset + 8,
+                               hf_dcerpc_cn_bind_trans_btfn,
+                               ett_dcerpc_cn_bind_trans_btfn,
+                               dcerpc_cn_bind_trans_btfn_fields,
+                               ENC_LITTLE_ENDIAN);
+                    proto_item_append_text(trans_item, "[%u]: Bind Time Feature Negotiation", j+1);
+                    proto_item_append_text(ctx_item, ", Bind Time Feature Negotiation");
+                } else if (uuid_name) {
+                    proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
+                                               tvb, offset, 16, (e_guid_t *) &trans_id,
+                                               "Transfer Syntax: %s UUID:%s", uuid_name, uuid_str);
                     proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
                     proto_item_append_text(ctx_item, ", %s", uuid_name);
                 } else {
-                    uuid_item = proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id, tvb, offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s", uuid_str);
+                    proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
+                                               tvb, offset, 16, (e_guid_t *) &trans_id,
+                                               "Transfer Syntax: %s", uuid_str);
                     proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
                     proto_item_append_text(ctx_item, ", %s", uuid_str);
                 }
 
-                /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
-                if (trans_id.Data1 == 0x6cb71c2c && trans_id.Data2 == 0x9812 && trans_id.Data3 == 0x4540) {
-                    proto_tree *uuid_tree = proto_item_add_subtree(uuid_item, ett_dcerpc_cn_trans_btfn);
-                    proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, offset+8, 1, trans_id.Data4[0]);
-                    proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, offset+8, 1, trans_id.Data4[0]);
-                }
             }
             offset += 16;
 
@@ -3082,7 +3993,7 @@ dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
             key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
             key->conv = conv;
             key->ctx_id = ctx_id;
-            key->smb_fid = dcerpc_get_transport_salt(pinfo);
+            key->transport_salt = dcerpc_get_transport_salt(pinfo);
 
             value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
             value->uuid = if_id;
@@ -3096,8 +4007,8 @@ dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         if (i > 0)
             col_append_fstr(pinfo->cinfo, COL_INFO, ",");
         col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
-                        guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor,
-                        guids_resolve_uuid_to_str(&trans_id));
+                        guids_resolve_guid_to_str(&if_id), if_ver, if_ver_minor,
+                        guids_resolve_guid_to_str(&trans_id));
 
         if (ctx_tree) {
             proto_item_set_len(ctx_item, offset - ctx_offset);
@@ -3109,7 +4020,7 @@ dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
      * an authentication header, and associate it with an authentication
      * context, so subsequent PDUs can use that context.
      */
-    dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
+    dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
 }
 
 static void
@@ -3122,7 +4033,7 @@ dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
     guint             i;
     guint16           result    = 0;
     guint16           reason    = 0;
-    e_uuid_t          trans_id;
+    e_guid_t          trans_id;
     guint32           trans_ver;
     dcerpc_auth_info  auth_info;
     const char       *uuid_name = NULL;
@@ -3140,7 +4051,6 @@ dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
     offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
                                    hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
     if (sec_addr_len != 0) {
-        tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
         proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
                             sec_addr_len, ENC_ASCII|ENC_NA);
         offset += sec_addr_len;
@@ -3164,8 +4074,7 @@ dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         proto_item *ctx_item = NULL;
 
         if (dcerpc_tree) {
-            ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Ctx Item[%u]:", i+1);
-            ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
+            ctx_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, 24, ett_dcerpc_cn_ctx, &ctx_item, "Ctx Item[%u]:", i+1);
         }
 
         offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
@@ -3174,10 +4083,12 @@ dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
         /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
         if (result == 3) {
-            const int old_offset = offset;
-            offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep, hf_dcerpc_cn_ack_btfn, &reason);
-            proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, old_offset, 1, reason);
-            proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, old_offset, 1, reason);
+            proto_tree_add_bitmask(ctx_tree, tvb, offset,
+                                   hf_dcerpc_cn_bind_trans_btfn,
+                                   ett_dcerpc_cn_bind_trans_btfn,
+                                   dcerpc_cn_bind_trans_btfn_fields,
+                                   ENC_LITTLE_ENDIAN);
+            offset += 2;
         } else if (result != 0) {
             offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
                                            hdr->drep, hf_dcerpc_cn_ack_reason,
@@ -3196,7 +4107,7 @@ dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
             dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
             uuid_name = guids_get_uuid_name(&trans_id);
             if (! uuid_name) {
-                uuid_name = guid_to_str((e_guid_t *) &trans_id);
+                uuid_name = guid_to_str(wmem_packet_scope(), (e_guid_t *) &trans_id);
             }
             proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
                                        offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
@@ -3217,7 +4128,7 @@ dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
      * XXX - do we need to do anything with the authentication level
      * we get back from this?
      */
-    dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
+    dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
 }
 
 static void
@@ -3281,14 +4192,14 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
     gboolean       save_fragmented;
     fragment_head *fd_head = NULL;
 
-    tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
+    tvbuff_t *payload_tvb, *decrypted_tvb = NULL;
     proto_item *pi;
     proto_item *parent_pi;
     proto_item *dcerpc_tree_item;
 
     save_fragmented = pinfo->fragmented;
 
-    length = tvb_length_remaining(tvb, offset);
+    length = tvb_reported_length_remaining(tvb, offset);
     reported_length = tvb_reported_length_remaining(tvb, offset);
     if (reported_length < 0 ||
         (guint32)reported_length < auth_info->auth_size) {
@@ -3301,53 +4212,19 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
         length = reported_length;
     payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
 
-    auth_tvb = NULL;
-    /*don't bother if we don't have the entire tvb */
-    /*XXX we should really make sure we calculate auth_info->auth_data
-      and use that one instead of this auth_tvb hack
-    */
-    if (tvb_length(tvb) == tvb_reported_length(tvb)) {
-        if (tvb_length_remaining(tvb, offset+length) > 8) {
-            auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
-        }
-    }
-
     /* Decrypt the PDU if it is encrypted */
 
     if (auth_info->auth_type &&
         (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
-        /*
-         * We know the authentication type, and the authentication
-         * level is "Packet privacy", meaning the payload is
-         * encrypted; attempt to decrypt it.
-         */
-        dcerpc_auth_subdissector_fns *auth_fns;
 
         /* Start out assuming we won't succeed in decrypting. */
-        decrypted_tvb = NULL;
-        /* Schannel needs information into the footer (verifier) in order to setup decryption keys
-         * so we call it in order to have a chance to decipher the data
-         */
-        if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
-            dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
-        }
 
-        if ((auth_fns = get_auth_subdissector_fns(
-                 auth_info->auth_level, auth_info->auth_type))) {
+        if (auth_info->auth_fns != NULL) {
             tvbuff_t *result;
 
-            result = decode_encrypted_data(
-                payload_tvb, auth_tvb, pinfo, auth_fns,
-                hdr->ptype == PDU_REQ, auth_info);
-
+            result = decode_encrypted_data(payload_tvb, pinfo, hdr, auth_info);
             if (result) {
-                if (dcerpc_tree)
-                    proto_tree_add_text(
-                        dcerpc_tree, payload_tvb, 0, -1,
-                        "Encrypted stub data (%d byte%s)",
-                        tvb_reported_length(payload_tvb),
-
-                        plurality(tvb_length(payload_tvb), "", "s"));
+                proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, payload_tvb, 0, -1, ENC_NA);
 
                 add_new_data_source(
                     pinfo, result, "Decrypted stub data");
@@ -3363,8 +4240,9 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
     if (PFC_NOT_FRAGMENTED(hdr)) {
         pinfo->fragmented = FALSE;
 
-        dcerpc_try_handoff(
-            pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
+        dcerpc_try_handoff(pinfo, tree, dcerpc_tree,
+            ((decrypted_tvb != NULL) ? decrypted_tvb : payload_tvb),
+            ((decrypted_tvb != NULL) ? TRUE : FALSE),
             hdr->drep, di, auth_info);
 
         pinfo->fragmented = save_fragmented;
@@ -3377,7 +4255,7 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
     /* debug output of essential fragment data. */
     /* leave it here for future debugging sessions */
     /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
-      pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
+      pinfo->num, offset, hdr->frag_len, tvb_reported_length(decrypted_tvb));*/
 
     /* if we are not doing reassembly and this is the first fragment
        then just dissect it and exit
@@ -3386,8 +4264,9 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
     */
     if ( (!dcerpc_reassemble) && (hdr->flags & PFC_FIRST_FRAG) ) {
 
-        dcerpc_try_handoff(
-            pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
+        dcerpc_try_handoff(pinfo, tree, dcerpc_tree,
+            ((decrypted_tvb != NULL) ? decrypted_tvb : payload_tvb),
+            ((decrypted_tvb != NULL) ? TRUE : FALSE),
             hdr->drep, di, auth_info);
 
         expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
@@ -3409,7 +4288,7 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
        nor the first fragment then there is nothing more we can do
        so we just have to exit
     */
-    if ( !dcerpc_reassemble || (tvb_length(tvb) != tvb_reported_length(tvb)) )
+    if ( !dcerpc_reassemble || (tvb_captured_length(tvb) != tvb_reported_length(tvb)) )
         goto end_cn_stub;
 
     /* if we didn't get 'frame' we don't know where the PDU started and thus
@@ -3440,7 +4319,7 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
      */
     fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
                                     decrypted_tvb, 0, pinfo, frame, NULL,
-                                    tvb_length(decrypted_tvb),
+                                    tvb_reported_length(decrypted_tvb),
                                     hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
 
 end_cn_stub:
@@ -3451,7 +4330,7 @@ end_cn_stub:
      */
     if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
 
-        if ((pinfo->fd->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
+        if ((pinfo->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
             tvbuff_t *next_tvb;
             proto_item *frag_tree_item;
 
@@ -3472,8 +4351,7 @@ end_cn_stub:
 
             expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
 
-            dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
-                               next_tvb, hdr->drep, di, auth_info);
+            dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, auth_info);
 
         } else {
             if (decrypted_tvb) {
@@ -3498,72 +4376,15 @@ end_cn_stub:
         expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
 
         if (decrypted_tvb) {
-            show_stub_data(decrypted_tvb, 0, tree, auth_info, FALSE);
+            show_stub_data(pinfo, decrypted_tvb, 0, tree, auth_info, FALSE);
         } else {
-            show_stub_data(payload_tvb, 0, tree, auth_info, TRUE);
+            show_stub_data(pinfo, payload_tvb, 0, tree, auth_info, TRUE);
         }
     }
 
     pinfo->fragmented = save_fragmented;
 }
 
-/**
- *  Registers a conversation/UUID binding association, so that
- *  we can invoke the proper sub-dissector for a given DCERPC
- *  conversation.
- *
- *  @param binding all values needed to create and bind a new conversation
- *
- *  @return Pointer to newly-added UUID/conversation binding.
- */
-struct _dcerpc_bind_value *
-dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
-{
-    dcerpc_bind_value *bind_value;
-    dcerpc_bind_key   *key;
-    conversation_t    *conv;
-
-    conv = find_conversation(
-        0,
-        &binding->addr_a,
-        &binding->addr_b,
-        binding->ptype,
-        binding->port_a,
-        binding->port_b,
-        0);
-
-    if (!conv) {
-        conv = conversation_new(
-            0,
-            &binding->addr_a,
-            &binding->addr_b,
-            binding->ptype,
-            binding->port_a,
-            binding->port_b,
-            0);
-    }
-
-    bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
-    bind_value->uuid = binding->uuid;
-    bind_value->ver = binding->ver;
-    /* For now, assume all DCE/RPC we pick from "decode as" is using
-       standard ndr and not ndr64.
-       We should make this selectable from the dialog in the future
-    */
-    bind_value->transport = uuid_data_repr_proto;
-
-    key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
-    key->conv = conv;
-    key->ctx_id = binding->ctx_id;
-    key->smb_fid = binding->smb_fid;
-
-    /* add this entry to the bind table */
-    g_hash_table_insert(dcerpc_binds, key, bind_value);
-
-    return bind_value;
-
-}
-
 static void
 dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                        proto_tree *dcerpc_tree, proto_tree *tree,
@@ -3572,11 +4393,12 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
     conversation_t   *conv;
     guint16           ctx_id;
     guint16           opnum;
-    e_uuid_t          obj_id = DCERPC_UUID_NULL;
+    e_guid_t          obj_id = DCERPC_UUID_NULL;
     dcerpc_auth_info  auth_info;
     guint32           alloc_hint;
     proto_item       *pi;
     proto_item       *parent_pi;
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
 
     offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
                                    hf_dcerpc_cn_alloc_hint, &alloc_hint);
@@ -3592,7 +4414,7 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                                    hf_dcerpc_opnum, &opnum);
 
     /* save context ID for use with dcerpc_add_conv_to_bind_table() */
-    pinfo->dcectxid = ctx_id;
+    decode_data->dcectxid = ctx_id;
 
     col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
                     opnum, ctx_id);
@@ -3602,7 +4424,7 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         if (dcerpc_tree) {
             proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
                                        offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
-                                       guid_to_str((e_guid_t *) &obj_id));
+                                       guid_to_str(wmem_packet_scope(), (e_guid_t *) &obj_id));
         }
         offset += 16;
     }
@@ -3611,12 +4433,12 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
      * XXX - what if this was set when the connection was set up,
      * and we just have a security context?
      */
-    dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+    dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
 
-    conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+    conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
                              pinfo->srcport, pinfo->destport, 0);
     if (!conv)
-        show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
+        show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
     else {
         dcerpc_matched_key matched_key, *new_matched_key;
         dcerpc_call_value *value;
@@ -3626,7 +4448,7 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
            and desegmented pdu's .
            Instead we check if this pdu is already in the matched table or not
         */
-        matched_key.frame = pinfo->fd->num;
+        matched_key.frame = pinfo->num;
         matched_key.call_id = hdr->call_id;
         value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
         if (!value) {
@@ -3635,7 +4457,7 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
             bind_key.conv = conv;
             bind_key.ctx_id = ctx_id;
-            bind_key.smb_fid = dcerpc_get_transport_salt(pinfo);
+            bind_key.transport_salt = dcerpc_get_transport_salt(pinfo);
 
             if ((bind_value = (dcerpc_bind_value *)g_hash_table_lookup(dcerpc_binds, &bind_key)) ) {
                 if (!(hdr->flags&PFC_FIRST_FRAG)) {
@@ -3644,7 +4466,7 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
                     call_key.conv = conv;
                     call_key.call_id = hdr->call_id;
-                    call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
+                    call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
                     if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
                         new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
                         *new_matched_key = matched_key;
@@ -3663,7 +4485,7 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                     call_key = (dcerpc_cn_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_cn_call_key));
                     call_key->conv = conv;
                     call_key->call_id = hdr->call_id;
-                    call_key->smb_fid = dcerpc_get_transport_salt(pinfo);
+                    call_key->transport_salt = dcerpc_get_transport_salt(pinfo);
 
                     /* if there is already a matching call in the table
                        remove it so it is replaced with the new one */
@@ -3676,8 +4498,8 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                     call_value->ver = bind_value->ver;
                     call_value->object_uuid = obj_id;
                     call_value->opnum = opnum;
-                    call_value->req_frame = pinfo->fd->num;
-                    call_value->req_time = pinfo->fd->abs_ts;
+                    call_value->req_frame = pinfo->num;
+                    call_value->req_time = pinfo->abs_ts;
                     call_value->rep_frame = 0;
                     call_value->max_ptr = 0;
                     call_value->se_data = NULL;
@@ -3701,11 +4523,12 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         if (value) {
             dcerpc_info *di;
 
-            di = get_next_di();
+            di = wmem_new0(wmem_packet_scope(), dcerpc_info);
             /* handoff this call */
+            di->dcerpc_procedure_name = "";
             di->conv = conv;
             di->call_id = hdr->call_id;
-            di->smb_fid = dcerpc_get_transport_salt(pinfo);
+            di->transport_salt = dcerpc_get_transport_salt(pinfo);
             di->ptype = PDU_REQ;
             di->call_data = value;
             di->hf_index = -1;
@@ -3725,13 +4548,9 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         } else {
             /* no bind information, simply show stub data */
             proto_tree_add_expert_format(dcerpc_tree, pinfo, &ei_dcerpc_cn_ctx_id_no_bind, tvb, offset, 0, "No bind info for interface Context ID %u - capture start too late?", ctx_id);
-            show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
+            show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
         }
     }
-
-    /* Dissect the verifier */
-    dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
-
 }
 
 static void
@@ -3746,7 +4565,8 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
     guint32            alloc_hint;
     proto_item        *pi;
     proto_item        *parent_pi;
-    e_uuid_t           obj_id_null = DCERPC_UUID_NULL;
+    e_guid_t           obj_id_null = DCERPC_UUID_NULL;
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
 
     offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
                                    hf_dcerpc_cn_alloc_hint, &alloc_hint);
@@ -3759,7 +4579,7 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
     }
 
     /* save context ID for use with dcerpc_add_conv_to_bind_table() */
-    pinfo->dcectxid = ctx_id;
+    decode_data->dcectxid = ctx_id;
 
     col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
 
@@ -3772,14 +4592,14 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
      * XXX - what if this was set when the connection was set up,
      * and we just have a security context?
      */
-    dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+    dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
 
-    conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+    conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
                              pinfo->srcport, pinfo->destport, 0);
 
     if (!conv) {
         /* no point in creating one here, really */
-        show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
+        show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
     } else {
         dcerpc_matched_key matched_key, *new_matched_key;
 
@@ -3788,7 +4608,7 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
            and desegmented pdu's .
            Instead we check if this pdu is already in the matched table or not
         */
-        matched_key.frame = pinfo->fd->num;
+        matched_key.frame = pinfo->num;
         matched_key.call_id = hdr->call_id;
         value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
         if (!value) {
@@ -3797,18 +4617,18 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
             call_key.conv = conv;
             call_key.call_id = hdr->call_id;
-            call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
+            call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
 
             if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
                 /* extra sanity check,  only match them if the reply
                    came after the request */
-                if (call_value->req_frame<pinfo->fd->num) {
+                if (call_value->req_frame<pinfo->num) {
                     new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
                     *new_matched_key = matched_key;
                     g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
                     value = call_value;
                     if (call_value->rep_frame == 0) {
-                        call_value->rep_frame = pinfo->fd->num;
+                        call_value->rep_frame = pinfo->num;
                     }
                 }
             }
@@ -3817,21 +4637,23 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         if (value) {
             dcerpc_info *di;
 
-            di = get_next_di();
+            di = wmem_new0(wmem_packet_scope(), dcerpc_info);
             /* handoff this call */
+            di->dcerpc_procedure_name = "";
             di->conv = conv;
             di->call_id = hdr->call_id;
-            di->smb_fid = dcerpc_get_transport_salt(pinfo);
+            di->transport_salt = dcerpc_get_transport_salt(pinfo);
             di->ptype = PDU_RESP;
             di->call_data = value;
 
-            proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
+            pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
+            PROTO_ITEM_SET_GENERATED(pi);
 
             /* (optional) "Object UUID" from request */
             if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
                 pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
                                                 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
-                                                guid_to_str((e_guid_t *) &value->object_uuid));
+                                                guid_to_str(wmem_packet_scope(), (e_guid_t *) &value->object_uuid));
                 PROTO_ITEM_SET_GENERATED(pi);
             }
 
@@ -3844,7 +4666,7 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                 if (parent_pi != NULL) {
                     proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
                 }
-                nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
+                nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
                 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
                 PROTO_ITEM_SET_GENERATED(pi);
             } else {
@@ -3857,12 +4679,9 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         } else {
             /* no bind information, simply show stub data */
             proto_tree_add_expert_format(dcerpc_tree, pinfo, &ei_dcerpc_cn_ctx_id_no_bind, tvb, offset, 0, "No bind info for interface Context ID %u - capture start too late?", ctx_id);
-            show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
+            show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
         }
     }
-
-    /* Dissect the verifier */
-    dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
 }
 
 static void
@@ -3876,6 +4695,7 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
     guint32            alloc_hint;
     dcerpc_auth_info   auth_info;
     proto_item        *pi    = NULL;
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
 
     offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
                                    hf_dcerpc_cn_alloc_hint, &alloc_hint);
@@ -3902,7 +4722,7 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
     expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
 
     /* save context ID for use with dcerpc_add_conv_to_bind_table() */
-    pinfo->dcectxid = ctx_id;
+    decode_data->dcectxid = ctx_id;
 
     col_append_fstr(pinfo->cinfo, COL_INFO,
                     ", Ctx: %u, status: %s", ctx_id,
@@ -3916,9 +4736,9 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
      * XXX - what if this was set when the connection was set up,
      * and we just have a security context?
      */
-    dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+    dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
 
-    conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+    conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
                              pinfo->srcport, pinfo->destport, 0);
     if (!conv) {
         /* no point in creating one here, really */
@@ -3930,7 +4750,7 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
            and desegmented pdu's .
            Instead we check if this pdu is already in the matched table or not
         */
-        matched_key.frame = pinfo->fd->num;
+        matched_key.frame = pinfo->num;
         matched_key.call_id = hdr->call_id;
         value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
         if (!value) {
@@ -3939,7 +4759,7 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
             call_key.conv = conv;
             call_key.call_id = hdr->call_id;
-            call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
+            call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
 
             if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
                 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
@@ -3948,7 +4768,7 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
                 value = call_value;
                 if (call_value->rep_frame == 0) {
-                    call_value->rep_frame = pinfo->fd->num;
+                    call_value->rep_frame = pinfo->num;
                 }
 
             }
@@ -3959,15 +4779,17 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
             dcerpc_info *di;
             proto_item *parent_pi;
 
-            di = get_next_di();
+            di = wmem_new0(wmem_packet_scope(), dcerpc_info);
             /* handoff this call */
+            di->dcerpc_procedure_name = "";
             di->conv = conv;
             di->call_id = hdr->call_id;
-            di->smb_fid = dcerpc_get_transport_salt(pinfo);
+            di->transport_salt = dcerpc_get_transport_salt(pinfo);
             di->ptype = PDU_FAULT;
             di->call_data = value;
 
-            proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
+            pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
+            PROTO_ITEM_SET_GENERATED(pi);
             if (value->req_frame != 0) {
                 nstime_t delta_ts;
                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
@@ -3977,14 +4799,14 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                 if (parent_pi != NULL) {
                     proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
                 }
-                nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
+                nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
                 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
                 PROTO_ITEM_SET_GENERATED(pi);
             } else {
                 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
             }
 
-            length = tvb_length_remaining(tvb, offset);
+            length = tvb_reported_length_remaining(tvb, offset);
             /* as we now create a tvb in dissect_dcerpc_cn() containing only the
              * stub_data, the following calculation is no longer valid:
              * stub_length = hdr->frag_len - offset - auth_info.auth_size;
@@ -4013,25 +4835,13 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                      * It should probably get passed the status code
                      * as well, as that might be protocol-specific.
                      */
-                    if (dcerpc_tree) {
-                        if (stub_length > 0) {
-                            tvb_ensure_bytes_exist(tvb, offset, stub_length);
-                            proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
-                                                "Fault stub data (%d byte%s)",
-                                                stub_length,
-                                                plurality(stub_length, "", "s"));
-                        }
+                    if (stub_length > 0) {
+                        proto_tree_add_item(dcerpc_tree, hf_dcerpc_fault_stub_data, tvb, offset, stub_length, ENC_NA);
                     }
                 } else {
                     /* PDU is fragmented and this isn't the first fragment */
-                    if (dcerpc_tree) {
-                        if (stub_length > 0) {
-                            tvb_ensure_bytes_exist(tvb, offset, stub_length);
-                            proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
-                                                "Fragment data (%d byte%s)",
-                                                stub_length,
-                                                plurality(stub_length, "", "s"));
-                        }
+                    if (stub_length > 0) {
+                        proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
                     }
                 }
             } else {
@@ -4041,11 +4851,7 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                    third means we can attempt reassembly. */
                 if (dcerpc_tree) {
                     if (length > 0) {
-                        tvb_ensure_bytes_exist(tvb, offset, stub_length);
-                        proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
-                                            "Fragment data (%d byte%s)",
-                                            stub_length,
-                                            plurality(stub_length, "", "s"));
+                        proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
                     }
                 }
                 if (hdr->flags&PFC_FIRST_FRAG) {  /* FIRST fragment */
@@ -4088,11 +4894,7 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
                              */
                             if (dcerpc_tree) {
                                 if (length > 0) {
-                                    tvb_ensure_bytes_exist(tvb, offset, stub_length);
-                                    proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
-                                                        "Fault stub data (%d byte%s)",
-                                                        stub_length,
-                                                        plurality(stub_length, "", "s"));
+                                    proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, stub_length, ENC_NA);
                                 }
                             }
                         }
@@ -4123,30 +4925,28 @@ dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
     guint32    *cmd;
     guint32     i;
     const char *info_str        = NULL;
+    static const int * flags[] = {
+        &hf_dcerpc_cn_rts_flags_none,
+        &hf_dcerpc_cn_rts_flags_ping,
+        &hf_dcerpc_cn_rts_flags_other_cmd,
+        &hf_dcerpc_cn_rts_flags_recycle_channel,
+        &hf_dcerpc_cn_rts_flags_in_channel,
+        &hf_dcerpc_cn_rts_flags_out_channel,
+        &hf_dcerpc_cn_rts_flags_eof,
+        NULL
+    };
 
     /* Dissect specific RTS header */
     rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
-    if (dcerpc_tree) {
-        proto_tree *cn_rts_flags_tree;
-
-        tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_rts_flags, tvb, offset, 2, rts_flags);
-        cn_rts_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_flags);
-        proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_none, tvb, offset, 1, rts_flags);
-        proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_ping, tvb, offset, 1, rts_flags);
-        proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_other_cmd, tvb, offset, 1, rts_flags);
-        proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_recycle_channel, tvb, offset, 1, rts_flags);
-        proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_in_channel, tvb, offset, 1, rts_flags);
-        proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_out_channel, tvb, offset, 1, rts_flags);
-        proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_eof, tvb, offset, 1, rts_flags);
-    }
+    proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_rts_flags,
+                                ett_dcerpc_cn_rts_flags, flags, rts_flags, BMT_NO_APPEND);
     offset += 2;
 
     offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
                                    hf_dcerpc_cn_rts_commands_nb, &commands_nb);
 
     /* Create the RTS PDU tree - we do not yet know its name */
-    tf = proto_tree_add_text(dcerpc_tree, tvb, offset, tvb_length_remaining(tvb, offset), "RTS PDU: %u commands", commands_nb);
-    cn_rts_pdu_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_pdu);
+    cn_rts_pdu_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, -1, ett_dcerpc_cn_rts_pdu, &tf, "RTS PDU: %u commands", commands_nb);
 
     cmd = (guint32 *)wmem_alloc(wmem_packet_scope(), sizeof (guint32) * (commands_nb + 1));
 
@@ -4189,7 +4989,7 @@ dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
             const guint32 conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
             proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
             offset += 4;
-            padding = (guint8 *)tvb_memdup(NULL, tvb, offset, conformance_count);
+            padding = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, offset, conformance_count);
             proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
             offset += conformance_count;
         } break;
@@ -4205,17 +5005,17 @@ dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
             switch (addrtype) {
             case RTS_IPV4: {
                const guint32 addr4 = tvb_get_ipv4(tvb, offset);
-               proto_tree_add_text(cn_rts_command_tree, tvb, offset, 4, "%s", get_hostname(addr4));
+               proto_tree_add_ipv4_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv4, tvb, offset, 4, addr4, "%s", get_hostname(addr4));
                offset += 4;
             } break;
             case RTS_IPV6: {
                struct e_in6_addr addr6;
                tvb_get_ipv6(tvb, offset, &addr6);
-               proto_tree_add_text(cn_rts_command_tree, tvb, offset, 16, "%s", get_hostname6(&addr6));
+               proto_tree_add_ipv6_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv6, tvb, offset, 16, &addr6, "%s", get_hostname6(&addr6));
                offset += 16;
             } break;
             }
-            padding = (guint8 *)tvb_memdup(NULL, tvb, offset, 12);
+            padding = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, offset, 12);
             proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
             offset += 12;
         } break;
@@ -4229,7 +5029,7 @@ dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
             offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
             break;
         default:
-            proto_tree_add_text(cn_rts_command_tree, tvb, offset, 0, "unknown RTS command number");
+            expert_add_info(pinfo, tf, &ei_dcerpc_cn_rts_command);
             break;
         }
     }
@@ -4350,6 +5150,7 @@ dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         default:
             break;
         }
+        break;
      case RTS_FLAG_IN_CHANNEL:
         switch (commands_nb) {
         case 7:
@@ -4360,6 +5161,7 @@ dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         default:
             break;
         }
+        break;
      case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
         switch (commands_nb) {
         case 7:
@@ -4393,6 +5195,7 @@ dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
         default:
             break;
         }
+        break;
     case RTS_FLAG_EOF:
         switch (commands_nb) {
         case 1:
@@ -4426,10 +5229,31 @@ dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
     }
 }
 
+static gboolean
+is_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo _U_)
+{
+    guint8 rpc_ver;
+    guint8 rpc_ver_minor;
+    guint8 ptype;
+
+    if (!tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t)))
+        return FALSE;   /* not enough information to check */
+
+    rpc_ver = tvb_get_guint8(tvb, offset++);
+    if (rpc_ver != 5)
+        return FALSE;
+    rpc_ver_minor = tvb_get_guint8(tvb, offset++);
+    if ((rpc_ver_minor != 0) && (rpc_ver_minor != 1))
+        return FALSE;
+    ptype = tvb_get_guint8(tvb, offset++);
+    if (ptype > PDU_RTS)
+        return FALSE;
+
+    return TRUE;
+}
+
 /*
  * DCERPC dissector for connection oriented calls.
- * We use transport type to later multiplex between what kind of
- * pinfo->private_data structure to expect.
  */
 static gboolean
 dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
@@ -4442,11 +5266,21 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
     proto_item            *ti            = NULL;
     proto_item            *tf            = NULL;
     proto_tree            *dcerpc_tree   = NULL;
-    proto_tree            *cn_flags_tree = NULL;
-    proto_tree            *drep_tree     = NULL;
     e_dce_cn_common_hdr_t  hdr;
     dcerpc_auth_info       auth_info;
     tvbuff_t              *fragment_tvb;
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+    static const int * hdr_flags[] = {
+        &hf_dcerpc_cn_flags_object,
+        &hf_dcerpc_cn_flags_maybe,
+        &hf_dcerpc_cn_flags_dne,
+        &hf_dcerpc_cn_flags_mpx,
+        &hf_dcerpc_cn_flags_reserved,
+        &hf_dcerpc_cn_flags_cancel_pending,
+        &hf_dcerpc_cn_flags_last_frag,
+        &hf_dcerpc_cn_flags_first_frag,
+        NULL
+    };
 
     /*
      * when done over nbt, dcerpc requests are padded with 4 bytes of null
@@ -4468,19 +5302,13 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
     /*
      * Check if this looks like a C/O DCERPC call
      */
-    if (!tvb_bytes_exist(tvb, offset, sizeof (hdr))) {
-        return FALSE;   /* not enough information to check */
-    }
+    if (!is_dcerpc(tvb, offset, pinfo))
+        return FALSE;
+
     start_offset = offset;
     hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
-    if (hdr.rpc_ver != 5)
-        return FALSE;
     hdr.rpc_ver_minor = tvb_get_guint8(tvb, offset++);
-    if ((hdr.rpc_ver_minor != 0) && (hdr.rpc_ver_minor != 1))
-        return FALSE;
     hdr.ptype = tvb_get_guint8(tvb, offset++);
-    if (hdr.ptype > PDU_RTS)
-        return FALSE;
 
     hdr.flags = tvb_get_guint8(tvb, offset++);
     tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
@@ -4493,7 +5321,7 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
     hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
     /*offset += 4;*/
 
-    if (pinfo->dcectxid == 0) {
+    if (decode_data->dcectxid == 0) {
         col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
     } else {
         /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
@@ -4504,14 +5332,14 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
     if (can_desegment && pinfo->can_desegment
         && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
         pinfo->desegment_offset = start_offset;
-        pinfo->desegment_len = hdr.frag_len - tvb_length_remaining(tvb, start_offset);
+        pinfo->desegment_len = hdr.frag_len - tvb_reported_length_remaining(tvb, start_offset);
         *pkt_len = 0;   /* desegmentation required */
         return TRUE;
     }
 
     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
 
-    if (pinfo->dcectxid != 0) {
+    if (decode_data->dcectxid != 0) {
         /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
          * append a delimiter and set a column fence */
         col_append_str(pinfo->cinfo, COL_INFO, " # ");
@@ -4520,7 +5348,7 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
     col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
                  pckt_vals[hdr.ptype].strptr, hdr.call_id);
 
-    if (pinfo->dcectxid != 0) {
+    if (decode_data->dcectxid != 0) {
         /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
         expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
     }
@@ -4553,29 +5381,15 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
         proto_item_append_text(ti, " %s, Fragment: %s",
                                val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
                                fragment_type(hdr.flags));
+    }
 
-        tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
-        cn_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_flags);
-    }
-    proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
-    proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
-    proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
-    proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
-    proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
-    proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
-    proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
-    proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
+    proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_flags,
+                                ett_dcerpc_cn_flags, hdr_flags, hdr.flags, BMT_NO_APPEND);
     offset++;
 
     col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
 
-    if (dcerpc_tree) {
-        tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
-        drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
-    }
-    proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
-    proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
-    proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
+    proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
     offset += (int)sizeof (hdr.drep);
 
     proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
@@ -4615,7 +5429,7 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
      * (and other functions might fail as well) computing the right start
      * offset otherwise.
      */
-    subtvb_len = MIN(hdr.frag_len, tvb_length(tvb));
+    subtvb_len = MIN(hdr.frag_len, tvb_reported_length(tvb));
     fragment_tvb = tvb_new_subset(tvb, start_offset,
                                   subtvb_len /* length */,
                                   hdr.frag_len /* reported_length */);
@@ -4638,7 +5452,7 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
         /*
          * Nothing after the common header other than credentials.
          */
-        dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, TRUE,
+        dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
                                &auth_info);
         break;
 
@@ -4664,7 +5478,7 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
          * Nothing after the common header other than an authentication
          * verifier.
          */
-        dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
+        dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
                                &auth_info);
         break;
 
@@ -4680,7 +5494,7 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
 
     default:
         /* might as well dissect the auth info */
-        dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
+        dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
                                &auth_info);
         break;
     }
@@ -4694,11 +5508,13 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
 static gboolean
 dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
 {
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
     /*
      * Only one PDU per transport packet, and only one transport
      * packet per PDU.
      */
-    pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
+    decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
     if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, FALSE, NULL)) {
         /*
          * It wasn't a DCERPC PDU.
@@ -4760,7 +5576,7 @@ dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
             gboolean try_desegment = FALSE;
             if (dcerpc_cn_desegment && pinfo->can_desegment &&
                     !tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
-                /* look for a previous occurence of the DCE-RPC protocol */
+                /* look for a previous occurrence of the DCE-RPC protocol */
                 wmem_list_frame_t *cur;
                 cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
                 while (cur != NULL) {
@@ -4778,7 +5594,7 @@ dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                  * it was just too short to tell and ask the TCP layer for more
                  * data. */
                 pinfo->desegment_offset = offset;
-                pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_length_remaining(tvb, offset));
+                pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_reported_length_remaining(tvb, offset));
             } else {
                 /* Really not DCE-RPC */
                 break;
@@ -4819,21 +5635,67 @@ dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 static gboolean
 dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
 {
-    pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+    decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
     return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
 }
 
+static guint
+get_dcerpc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
+                   int offset _U_, void *data _U_)
+{
+    guint8 drep[4];
+    guint16 frag_len;
+
+    /* XXX: why does htis not take offset into account? */
+    tvb_memcpy(tvb, (guint8 *)drep, 4, sizeof(drep));
+    frag_len = dcerpc_tvb_get_ntohs(tvb, 8, drep);
+
+    return frag_len;
+}
+
+static int
+dissect_dcerpc_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+    int  pdu_len     = 0;
+    dissect_dcerpc_cn(tvb, 0, pinfo, tree,
+                                  /* Desegment is already handled by TCP, don't confuse it */
+                                  FALSE,
+                                  &pdu_len);
+    return pdu_len;
+}
+
+static gboolean
+dissect_dcerpc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+    dcerpc_decode_as_data* decode_data;
+
+    if (!is_dcerpc(tvb, 0, pinfo))
+        return 0;
+
+    decode_data = dcerpc_get_decode_data(pinfo);
+    decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
+
+    tcp_dissect_pdus(tvb, pinfo, tree, dcerpc_cn_desegment, 10, get_dcerpc_pdu_len, dissect_dcerpc_pdu, data);
+    return TRUE;
+}
+
 static gboolean
 dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
 {
-    pinfo->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+    decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
     return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
 }
 
 static gboolean
 dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
 {
-    pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
+    dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+    decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
     return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
 }
 
@@ -4843,7 +5705,6 @@ static void
 dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
                        e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
 {
-    proto_item *ti        = NULL;
     proto_tree *auth_tree = NULL;
     guint8      protection_level;
 
@@ -4863,12 +5724,11 @@ dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
      * packet body, then dissect the auth info.
      */
     offset += hdr->frag_len;
-    if (tvb_length_remaining(tvb, offset) > 0) {
+    if (tvb_reported_length_remaining(tvb, offset) > 0) {
         switch (hdr->auth_proto) {
 
         case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
-            ti = proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
-            auth_tree = proto_item_add_subtree(ti, ett_dcerpc_krb5_auth_verf);
+            auth_tree = proto_tree_add_subtree(dcerpc_tree, tvb, offset, -1, ett_dcerpc_krb5_auth_verf, NULL, "Kerberos authentication verifier");
             protection_level = tvb_get_guint8(tvb, offset);
             if (auth_level_p != NULL)
                 *auth_level_p = protection_level;
@@ -4885,7 +5745,7 @@ dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
             break;
 
         default:
-            proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Authentication verifier");
+            proto_tree_add_item(dcerpc_tree, hf_dcerpc_authentication_verifier, tvb, offset, -1, ENC_NA);
             break;
         }
     }
@@ -5023,7 +5883,7 @@ dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
     col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
                     di->call_data->opnum, hdr->frag_len );
 
-    length = tvb_length_remaining(tvb, offset);
+    length = tvb_reported_length_remaining(tvb, offset);
     reported_length = tvb_reported_length_remaining(tvb, offset);
     stub_length = hdr->frag_len;
     if (length > stub_length)
@@ -5051,18 +5911,11 @@ dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
             pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
             next_tvb = tvb_new_subset(tvb, offset, length,
                                       reported_length);
-            dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
-                               next_tvb, hdr->drep, di, NULL);
+            dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, NULL);
         } else {
             /* PDU is fragmented and this isn't the first fragment */
-            if (dcerpc_tree) {
-                if (length > 0) {
-                    tvb_ensure_bytes_exist(tvb, offset, stub_length);
-                    proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
-                                        "Fragment data (%d byte%s)",
-                                        stub_length,
-                                        plurality(stub_length, "", "s"));
-                }
+            if (length > 0) {
+                proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
             }
         }
     } else {
@@ -5070,13 +5923,8 @@ dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
            we have all the data in the fragment; the first two
            of those mean we should attempt reassembly, and the
            third means we can attempt reassembly. */
-        if (dcerpc_tree) {
-            if (length > 0) {
-                tvb_ensure_bytes_exist(tvb, offset, stub_length);
-                proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
-                                    "Fragment data (%d byte%s)", stub_length,
-                                    plurality(stub_length, "", "s"));
-            }
+        if (length > 0) {
+            proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
         }
 
         fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
@@ -5086,7 +5934,7 @@ dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
                                    !(hdr->flags1 & PFCL1_LASTFRAG), 0);
         if (fd_head != NULL) {
             /* We completed reassembly... */
-            if (pinfo->fd->num == fd_head->reassembled_in) {
+            if (pinfo->num == fd_head->reassembled_in) {
                 /* ...and this is the reassembled RPC PDU */
                 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
                 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
@@ -5097,8 +5945,7 @@ dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
                  * XXX - authentication info?
                  */
                 pinfo->fragmented = FALSE;
-                dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
-                                   next_tvb, hdr->drep, di, NULL);
+                dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, NULL);
             } else {
                 /* ...and this isn't the reassembled RPC PDU */
                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
@@ -5122,12 +5969,11 @@ dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
                        e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
 {
     dcerpc_info        *di;
-    dcerpc_call_value  *value, v;
+    dcerpc_call_value  *value;
     dcerpc_matched_key  matched_key, *new_matched_key;
     proto_item         *pi;
     proto_item         *parent_pi;
 
-    di = get_next_di();
     if (!(pinfo->fd->flags.visited)) {
         dcerpc_call_value *call_value;
         dcerpc_dg_call_key *call_key;
@@ -5142,8 +5988,8 @@ dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
         call_value->ver = hdr->if_ver;
         call_value->object_uuid = hdr->obj_id;
         call_value->opnum = hdr->opnum;
-        call_value->req_frame = pinfo->fd->num;
-        call_value->req_time = pinfo->fd->abs_ts;
+        call_value->req_frame = pinfo->num;
+        call_value->req_time = pinfo->abs_ts;
         call_value->rep_frame = 0;
         call_value->max_ptr = 0;
         call_value->se_data = NULL;
@@ -5155,30 +6001,32 @@ dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
         g_hash_table_insert(dcerpc_dg_calls, call_key, call_value);
 
         new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof(dcerpc_matched_key));
-        new_matched_key->frame = pinfo->fd->num;
+        new_matched_key->frame = pinfo->num;
         new_matched_key->call_id = hdr->seqnum;
         g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
     }
 
-    matched_key.frame = pinfo->fd->num;
+    matched_key.frame = pinfo->num;
     matched_key.call_id = hdr->seqnum;
     value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
     if (!value) {
-        v.uuid = hdr->if_id;
-        v.ver = hdr->if_ver;
-        v.object_uuid = hdr->obj_id;
-        v.opnum = hdr->opnum;
-        v.req_frame = pinfo->fd->num;
-        v.rep_frame = 0;
-        v.max_ptr = 0;
-        v.se_data = NULL;
-        v.private_data = NULL;
-        value = &v;
+        value = wmem_new(wmem_packet_scope(), dcerpc_call_value);
+        value->uuid = hdr->if_id;
+        value->ver = hdr->if_ver;
+        value->object_uuid = hdr->obj_id;
+        value->opnum = hdr->opnum;
+        value->req_frame = pinfo->num;
+        value->rep_frame = 0;
+        value->max_ptr = 0;
+        value->se_data = NULL;
+        value->private_data = NULL;
     }
 
+    di = wmem_new0(wmem_packet_scope(), dcerpc_info);
+    di->dcerpc_procedure_name = "";
     di->conv = conv;
     di->call_id = hdr->seqnum;
-    di->smb_fid = -1;
+    di->transport_salt = -1;
     di->ptype = PDU_REQ;
     di->call_data = value;
 
@@ -5200,12 +6048,11 @@ dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
                        e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
 {
     dcerpc_info        *di;
-    dcerpc_call_value  *value, v;
+    dcerpc_call_value  *value;
     dcerpc_matched_key  matched_key, *new_matched_key;
     proto_item         *pi;
     proto_item         *parent_pi;
 
-    di = get_next_di();
     if (!(pinfo->fd->flags.visited)) {
         dcerpc_call_value *call_value;
         dcerpc_dg_call_key call_key;
@@ -5216,33 +6063,31 @@ dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
 
         if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
             new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
-            new_matched_key->frame = pinfo->fd->num;
+            new_matched_key->frame = pinfo->num;
             new_matched_key->call_id = hdr->seqnum;
             g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
             if (call_value->rep_frame == 0) {
-                call_value->rep_frame = pinfo->fd->num;
+                call_value->rep_frame = pinfo->num;
             }
         }
     }
 
-    matched_key.frame = pinfo->fd->num;
+    matched_key.frame = pinfo->num;
     matched_key.call_id = hdr->seqnum;
     value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
     if (!value) {
-        v.uuid = hdr->if_id;
-        v.ver = hdr->if_ver;
-        v.object_uuid = hdr->obj_id;
-        v.opnum = hdr->opnum;
-        v.req_frame = 0;
-        v.rep_frame = pinfo->fd->num;
-        v.se_data = NULL;
-        v.private_data = NULL;
-        value = &v;
+        value = wmem_new0(wmem_packet_scope(), dcerpc_call_value);
+        value->uuid = hdr->if_id;
+        value->ver = hdr->if_ver;
+        value->object_uuid = hdr->obj_id;
+        value->opnum = hdr->opnum;
+        value->rep_frame = pinfo->num;
     }
 
+    di = wmem_new0(wmem_packet_scope(), dcerpc_info);
+    di->dcerpc_procedure_name = "";
     di->conv = conv;
-    di->call_id = 0;
-    di->smb_fid = -1;
+    di->transport_salt = -1;
     di->ptype = PDU_RESP;
     di->call_data = value;
 
@@ -5255,7 +6100,7 @@ dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
         if (parent_pi != NULL) {
             proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
         }
-        nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
+        nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
         pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
         PROTO_ITEM_SET_GENERATED(pi);
     } else {
@@ -5292,7 +6137,7 @@ dissect_dcerpc_dg_ping_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
 
         col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
 
-        nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
+        nstime_delta(&delta_ts, &pinfo->abs_ts, &call_value->req_time);
         pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
         PROTO_ITEM_SET_GENERATED(pi);
 /*    }*/
@@ -5306,24 +6151,43 @@ static gboolean
 dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
 {
     proto_item            *ti             = NULL;
-    proto_item            *tf             = NULL;
     proto_tree            *dcerpc_tree    = NULL;
-    proto_tree            *dg_flags1_tree = NULL;
-    proto_tree            *dg_flags2_tree = NULL;
-    proto_tree            *drep_tree      = NULL;
     e_dce_dg_common_hdr_t  hdr;
     int                    offset         = 0;
     conversation_t        *conv;
     int                    auth_level;
     char                  *uuid_str;
     const char            *uuid_name      = NULL;
+    static const int * hdr_flags1[] = {
+        &hf_dcerpc_dg_flags1_rsrvd_80,
+        &hf_dcerpc_dg_flags1_broadcast,
+        &hf_dcerpc_dg_flags1_idempotent,
+        &hf_dcerpc_dg_flags1_maybe,
+        &hf_dcerpc_dg_flags1_nofack,
+        &hf_dcerpc_dg_flags1_frag,
+        &hf_dcerpc_dg_flags1_last_frag,
+        &hf_dcerpc_dg_flags1_rsrvd_01,
+        NULL
+    };
+
+    static const int * hdr_flags2[] = {
+        &hf_dcerpc_dg_flags2_rsrvd_80,
+        &hf_dcerpc_dg_flags2_rsrvd_40,
+        &hf_dcerpc_dg_flags2_rsrvd_20,
+        &hf_dcerpc_dg_flags2_rsrvd_10,
+        &hf_dcerpc_dg_flags2_rsrvd_08,
+        &hf_dcerpc_dg_flags2_rsrvd_04,
+        &hf_dcerpc_dg_flags2_cancel_pending,
+        &hf_dcerpc_dg_flags2_rsrvd_01,
+        NULL
+    };
 
     /*
      * Check if this looks like a CL DCERPC call.  All dg packets
      * have an 80 byte header on them.  Which starts with
      * version (4), pkt_type.
      */
-    if (tvb_length(tvb) < sizeof (hdr)) {
+    if (tvb_reported_length(tvb) < sizeof (hdr)) {
         return FALSE;
     }
 
@@ -5395,71 +6259,22 @@ dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat
     }
     offset = 0;
 
-    if (tree)
-        proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
+    proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
     offset++;
 
-    if (tree)
-        proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
+    proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
     offset++;
 
-    if (tree) {
-        tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
-        dg_flags1_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags1);
-        if (dg_flags1_tree) {
-            proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
-            proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
-            proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
-            proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
-            proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
-            proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
-            proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
-            proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
-            if (hdr.flags1) {
-                proto_item_append_text(tf, " %s%s%s%s%s%s",
-                                       (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
-                                       (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
-                                       (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
-                                       (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
-                                       (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
-                                       (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
-            }
-        }
-    }
+    proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags1,
+                                ett_dcerpc_dg_flags1, hdr_flags1, hdr.flags1);
     offset++;
 
-    if (tree) {
-        tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
-        dg_flags2_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags2);
-        if (dg_flags2_tree) {
-            proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
-            proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
-            proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
-            proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
-            proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
-            proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
-            proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
-            proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
-            if (hdr.flags2) {
-                proto_item_append_text(tf, " %s",
-                                       (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
-            }
-        }
-    }
+    proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags2,
+                                ett_dcerpc_dg_flags2, hdr_flags2, hdr.flags2);
     offset++;
 
     if (tree) {
-        tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
-        drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
-        if (drep_tree) {
-            proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
-            proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
-            proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
-            proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
-                                   val_to_str_const(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
-                                   val_to_str_const(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
-                                   val_to_str_const(hdr.drep[1], drep_fp_vals, "Unknown"));
-        }
+        proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
     }
     offset += (int)sizeof (hdr.drep);
 
@@ -5470,12 +6285,12 @@ dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat
     if (tree) {
         proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
                                    offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
-                                   guid_to_str((e_guid_t *) &hdr.obj_id));
+                                   guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.obj_id));
     }
     offset += 16;
 
     if (tree) {
-        uuid_str = guid_to_str((e_guid_t*)&hdr.if_id);
+        uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t*)&hdr.if_id);
         uuid_name = guids_get_uuid_name(&hdr.if_id);
         if (uuid_name) {
             proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
@@ -5490,7 +6305,7 @@ dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat
     if (tree) {
         proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
                                    offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
-                                   guid_to_str((e_guid_t *) &hdr.act_id));
+                                   guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.act_id));
     }
     offset += 16;
 
@@ -5649,32 +6464,24 @@ static void
 dcerpc_init_protocol(void)
 {
     /* structures and data for BIND */
-    if (dcerpc_binds) {
-        g_hash_table_destroy(dcerpc_binds);
-        dcerpc_binds = NULL;
-    }
-    if (!dcerpc_binds) {
-        dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
-    }
+    dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
 
     /* structures and data for CALL */
-    if (dcerpc_cn_calls) {
-        g_hash_table_destroy(dcerpc_cn_calls);
-    }
     dcerpc_cn_calls = g_hash_table_new(dcerpc_cn_call_hash, dcerpc_cn_call_equal);
-    if (dcerpc_dg_calls) {
-        g_hash_table_destroy(dcerpc_dg_calls);
-    }
     dcerpc_dg_calls = g_hash_table_new(dcerpc_dg_call_hash, dcerpc_dg_call_equal);
 
     /* structure and data for MATCHED */
-    if (dcerpc_matched) {
-        g_hash_table_destroy(dcerpc_matched);
-    }
     dcerpc_matched = g_hash_table_new(dcerpc_matched_hash, dcerpc_matched_equal);
+    decode_dcerpc_inject_bindings();
+}
 
-    /* call the registered hooks */
-    g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
+static void
+dcerpc_cleanup_protocol(void)
+{
+    g_hash_table_destroy(dcerpc_binds);
+    g_hash_table_destroy(dcerpc_cn_calls);
+    g_hash_table_destroy(dcerpc_dg_calls);
+    g_hash_table_destroy(dcerpc_matched);
 }
 
 void
@@ -5687,9 +6494,12 @@ proto_register_dcerpc(void)
         { &hf_dcerpc_response_in,
           { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
             NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
-        { &hf_dcerpc_referent_id,
+        { &hf_dcerpc_referent_id32,
           { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
             NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
+        { &hf_dcerpc_referent_id64,
+          { "Referent ID", "dcerpc.referent_id64", FT_UINT64, BASE_HEX,
+            NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
         { &hf_dcerpc_ver,
           { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
         { &hf_dcerpc_ver_minor,
@@ -5718,6 +6528,8 @@ proto_register_dcerpc(void)
           { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
         { &hf_dcerpc_drep_byteorder,
           { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
+        { &hf_dcerpc_ndr_padding,
+          { "NDR-Padding", "dcerpc.ndr_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
         { &hf_dcerpc_drep_character,
           { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
         { &hf_dcerpc_drep_fp,
@@ -5756,10 +6568,12 @@ proto_register_dcerpc(void)
           { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
         { &hf_dcerpc_cn_bind_trans_ver,
           { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
-        { &hf_dcerpc_cn_bind_trans_btfn_01, /* [MS-RPCE] 2.2.2.14 */
-          { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01, NULL, HFILL }},
+        { &hf_dcerpc_cn_bind_trans_btfn, /* [MS-RPCE] 2.2.2.14 */
+          {"Bind Time Features", "dcerpc.cn_bind_trans_btfn", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
+        { &hf_dcerpc_cn_bind_trans_btfn_01,
+          { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 16, NULL, 0x01, NULL, HFILL }},
         { &hf_dcerpc_cn_bind_trans_btfn_02,
-          { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02, NULL, HFILL }},
+          { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 16, NULL, 0x02, NULL, HFILL }},
         { &hf_dcerpc_cn_alloc_hint,
           { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
         { &hf_dcerpc_cn_sec_addr_len,
@@ -5776,8 +6590,6 @@ proto_register_dcerpc(void)
           { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
         { &hf_dcerpc_cn_ack_trans_ver,
           { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
-        { &hf_dcerpc_cn_ack_btfn,
-          { "Bind Time Feature Negotiation Bitmask", "dcerpc.cn_ack_btfn", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
         { &hf_dcerpc_cn_reject_reason,
           { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
         { &hf_dcerpc_cn_num_protocols,
@@ -5915,12 +6727,12 @@ proto_register_dcerpc(void)
         { &hf_dcerpc_array_actual_count,
           { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
 
-        { &hf_dcerpc_array_buffer,
-          { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
-
         { &hf_dcerpc_op,
           { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
 
+        { &hf_dcerpc_null_pointer,
+          { "NULL Pointer", "dcerpc.null_pointer", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+
         { &hf_dcerpc_fragments,
           { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
             NULL, 0x0, "DCE/RPC Fragments", HFILL }},
@@ -6018,6 +6830,48 @@ proto_register_dcerpc(void)
           {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
         { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
           {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_sec_vt_signature,
+          {"SEC_VT_SIGNATURE", "dcerpc.rpc_sec_vt.signature", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_sec_vt_command_end,
+          {"SEC_VT_COMMAND_END", "dcerpc.rpc_sec_vt.command.end", FT_BOOLEAN, 16, NULL, 0x4000, NULL, HFILL }},
+        { &hf_dcerpc_sec_vt_command_must,
+          {"SEC_VT_MUST_PROCESS_COMMAND", "dcerpc.rpc_sec_vt.command.must_process", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL }},
+        { &hf_dcerpc_sec_vt_command_cmd,
+          {"Cmd", "dcerpc.rpc_sec_vt.command.cmd", FT_UINT16, BASE_HEX, VALS(sec_vt_command_cmd_vals), 0x3fff, NULL, HFILL }},
+        { &hf_dcerpc_sec_vt_command,
+          {"Command", "dcerpc.rpc_sec_vt.command", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
+        { &hf_dcerpc_sec_vt_command_length,
+          {"Length", "dcerpc.rpc_sec_vt.command.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL}},
+        { &hf_dcerpc_sec_vt_bitmask,
+          {"rpc_sec_vt_bitmask", "dcerpc.rpc_sec_vt.bitmask", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
+        { &hf_dcerpc_sec_vt_bitmask_sign,
+          {"CLIENT_SUPPORT_HEADER_SIGNING", "dcerpc.rpc_sec_vt.bitmask.sign", FT_BOOLEAN, 32, NULL, 0x1, NULL, HFILL }},
+        { &hf_dcerpc_sec_vt_pcontext_uuid,
+          {"UUID", "dcerpc.rpc_sec_vt.pcontext.interface.uuid", FT_GUID, BASE_NONE, NULL, 0, NULL, HFILL }},
+        { &hf_dcerpc_sec_vt_pcontext_ver,
+          {"Version", "dcerpc.rpc_sec_vt.pcontext.interface.ver", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
+        { &hf_dcerpc_reserved,
+          {"Reserved", "dcerpc.reserved", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+        { &hf_dcerpc_unknown,
+          {"Unknown", "dcerpc.unknown", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+        { &hf_dcerpc_missalign,
+          {"missalign", "dcerpc.missalign", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+        /* Generated from convert_proto_tree_add_text.pl */
+        { &hf_dcerpc_duplicate_ptr, { "duplicate PTR", "dcerpc.duplicate_ptr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_encrypted_stub_data, { "Encrypted stub data", "dcerpc.encrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_decrypted_stub_data, { "Decrypted stub data", "dcerpc.decrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_payload_stub_data, { "Payload stub data", "dcerpc.payload_stub_data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_stub_data_with_sec_vt, { "Stub data with rpc_sec_verification_trailer", "dcerpc.stub_data_with_sec_vt", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_stub_data, { "Stub data", "dcerpc.stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_auth_padding, { "Auth Padding", "dcerpc.auth_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_auth_info, { "Auth Info", "dcerpc.auth_info", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_auth_verifier, { "Auth Verifier", "dcerpc.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_auth_credentials, { "Auth Credentials", "dcerpc.auth_credentials", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_fault_stub_data, { "Fault stub data", "dcerpc.fault_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_fragment_data, { "Fragment data", "dcerpc.fragment_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_cmd_client_ipv4, { "RTS Client address", "dcerpc.cmd_client_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_cmd_client_ipv6, { "RTS Client address", "dcerpc.cmd_client_ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+        { &hf_dcerpc_authentication_verifier, { "Authentication verifier", "dcerpc.authentication_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
     };
     static gint *ett[] = {
         &ett_dcerpc,
@@ -6026,6 +6880,7 @@ proto_register_dcerpc(void)
         &ett_dcerpc_cn_iface,
         &ett_dcerpc_cn_trans_syntax,
         &ett_dcerpc_cn_trans_btfn,
+        &ett_dcerpc_cn_bind_trans_btfn,
         &ett_dcerpc_cn_rts_flags,
         &ett_dcerpc_cn_rts_command,
         &ett_dcerpc_cn_rts_pdu,
@@ -6037,10 +6892,17 @@ proto_register_dcerpc(void)
         &ett_dcerpc_fragments,
         &ett_dcerpc_fragment,
         &ett_dcerpc_krb5_auth_verf,
+        &ett_dcerpc_auth_info,
+        &ett_dcerpc_verification_trailer,
+        &ett_dcerpc_sec_vt_command,
+        &ett_dcerpc_sec_vt_bitmask,
+        &ett_dcerpc_sec_vt_pcontext,
+        &ett_dcerpc_sec_vt_header,
+        &ett_dcerpc_complete_stub_data,
     };
 
     static ei_register_info ei[] = {
-        { &ei_dcerpc_fragment, { "dcerpc.fragment", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
+        { &ei_dcerpc_fragment, { "dcerpc.fragment.reassemble", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
         { &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "%s fragment, reassembled", EXPFILL }},
         { &ei_dcerpc_cn_ctx_id_no_bind, { "dcerpc.cn_ctx_id.no_bind", PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID %u - capture start too late?", EXPFILL }},
         { &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
@@ -6048,8 +6910,20 @@ proto_register_dcerpc(void)
         { &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
         { &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change: %s", EXPFILL }},
         { &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
+        { &ei_dcerpc_verifier_unavailable, { "dcerpc.verifier_unavailable", PI_UNDECODED, PI_WARN, NULL, EXPFILL }},
+        { &ei_dcerpc_invalid_pdu_authentication_attempt, { "dcerpc.invalid_pdu_authentication_attempt", PI_UNDECODED, PI_WARN, NULL, EXPFILL }},
+        /* Generated from convert_proto_tree_add_text.pl */
+        { &ei_dcerpc_long_frame, { "dcerpc.long_frame", PI_PROTOCOL, PI_WARN, "Long frame", EXPFILL }},
+        { &ei_dcerpc_cn_rts_command, { "dcerpc.cn_rts_command.unknown", PI_PROTOCOL, PI_WARN, "unknown RTS command number", EXPFILL }},
     };
 
+    /* Decode As handling */
+    static build_valid_func dcerpc_da_build_value[1] = {dcerpc_value};
+    static decode_as_value_t dcerpc_da_values = {dcerpc_prompt, 1, dcerpc_da_build_value};
+    static decode_as_t dcerpc_da = {"dcerpc", "DCE-RPC", "dcerpc.uuid",
+                                    1, 0, &dcerpc_da_values, NULL, NULL,
+                                    dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free};
+
     module_t *dcerpc_module;
     expert_module_t* expert_dcerpc;
 
@@ -6059,7 +6933,10 @@ proto_register_dcerpc(void)
     expert_dcerpc = expert_register_protocol(proto_dcerpc);
     expert_register_field_array(expert_dcerpc, ei, array_length(ei));
 
+    uuid_dissector_table = register_dissector_table("dcerpc.uuid", "DCE/RPC UUIDs", proto_dcerpc, FT_GUID, BASE_HEX);
+
     register_init_routine(dcerpc_init_protocol);
+    register_cleanup_routine(dcerpc_cleanup_protocol);
     dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
     prefs_register_bool_preference(dcerpc_module,
                                    "desegment_dcerpc",
@@ -6078,26 +6955,28 @@ proto_register_dcerpc(void)
     dcerpc_uuids = g_hash_table_new(dcerpc_uuid_hash, dcerpc_uuid_equal);
     dcerpc_tap = register_tap("dcerpc");
 
-    g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
+    register_decode_as(&dcerpc_da);
+
+    register_srt_table(proto_dcerpc, NULL, 1, dcerpcstat_packet, dcerpcstat_init, dcerpcstat_param);
+
+    tvb_trailer_signature = tvb_new_real_data(TRAILER_SIGNATURE,
+                                              sizeof(TRAILER_SIGNATURE),
+                                              sizeof(TRAILER_SIGNATURE));
 }
 
 void
 proto_reg_handoff_dcerpc(void)
 {
-    heur_dissector_add("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
-    heur_dissector_add("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
-    heur_dissector_add("udp", dissect_dcerpc_dg, proto_dcerpc);
-    heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
-    heur_dissector_add("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
-    heur_dissector_add("http", dissect_dcerpc_cn_bs, proto_dcerpc);
+    heur_dissector_add("tcp", dissect_dcerpc_tcp, "DCE/RPC over TCP", "dcerpc_tcp", proto_dcerpc, HEURISTIC_ENABLE);
+    heur_dissector_add("netbios", dissect_dcerpc_cn_pk, "DCE/RPC over NetBios", "dcerpc_netbios", proto_dcerpc, HEURISTIC_ENABLE);
+    heur_dissector_add("udp", dissect_dcerpc_dg, "DCE/RPC over UDP", "dcerpc_udp", proto_dcerpc, HEURISTIC_ENABLE);
+    heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, "DCE/RPC over SMB", "dcerpc_smb_transact", proto_dcerpc, HEURISTIC_ENABLE);
+    heur_dissector_add("smb2_pipe_subdissectors", dissect_dcerpc_cn_smb2, "DCE/RPC over SMB2", "dcerpc_smb2", proto_dcerpc, HEURISTIC_ENABLE);
+    heur_dissector_add("http", dissect_dcerpc_cn_bs, "DCE/RPC over HTTP", "dcerpc_http", proto_dcerpc, HEURISTIC_ENABLE);
     dcerpc_smb_init(proto_dcerpc);
 
     guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
     guids_add_uuid(&uuid_ndr64, "64bit NDR");
-    guids_add_uuid(&uuid_bind_time_feature_nego_00, "bind time feature negotiation");
-    guids_add_uuid(&uuid_bind_time_feature_nego_01, "bind time feature negotiation");
-    guids_add_uuid(&uuid_bind_time_feature_nego_02, "bind time feature negotiation");
-    guids_add_uuid(&uuid_bind_time_feature_nego_03, "bind time feature negotiation");
     guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
 }