packet-dcerpc: let dissect_dcerpc_cn_auth() always dissect the whole auth_info
[metze/wireshark/wip.git] / epan / dissectors / packet-dcerpc.c
index 15c9fd983f4ee4f1242cc909f6f6499da349fb57..a9f931fbfc3a3871b82d939f55deb8e779e82819 100644 (file)
 
 #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/decode_as.h>
-#include <epan/dissectors/packet-dcerpc.h>
-#include <epan/dissectors/packet-dcerpc-nt.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);
@@ -54,21 +53,15 @@ 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[] = {
@@ -271,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" },
@@ -454,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;
@@ -473,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;
@@ -483,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;
@@ -573,6 +568,7 @@ static int hf_dcerpc_array_actual_count = -1;
 static int hf_dcerpc_op = -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;
@@ -584,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;
@@ -591,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;
@@ -602,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;
@@ -611,7 +670,14 @@ 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;
 /*
@@ -626,13 +692,13 @@ static GHashTable *dcerpc_binds = NULL;
 typedef struct _dcerpc_bind_key {
     conversation_t *conv;
     guint16         ctx_id;
-    guint16         smb_fid;
+    guint64         transport_salt;
 } dcerpc_bind_key;
 
 typedef struct _dcerpc_bind_value {
-    e_uuid_t uuid;
+    e_guid_t uuid;
     guint16  ver;
-    e_uuid_t transport;
+    e_guid_t transport;
 } dcerpc_bind_value;
 
 /* Extra data for DCERPC handling and tracking of context ids */
@@ -641,7 +707,7 @@ typedef struct _dcerpc_decode_as_data {
     int     dcetransporttype;     /**< Transport type
                                     * Value -1 means "not a DCERPC packet"
                                     */
-    guint16 dcetransportsalt;     /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
+    guint64 dcetransportsalt;     /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
 } dcerpc_decode_as_data;
 
 static dcerpc_decode_as_data*
@@ -706,7 +772,7 @@ dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
     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;
+    key->transport_salt = binding->transport_salt;
 
     /* add this entry to the bind table */
     g_hash_table_insert(dcerpc_binds, key, bind_value);
@@ -734,8 +800,8 @@ decode_dcerpc_binding_free(void *binding_in)
 {
     decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)binding_in;
 
-    g_free((void *) binding->addr_a.data);
-    g_free((void *) binding->addr_b.data);
+    free_address(&binding->addr_a);
+    free_address(&binding->addr_b);
     if (binding->ifname)
         g_string_free(binding->ifname, TRUE);
     g_free(binding);
@@ -794,7 +860,8 @@ dcerpc_prompt(packet_info *pinfo, gchar* result)
     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: %u\r\n", dcerpc_get_transport_salt(pinfo));
+    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);
@@ -810,13 +877,13 @@ dcerpc_value(packet_info *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);
+    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->smb_fid = dcerpc_get_transport_salt(pinfo);
+    binding->transport_salt = dcerpc_get_transport_salt(pinfo);
     binding->ifname = NULL;
     /*binding->uuid = NULL;*/
     binding->ver = 0;
@@ -835,7 +902,7 @@ 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;
 
-    /*dcerpc_uuid_key *k = key;*/
+    /*guid_key *k = key;*/
     dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
 
     if (strcmp(v->name, "(none)"))
@@ -863,13 +930,13 @@ decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer 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) &&
+        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->smb_fid == binding_b->smb_fid)
+        binding_a->transport_salt == binding_b->transport_salt)
     {
         /* equal */
         return 0;
@@ -881,9 +948,9 @@ decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b)
 
 /* remove a binding (looking the same way as the given one) */
 static gboolean
-decode_dcerpc_binding_reset(const char *name _U_, const gpointer pattern)
+decode_dcerpc_binding_reset(const char *name _U_, gconstpointer pattern)
 {
-    decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
+    const decode_dcerpc_bind_values_t *binding = (const decode_dcerpc_bind_values_t *)pattern;
     GSList *le;
     decode_dcerpc_bind_values_t *old_binding;
 
@@ -898,23 +965,23 @@ decode_dcerpc_binding_reset(const char *name _U_, const gpointer pattern)
 
     decode_dcerpc_bindings = g_slist_remove(decode_dcerpc_bindings, le->data);
 
-    g_free((void *) old_binding->addr_a.data);
-    g_free((void *) old_binding->addr_b.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, const gpointer pattern, gpointer handle, gchar* list_name)
+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;
-    dcerpc_uuid_key     *key = *((dcerpc_uuid_key**)handle);
+    guid_key     *key = *((guid_key**)handle);
 
 
     binding->ifname = g_string_new(list_name);
-    binding->uuid = key->uuid;
+    binding->uuid = key->guid;
     binding->ver = key->ver;
 
     /* remove a probably existing old binding */
@@ -923,8 +990,8 @@ dcerpc_decode_as_change(const char *name, const gpointer pattern, gpointer handl
     /* 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);
+    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);
@@ -974,7 +1041,7 @@ typedef struct _dcerpc_fragment_key {
     address src;
     address dst;
     guint32 id;
-    e_uuid_t act_id;
+    e_guid_t act_id;
 } dcerpc_fragment_key;
 
 static guint
@@ -986,9 +1053,9 @@ dcerpc_fragment_hash(gconstpointer k)
     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->act_id.data1;
+    hash_val += key->act_id.data2 << 16;
+    hash_val += key->act_id.data3;
 
     return hash_val;
 }
@@ -1004,9 +1071,9 @@ dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
       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))
+             && (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);
 }
 
@@ -1016,10 +1083,10 @@ 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;
+    const e_dce_dg_common_hdr_t *hdr = (const e_dce_dg_common_hdr_t *)data;
 
-    key->src = pinfo->src;
-    key->dst = pinfo->dst;
+    copy_address_shallow(&key->src, &pinfo->src);
+    copy_address_shallow(&key->dst, &pinfo->dst);
     key->id = id;
     key->act_id = hdr->act_id;
 
@@ -1032,10 +1099,10 @@ 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;
+    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);
+    copy_address(&key->src, &pinfo->src);
+    copy_address(&key->dst, &pinfo->dst);
     key->id = id;
     key->act_id = hdr->act_id;
 
@@ -1060,8 +1127,8 @@ dcerpc_fragment_free_persistent_key(gpointer ptr)
         /*
          * Free up the copies of the addresses from the old key.
          */
-        g_free((gpointer)key->src.data);
-        g_free((gpointer)key->dst.data);
+        free_address(&key->src);
+        free_address(&key->dst);
 
         g_slice_free(dcerpc_fragment_key, key);
     }
@@ -1139,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);
@@ -1264,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));
 
@@ -1279,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;
@@ -1342,12 +1765,12 @@ 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;
+    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 NULL;
@@ -1364,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
@@ -1373,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;
 }
 
 /*
@@ -1388,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;
 
 
@@ -1405,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
@@ -1415,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
@@ -1467,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,
@@ -1481,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;
 }
 
@@ -1500,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;
 }
 
@@ -1519,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;
 }
 
@@ -1542,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");
@@ -1553,6 +2166,7 @@ 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;
 }
 
@@ -1567,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
@@ -1592,6 +2206,7 @@ dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
     }
     if (pdata)
         *pdata = data;
+    tvb_ensure_bytes_exist(tvb, offset, 8);
     return offset+8;
 }
 
@@ -1609,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;
@@ -1620,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;
 }
 
@@ -1643,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;
@@ -1654,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;
 }
 
@@ -1667,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) {
@@ -1677,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) {
@@ -1711,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);
@@ -1723,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;
     }
@@ -1753,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
@@ -1810,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 {
+                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;
             }
         }
     }
@@ -1923,8 +2567,7 @@ 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);
+    if (len) {
         proto_tree_add_item(tree, di->hf_index, tvb, offset, (guint32)len,
                             ENC_NA);
     }
@@ -1964,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;
@@ -2150,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;
@@ -2499,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);
@@ -2518,12 +3158,10 @@ 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;
         }
 
@@ -2534,17 +3172,13 @@ dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
         /* 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);
+        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);
@@ -2565,20 +3199,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);
         /* 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);
+                                   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);
@@ -2600,12 +3231,10 @@ 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);
+                                 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);
@@ -2627,20 +3256,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);
         /* 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);
+                                   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);
@@ -2663,12 +3289,10 @@ 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;
         }
 
@@ -2679,17 +3303,14 @@ dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
 
         /* 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);
+                                   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);
@@ -2757,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)
-{
-    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"));
-        }
-    }
-}
-
-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)
-{
-    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;
-
-    dcerpc_dissect_fnct_t *volatile sub_dissect;
+dissect_sec_vt_bitmask(proto_tree *tree, tvbuff_t *tvb)
+{
+    proto_tree_add_bitmask(tree, tvb, 0,
+                           hf_dcerpc_sec_vt_bitmask,
+                           ett_dcerpc_sec_vt_bitmask,
+                           sec_vt_bitmask_fields,
+                           ENC_LITTLE_ENDIAN);
+}
 
-    key.uuid = info->call_data->uuid;
-    key.ver = info->call_data->ver;
+static void
+dissect_sec_vt_pcontext(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_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);
+    }
 
-    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.
-         */
+    proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
+                               offset, 16, &uuid, "Abstract Syntax: %s", uuid_name);
+    offset += 16;
 
-        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_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
+                        tvb, offset, 4, ENC_LITTLE_ENDIAN);
+    offset += 4;
 
-        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;
+    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);
     }
 
-    for (proc = sub_proto->procs; proc->name; proc++) {
-        if (proc->num == info->call_data->opnum) {
-            name = proc->name;
-            break;
-        }
-    }
+    proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
+                               offset, 16, &uuid, "Transfer Syntax: %s", uuid_name);
+    offset += 16;
 
-    col_set_str(pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
+    proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
+                        tvb, offset, 4, ENC_LITTLE_ENDIAN);
+    offset += 4;
 
-    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_item_set_len(ti, offset);
+}
 
-    sub_dissect = (info->ptype == PDU_REQ) ?
-        proc->dissect_rqst : proc->dissect_resp;
+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 (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_uint(tr, hf_dcerpc_packet_type, tvb, offset, 1, ptype);
+    offset += 1;
 
-        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);
-        }
+    proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 1, ENC_NA);
+    offset += 1;
 
-        /*
-         * 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);
+    proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 2, ENC_NA);
+    offset += 2;
 
-        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 */
+    tvb_memcpy(tvb, drep, offset, 4);
+    proto_tree_add_dcerpc_drep(tr, tvb, offset, drep, 4);
+    offset += 4;
 
-    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_uint32(tvb, offset, pinfo, tr, drep,
+                                   hf_dcerpc_cn_call_id, NULL);
 
-            init_ndr_pointer_list(info);
+    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tr, drep,
+                                   hf_dcerpc_cn_ctx_id, NULL);
 
-            length = tvb_length(decrypted_tvb);
-            reported_length = tvb_reported_length(decrypted_tvb);
+    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tr, drep,
+                                   hf_dcerpc_opnum, NULL);
 
-            /*
-             * 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;
+    proto_item_set_len(ti, offset);
+}
 
-                    /*
-                     * 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;
+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;
+    }
 
-                    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;
-            }
+    /* We need at least signature + the header of one command */
+    if (remaining < (int)(sizeof(TRAILER_SIGNATURE) + 4)) {
+         return -1;
+    }
 
-            if (sub_item) {
-                proto_item_set_len(sub_item, 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;
 
-            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"));
+    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");
+        }
 
-                    }
-                } 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;
-            }
+        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 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"));
-            }
+        offset += len;
+        remaining -= (4 + len);
 
-            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);
-            }
+        len_missalign = len & 1;
+
+        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;
         }
-    } else
-        show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
 
-    tap_queue_packet(dcerpc_tap, pinfo, info);
-    return 0;
+        if (cmd_end) {
+            break;
+        }
+    }
+
+    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;
 
@@ -3112,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
@@ -3141,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
@@ -3152,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;
@@ -3208,7 +3794,8 @@ 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)
 {
     dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
 
@@ -3222,7 +3809,8 @@ guint16 dcerpc_get_transport_salt(packet_info *pinfo)
     return 0;
 }
 
-void dcerpc_set_transport_salt(guint16 dcetransportsalt, packet_info *pinfo)
+void
+dcerpc_set_transport_salt(guint64 dcetransportsalt, packet_info *pinfo)
 {
     dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
 
@@ -3243,8 +3831,8 @@ 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;
@@ -3308,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_ep_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,
@@ -3345,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) {
@@ -3353,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_ep_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;
 
@@ -3395,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;
@@ -3409,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);
@@ -3422,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
@@ -3435,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;
@@ -3453,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;
@@ -3477,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,
@@ -3487,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,
@@ -3509,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_ep_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",
@@ -3530,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
@@ -3594,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) {
@@ -3614,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");
@@ -3676,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;
@@ -3690,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
@@ -3699,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));
@@ -3722,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
@@ -3753,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:
@@ -3764,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;
 
@@ -3785,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) {
@@ -3811,9 +4376,9 @@ 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);
         }
     }
 
@@ -3828,7 +4393,7 @@ 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;
@@ -3859,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_ep_str((e_guid_t *) &obj_id));
+                                       guid_to_str(wmem_packet_scope(), (e_guid_t *) &obj_id));
         }
         offset += 16;
     }
@@ -3868,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;
@@ -3883,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) {
@@ -3892,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)) {
@@ -3901,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;
@@ -3920,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 */
@@ -3933,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;
@@ -3963,7 +4528,7 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
             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;
@@ -3983,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
@@ -4004,7 +4565,7 @@ 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,
@@ -4031,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;
 
@@ -4047,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) {
@@ -4056,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;
                     }
                 }
             }
@@ -4081,17 +4642,18 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
             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_ep_str((e_guid_t *) &value->object_uuid));
+                                                guid_to_str(wmem_packet_scope(), (e_guid_t *) &value->object_uuid));
                 PROTO_ITEM_SET_GENERATED(pi);
             }
 
@@ -4104,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 {
@@ -4117,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
@@ -4177,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 */
@@ -4191,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) {
@@ -4200,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));
@@ -4209,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;
                 }
 
             }
@@ -4225,11 +4784,12 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
             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,
@@ -4239,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;
@@ -4275,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 {
@@ -4303,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 */
@@ -4350,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);
                                 }
                             }
                         }
@@ -4385,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));
 
@@ -4451,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;
@@ -4467,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;
@@ -4491,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;
         }
     }
@@ -4612,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:
@@ -4622,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:
@@ -4655,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:
@@ -4688,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,
@@ -4704,12 +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
@@ -4731,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));
@@ -4767,7 +5332,7 @@ 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;
     }
@@ -4816,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);
@@ -4878,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 */);
@@ -4901,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;
 
@@ -4927,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;
 
@@ -4943,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;
     }
@@ -5043,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;
@@ -5090,6 +5641,46 @@ dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *
     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_)
 {
@@ -5104,7 +5695,7 @@ dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
 {
     dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
 
-    decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
+    decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
     return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
 }
 
@@ -5114,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;
 
@@ -5134,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;
@@ -5156,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;
         }
     }
@@ -5294,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)
@@ -5322,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 {
@@ -5341,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,
@@ -5357,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");
@@ -5368,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,
@@ -5412,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;
@@ -5425,12 +6001,12 @@ 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) {
@@ -5439,7 +6015,7 @@ dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
         value->ver = hdr->if_ver;
         value->object_uuid = hdr->obj_id;
         value->opnum = hdr->opnum;
-        value->req_frame = pinfo->fd->num;
+        value->req_frame = pinfo->num;
         value->rep_frame = 0;
         value->max_ptr = 0;
         value->se_data = NULL;
@@ -5450,7 +6026,7 @@ dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
     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;
 
@@ -5487,35 +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) {
-        value = wmem_new(wmem_packet_scope(), dcerpc_call_value);
+        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->req_frame = 0;
-        value->rep_frame = pinfo->fd->num;
-        value->se_data = NULL;
-        value->private_data = NULL;
+        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;
 
@@ -5528,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 {
@@ -5565,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);
 /*    }*/
@@ -5579,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;
     }
 
@@ -5668,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);
 
@@ -5743,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_ep_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_ep_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,
@@ -5763,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_ep_str((e_guid_t *) &hdr.act_id));
+                                   guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.act_id));
     }
     offset += 16;
 
@@ -5922,33 +6464,26 @@ 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();
 }
 
+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
 proto_register_dcerpc(void)
 {
@@ -5963,7 +6498,7 @@ proto_register_dcerpc(void)
           { "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_id", FT_UINT64, BASE_HEX,
+          { "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 }},
@@ -5993,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,
@@ -6031,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,
@@ -6051,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,
@@ -6193,6 +6730,9 @@ proto_register_dcerpc(void)
         { &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 }},
@@ -6290,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,
@@ -6298,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,
@@ -6309,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 }},
@@ -6320,15 +6910,17 @@ 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",
-                                    /* XXX - DCE/RPC doesn't have a true (sub)dissector table, so
-                                     provide a "fake" one to fit the Decode As algorithm */
-                                    "dcerpc.fake",
+    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};
 
@@ -6341,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",
@@ -6361,25 +6956,27 @@ proto_register_dcerpc(void)
     dcerpc_tap = register_tap("dcerpc");
 
     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");
 }