SMB2 ioctl FSCTL_OFFLOAD_WRITE
[metze/wireshark/wip.git] / epan / dissectors / packet-smb2.c
index a38e9404ebe9ba3889834aa3c695d7aaed5df944..bf8f393ca6484a3b354aaf3b36fd9e1d3570f50c 100644 (file)
 #include <epan/prefs.h>
 #include <epan/expert.h>
 #include <epan/tap.h>
+#include <epan/srt_table.h>
 #include <epan/aftypes.h>
 #include <epan/to_str.h>
 #include <epan/asn1.h>
+#include <epan/reassemble.h>
 
 #include "packet-smb2.h"
 #include "packet-ntlmssp.h"
 #include "packet-smb-common.h"
 #include "packet-dcerpc-nt.h"
 
-/* Use libgcrypt for cipher libraries. */
-#ifdef HAVE_LIBGCRYPT
 #include <wsutil/wsgcrypt.h>
-#endif /* HAVE_LIBGCRYPT */
+
+#define NT_STATUS_PENDING      0x00000103
 
 void proto_register_smb2(void);
 void proto_reg_handoff_smb2(void);
@@ -76,11 +77,13 @@ static int hf_smb2_flags_dfs_op = -1;
 static int hf_smb2_flags_chained = -1;
 static int hf_smb2_flags_signature = -1;
 static int hf_smb2_flags_replay_operation = -1;
+static int hf_smb2_flags_priority_mask = -1;
 static int hf_smb2_chain_offset = -1;
 static int hf_smb2_security_blob = -1;
 static int hf_smb2_ioctl_in_data = -1;
 static int hf_smb2_ioctl_out_data = -1;
 static int hf_smb2_unknown = -1;
+static int hf_smb2_root_directory_mbz = -1;
 static int hf_smb2_twrp_timestamp = -1;
 static int hf_smb2_mxac_timestamp = -1;
 static int hf_smb2_mxac_status = -1;
@@ -96,6 +99,7 @@ static int hf_smb2_current_time = -1;
 static int hf_smb2_boot_time = -1;
 static int hf_smb2_filename = -1;
 static int hf_smb2_filename_len = -1;
+static int hf_smb2_replace_if = -1;
 static int hf_smb2_nlinks = -1;
 static int hf_smb2_delete_pending = -1;
 static int hf_smb2_is_directory = -1;
@@ -117,6 +121,7 @@ static int hf_smb2_infolevel = -1;
 static int hf_smb2_infolevel_file_info = -1;
 static int hf_smb2_infolevel_fs_info = -1;
 static int hf_smb2_infolevel_sec_info = -1;
+static int hf_smb2_infolevel_posix_info = -1;
 static int hf_smb2_max_response_size = -1;
 static int hf_smb2_max_ioctl_in_size = -1;
 static int hf_smb2_max_ioctl_out_size = -1;
@@ -162,6 +167,11 @@ static int hf_smb2_write_remaining = -1;
 static int hf_smb2_read_length = -1;
 static int hf_smb2_read_remaining = -1;
 static int hf_smb2_file_offset = -1;
+static int hf_smb2_qfr_length = -1;
+static int hf_smb2_qfr_usage = -1;
+static int hf_smb2_qfr_flags = -1;
+static int hf_smb2_qfr_total_region_entry_count = -1;
+static int hf_smb2_qfr_region_entry_count = -1;
 static int hf_smb2_read_data = -1;
 static int hf_smb2_disposition_delete_on_close = -1;
 static int hf_smb2_create_disposition = -1;
@@ -194,6 +204,23 @@ static int hf_smb2_ioctl_function = -1;
 static int hf_smb2_ioctl_function_device = -1;
 static int hf_smb2_ioctl_function_access = -1;
 static int hf_smb2_ioctl_function_function = -1;
+static int hf_smb2_fsctl_pipe_wait_timeout = -1;
+static int hf_smb2_fsctl_pipe_wait_name = -1;
+
+static int hf_smb2_fsctl_odx_token_type = -1;
+static int hf_smb2_fsctl_odx_token_idlen = -1;
+static int hf_smb2_fsctl_odx_token_idraw = -1;
+static int hf_smb2_fsctl_odx_token_ttl = -1;
+static int hf_smb2_fsctl_odx_size = -1;
+static int hf_smb2_fsctl_odx_flags = -1;
+static int hf_smb2_fsctl_odx_file_offset = -1;
+static int hf_smb2_fsctl_odx_copy_length = -1;
+static int hf_smb2_fsctl_odx_xfer_length = -1;
+static int hf_smb2_fsctl_odx_token_offset = -1;
+
+static int hf_smb2_fsctl_sparse_flag = -1;
+static int hf_smb2_fsctl_range_offset = -1;
+static int hf_smb2_fsctl_range_length = -1;
 static int hf_smb2_ioctl_function_method = -1;
 static int hf_smb2_ioctl_resiliency_timeout = -1;
 static int hf_smb2_ioctl_resiliency_reserved = -1;
@@ -302,6 +329,9 @@ static int hf_smb2_close_pq_attrib = -1;
 static int hf_smb2_notify_watch_tree = -1;
 static int hf_smb2_output_buffer_len = -1;
 static int hf_smb2_notify_out_data = -1;
+static int hf_smb2_notify_info = -1;
+static int hf_smb2_notify_next_offset = -1;
+static int hf_smb2_notify_action = -1;
 static int hf_smb2_find_flags = -1;
 static int hf_smb2_find_flags_restart_scans = -1;
 static int hf_smb2_find_flags_single_entry = -1;
@@ -339,10 +369,39 @@ static int hf_smb2_svhdx_open_device_context_originator_flags = -1;
 static int hf_smb2_svhdx_open_device_context_open_request_id = -1;
 static int hf_smb2_svhdx_open_device_context_initiator_host_name_len = -1;
 static int hf_smb2_svhdx_open_device_context_initiator_host_name = -1;
+static int hf_smb2_posix_v1_version = -1;
+static int hf_smb2_posix_v1_request = -1;
+static int hf_smb2_posix_v1_supported_features = -1;
+static int hf_smb2_posix_v1_posix_lock = -1;
+static int hf_smb2_posix_v1_posix_file_semantics = -1;
+static int hf_smb2_posix_v1_posix_utf8_paths = -1;
+static int hf_smb2_posix_v1_case_sensitive = -1;
+static int hf_smb2_posix_v1_posix_will_convert_nt_acls = -1;
+static int hf_smb2_posix_v1_posix_fileinfo = -1;
+static int hf_smb2_posix_v1_posix_acls = -1;
+static int hf_smb2_posix_v1_rich_acls = -1;
+static int hf_smb2_aapl_command_code = -1;
+static int hf_smb2_aapl_reserved = -1;
+static int hf_smb2_aapl_server_query_bitmask = -1;
+static int hf_smb2_aapl_server_query_bitmask_server_caps = -1;
+static int hf_smb2_aapl_server_query_bitmask_volume_caps = -1;
+static int hf_smb2_aapl_server_query_bitmask_model_info = -1;
+static int hf_smb2_aapl_server_query_caps = -1;
+static int hf_smb2_aapl_server_query_caps_supports_read_dir_attr = -1;
+static int hf_smb2_aapl_server_query_caps_supports_osx_copyfile = -1;
+static int hf_smb2_aapl_server_query_caps_unix_based = -1;
+static int hf_smb2_aapl_server_query_caps_supports_nfs_ace = -1;
+static int hf_smb2_aapl_server_query_volume_caps = -1;
+static int hf_smb2_aapl_server_query_volume_caps_support_resolve_id = -1;
+static int hf_smb2_aapl_server_query_volume_caps_case_sensitive = -1;
+static int hf_smb2_aapl_server_query_volume_caps_supports_full_sync = -1;
+static int hf_smb2_aapl_server_query_model_string = -1;
+static int hf_smb2_aapl_server_query_server_path = -1;
 static int hf_smb2_error_byte_count = -1;
 static int hf_smb2_error_data = -1;
 static int hf_smb2_error_reserved = -1;
 static int hf_smb2_reserved = -1;
+static int hf_smb2_reserved_random = -1;
 static int hf_smb2_transform_signature = -1;
 static int hf_smb2_transform_nonce = -1;
 static int hf_smb2_transform_msg_size = -1;
@@ -353,6 +412,25 @@ static int hf_smb2_transform_encrypted_data = -1;
 static int hf_smb2_server_component_smb2 = -1;
 static int hf_smb2_server_component_smb2_transform = -1;
 static int hf_smb2_truncated = -1;
+static int hf_smb2_pipe_fragments = -1;
+static int hf_smb2_pipe_fragment = -1;
+static int hf_smb2_pipe_fragment_overlap = -1;
+static int hf_smb2_pipe_fragment_overlap_conflict = -1;
+static int hf_smb2_pipe_fragment_multiple_tails = -1;
+static int hf_smb2_pipe_fragment_too_long_fragment = -1;
+static int hf_smb2_pipe_fragment_error = -1;
+static int hf_smb2_pipe_fragment_count = -1;
+static int hf_smb2_pipe_reassembled_in = -1;
+static int hf_smb2_pipe_reassembled_length = -1;
+static int hf_smb2_pipe_reassembled_data = -1;
+static int hf_smb2_cchunk_resume_key = -1;
+static int hf_smb2_cchunk_count = -1;
+static int hf_smb2_cchunk_src_offset = -1;
+static int hf_smb2_cchunk_dst_offset = -1;
+static int hf_smb2_cchunk_xfer_len = -1;
+static int hf_smb2_cchunk_chunks_written = -1;
+static int hf_smb2_cchunk_bytes_written = -1;
+static int hf_smb2_cchunk_total_written = -1;
 
 static gint ett_smb2 = -1;
 static gint ett_smb2_olb = -1;
@@ -410,8 +488,10 @@ static gint ett_smb2_create_rep_flags = -1;
 static gint ett_smb2_share_caps = -1;
 static gint ett_smb2_ioctl_flags = -1;
 static gint ett_smb2_ioctl_network_interface = -1;
+static gint ett_smb2_fsctl_range_data = -1;
 static gint ett_windows_sockaddr = -1;
 static gint ett_smb2_close_flags = -1;
+static gint ett_smb2_notify_info = -1;
 static gint ett_smb2_notify_flags = -1;
 static gint ett_smb2_write_flags = -1;
 static gint ett_smb2_rdma_v1 = -1;
@@ -420,6 +500,14 @@ static gint ett_smb2_DH2C_buffer = -1;
 static gint ett_smb2_dh2x_flags = -1;
 static gint ett_smb2_APP_INSTANCE_buffer = -1;
 static gint ett_smb2_svhdx_open_device_context = -1;
+static gint ett_smb2_posix_v1_request = -1;
+static gint ett_smb2_posix_v1_response = -1;
+static gint ett_smb2_posix_v1_supported_features = -1;
+static gint ett_smb2_aapl_create_context_request = -1;
+static gint ett_smb2_aapl_server_query_bitmask = -1;
+static gint ett_smb2_aapl_server_query_caps = -1;
+static gint ett_smb2_aapl_create_context_response = -1;
+static gint ett_smb2_aapl_server_query_volume_caps = -1;
 static gint ett_smb2_integrity_flags = -1;
 static gint ett_smb2_find_flags = -1;
 static gint ett_smb2_file_directory_info = -1;
@@ -432,6 +520,11 @@ static gint ett_smb2_lock_flags = -1;
 static gint ett_smb2_transform_enc_alg = -1;
 static gint ett_smb2_buffercode = -1;
 static gint ett_smb2_ioctl_network_interface_capabilities = -1;
+static gint ett_qfr_entry = -1;
+static gint ett_smb2_pipe_fragment = -1;
+static gint ett_smb2_pipe_fragments = -1;
+static gint ett_smb2_cchunk_entry = -1;
+static gint ett_smb2_fsctl_odx_token = -1;
 
 static expert_field ei_smb2_invalid_length = EI_INIT;
 static expert_field ei_smb2_bad_response = EI_INIT;
@@ -443,15 +536,34 @@ static dissector_handle_t gssapi_handle  = NULL;
 static dissector_handle_t ntlmssp_handle = NULL;
 static dissector_handle_t rsvd_handle = NULL;
 
-static heur_dissector_list_t smb2_heur_subdissector_list;
+static heur_dissector_list_t smb2_pipe_subdissector_list;
+
+static const fragment_items smb2_pipe_frag_items = {
+       &ett_smb2_pipe_fragment,
+       &ett_smb2_pipe_fragments,
+       &hf_smb2_pipe_fragments,
+       &hf_smb2_pipe_fragment,
+       &hf_smb2_pipe_fragment_overlap,
+       &hf_smb2_pipe_fragment_overlap_conflict,
+       &hf_smb2_pipe_fragment_multiple_tails,
+       &hf_smb2_pipe_fragment_too_long_fragment,
+       &hf_smb2_pipe_fragment_error,
+       &hf_smb2_pipe_fragment_count,
+       &hf_smb2_pipe_reassembled_in,
+       &hf_smb2_pipe_reassembled_length,
+       &hf_smb2_pipe_reassembled_data,
+       "Fragments"
+};
 
 #define SMB2_CLASS_FILE_INFO   0x01
 #define SMB2_CLASS_FS_INFO     0x02
 #define SMB2_CLASS_SEC_INFO    0x03
+#define SMB2_CLASS_POSIX_INFO  0x80
 static const value_string smb2_class_vals[] = {
        { SMB2_CLASS_FILE_INFO, "FILE_INFO"},
        { SMB2_CLASS_FS_INFO,   "FS_INFO"},
        { SMB2_CLASS_SEC_INFO,  "SEC_INFO"},
+       { SMB2_CLASS_POSIX_INFO, "POSIX_INFO"},
        { 0, NULL }
 };
 
@@ -549,6 +661,17 @@ static const value_string smb2_sec_info_levels[] = {
 };
 static value_string_ext smb2_sec_info_levels_ext = VALUE_STRING_EXT_INIT(smb2_sec_info_levels);
 
+static const value_string smb2_posix_info_levels[] = {
+       { 0,    "QueryFileUnixBasic" },
+       { 1,    "QueryFileUnixLink" },
+       { 3,    "QueryFileUnixHLink" },
+       { 5,    "QueryFileUnixXAttr" },
+       { 0x0B, "QueryFileUnixInfo2" },
+       { 0, NULL }
+};
+
+static value_string_ext smb2_posix_info_levels_ext = VALUE_STRING_EXT_INIT(smb2_posix_info_levels);
+
 #define SMB2_FIND_DIRECTORY_INFO         0x01
 #define SMB2_FIND_FULL_DIRECTORY_INFO    0x02
 #define SMB2_FIND_BOTH_DIRECTORY_INFO    0x03
@@ -575,6 +698,53 @@ static const value_string smb2_negotiate_context_types[] = {
        { 0, NULL }
 };
 
+#define SMB2_NUM_PROCEDURES     256
+
+static void
+smb2stat_init(struct register_srt* srt _U_, GArray* srt_array, srt_gui_init_cb gui_callback, void* gui_data)
+{
+       srt_stat_table *smb2_srt_table;
+       guint32 i;
+
+       smb2_srt_table = init_srt_table("SMB2", NULL, srt_array, SMB2_NUM_PROCEDURES, "Commands", "smb2.cmd", gui_callback, gui_data, NULL);
+       for (i = 0; i < SMB2_NUM_PROCEDURES; i++)
+       {
+               init_srt_table_row(smb2_srt_table, i, val_to_str_ext_const(i, &smb2_cmd_vals_ext, "<unknown>"));
+       }
+}
+
+static int
+smb2stat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
+{
+       guint i = 0;
+       srt_stat_table *smb2_srt_table;
+       srt_data_t *data = (srt_data_t *)pss;
+       const smb2_info_t *si=(const smb2_info_t *)prv;
+
+       /* we are only interested in response packets */
+       if(!(si->flags&SMB2_FLAGS_RESPONSE)){
+               return 0;
+       }
+       /* if we haven't seen the request, just ignore it */
+       if(!si->saved){
+               return 0;
+       }
+
+       /* SMB2 SRT can be very inaccurate in the presence of retransmissions. Retransmitted responses
+        * not only add additional (bogus) transactions but also the latency associated with them.
+        * This can greatly inflate the maximum and average SRT stats especially in the case of
+        * retransmissions triggered by the expiry of the rexmit timer (RTOs). Only calculating SRT
+        * for the last received response accomplishes this goal without requiring the TCP pref
+        * "Do not call subdissectors for error packets" to be set. */
+       if ((si->saved->frame_req == 0) || (si->saved->frame_res != pinfo->num))
+               return 0;
+
+       smb2_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
+       add_srt_table_data(smb2_srt_table, si->opcode, &si->saved->req_time, pinfo);
+       return 1;
+}
+
+
 static const gint8 zeros[NTLMSSP_KEY_LEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 
 /* ExportObject preferences variable */
@@ -670,6 +840,54 @@ smb2_sesid_info_hash(gconstpointer k)
        return hash;
 }
 
+/*
+ * For File IDs of a specific conversation.
+ * This keeps track of fid to name mapping and application level conversations
+ * over named pipes.
+ *
+ * This handles implementation bugs, where the fid_persitent is 0 or
+ * the fid_persitent/fid_volative is not unique per conversation.
+ */
+static gint
+smb2_fid_info_equal(gconstpointer k1, gconstpointer k2)
+{
+       const smb2_fid_info_t *key1 = (const smb2_fid_info_t *)k1;
+       const smb2_fid_info_t *key2 = (const smb2_fid_info_t *)k2;
+
+       if (key1->fid_persistent != key2->fid_persistent) {
+               return 0;
+       };
+
+       if (key1->fid_volatile != key2->fid_volatile) {
+               return 0;
+       };
+
+       if (key1->sesid != key2->sesid) {
+               return 0;
+       };
+
+       if (key1->tid != key2->tid) {
+               return 0;
+       };
+
+       return 1;
+}
+
+static guint
+smb2_fid_info_hash(gconstpointer k)
+{
+       const smb2_fid_info_t *key = (const smb2_fid_info_t *)k;
+       guint32 hash;
+
+       if (key->fid_persistent != 0) {
+               hash = (guint32)( ((key->fid_persistent>>32)&0xffffffff)+((key->fid_persistent)&0xffffffff) );
+       } else {
+               hash = (guint32)( ((key->fid_volatile>>32)&0xffffffff)+((key->fid_volatile)&0xffffffff) );
+       }
+
+       return hash;
+}
+
 /* Callback for destroying the glib hash tables associated with a conversation
  * struct. */
 static gboolean
@@ -680,6 +898,7 @@ smb2_conv_destroy(wmem_allocator_t *allocator _U_, wmem_cb_event_t event _U_,
 
        g_hash_table_destroy(conv->matched);
        g_hash_table_destroy(conv->unmatched);
+       g_hash_table_destroy(conv->fids);
        g_hash_table_destroy(conv->sesids);
        g_hash_table_destroy(conv->files);
 
@@ -790,7 +1009,7 @@ feed_eo_smb2(tvbuff_t * tvb,packet_info *pinfo,smb2_info_t * si, guint16 dataoff
 
        /* Try to get file id and filename */
        file_id=policy_hnd_to_file_id(&si->saved->policy_hnd);
-       dcerpc_fetch_polhnd_data(&si->saved->policy_hnd, &fid_name, NULL, &open_frame, &close_frame, pinfo->fd->num);
+       dcerpc_fetch_polhnd_data(&si->saved->policy_hnd, &fid_name, NULL, &open_frame, &close_frame, pinfo->num);
        if (fid_name && g_strcmp0(fid_name,"File: ")!=0) {
                auxstring=fid_name;
                /* Remove "File: " from filename */
@@ -832,7 +1051,7 @@ feed_eo_smb2(tvbuff_t * tvb,packet_info *pinfo,smb2_info_t * si, guint16 dataoff
        }
 
        /* packet number */
-       eo_info->pkt_num = pinfo->fd->num;
+       eo_info->pkt_num = pinfo->num;
 
        /* fid type */
        if (si->eo_file_info->attr_mask & SMB2_FLAGS_ATTR_DIRECTORY) {
@@ -957,7 +1176,7 @@ dissect_smb2_olb_string(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *t
        offset = olb->off;
        len = olb->len;
        off = olb->off;
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
 
 
        /* sanity check */
@@ -1086,7 +1305,7 @@ dissect_smb2_olb_buffer(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *t
                return;
        }
 
-       sub_tvb = tvb_new_subset(tvb, off, MIN((int)len, tvb_length_remaining(tvb, off)), len);
+       sub_tvb = tvb_new_subset(tvb, off, MIN((int)len, tvb_captured_length_remaining(tvb, off)), len);
 
        dissector(sub_tvb, pinfo, sub_tree, si);
 }
@@ -1140,6 +1359,11 @@ static const true_false_string tfs_flags_replay_operation = {
        "This is NOT a replay operation"
 };
 
+static const true_false_string tfs_flags_priority_mask = {
+       "This pdu contains a PRIORITY",
+       "This pdu does NOT contain a PRIORITY1"
+};
+
 static const true_false_string tfs_cap_dfs = {
        "This host supports DFS",
        "This host does NOT support DFS"
@@ -1185,12 +1409,57 @@ static const true_false_string tfs_smb2_ioctl_network_interface_capability_rdma
        "This interface does not support RDMA"
 };
 
+static const value_string file_region_usage_vals[] = {
+       { 0x00000001, "FILE_REGION_USAGE_VALID_CACHED_DATA" },
+       { 0, NULL }
+};
+
 static const value_string originator_flags_vals[] = {
        { 1, "SVHDX_ORIGINATOR_PVHDPARSER" },
        { 4, "SVHDX_ORIGINATOR_VHDMP" },
        { 0, NULL }
 };
 
+static const value_string posix_locks_vals[] = {
+       { 1, "POSIX_V1_POSIX_LOCK" },
+       { 0, NULL }
+};
+
+static const value_string posix_utf8_paths_vals[] = {
+       { 1, "POSIX_V1_UTF8_PATHS" },
+       { 0, NULL }
+};
+
+static const value_string posix_file_semantics_vals[] = {
+       { 1, "POSIX_V1_POSIX_FILE_SEMANTICS" },
+       { 0, NULL }
+};
+
+static const value_string posix_case_sensitive_vals[] = {
+       { 1, "POSIX_V1_CASE_SENSITIVE" },
+       { 0, NULL }
+};
+
+static const value_string posix_will_convert_ntacls_vals[] = {
+       { 1, "POSIX_V1_WILL_CONVERT_NT_ACLS" },
+       { 0, NULL }
+};
+
+static const value_string posix_fileinfo_vals[] = {
+       { 1, "POSIX_V1_POSIX_FILEINFO" },
+       { 0, NULL }
+};
+
+static const value_string posix_acls_vals[] = {
+       { 1, "POSIX_V1_POSIX_ACLS" },
+       { 0, NULL }
+};
+
+static const value_string posix_rich_acls_vals[] = {
+       { 1, "POSIX_V1_RICH_ACLS" },
+       { 0, NULL }
+};
+
 static const value_string compression_format_vals[] = {
        { 0, "COMPRESSION_FORMAT_NONE" },
        { 1, "COMPRESSION_FORMAT_DEFAULT" },
@@ -1208,6 +1477,7 @@ static const value_string checksum_algorithm_vals[] = {
 /* Note: All uncommented are "dissector not implemented" */
 static const value_string smb2_ioctl_vals[] = {
        {0x00060194, "FSCTL_DFS_GET_REFERRALS"},                      /* dissector implemented */
+       {0x000601B0, "FSCTL_DFS_GET_REFERRALS_EX"},
        {0x00090000, "FSCTL_REQUEST_OPLOCK_LEVEL_1"},
        {0x00090004, "FSCTL_REQUEST_OPLOCK_LEVEL_2"},
        {0x00090008, "FSCTL_REQUEST_BATCH_OPLOCK"},
@@ -1241,8 +1511,10 @@ static const value_string smb2_ioctl_vals[] = {
        {0x0009008F, "FSCTL_FIND_FILES_BY_SID"},
        {0x00090097, "FSCTL_DUMP_PROPERTY_DATA"},
        {0x0009009C, "FSCTL_GET_OBJECT_ID"},                          /* dissector implemented */
+       {0x000900A4, "FSCTL_SET_REPARSE_POINT"},
        {0x000900A8, "FSCTL_GET_REPARSE_POINT"},
        {0x000900C0, "FSCTL_CREATE_OR_GET_OBJECT_ID"},                /* dissector implemented */
+       {0x000900C4, "FSCTL_SET_SPARSE"},                             /* dissector implemented */
        {0x000900D4, "FSCTL_SET_ENCRYPTION"},
        {0x000900DB, "FSCTL_ENCRYPTION_FSCTL_IO"},
        {0x000900DF, "FSCTL_WRITE_RAW_ENCRYPTED"},
@@ -1250,8 +1522,8 @@ static const value_string smb2_ioctl_vals[] = {
        {0x000900F0, "FSCTL_EXTEND_VOLUME"},
        {0x0009027C, "FSCTL_GET_INTEGRITY_INFORMATION"},
        {0x00090284, "FSCTL_QUERY_FILE_REGIONS"},
-       {0x00090300, "FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT"},
-       {0x00090304, "FSCTL_SVHDX_SYNC_TUNNEL_REQUEST"},
+       {0x00090300, "FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT"},      /* dissector implemented */
+       {0x00090304, "FSCTL_SVHDX_SYNC_TUNNEL_REQUEST"},              /* dissector implemented */
        {0x00090308, "FSCTL_SVHDX_SET_INITIATOR_INFORMATION"},
        {0x0009030C, "FSCTL_SET_EXTERNAL_BACKING"},
        {0x00090310, "FSCTL_GET_EXTERNAL_BACKING"},
@@ -1261,27 +1533,31 @@ static const value_string smb2_ioctl_vals[] = {
        {0x000940B3, "FSCTL_ENUM_USN_DATA"},
        {0x000940B7, "FSCTL_SECURITY_ID_CHECK"},
        {0x000940BB, "FSCTL_READ_USN_JOURNAL"},
-       {0x000940CF, "FSCTL_QUERY_ALLOCATED_RANGES"},
+       {0x000940CF, "FSCTL_QUERY_ALLOCATED_RANGES"},                 /* dissector implemented */
        {0x000940E7, "FSCTL_CREATE_USN_JOURNAL"},
        {0x000940EB, "FSCTL_READ_FILE_USN_DATA"},
        {0x000940EF, "FSCTL_WRITE_USN_CLOSE_RECORD"},
+       {0x00094264, "FSCTL_OFFLOAD_READ"},                           /* dissector implemented */
        {0x00098098, "FSCTL_SET_OBJECT_ID"},                          /* dissector implemented */
-       {0x000980A0, "FSCTL_DELETE_OBJECT_ID"}, /* no data in/out */  /* dissector implemented */
+       {0x000980A0, "FSCTL_DELETE_OBJECT_ID"}, /* no data in/out */
        {0x000980A4, "FSCTL_SET_REPARSE_POINT"},
        {0x000980AC, "FSCTL_DELETE_REPARSE_POINT"},
        {0x000980BC, "FSCTL_SET_OBJECT_ID_EXTENDED"},                 /* dissector implemented */
-       {0x000980C4, "FSCTL_SET_SPARSE"},
-       {0x000980C8, "FSCTL_SET_ZERO_DATA"},
+       {0x000980C8, "FSCTL_SET_ZERO_DATA"},                          /* dissector implemented */
        {0x000980D0, "FSCTL_ENABLE_UPGRADE"},
+       {0x00098208, "FSCTL_FILE_LEVEL_TRIM"},
+       {0x00098268, "FSCTL_OFFLOAD_WRITE"},                          /* dissector implemented */
        {0x0009C040, "FSCTL_SET_COMPRESSION"},                        /* dissector implemented */
-       {0x0009C280, "FSCTL_SET_INTEGRITY_INFORMATION"},
+       {0x0009C280, "FSCTL_SET_INTEGRITY_INFORMATION"},              /* dissector implemented */
+       {0x00110018, "FSCTL_PIPE_WAIT"},                              /* dissector implemented */
+       {0x0011400C, "FSCTL_PIPE_PEEK"},
        {0x0011C017, "FSCTL_PIPE_TRANSCEIVE"},                        /* dissector implemented */
        {0x00140078, "FSCTL_SRV_REQUEST_RESUME_KEY"},
        {0x001401D4, "FSCTL_LMR_REQUEST_RESILIENCY"},                 /* dissector implemented */
        {0x001401FC, "FSCTL_QUERY_NETWORK_INTERFACE_INFO"},           /* dissector implemented */
        {0x00140200, "FSCTL_VALIDATE_NEGOTIATE_INFO_224"},            /* dissector implemented */
        {0x00140204, "FSCTL_VALIDATE_NEGOTIATE_INFO"},                /* dissector implemented */
-       {0x00144064, "FSCTL_GET_SHADOW_COPY_DATA"},                   /* dissector implemented */
+       {0x00144064, "FSCTL_SRV_ENUMERATE_SNAPSHOTS"},                /* dissector implemented */
        {0x001440F2, "FSCTL_SRV_COPYCHUNK"},
        {0x001441bb, "FSCTL_SRV_READ_HASH"},
        {0x001480F2, "FSCTL_SRV_COPYCHUNK_WRITE"},
@@ -1453,16 +1729,31 @@ dissect_smb2_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset
        char       *fid_name;
        guint32     open_frame = 0, close_frame = 0;
        smb2_eo_file_info_t     *eo_file_info;
+       smb2_fid_info_t sfi_key;
+       smb2_fid_info_t *sfi = NULL;
+
+       sfi_key.fid_persistent = tvb_get_letoh64(tvb, offset);
+       sfi_key.fid_volatile = tvb_get_letoh64(tvb, offset+8);
+       sfi_key.sesid = si->sesid;
+       sfi_key.tid = si->tid;
+       sfi_key.name = NULL;
 
        di.conformant_run = 0;
        /* we need di->call_data->flags.NDR64 == 0 */
        di.call_data = &call_data;
-       di.dcerpc_procedure_name = "";
 
        switch (mode) {
        case FID_MODE_OPEN:
                offset = dissect_nt_guid_hnd(tvb, offset, pinfo, tree, &di, drep, hf_smb2_fid, &policy_hnd, &hnd_item, TRUE, FALSE);
                if (!pinfo->fd->flags.visited) {
+                       sfi = wmem_new(wmem_file_scope(), smb2_fid_info_t);
+                       *sfi = sfi_key;
+                       if (si->saved && si->saved->extra_info_type == SMB2_EI_FILENAME) {
+                               sfi->name = wmem_strdup(wmem_file_scope(), (char *)si->saved->extra_info);
+                       } else {
+                               sfi->name = wmem_strdup_printf(wmem_file_scope(), "[unknown]");
+                       }
+
                        if (si->saved && si->saved->extra_info_type == SMB2_EI_FILENAME) {
                                fid_name = wmem_strdup_printf(wmem_file_scope(), "File: %s", (char *)si->saved->extra_info);
                        } else {
@@ -1471,8 +1762,14 @@ dissect_smb2_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset
                        dcerpc_store_polhnd_name(&policy_hnd, pinfo,
                                                  fid_name);
 
+                       g_hash_table_insert(si->conv->fids, sfi, sfi);
+                       si->file = sfi;
+
                        /* If needed, create the file entry and save the policy hnd */
-                       if (si->saved) { si->saved->policy_hnd = policy_hnd; }
+                       if (si->saved) {
+                               si->saved->file = sfi;
+                               si->saved->policy_hnd = policy_hnd;
+                       }
 
                        if (si->conv) {
                                eo_file_info = (smb2_eo_file_info_t *)g_hash_table_lookup(si->conv->files,&policy_hnd);
@@ -1497,15 +1794,20 @@ dissect_smb2_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset
                break;
        }
 
-       if (dcerpc_fetch_polhnd_data(&policy_hnd, &fid_name, NULL, &open_frame, &close_frame, pinfo->fd->num)) {
-               /* put the filename in col_info */
-               if (fid_name) {
+       si->file = (smb2_fid_info_t *)g_hash_table_lookup(si->conv->fids, &sfi_key);
+       if (si->file) {
+               if (si->saved) {
+                       si->saved->file = si->file;
+               }
+               if (si->file->name) {
                        if (hnd_item) {
-                               proto_item_append_text(hnd_item, " %s", fid_name);
+                               proto_item_append_text(hnd_item, " File: %s", si->file->name);
                        }
-                       col_append_fstr(pinfo->cinfo, COL_INFO, " %s", fid_name);
+                       col_append_fstr(pinfo->cinfo, COL_INFO, " File: %s", si->file->name);
                }
+       }
 
+       if (dcerpc_fetch_polhnd_data(&policy_hnd, &fid_name, NULL, &open_frame, &close_frame, pinfo->num)) {
                /* look for the eo_file_info */
                if (!si->eo_file_info) {
                        if (si->saved) { si->saved->policy_hnd = policy_hnd; }
@@ -1605,16 +1907,12 @@ dissect_smb2_file_all_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *pa
 
        /* file name length */
        length = tvb_get_letohs(tvb, offset);
-       proto_tree_add_item(tree, hf_smb2_filename_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
-       offset += 2;
-
-       /* some unknown bytes */
-       proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 2, ENC_NA);
-       offset += 2;
+       proto_tree_add_item(tree, hf_smb2_filename_len, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
 
        /* file name */
        if (length) {
-               bc = tvb_length_remaining(tvb, offset);
+               bc = tvb_captured_length_remaining(tvb, offset);
                name = get_unicode_or_ascii_string(tvb, &offset,
                        TRUE, &length, TRUE, TRUE, &bc);
                if (name) {
@@ -1625,7 +1923,6 @@ dissect_smb2_file_all_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *pa
        }
        offset += length;
 
-
        return offset;
 }
 
@@ -1643,7 +1940,7 @@ dissect_smb2_file_allocation_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_t
                tree = proto_item_add_subtree(item, ett_smb2_file_allocation_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qsfi_SMB_FILE_ALLOCATION_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1662,7 +1959,7 @@ dissect_smb2_file_endoffile_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tr
                tree = proto_item_add_subtree(item, ett_smb2_file_endoffile_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qsfi_SMB_FILE_ENDOFFILE_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1681,7 +1978,7 @@ dissect_smb2_file_alternate_name_info(tvbuff_t *tvb, packet_info *pinfo _U_, pro
                tree = proto_item_add_subtree(item, ett_smb2_file_alternate_name_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfi_SMB_FILE_NAME_INFO(tvb, pinfo, tree, offset, &bc, &trunc, /* XXX assumption hack */ TRUE);
 
        return offset;
@@ -1734,7 +2031,7 @@ dissect_smb2_file_standard_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tre
                tree = proto_item_add_subtree(item, ett_smb2_file_standard_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfi_SMB_FILE_STANDARD_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1752,7 +2049,7 @@ dissect_smb2_file_internal_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tre
                tree = proto_item_add_subtree(item, ett_smb2_file_internal_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfi_SMB_FILE_INTERNAL_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1770,7 +2067,7 @@ dissect_smb2_file_mode_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *p
                tree = proto_item_add_subtree(item, ett_smb2_file_mode_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qsfi_SMB_FILE_MODE_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1788,7 +2085,7 @@ dissect_smb2_file_alignment_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tr
                tree = proto_item_add_subtree(item, ett_smb2_file_alignment_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfi_SMB_FILE_ALIGNMENT_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1806,7 +2103,7 @@ dissect_smb2_file_position_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tre
                tree = proto_item_add_subtree(item, ett_smb2_file_position_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qsfi_SMB_FILE_POSITION_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1842,7 +2139,7 @@ dissect_smb2_file_ea_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *par
                tree = proto_item_add_subtree(item, ett_smb2_file_ea_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfi_SMB_FILE_EA_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1861,7 +2158,7 @@ dissect_smb2_file_stream_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
                tree = proto_item_add_subtree(item, ett_smb2_file_stream_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfi_SMB_FILE_STREAM_INFO(tvb, pinfo, tree, offset, &bc, &trunc, TRUE);
 
        return offset;
@@ -1880,7 +2177,7 @@ dissect_smb2_file_pipe_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *p
                tree = proto_item_add_subtree(item, ett_smb2_file_pipe_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_sfi_SMB_FILE_PIPE_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1899,7 +2196,7 @@ dissect_smb2_file_compression_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_
                tree = proto_item_add_subtree(item, ett_smb2_file_compression_info);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfi_SMB_FILE_COMPRESSION_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1919,7 +2216,7 @@ dissect_smb2_file_network_open_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto
        }
 
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfi_SMB_FILE_NETWORK_OPEN_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -1939,7 +2236,7 @@ dissect_smb2_file_attribute_tag_info(tvbuff_t *tvb, packet_info *pinfo _U_, prot
        }
 
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfi_SMB_FILE_ATTRIBUTE_TAG_INFO(tvb, pinfo, tree, offset, &bc, &trunc);
 
        return offset;
@@ -2014,7 +2311,7 @@ dissect_smb2_file_full_ea_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
                /* ea name */
                length = ea_name_len;
                if (length) {
-                       bc = tvb_length_remaining(tvb, offset);
+                       bc = tvb_captured_length_remaining(tvb, offset);
                        name = get_unicode_or_ascii_string(tvb, &offset,
                                FALSE, &length, TRUE, TRUE, &bc);
                        if (name) {
@@ -2029,7 +2326,7 @@ dissect_smb2_file_full_ea_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
                /* ea data */
                length = ea_data_len;
                if (length) {
-                       bc = tvb_length_remaining(tvb, offset);
+                       bc = tvb_captured_length_remaining(tvb, offset);
                        data = get_unicode_or_ascii_string(tvb, &offset,
                                FALSE, &length, TRUE, TRUE, &bc);
                        /*
@@ -2057,6 +2354,11 @@ dissect_smb2_file_full_ea_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
        return offset;
 }
 
+static const true_false_string tfs_replace_if_exists = {
+       "Replace the target if it exists",
+       "Fail if the target exists"
+};
+
 static int
 dissect_smb2_file_rename_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *parent_tree, int offset, smb2_info_t *si _U_)
 {
@@ -2072,22 +2374,26 @@ dissect_smb2_file_rename_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
                tree = proto_item_add_subtree(item, ett_smb2_file_rename_info);
        }
 
-       /* some unknown bytes */
-       proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 16, ENC_NA);
-       offset += 16;
+       /* ReplaceIfExists */
+       proto_tree_add_item(tree, hf_smb2_replace_if, tvb, offset, 1, ENC_NA);
+       offset += 1;
+
+       /* reserved */
+       proto_tree_add_item(tree, hf_smb2_reserved_random, tvb, offset, 7, ENC_NA);
+       offset += 7;
+
+       /* Root Directory Handle, MBZ */
+       proto_tree_add_item(tree, hf_smb2_root_directory_mbz, tvb, offset, 8, ENC_NA);
+       offset += 8;
 
        /* file name length */
        length = tvb_get_letohs(tvb, offset);
-       proto_tree_add_item(tree, hf_smb2_filename_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
-       offset += 2;
-
-       /* some unknown bytes */
-       proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 2, ENC_NA);
-       offset += 2;
+       proto_tree_add_item(tree, hf_smb2_filename_len, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
 
        /* file name */
        if (length) {
-               bc = tvb_length_remaining(tvb, offset);
+               bc = tvb_captured_length_remaining(tvb, offset);
                name = get_unicode_or_ascii_string(tvb, &offset,
                        TRUE, &length, TRUE, TRUE, &bc);
                if (name) {
@@ -2099,10 +2405,6 @@ dissect_smb2_file_rename_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
        }
        offset += length;
 
-       /* some unknown bytes */
-       proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 4, ENC_NA);
-       offset += 4;
-
        return offset;
 }
 
@@ -2118,7 +2420,7 @@ dissect_smb2_sec_info_00(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *pare
        }
 
        /* security descriptor */
-       offset = dissect_nt_sec_desc(tvb, offset, pinfo, tree, NULL, TRUE, tvb_length_remaining(tvb, offset), NULL);
+       offset = dissect_nt_sec_desc(tvb, offset, pinfo, tree, NULL, TRUE, tvb_captured_length_remaining(tvb, offset), NULL);
 
        return offset;
 }
@@ -2135,7 +2437,7 @@ dissect_smb2_fs_info_05(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *paren
                tree = proto_item_add_subtree(item, ett_smb2_fs_info_05);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfsi_FS_ATTRIBUTE_INFO(tvb, pinfo, tree, offset, &bc, TRUE);
 
        return offset;
@@ -2153,7 +2455,7 @@ dissect_smb2_fs_info_06(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *paren
                tree = proto_item_add_subtree(item, ett_smb2_fs_info_06);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_nt_quota(tvb, tree, offset, &bc);
 
        return offset;
@@ -2188,7 +2490,7 @@ dissect_smb2_fs_info_07(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *paren
                tree = proto_item_add_subtree(item, ett_smb2_fs_info_07);
        }
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfsi_FS_FULL_SIZE_INFO(tvb, pinfo, tree, offset, &bc);
 
        return offset;
@@ -2207,7 +2509,7 @@ dissect_smb2_fs_info_01(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *paren
        }
 
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfsi_FS_VOLUME_INFO(tvb, pinfo, tree, offset, &bc, TRUE);
 
        return offset;
@@ -2226,7 +2528,7 @@ dissect_smb2_fs_info_03(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *paren
        }
 
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfsi_FS_SIZE_INFO(tvb, pinfo, tree, offset, &bc);
 
        return offset;
@@ -2245,7 +2547,7 @@ dissect_smb2_fs_info_04(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *paren
        }
 
 
-       bc = tvb_length_remaining(tvb, offset);
+       bc = tvb_captured_length_remaining(tvb, offset);
        offset = dissect_qfsi_FS_DEVICE_INFO(tvb, pinfo, tree, offset, &bc);
 
        return offset;
@@ -2285,7 +2587,7 @@ dissect_smb2_buffercode(proto_tree *parent_tree, tvbuff_t *tvb, int offset, guin
        offset += 2;
 
        if (length) {
-               *length = buffer_code&0xfffe;
+               *length = buffer_code; /*&0xfffe don't mask it here, mask it on caller side */
        }
 
        return offset;
@@ -2453,7 +2755,7 @@ dissect_smb2_share_caps(proto_tree *tree, tvbuff_t *tvb, int offset)
 static void
 dissect_smb2_secblob(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, smb2_info_t *si _U_)
 {
-       if ((tvb_length(tvb)>=7)
+       if ((tvb_captured_length(tvb)>=7)
        &&  (!tvb_memeql(tvb, 0, "NTLMSSP", 7))) {
                call_dissector(ntlmssp_handle, tvb, pinfo, tree);
        } else {
@@ -2545,7 +2847,7 @@ dissect_smb2_session_setup_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree
                                               sizeof(sesid->client_decryption_key));
                                }
                                sesid->server_port = pinfo->destport;
-                               sesid->auth_frame = pinfo->fd->num;
+                               sesid->auth_frame = pinfo->num;
                                sesid->tids = g_hash_table_new(smb2_tid_info_hash, smb2_tid_info_equal);
                                g_hash_table_insert(si->conv->sesids, sesid, sesid);
                        }
@@ -2555,32 +2857,46 @@ dissect_smb2_session_setup_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree
        return offset;
 }
 
+/* This needs more fixes for cases when the original header had also the constant value of 9.
+   This should be fixed on caller side where it decides if it has to call this or not.
+*/
 static int
-dissect_smb2_error_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, smb2_info_t *si _U_)
+dissect_smb2_error_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, smb2_info_t *si _U_,
+                                                       gboolean* continue_dissection)
 {
        gint byte_count;
+       guint16 length;
 
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       offset = dissect_smb2_buffercode(tree, tvb, offset, &length);
 
+       /* FIX: error response uses this constant, if not then it is not an error response */
+       if(length != 9)
+       {
+               if(continue_dissection)
+                       *continue_dissection = TRUE;
+       } else {
+               if(continue_dissection)
+                       *continue_dissection = FALSE;
 
-       /* Reserved (2 bytes) */
-       proto_tree_add_item(tree, hf_smb2_error_reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN);
-       offset += 2;
+               /* Reserved (2 bytes) */
+               proto_tree_add_item(tree, hf_smb2_error_reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               offset += 2;
 
-       /* ByteCount (4 bytes): The number of bytes of data contained in ErrorData[]. */
-       byte_count = tvb_get_ntohl(tvb, offset);
-       proto_tree_add_item(tree, hf_smb2_error_byte_count, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-       offset += 4;
+               /* ByteCount (4 bytes): The number of bytes of data contained in ErrorData[]. */
+               byte_count = tvb_get_ntohl(tvb, offset);
+               proto_tree_add_item(tree, hf_smb2_error_byte_count, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
 
-       /* If the ByteCount field is zero then the server MUST supply an ErrorData field
-          that is one byte in length */
-       if (byte_count == 0) byte_count = 1;
+               /* If the ByteCount field is zero then the server MUST supply an ErrorData field
+                  that is one byte in length */
+               if (byte_count == 0) byte_count = 1;
 
-       /* ErrorData (variable): A variable-length data field that contains extended
-          error information.*/
-       proto_tree_add_item(tree, hf_smb2_error_data, tvb, offset, byte_count, ENC_NA);
-       offset += byte_count;
+               /* ErrorData (variable): A variable-length data field that contains extended
+                  error information.*/
+               proto_tree_add_item(tree, hf_smb2_error_data, tvb, offset, byte_count, ENC_NA);
+               offset += byte_count;
+       }
 
        return offset;
 }
@@ -2616,7 +2932,7 @@ dissect_smb2_session_setup_response(tvbuff_t *tvb, packet_info *pinfo, proto_tre
                }
 
                for (ek=enc_key_list;ek;ek=ek->next) {
-                       if (ek->fd_num == (int)pinfo->fd->num) {
+                       if (ek->fd_num == (int)pinfo->num) {
                                break;
                        }
                }
@@ -2642,7 +2958,7 @@ dissect_smb2_session_setup_response(tvbuff_t *tvb, packet_info *pinfo, proto_tre
                                            "ServerOut", 10,
                                            sesid->client_decryption_key);
                        sesid->server_port = pinfo->srcport;
-                       sesid->auth_frame = pinfo->fd->num;
+                       sesid->auth_frame = pinfo->num;
                        sesid->tids = g_hash_table_new(smb2_tid_info_hash, smb2_tid_info_equal);
                        g_hash_table_insert(si->conv->sesids, sesid, sesid);
                }
@@ -2689,14 +3005,14 @@ static int
 dissect_smb2_tree_connect_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_info_t *si _U_)
 {
        guint16 share_type;
+       gboolean continue_dissection;
 
        switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
-
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* share type */
        share_type = tvb_get_letohs(tvb, offset);
@@ -2715,7 +3031,7 @@ dissect_smb2_tree_connect_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree
                tid = wmem_new(wmem_file_scope(), smb2_tid_info_t);
                tid->tid = si->tid;
                tid->name = (char *)si->saved->extra_info;
-               tid->connect_frame = pinfo->fd->num;
+               tid->connect_frame = pinfo->num;
                tid->share_type = share_type;
 
                g_hash_table_insert(si->session->tids, tid, tid);
@@ -2751,13 +3067,14 @@ dissect_smb2_tree_disconnect_request(tvbuff_t *tvb, packet_info *pinfo _U_, prot
 static int
 dissect_smb2_tree_disconnect_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, smb2_info_t *si _U_)
 {
-       switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
+       gboolean continue_dissection;
 
+       switch (si->status) {
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* reserved */
        offset += 2;
@@ -2780,13 +3097,14 @@ dissect_smb2_sessionlogoff_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_
 static int
 dissect_smb2_sessionlogoff_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, smb2_info_t *si _U_)
 {
-       switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
+       gboolean continue_dissection;
 
+       switch (si->status) {
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* reserved bytes */
        offset += 2;
@@ -2810,13 +3128,14 @@ dissect_smb2_keepalive_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
 static int
 dissect_smb2_keepalive_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, smb2_info_t *si _U_)
 {
-       switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
+       gboolean continue_dissection;
 
+       switch (si->status) {
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* some unknown bytes */
        proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 2, ENC_NA);
@@ -2858,25 +3177,87 @@ dissect_smb2_notify_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        return offset;
 }
 
+static const value_string notify_action_vals[] = {
+       {0x01, "FILE_ACTION_ADDED"},
+       {0x02, "FILE_ACTION_REMOVED"},
+       {0x03, "FILE_ACTION_MODIFIED"},
+       {0x04, "FILE_ACTION_RENAMED_OLD_NAME"},
+       {0x05, "FILE_ACTION_RENAMED_NEW_NAME"},
+       {0x06, "FILE_ACTION_ADDED_STREAM"},
+       {0x07, "FILE_ACTION_REMOVED_STREAM"},
+       {0x08, "FILE_ACTION_MODIFIED_STREAM"},
+       {0x09, "FILE_ACTION_REMOVED_BY_DELETE"},
+       {0, NULL}
+};
+
 static void
-dissect_smb2_notify_data_out(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, smb2_info_t *si _U_)
+dissect_smb2_notify_data_out(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *parent_tree, smb2_info_t *si _U_)
 {
-       proto_tree_add_item(tree, hf_smb2_unknown, tvb, 0, tvb_length(tvb), ENC_NA);
+       proto_tree *tree = NULL;
+       proto_item *item = NULL;
+       int offset = 0;
+
+       while (tvb_reported_length_remaining(tvb, offset) > 4) {
+               guint32 start_offset = offset;
+               guint32 next_offset;
+               guint32 length;
+
+               if (parent_tree) {
+                       item = proto_tree_add_item(parent_tree, hf_smb2_notify_info, tvb, offset, -1, ENC_NA);
+                       tree = proto_item_add_subtree(item, ett_smb2_notify_info);
+               }
+
+               /* next offset */
+               proto_tree_add_item_ret_uint(tree, hf_smb2_notify_next_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN, &next_offset);
+               offset += 4;
+
+               proto_tree_add_item(tree, hf_smb2_notify_action, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+
+               /* file name length */
+               proto_tree_add_item_ret_uint(tree, hf_smb2_filename_len, tvb, offset, 4, ENC_LITTLE_ENDIAN, &length);
+               offset += 4;
+
+               /* file name */
+               if (length) {
+                       const guchar *name = "";
+                       guint16     bc;
+
+                       bc = tvb_reported_length_remaining(tvb, offset);
+                       name = get_unicode_or_ascii_string(tvb, &offset,
+                                       TRUE, &length, TRUE, TRUE, &bc);
+                       if (name) {
+                               proto_tree_add_string(tree, hf_smb2_filename,
+                                                     tvb, offset, length,
+                                                     name);
+                       }
+
+                       offset += length;
+               }
+
+               if (!next_offset) {
+                       break;
+               }
+
+               offset = start_offset+next_offset;
+       }
 }
 
 static int
 dissect_smb2_notify_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, smb2_info_t *si)
 {
        offset_length_buffer_t olb;
+       gboolean continue_dissection;
 
        switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
+       /* MS-SMB2 3.3.4.4 says STATUS_NOTIFY_ENUM_DIR is not treated as an error */
+       case 0x0000010c: /* STATUS_NOTIFY_ENUM_DIR */
+       case 0x00000000: /* buffer code */
+        offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
        }
 
-       /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
-
        /* out buffer offset/length */
        offset = dissect_smb2_olb_length_offset(tvb, offset, &olb, OLB_O_UINT16_S_UINT32, hf_smb2_notify_out_data);
 
@@ -2962,7 +3343,7 @@ static void dissect_smb2_file_directory_info(tvbuff_t *tvb, packet_info *pinfo _
        const char *name   = NULL;
        guint16     bc;
 
-       while (tvb_length_remaining(tvb, offset) > 4) {
+       while (tvb_reported_length_remaining(tvb, offset) > 4) {
                int old_offset = offset;
                int next_offset;
                int file_name_len;
@@ -3045,7 +3426,7 @@ static void dissect_smb2_full_directory_info(tvbuff_t *tvb, packet_info *pinfo _
        const char *name   = NULL;
        guint16     bc;
 
-       while (tvb_length_remaining(tvb, offset) > 4) {
+       while (tvb_reported_length_remaining(tvb, offset) > 4) {
                int old_offset = offset;
                int next_offset;
                int file_name_len;
@@ -3132,7 +3513,7 @@ static void dissect_smb2_both_directory_info(tvbuff_t *tvb, packet_info *pinfo _
        const char *name   = NULL;
        guint16     bc;
 
-       while (tvb_length_remaining(tvb, offset) > 4) {
+       while (tvb_reported_length_remaining(tvb, offset) > 4) {
                int old_offset = offset;
                int next_offset;
                int file_name_len;
@@ -3240,7 +3621,7 @@ static void dissect_smb2_file_name_info(tvbuff_t *tvb, packet_info *pinfo _U_, p
        const char *name   = NULL;
        guint16     bc;
 
-       while (tvb_length_remaining(tvb, offset) > 4) {
+       while (tvb_reported_length_remaining(tvb, offset) > 4) {
                int old_offset = offset;
                int next_offset;
                int file_name_len;
@@ -3300,7 +3681,7 @@ static void dissect_smb2_id_both_directory_info(tvbuff_t *tvb, packet_info *pinf
        const char *name   = NULL;
        guint16     bc;
 
-       while (tvb_length_remaining(tvb, offset) > 4) {
+       while (tvb_reported_length_remaining(tvb, offset) > 4) {
                int old_offset = offset;
                int next_offset;
                int file_name_len;
@@ -3428,8 +3809,8 @@ dissect_smb2_find_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, smb2
        smb2_find_dissector_t *dis = smb2_find_dissectors;
 
        while (dis->dissector) {
-               if (si && si->saved && si->saved) {
-                       if (dis->level ==si->saved->infolevel) {
+               if (si && si->saved) {
+                       if (dis->level == si->saved->infolevel) {
                                dis->dissector(tvb, pinfo, tree, si);
                                return;
                        }
@@ -3437,7 +3818,7 @@ dissect_smb2_find_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, smb2
                dis++;
        }
 
-       proto_tree_add_item(tree, hf_smb2_unknown, tvb, 0, tvb_length(tvb), ENC_NA);
+       proto_tree_add_item(tree, hf_smb2_unknown, tvb, 0, tvb_captured_length(tvb), ENC_NA);
 }
 
 static int
@@ -3445,6 +3826,7 @@ dissect_smb2_find_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tr
 {
        offset_length_buffer_t olb;
        proto_item *item = NULL;
+       gboolean continue_dissection;
 
        if (si->saved) {
                /* infolevel */
@@ -3463,12 +3845,11 @@ dissect_smb2_find_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tr
        }
 
        switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
-
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* findinfo offset */
        offset = dissect_smb2_olb_length_offset(tvb, offset, &olb, OLB_O_UINT16_S_UINT32, hf_smb2_find_info_blob);
@@ -3611,14 +3992,14 @@ dissect_smb2_negotiate_protocol_response(tvbuff_t *tvb, packet_info *pinfo, prot
        guint16 i;
        guint32 nco;
        guint16 ncc;
+       gboolean continue_dissection;
 
        switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
-
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* security mode, skip second byte */
        offset = dissect_smb2_secmode(tree, tvb, offset);
@@ -3705,7 +4086,7 @@ dissect_smb2_getinfo_parameters(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tre
                default:
                        /* we don't handle this infolevel yet */
                        proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 16, ENC_NA);
-                       offset += tvb_length_remaining(tvb, offset);
+                       offset += tvb_captured_length_remaining(tvb, offset);
                }
                break;
        case SMB2_CLASS_FS_INFO:
@@ -3713,7 +4094,7 @@ dissect_smb2_getinfo_parameters(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tre
                default:
                        /* we don't handle this infolevel yet */
                        proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 16, ENC_NA);
-                       offset += tvb_length_remaining(tvb, offset);
+                       offset += tvb_captured_length_remaining(tvb, offset);
                }
                break;
        case SMB2_CLASS_SEC_INFO:
@@ -3724,13 +4105,13 @@ dissect_smb2_getinfo_parameters(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tre
                default:
                        /* we don't handle this infolevel yet */
                        proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 16, ENC_NA);
-                       offset += tvb_length_remaining(tvb, offset);
+                       offset += tvb_captured_length_remaining(tvb, offset);
                }
                break;
        default:
                /* we don't handle this class yet */
                proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 16, ENC_NA);
-               offset += tvb_length_remaining(tvb, offset);
+               offset += tvb_captured_length_remaining(tvb, offset);
        }
        return offset;
 }
@@ -3739,7 +4120,7 @@ dissect_smb2_getinfo_parameters(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tre
 static int
 dissect_smb2_class_infolevel(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree, smb2_info_t *si)
 {
-       char              cl, il;
+       guint8            cl, il;
        proto_item       *item;
        int               hfindex;
        value_string_ext *vsx;
@@ -3773,6 +4154,10 @@ dissect_smb2_class_infolevel(packet_info *pinfo, tvbuff_t *tvb, int offset, prot
                hfindex = hf_smb2_infolevel_sec_info;
                vsx = &smb2_sec_info_levels_ext;
                break;
+       case SMB2_CLASS_POSIX_INFO:
+               hfindex = hf_smb2_infolevel_posix_info;
+               vsx = &smb2_posix_info_levels_ext;
+               break;
        default:
                hfindex = hf_smb2_infolevel;
                vsx = NULL;  /* allowed arg to val_to_str_ext() */
@@ -3902,8 +4287,8 @@ dissect_smb2_infolevel(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
                        break;
                default:
                        /* we don't handle this infolevel yet */
-                       proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, tvb_length_remaining(tvb, offset), ENC_NA);
-                       offset += tvb_length_remaining(tvb, offset);
+                       proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA);
+                       offset += tvb_captured_length_remaining(tvb, offset);
                }
                break;
        case SMB2_CLASS_FS_INFO:
@@ -3931,8 +4316,8 @@ dissect_smb2_infolevel(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
                        break;
                default:
                        /* we don't handle this infolevel yet */
-                       proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, tvb_length_remaining(tvb, offset), ENC_NA);
-                       offset += tvb_length_remaining(tvb, offset);
+                       proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA);
+                       offset += tvb_captured_length_remaining(tvb, offset);
                }
                break;
        case SMB2_CLASS_SEC_INFO:
@@ -3942,14 +4327,14 @@ dissect_smb2_infolevel(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
                        break;
                default:
                        /* we don't handle this infolevel yet */
-                       proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, tvb_length_remaining(tvb, offset), ENC_NA);
-                       offset += tvb_length_remaining(tvb, offset);
+                       proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA);
+                       offset += tvb_captured_length_remaining(tvb, offset);
                }
                break;
        default:
                /* we don't handle this class yet */
-               proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, tvb_length_remaining(tvb, offset), ENC_NA);
-               offset += tvb_length_remaining(tvb, offset);
+               proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA);
+               offset += tvb_captured_length_remaining(tvb, offset);
        }
 
        /* if we get BUFFER_OVERFLOW there will be truncated data */
@@ -3969,7 +4354,7 @@ dissect_smb2_getinfo_response_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree
                dissect_smb2_infolevel(tvb, pinfo, tree, 0, si, si->saved->smb2_class, si->saved->infolevel);
        } else {
                /* some unknown bytes */
-               proto_tree_add_item(tree, hf_smb2_unknown, tvb, 0, tvb_length(tvb), ENC_NA);
+               proto_tree_add_item(tree, hf_smb2_unknown, tvb, 0, tvb_captured_length(tvb), ENC_NA);
        }
 
 }
@@ -3979,17 +4364,21 @@ static int
 dissect_smb2_getinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_info_t *si)
 {
        offset_length_buffer_t olb;
+       gboolean continue_dissection;
 
        /* class/infolevel */
        dissect_smb2_class_infolevel(pinfo, tvb, offset, tree, si);
 
        switch (si->status) {
-       case 0x00000000: break;
+       case 0x00000000:
        /* if we get BUFFER_OVERFLOW there will be truncated data */
-       case 0x80000005: break;
+       case 0x80000005:
        /* if we get BUFFER_TOO_SMALL there will not be any data there, only
         * a guin32 specifying how big the buffer needs to be
         */
+               /* buffer code */
+               offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+               break;
        case 0xc0000023:
                offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
                offset = dissect_smb2_olb_length_offset(tvb, offset, &olb, OLB_O_UINT16_S_UINT32, -1);
@@ -3997,12 +4386,10 @@ dissect_smb2_getinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
                offset += 4;
 
                return offset;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
        }
 
-
-       /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
         /* response buffer offset  and size */
        offset = dissect_smb2_olb_length_offset(tvb, offset, &olb, OLB_O_UINT16_S_UINT32, -1);
 
@@ -4043,14 +4430,14 @@ dissect_smb2_close_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *t
 {
        proto_tree *flags_tree = NULL;
        proto_item *flags_item = NULL;
+       gboolean continue_dissection;
 
        switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
-
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* close flags */
        if (tree) {
@@ -4108,13 +4495,14 @@ dissect_smb2_flush_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 static int
 dissect_smb2_flush_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, smb2_info_t *si _U_)
 {
-       switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
+       gboolean continue_dissection;
 
+       switch (si->status) {
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* some unknown bytes */
        proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 2, ENC_NA);
@@ -4181,13 +4569,14 @@ dissect_smb2_lock_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i
 static int
 dissect_smb2_lock_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, smb2_info_t *si _U_)
 {
-       switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
+       gboolean continue_dissection;
 
+       switch (si->status) {
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* some unknown bytes */
        proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 2, ENC_NA);
@@ -4208,59 +4597,285 @@ dissect_smb2_cancel_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *t
        return offset;
 }
 
-static void
-smb2_set_dcerpc_file_id(packet_info *pinfo, smb2_info_t *si)
+static const smb2_fid_info_t *
+smb2_pipe_get_fid_info(const smb2_info_t *si)
 {
-       guint64 persistent;
+       smb2_fid_info_t *file = NULL;
 
        if (si == NULL) {
-               return;
+               return NULL;
+       }
+       if (si->file != NULL) {
+               file = si->file;
+       } else if (si->saved != NULL) {
+               file = si->saved->file;
+       }
+       if (file == NULL) {
+               return NULL;
        }
-       if (si->saved == NULL) {
+
+       return file;
+}
+
+static void
+smb2_pipe_set_file_id(packet_info *pinfo, smb2_info_t *si)
+{
+       guint64 persistent;
+       const smb2_fid_info_t *file = NULL;
+
+       file = smb2_pipe_get_fid_info(si);
+       if (file == NULL) {
                return;
        }
 
-       /*
-        * the first 8 bytes are the persistent part of the file handle
-        */
-       persistent =  si->saved->policy_hnd.uuid.data1;
-       persistent |= ((guint64)si->saved->policy_hnd.uuid.data2) << 32;
-       persistent |= ((guint64)si->saved->policy_hnd.uuid.data3) << 48;
+       persistent = GPOINTER_TO_UINT(file);
 
        dcerpc_set_transport_salt(persistent, pinfo);
 }
 
+static gboolean smb2_pipe_reassembly = TRUE;
+static reassembly_table smb2_pipe_reassembly_table;
+
+static void
+smb2_pipe_reassembly_init(void)
+{
+       /*
+        * XXX - addresses_ports_reassembly_table_functions?
+        * Probably correct for SMB-over-NBT and SMB-over-TCP,
+        * as stuff from two different connections should
+        * probably not be combined, but what about other
+        * transports for SMB, e.g. NBF or Netware?
+        */
+       reassembly_table_init(&smb2_pipe_reassembly_table,
+           &addresses_reassembly_table_functions);
+}
+
 static int
-dissect_file_data_dcerpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, guint32 datalen, proto_tree *top_tree)
+dissect_file_data_smb2_pipe(tvbuff_t *raw_tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, guint32 datalen, proto_tree *top_tree, void *data)
 {
-       tvbuff_t *dcerpc_tvb;
+       /*
+        * Note: si is NULL for some callers from packet-smb.c
+        */
+       const smb2_info_t *si = (const smb2_info_t *)data;
+       gboolean result=0;
+       gboolean save_fragmented;
+       gint remaining;
+       guint reported_len;
+       const smb2_fid_info_t *file = NULL;
+       guint32 id;
+       fragment_head *fd_head;
+       tvbuff_t *tvb;
+       tvbuff_t *new_tvb;
+       proto_item *frag_tree_item;
        heur_dtbl_entry_t *hdtbl_entry;
 
-       dcerpc_tvb = tvb_new_subset(tvb, offset, MIN((int)datalen, tvb_length_remaining(tvb, offset)), datalen);
+       file = smb2_pipe_get_fid_info(si);
+       id = (guint32)(GPOINTER_TO_UINT(file) & G_MAXUINT32);
 
-       /* dissect the full PDU */
-       dissector_try_heuristic(smb2_heur_subdissector_list, dcerpc_tvb, pinfo, top_tree, &hdtbl_entry, NULL);
+       remaining = tvb_captured_length_remaining(raw_tvb, offset);
 
+       tvb = tvb_new_subset(raw_tvb, offset,
+                            MIN((int)datalen, remaining),
+                            datalen);
 
-       offset += datalen;
+       /*
+        * Offer desegmentation service to Named Pipe subdissectors (e.g. DCERPC)
+        * if we have all the data.  Otherwise, reassembly is (probably) impossible.
+        */
+       pinfo->can_desegment = 0;
+       pinfo->desegment_offset = 0;
+       pinfo->desegment_len = 0;
+       reported_len = tvb_reported_length(tvb);
+       if (smb2_pipe_reassembly && tvb_captured_length(tvb) >= reported_len) {
+               pinfo->can_desegment = 2;
+       }
 
-       return offset;
-}
+       save_fragmented = pinfo->fragmented;
 
-#define SMB2_CHANNEL_NONE              0x00000000
-#define SMB2_CHANNEL_RDMA_V1           0x00000001
-#define SMB2_CHANNEL_RDMA_V1_INVALIDATE        0x00000002
+       /*
+        * if we are not offering desegmentation, just try the heuristics
+        *and bail out
+        */
+       if (!pinfo->can_desegment) {
+               result = dissector_try_heuristic(smb2_pipe_subdissector_list,
+                                                tvb, pinfo, top_tree,
+                                                &hdtbl_entry, data);
+               goto clean_up_and_exit;
+       }
 
-static const value_string smb2_channel_vals[] = {
-       { SMB2_CHANNEL_NONE,    "None" },
-       { SMB2_CHANNEL_RDMA_V1, "RDMA V1" },
-       { SMB2_CHANNEL_RDMA_V1_INVALIDATE,      "RDMA V1_INVALIDATE" },
-       { 0, NULL }
-};
+       /* below this line, we know we are doing reassembly */
 
-static void
-dissect_smb2_rdma_v1_blob(tvbuff_t *tvb, packet_info *pinfo _U_,
-                         proto_tree *parent_tree, smb2_info_t *si _U_)
+       /*
+        * this is a new packet, see if we are already reassembling this
+        * pdu and if not, check if the dissector wants us
+        * to reassemble it
+        */
+       if (!pinfo->fd->flags.visited) {
+               /*
+                * This is the first pass.
+                *
+                * Check if we are already reassembling this PDU or not;
+                * we check for an in-progress reassembly for this FID
+                * in this direction, by searching for its reassembly
+                * structure.
+                */
+               fd_head = fragment_get(&smb2_pipe_reassembly_table,
+                                      pinfo, id, NULL);
+               if (!fd_head) {
+                       /*
+                        * No reassembly, so this is a new pdu. check if the
+                        * dissector wants us to reassemble it or if we
+                        * already got the full pdu in this tvb.
+                        */
+
+                       /*
+                        * Try the heuristic dissectors and see if we
+                        * find someone that recognizes this payload.
+                        */
+                       result = dissector_try_heuristic(smb2_pipe_subdissector_list,
+                                                        tvb, pinfo, top_tree,
+                                                        &hdtbl_entry, data);
+
+                       /* no this didn't look like something we know */
+                       if (!result) {
+                               goto clean_up_and_exit;
+                       }
+
+                       /* did the subdissector want us to reassemble any
+                          more data ?
+                       */
+                       if (pinfo->desegment_len) {
+                               fragment_add_check(&smb2_pipe_reassembly_table,
+                                       tvb, 0, pinfo, id, NULL,
+                                       0, reported_len, TRUE);
+                               fragment_set_tot_len(&smb2_pipe_reassembly_table,
+                                       pinfo, id, NULL,
+                                       pinfo->desegment_len+reported_len);
+                       }
+                       goto clean_up_and_exit;
+               }
+
+               /* OK, we're already doing a reassembly for this FID.
+                  skip to last segment in the existing reassembly structure
+                  and add this fragment there
+
+                  XXX we might add code here to use any offset values
+                  we might pick up from the Read/Write calls instead of
+                  assuming we always get them in the correct order
+               */
+               while (fd_head->next) {
+                       fd_head = fd_head->next;
+               }
+               fd_head = fragment_add_check(&smb2_pipe_reassembly_table,
+                       tvb, 0, pinfo, id, NULL,
+                       fd_head->offset+fd_head->len,
+                       reported_len, TRUE);
+
+               /* if we completed reassembly */
+               if (fd_head) {
+                       new_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
+                       add_new_data_source(pinfo, new_tvb,
+                                 "Named Pipe over SMB2");
+                       pinfo->fragmented=FALSE;
+
+                       tvb = new_tvb;
+
+                       /* list what segments we have */
+                       show_fragment_tree(fd_head, &smb2_pipe_frag_items,
+                                          tree, pinfo, tvb, &frag_tree_item);
+
+                       /* dissect the full PDU */
+                       result = dissector_try_heuristic(smb2_pipe_subdissector_list,
+                                                        tvb, pinfo, top_tree,
+                                                        &hdtbl_entry, data);
+               }
+               goto clean_up_and_exit;
+       }
+
+       /*
+        * This is not the first pass; see if it's in the table of
+        * reassembled packets.
+        *
+        * XXX - we know that several of the arguments aren't going to
+        * be used, so we pass bogus variables.  Can we clean this
+        * up so that we don't have to distinguish between the first
+        * pass and subsequent passes?
+        */
+       fd_head = fragment_add_check(&smb2_pipe_reassembly_table,
+                                    tvb, 0, pinfo, id, NULL, 0, 0, TRUE);
+       if (!fd_head) {
+               /* we didn't find it, try any of the heuristic dissectors
+                  and bail out
+               */
+               result = dissector_try_heuristic(smb2_pipe_subdissector_list,
+                                                tvb, pinfo, top_tree,
+                                                &hdtbl_entry, data);
+               goto clean_up_and_exit;
+       }
+       if (!(fd_head->flags&FD_DEFRAGMENTED)) {
+               /* we don't have a fully reassembled frame */
+               result = dissector_try_heuristic(smb2_pipe_subdissector_list,
+                                                tvb, pinfo, top_tree,
+                                                &hdtbl_entry, data);
+               goto clean_up_and_exit;
+       }
+
+       /* it is reassembled but it was reassembled in a different frame */
+       if (pinfo->num != fd_head->reassembled_in) {
+               proto_item *item;
+               item = proto_tree_add_uint(top_tree, hf_smb2_pipe_reassembled_in,
+                                          tvb, 0, 0, fd_head->reassembled_in);
+               PROTO_ITEM_SET_GENERATED(item);
+               goto clean_up_and_exit;
+       }
+
+       /* display the reassembled pdu */
+       new_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
+       add_new_data_source(pinfo, new_tvb,
+                 "Named Pipe over SMB2");
+       pinfo->fragmented = FALSE;
+
+       tvb = new_tvb;
+
+       /* list what segments we have */
+       show_fragment_tree(fd_head, &smb2_pipe_frag_items,
+                          top_tree, pinfo, tvb, &frag_tree_item);
+
+       /* dissect the full PDU */
+       result = dissector_try_heuristic(smb2_pipe_subdissector_list,
+                                        tvb, pinfo, top_tree,
+                                        &hdtbl_entry, data);
+
+clean_up_and_exit:
+       /* clear out the variables */
+       pinfo->can_desegment=0;
+       pinfo->desegment_offset = 0;
+       pinfo->desegment_len = 0;
+
+       if (!result) {
+               call_data_dissector(tvb, pinfo, top_tree);
+       }
+
+       pinfo->fragmented = save_fragmented;
+
+       offset += datalen;
+       return offset;
+}
+
+#define SMB2_CHANNEL_NONE              0x00000000
+#define SMB2_CHANNEL_RDMA_V1           0x00000001
+#define SMB2_CHANNEL_RDMA_V1_INVALIDATE        0x00000002
+
+static const value_string smb2_channel_vals[] = {
+       { SMB2_CHANNEL_NONE,    "None" },
+       { SMB2_CHANNEL_RDMA_V1, "RDMA V1" },
+       { SMB2_CHANNEL_RDMA_V1_INVALIDATE,      "RDMA V1_INVALIDATE" },
+       { 0, NULL }
+};
+
+static void
+dissect_smb2_rdma_v1_blob(tvbuff_t *tvb, packet_info *pinfo _U_,
+                         proto_tree *parent_tree, smb2_info_t *si _U_)
 {
        int         offset      = 0;
        int         len;
@@ -4361,19 +4976,23 @@ dissect_smb2_write_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                break;
        }
 
-       /* data or dcerpc ?*/
-       if (length && si->tree && si->tree->share_type == SMB2_SHARE_TYPE_PIPE) {
-               smb2_set_dcerpc_file_id(pinfo, si);
-               offset = dissect_file_data_dcerpc(tvb, pinfo, tree, offset, length, si->top_tree);
-               return offset;
+       /* data or namedpipe ?*/
+       if (length) {
+               int oldoffset = offset;
+               smb2_pipe_set_file_id(pinfo, si);
+               offset = dissect_file_data_smb2_pipe(tvb, pinfo, tree, offset, length, si->top_tree, si);
+               if (offset != oldoffset) {
+                       /* managed to dissect pipe data */
+                       return offset;
+               }
        }
 
        /* just ordinary data */
        proto_tree_add_item(tree, hf_smb2_write_data, tvb, offset, length, ENC_NA);
 
-       data_tvb_len=(guint32)tvb_length_remaining(tvb, offset);
+       data_tvb_len=(guint32)tvb_captured_length_remaining(tvb, offset);
 
-       offset += MIN(length,(guint32)tvb_length_remaining(tvb, offset));
+       offset += MIN(length,(guint32)tvb_captured_length_remaining(tvb, offset));
 
        offset = dissect_smb2_olb_tvb_max_offset(offset, &c_olb);
 
@@ -4390,13 +5009,14 @@ dissect_smb2_write_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 static int
 dissect_smb2_write_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, smb2_info_t *si _U_)
 {
-       switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
+       gboolean continue_dissection;
 
+       switch (si->status) {
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* reserved */
        proto_tree_add_item(tree, hf_smb2_reserved, tvb, offset, 2, ENC_NA);
@@ -4421,10 +5041,263 @@ dissect_smb2_write_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *t
        return offset;
 }
 
+/* The STORAGE_OFFLOAD_TOKEN is used for "Offload Data Transfer" (ODX) operations,
+   including FSCTL_OFFLOAD_READ, FSCTL_OFFLOAD_WRITE.  Ref: MS-FSCC 2.3.79
+   Note: Unlike most of SMB2, the token fields are BIG-endian! */
+static int
+dissect_smb2_STORAGE_OFFLOAD_TOKEN(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
+{
+       proto_tree *sub_tree;
+       proto_item *sub_item;
+       guint32 idlen = 0;
+       guint32 idtype = 0;
+
+       sub_tree = proto_tree_add_subtree(tree, tvb, offset, 512, ett_smb2_fsctl_odx_token, &sub_item, "Token");
+
+       proto_tree_add_item_ret_uint(sub_tree, hf_smb2_fsctl_odx_token_type, tvb, offset, 4, ENC_BIG_ENDIAN, &idtype);
+       offset += 4;
+
+       proto_item_append_text(sub_item, " (IdType 0x%x)", idtype);
+
+       /* reserved */
+       proto_tree_add_item(sub_tree, hf_smb2_reserved, tvb, offset, 2, ENC_NA);
+       offset += 2;
+
+       /* TokenIdLength */
+       proto_tree_add_item_ret_uint(sub_tree, hf_smb2_fsctl_odx_token_idlen, tvb, offset, 2, ENC_BIG_ENDIAN, &idlen);
+       offset += 2;
+
+       /* idlen is what the server says is the "meaningful" part of the token.
+               However, token ID is always 504 bytes */
+       proto_tree_add_bytes_format_value(sub_tree, hf_smb2_fsctl_odx_token_idraw, tvb,
+                                         offset, idlen, NULL, "Opaque Data");
+       offset += 504;
+
+       return (offset);
+}
+
+/* MS-FSCC 2.3.77, 2.3.78 */
 static void
-dissect_smb2_FSCTL_PIPE_TRANSCEIVE(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *top_tree, gboolean data_in _U_)
+dissect_smb2_FSCTL_OFFLOAD_READ(tvbuff_t *tvb,
+                               packet_info *pinfo _U_,
+                               proto_tree *tree,
+                               int offset,
+                               gboolean in)
 {
-       dissect_file_data_dcerpc(tvb, pinfo, tree, offset, tvb_length_remaining(tvb, offset), top_tree);
+       proto_tree_add_item(tree, hf_smb2_fsctl_odx_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
+
+       proto_tree_add_item(tree, hf_smb2_fsctl_odx_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
+
+       if (in) {
+               proto_tree_add_item(tree, hf_smb2_fsctl_odx_token_ttl, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+
+               proto_tree_add_item(tree, hf_smb2_reserved, tvb, offset, 4, ENC_NA);
+               offset += 4;
+
+               proto_tree_add_item(tree, hf_smb2_fsctl_odx_file_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               proto_tree_add_item(tree, hf_smb2_fsctl_odx_copy_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               /* offset += 8; */
+       } else {
+               proto_tree_add_item(tree, hf_smb2_fsctl_odx_xfer_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               (void) dissect_smb2_STORAGE_OFFLOAD_TOKEN(tvb, pinfo, tree, offset);
+       }
+}
+
+/* MS-FSCC 2.3.80, 2.3.81 */
+static void
+dissect_smb2_FSCTL_OFFLOAD_WRITE(tvbuff_t *tvb,
+                               packet_info *pinfo _U_,
+                               proto_tree *tree,
+                               int offset,
+                               gboolean in)
+{
+       proto_tree_add_item(tree, hf_smb2_fsctl_odx_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
+
+       proto_tree_add_item(tree, hf_smb2_fsctl_odx_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
+
+       if (in) {
+               proto_tree_add_item(tree, hf_smb2_fsctl_odx_file_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               proto_tree_add_item(tree, hf_smb2_fsctl_odx_copy_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               proto_tree_add_item(tree, hf_smb2_fsctl_odx_token_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               dissect_smb2_STORAGE_OFFLOAD_TOKEN(tvb, pinfo, tree, offset);
+
+       } else {
+               proto_tree_add_item(tree, hf_smb2_fsctl_odx_xfer_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               /* offset += 8; */
+       }
+}
+
+static void
+dissect_smb2_FSCTL_PIPE_TRANSCEIVE(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *top_tree, gboolean data_in _U_, void *data)
+{
+       dissect_file_data_smb2_pipe(tvb, pinfo, tree, offset, tvb_captured_length_remaining(tvb, offset), top_tree, data);
+}
+
+static void
+dissect_smb2_FSCTL_PIPE_WAIT(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, proto_tree *top_tree, gboolean data_in _U_)
+{
+       guint8 timeout_specified = tvb_get_guint8(tvb, offset + 12);
+       guint32 name_len = tvb_get_letohs(tvb, offset + 8);
+       const gchar *name;
+       int off = offset + 14;
+       guint16 bc = tvb_captured_length_remaining(tvb, off);
+       int len = name_len;
+
+       /* sanity check */
+       tvb_ensure_bytes_exist(tvb, off, name_len);
+
+       name = get_unicode_or_ascii_string(tvb, &off, TRUE, &len, TRUE, TRUE, &bc);
+       if (name == NULL) {
+               name = "";
+       }
+
+       col_append_fstr(pinfo->cinfo, COL_INFO, " Pipe: %s", name);
+
+       if (top_tree) {
+               proto_tree_add_string(top_tree, hf_smb2_fsctl_pipe_wait_name, tvb, offset + 14, name_len, name);
+               if (timeout_specified) {
+                       proto_tree_add_item(top_tree, hf_smb2_fsctl_pipe_wait_timeout, tvb, 0, 8, ENC_LITTLE_ENDIAN);
+               }
+       }
+}
+
+static int
+dissect_smb2_FSCTL_SET_SPARSE(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean data_in)
+{
+
+       /* There is no out data */
+       if (!data_in) {
+               return offset;
+       }
+
+       /* sparse flag (optional) */
+       if (tvb_reported_length_remaining(tvb, offset) >= 1) {
+               proto_tree_add_item(tree, hf_smb2_fsctl_sparse_flag, tvb, offset, 1, ENC_NA);
+               offset += 1;
+       }
+
+       return offset;
+}
+
+static int
+dissect_smb2_FSCTL_SET_ZERO_DATA(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean data_in)
+{
+       proto_tree *sub_tree;
+       proto_item *sub_item;
+
+       /* There is no out data */
+       if (!data_in) {
+               return offset;
+       }
+
+       sub_tree = proto_tree_add_subtree(tree, tvb, offset, 16, ett_smb2_fsctl_range_data, &sub_item, "Range");
+
+       proto_tree_add_item(sub_tree, hf_smb2_fsctl_range_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+       offset += 8;
+
+       proto_tree_add_item(sub_tree, hf_smb2_fsctl_range_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+       offset += 8;
+
+       return offset;
+}
+
+static void
+dissect_smb2_FSCTL_QUERY_ALLOCATED_RANGES(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, int offset _U_, gboolean data_in)
+{
+       proto_tree *sub_tree;
+       proto_item *sub_item;
+
+       if (data_in) {
+               sub_tree = proto_tree_add_subtree(tree, tvb, offset, 16, ett_smb2_fsctl_range_data, &sub_item, "Range");
+
+               proto_tree_add_item(sub_tree, hf_smb2_fsctl_range_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               proto_tree_add_item(sub_tree, hf_smb2_fsctl_range_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+       } else {
+               /* Zero or more allocated ranges may be reported. */
+               while (tvb_reported_length_remaining(tvb, offset) >= 16) {
+
+                       sub_tree = proto_tree_add_subtree(tree, tvb, offset, 16, ett_smb2_fsctl_range_data, &sub_item, "Range");
+
+                       proto_tree_add_item(sub_tree, hf_smb2_fsctl_range_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+                       offset += 8;
+
+                       proto_tree_add_item(sub_tree, hf_smb2_fsctl_range_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+                       offset += 8;
+               }
+       }
+}
+
+
+static void
+dissect_smb2_FSCTL_QUERY_FILE_REGIONS(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, int offset _U_, gboolean data_in)
+{
+
+       if (data_in) {
+               proto_tree_add_item(tree, hf_smb2_file_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               proto_tree_add_item(tree, hf_smb2_qfr_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               proto_tree_add_item(tree, hf_smb2_qfr_usage, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+
+               proto_tree_add_item(tree, hf_smb2_reserved, tvb, offset, 4, ENC_NA);
+               offset += 4;
+       } else {
+               guint32 entry_count = 0;
+
+               proto_tree_add_item(tree, hf_smb2_qfr_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+
+               proto_tree_add_item(tree, hf_smb2_qfr_total_region_entry_count, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+
+               proto_tree_add_item_ret_uint(tree, hf_smb2_qfr_region_entry_count, tvb, offset, 4, ENC_LITTLE_ENDIAN, &entry_count);
+               offset += 4;
+
+               proto_tree_add_item(tree, hf_smb2_reserved, tvb, offset, 4, ENC_NA);
+               offset += 4;
+
+               while (entry_count && tvb_reported_length_remaining(tvb, offset)) {
+                       proto_tree *sub_tree;
+                       proto_item *sub_item;
+
+                       sub_tree = proto_tree_add_subtree(tree, tvb, offset, 24, ett_qfr_entry, &sub_item, "Entry");
+
+                       proto_tree_add_item(sub_tree, hf_smb2_file_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+                       offset += 8;
+
+                       proto_tree_add_item(sub_tree, hf_smb2_qfr_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+                       offset += 8;
+
+                       proto_tree_add_item(sub_tree, hf_smb2_qfr_usage, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+                       offset += 4;
+
+                       proto_tree_add_item(sub_tree, hf_smb2_reserved, tvb, offset, 4, ENC_NA);
+                       offset += 4;
+
+                       entry_count--;
+               }
+       }
 }
 
 static void
@@ -4735,7 +5608,7 @@ dissect_smb2_FSCTL_VALIDATE_NEGOTIATE_INFO(tvbuff_t *tvb, packet_info *pinfo _U_
 }
 
 static void
-dissect_smb2_FSCTL_GET_SHADOW_COPY_DATA(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean data_in)
+dissect_smb2_FSCTL_SRV_ENUMERATE_SNAPSHOTS(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean data_in)
 {
        guint32 num_volumes;
 
@@ -4763,7 +5636,7 @@ dissect_smb2_FSCTL_GET_SHADOW_COPY_DATA(tvbuff_t *tvb, packet_info *pinfo _U_, p
                int len = 0;
                int old_offset = offset;
 
-               bc = tvb_length_remaining(tvb, offset);
+               bc = tvb_captured_length_remaining(tvb, offset);
                name = get_unicode_or_ascii_string(tvb, &offset,
                        TRUE, &len, TRUE, FALSE, &bc);
                proto_tree_add_string(tree, hf_smb2_ioctl_shadow_copy_label, tvb, old_offset, len, name);
@@ -4920,8 +5793,77 @@ dissect_smb2_FSCTL_SET_OBJECT_ID_EXTENDED(tvbuff_t *tvb, packet_info *pinfo _U_,
        return offset;
 }
 
+static int
+dissect_smb2_cchunk_RESUME_KEY(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
+{
+
+       proto_tree_add_bytes_format_value(tree, hf_smb2_cchunk_resume_key, tvb,
+                                         offset, 24, NULL, "Opaque Data");
+       offset += 24;
+
+       return (offset);
+}
+
+static void
+dissect_smb2_FSCTL_SRV_REQUEST_RESUME_KEY(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean data_in)
+{
+
+       /* There is no in data */
+       if (data_in) {
+               return;
+       }
+
+       offset = dissect_smb2_cchunk_RESUME_KEY(tvb, pinfo, tree, offset);
+
+       proto_tree_add_item(tree, hf_smb2_reserved, tvb, offset, 4, ENC_NA);
+       offset += 4;
+}
+
+static void
+dissect_smb2_FSCTL_SRV_COPYCHUNK(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean data_in)
+{
+       proto_tree *sub_tree;
+       proto_item *sub_item;
+       guint32 chunk_count = 0;
+
+       /* Output is simpler - handle that first. */
+       if (!data_in) {
+               proto_tree_add_item(tree, hf_smb2_cchunk_chunks_written, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(tree, hf_smb2_cchunk_bytes_written, tvb, offset+4, 4, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(tree, hf_smb2_cchunk_total_written, tvb, offset+8, 4, ENC_LITTLE_ENDIAN);
+               return;
+       }
+
+       /* Input data, fixed part */
+       offset = dissect_smb2_cchunk_RESUME_KEY(tvb, pinfo, tree, offset);
+       proto_tree_add_item_ret_uint(tree, hf_smb2_cchunk_count, tvb, offset, 4, ENC_LITTLE_ENDIAN, &chunk_count);
+       offset += 4;
+
+       proto_tree_add_item(tree, hf_smb2_reserved, tvb, offset, 4, ENC_NA);
+       offset += 4;
+
+       /* Zero or more allocated ranges may be reported. */
+       while (chunk_count && tvb_reported_length_remaining(tvb, offset) >= 24) {
+               sub_tree = proto_tree_add_subtree(tree, tvb, offset, 24, ett_smb2_cchunk_entry, &sub_item, "Chunk");
+
+               proto_tree_add_item(sub_tree, hf_smb2_cchunk_src_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               proto_tree_add_item(sub_tree, hf_smb2_cchunk_dst_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               proto_tree_add_item(sub_tree, hf_smb2_cchunk_xfer_len, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+
+               proto_tree_add_item(sub_tree, hf_smb2_reserved, tvb, offset, 4, ENC_NA);
+               offset += 4;
+
+               chunk_count--;
+       }
+}
+
 void
-dissect_smb2_ioctl_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *top_tree, guint32 ioctl_function, gboolean data_in)
+dissect_smb2_ioctl_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *top_tree, guint32 ioctl_function, gboolean data_in, void *private_data _U_)
 {
        guint16 dc;
 
@@ -4935,8 +5877,23 @@ dissect_smb2_ioctl_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, pro
                        dissect_get_dfs_referral_data(tvb, pinfo, tree, 0, &dc, TRUE);
                }
                break;
-       case 0x0011c017:
-               dissect_smb2_FSCTL_PIPE_TRANSCEIVE(tvb, pinfo, tree, 0, top_tree, data_in);
+       case 0x000940CF: /* FSCTL_QUERY_ALLOCATED_RANGES */
+               dissect_smb2_FSCTL_QUERY_ALLOCATED_RANGES(tvb, pinfo, tree, 0, data_in);
+               break;
+       case 0x00094264: /* FSCTL_OFFLOAD_READ */
+               dissect_smb2_FSCTL_OFFLOAD_READ(tvb, pinfo, tree, 0, data_in);
+               break;
+       case 0x00098268: /* FSCTL_OFFLOAD_WRITE */
+               dissect_smb2_FSCTL_OFFLOAD_WRITE(tvb, pinfo, tree, 0, data_in);
+               break;
+       case 0x0011c017: /* FSCTL_PIPE_TRANSCEIVE */
+               dissect_smb2_FSCTL_PIPE_TRANSCEIVE(tvb, pinfo, tree, 0, top_tree, data_in, private_data);
+               break;
+       case 0x00110018: /* FSCTL_PIPE_WAIT */
+               dissect_smb2_FSCTL_PIPE_WAIT(tvb, pinfo, tree, 0, top_tree, data_in);
+               break;
+       case 0x00140078: /* FSCTL_SRV_REQUEST_RESUME_KEY */
+               dissect_smb2_FSCTL_SRV_REQUEST_RESUME_KEY(tvb, pinfo, tree, 0, data_in);
                break;
        case 0x001401D4: /* FSCTL_LMR_REQUEST_RESILIENCY */
                dissect_smb2_FSCTL_LMR_REQUEST_RESILIENCY(tvb, pinfo, tree, 0, data_in);
@@ -4950,19 +5907,29 @@ dissect_smb2_ioctl_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, pro
        case 0x00140204: /* FSCTL_VALIDATE_NEGOTIATE_INFO */
                dissect_smb2_FSCTL_VALIDATE_NEGOTIATE_INFO(tvb, pinfo, tree, 0, data_in);
                break;
-       case 0x00144064: /* FSCTL_GET_SHADOW_COPY_DATA */
-               dissect_smb2_FSCTL_GET_SHADOW_COPY_DATA(tvb, pinfo, tree, 0, data_in);
+       case 0x00144064: /* FSCTL_SRV_ENUMERATE_SNAPSHOTS */
+               dissect_smb2_FSCTL_SRV_ENUMERATE_SNAPSHOTS(tvb, pinfo, tree, 0, data_in);
+               break;
+       case 0x001440F2: /* FSCTL_SRV_COPYCHUNK */
+       case 0x001480F2: /* FSCTL_SRV_COPYCHUNK_WRITE */
+               dissect_smb2_FSCTL_SRV_COPYCHUNK(tvb, pinfo, tree, 0, data_in);
                break;
        case 0x0009009C: /* FSCTL_GET_OBJECT_ID */
        case 0x000900c0: /* FSCTL_CREATE_OR_GET_OBJECT_ID */
                dissect_smb2_FSCTL_CREATE_OR_GET_OBJECT_ID(tvb, pinfo, tree, 0, data_in);
                break;
+       case 0x000900c4: /* FSCTL_SET_SPARSE */
+               dissect_smb2_FSCTL_SET_SPARSE(tvb, pinfo, tree, 0, data_in);
+               break;
        case 0x00098098: /* FSCTL_SET_OBJECT_ID */
                dissect_smb2_FSCTL_SET_OBJECT_ID(tvb, pinfo, tree, 0, data_in);
                break;
        case 0x000980BC: /* FSCTL_SET_OBJECT_ID_EXTENDED */
                dissect_smb2_FSCTL_SET_OBJECT_ID_EXTENDED(tvb, pinfo, tree, 0, data_in);
                break;
+       case 0x000980C8: /* FSCTL_SET_ZERO_DATA */
+               dissect_smb2_FSCTL_SET_ZERO_DATA(tvb, pinfo, tree, 0, data_in);
+               break;
        case 0x0009003C: /* FSCTL_GET_COMPRESSION */
                dissect_smb2_FSCTL_GET_COMPRESSION(tvb, pinfo, tree, 0, data_in);
                break;
@@ -4976,26 +5943,29 @@ dissect_smb2_ioctl_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, pro
        case 0x0009C040: /* FSCTL_SET_COMPRESSION */
                dissect_smb2_FSCTL_SET_COMPRESSION(tvb, pinfo, tree, 0, data_in);
                break;
+       case 0x00090284: /* FSCTL_QUERY_FILE_REGIONS */
+               dissect_smb2_FSCTL_QUERY_FILE_REGIONS(tvb, pinfo, tree, 0, data_in);
+               break;
        case 0x0009C280: /* FSCTL_SET_INTEGRITY_INFORMATION request or response */
                dissect_smb2_FSCTL_SET_INTEGRITY_INFORMATION(tvb, pinfo, tree, 0, data_in);
                break;
        default:
-               proto_tree_add_item(tree, hf_smb2_unknown, tvb, 0, tvb_length(tvb), ENC_NA);
+               proto_tree_add_item(tree, hf_smb2_unknown, tvb, 0, tvb_captured_length(tvb), ENC_NA);
        }
 }
 
 static void
 dissect_smb2_ioctl_data_in(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, smb2_info_t *si)
 {
-       smb2_set_dcerpc_file_id(pinfo, si);
-       dissect_smb2_ioctl_data(tvb, pinfo, tree, si->top_tree, si->ioctl_function, TRUE);
+       smb2_pipe_set_file_id(pinfo, si);
+       dissect_smb2_ioctl_data(tvb, pinfo, tree, si->top_tree, si->ioctl_function, TRUE, si);
 }
 
 static void
 dissect_smb2_ioctl_data_out(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, smb2_info_t *si)
 {
-       smb2_set_dcerpc_file_id(pinfo, si);
-       dissect_smb2_ioctl_data(tvb, pinfo, tree, si->top_tree, si->ioctl_function, FALSE);
+       smb2_pipe_set_file_id(pinfo, si);
+       dissect_smb2_ioctl_data(tvb, pinfo, tree, si->top_tree, si->ioctl_function, FALSE, si);
 }
 
 static int
@@ -5070,14 +6040,15 @@ dissect_smb2_ioctl_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 {
        offset_length_buffer_t o_olb;
        offset_length_buffer_t i_olb;
+       gboolean continue_dissection;
 
        switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
-
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       case 0x80000005: break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* some unknown bytes */
        proto_tree_add_item(tree, hf_smb2_unknown, tvb, offset, 2, ENC_NA);
@@ -5199,13 +6170,14 @@ dissect_smb2_read_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        guint16 dataoffset = 0;
        guint32 data_tvb_len;
        guint32 length;
-       switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
+       gboolean continue_dissection;
 
+       switch (si->status) {
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* data offset */
        dataoffset=tvb_get_letohl(tvb,offset);
@@ -5224,20 +6196,21 @@ dissect_smb2_read_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        /* reserved */
        offset += 4;
 
-       /* data or dcerpc ?
-        * If the pidvalid flag is set we assume it is a deferred
-        * STATUS_PENDING read and thus a named pipe (==dcerpc)
-        */
-       if (length && ( (si->tree && si->tree->share_type == SMB2_SHARE_TYPE_PIPE)||(si->flags & SMB2_FLAGS_ASYNC_CMD))) {
-               smb2_set_dcerpc_file_id(pinfo, si);
-               offset = dissect_file_data_dcerpc(tvb, pinfo, tree, offset, length, si->top_tree);
-               return offset;
+       /* data or namedpipe ?*/
+       if (length) {
+               int oldoffset = offset;
+               smb2_pipe_set_file_id(pinfo, si);
+               offset = dissect_file_data_smb2_pipe(tvb, pinfo, tree, offset, length, si->top_tree, si);
+               if (offset != oldoffset) {
+                       /* managed to dissect pipe data */
+                       return offset;
+               }
        }
 
        /* data */
        proto_tree_add_item(tree, hf_smb2_read_data, tvb, offset, length, ENC_NA);
 
-       data_tvb_len=(guint32)tvb_length_remaining(tvb, offset);
+       data_tvb_len=(guint32)tvb_captured_length_remaining(tvb, offset);
 
        offset += MIN(length,data_tvb_len);
 
@@ -5317,7 +6290,7 @@ dissect_smb2_QFid_buffer_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tr
        }
 
        if (item) {
-               if (tvb_length(tvb) == 0) {
+               if (tvb_reported_length(tvb) == 0) {
                        proto_item_append_text(item, ": NO DATA");
                } else {
                        proto_item_append_text(item, ": QFid request should have no data, malformed packet");
@@ -5490,7 +6463,7 @@ dissect_smb2_MxAc_buffer_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tr
                item = proto_tree_get_parent(tree);
        }
 
-       if (tvb_length(tvb) == 0) {
+       if (tvb_reported_length(tvb) == 0) {
                if (item) {
                        proto_item_append_text(item, ": NO DATA");
                }
@@ -5513,7 +6486,7 @@ dissect_smb2_MxAc_buffer_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_t
 
        item = proto_tree_get_parent(tree);
 
-       if (tvb_length(tvb) == 0) {
+       if (tvb_reported_length(tvb) == 0) {
                proto_item_append_text(item, ": NO DATA");
                return;
        }
@@ -5574,16 +6547,16 @@ dissect_SMB2_CREATE_LEASE_VX(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *
 
        parent_item = proto_tree_get_parent(parent_tree);
 
-       len = tvb_length(tvb);
+       len = tvb_reported_length(tvb);
 
        switch (len) {
        case 32: /* SMB2_CREATE_REQUEST/RESPONSE_LEASE */
                proto_item_append_text(parent_item, ": LEASE_V1");
-               sub_tree = proto_tree_add_subtree(parent_tree, tvb, offset, len, ett_smb2_RqLs_buffer, NULL, "LEASE_V1");
+               sub_tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_smb2_RqLs_buffer, NULL, "LEASE_V1");
                break;
        case 52: /* SMB2_CREATE_REQUEST/RESPONSE_LEASE_V2 */
                proto_item_append_text(parent_item, ": LEASE_V2");
-               sub_tree = proto_tree_add_subtree(parent_tree, tvb, offset, len, ett_smb2_RqLs_buffer, NULL, "LEASE_V2");
+               sub_tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, ett_smb2_RqLs_buffer, NULL, "LEASE_V2");
                break;
        default:
                report_create_context_malformed_buffer(tvb, pinfo, parent_tree, "RqLs");
@@ -5734,6 +6707,242 @@ dissect_smb2_svhdx_open_device_context_response(tvbuff_t *tvb, packet_info *pinf
        report_create_context_malformed_buffer(tvb, pinfo, tree, "SHVXD OPEN DEVICE CONTEXT Response");
 }
 
+static const int *posix_flags_fields[] = {
+       &hf_smb2_posix_v1_case_sensitive,
+       &hf_smb2_posix_v1_posix_lock,
+       &hf_smb2_posix_v1_posix_file_semantics,
+       &hf_smb2_posix_v1_posix_utf8_paths,
+       &hf_smb2_posix_v1_posix_will_convert_nt_acls,
+       &hf_smb2_posix_v1_posix_fileinfo,
+       &hf_smb2_posix_v1_posix_acls,
+       &hf_smb2_posix_v1_rich_acls,
+       NULL
+};
+
+static void
+dissect_smb2_posix_v1_caps_request(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree, smb2_info_t *si _U_)
+{
+       int         offset   = 0;
+       proto_item *item;
+       proto_item *sub_tree;
+
+       item = proto_tree_get_parent(tree);
+
+       proto_item_append_text(item, ": POSIX V1 CAPS request");
+       sub_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_smb2_posix_v1_request, NULL, "POSIX_V1_REQUEST");
+
+       /* Version */
+       proto_tree_add_item(sub_tree, hf_smb2_posix_v1_version,
+                           tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
+
+       /* Request */
+       proto_tree_add_item(sub_tree, hf_smb2_posix_v1_request,
+                           tvb, offset, 4, ENC_LITTLE_ENDIAN);
+}
+
+static void
+dissect_smb2_posix_v1_caps_response(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree, smb2_info_t *si _U_)
+{
+       int         offset   = 0;
+       proto_item *item;
+       proto_item *sub_tree;
+
+       item = proto_tree_get_parent(tree);
+
+       proto_item_append_text(item, ": POSIX V1 CAPS response");
+       sub_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_smb2_posix_v1_response, NULL, "POSIX_V1_RESPONSE");
+
+       /* Version */
+       proto_tree_add_item(sub_tree, hf_smb2_posix_v1_version,
+                           tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
+
+       /* Supported Features */
+       proto_tree_add_bitmask(sub_tree, tvb, offset,
+                              hf_smb2_posix_v1_supported_features,
+                              ett_smb2_posix_v1_supported_features,
+                              posix_flags_fields, ENC_LITTLE_ENDIAN);
+
+}
+
+#define SMB2_AAPL_SERVER_QUERY 1
+#define SMB2_AAPL_RESOLVE_ID   2
+
+static const value_string aapl_command_code_vals[] = {
+       { SMB2_AAPL_SERVER_QUERY,       "Server query"},
+       { SMB2_AAPL_RESOLVE_ID,         "Resolve ID"},
+       { 0, NULL }
+};
+
+#define SMB2_AAPL_SERVER_CAPS          0x00000001
+#define SMB2_AAPL_VOLUME_CAPS          0x00000002
+#define SMB2_AAPL_MODEL_INFO           0x00000004
+
+static const int *aapl_server_query_bitmap_fields[] = {
+       &hf_smb2_aapl_server_query_bitmask_server_caps,
+       &hf_smb2_aapl_server_query_bitmask_volume_caps,
+       &hf_smb2_aapl_server_query_bitmask_model_info,
+       NULL
+};
+
+#define SMB2_AAPL_SUPPORTS_READ_DIR_ATTR       0x00000001
+#define SMB2_AAPL_SUPPORTS_OSX_COPYFILE                0x00000002
+#define SMB2_AAPL_UNIX_BASED                   0x00000004
+#define SMB2_AAPL_SUPPORTS_NFS_ACE             0x00000008
+
+static const int *aapl_server_query_caps_fields[] = {
+       &hf_smb2_aapl_server_query_caps_supports_read_dir_attr,
+       &hf_smb2_aapl_server_query_caps_supports_osx_copyfile,
+       &hf_smb2_aapl_server_query_caps_unix_based,
+       &hf_smb2_aapl_server_query_caps_supports_nfs_ace,
+       NULL
+};
+
+static void
+dissect_smb2_AAPL_buffer_request(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, smb2_info_t *si _U_)
+{
+       int         offset   = 0;
+       proto_item *item;
+       proto_item *sub_tree;
+       guint32     command_code;
+
+       item = proto_tree_get_parent(tree);
+
+       proto_item_append_text(item, ": AAPL Create Context request");
+       sub_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_smb2_aapl_create_context_request, NULL, "AAPL Create Context request");
+
+       /* Command code */
+       proto_tree_add_item_ret_uint(sub_tree, hf_smb2_aapl_command_code,
+           tvb, offset, 4, ENC_LITTLE_ENDIAN, &command_code);
+       offset += 4;
+
+       /* Reserved */
+       proto_tree_add_item(sub_tree, hf_smb2_aapl_reserved,
+           tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
+
+       switch (command_code) {
+
+       case SMB2_AAPL_SERVER_QUERY:
+               /* Request bitmap */
+               proto_tree_add_bitmask(sub_tree, tvb, offset,
+                                      hf_smb2_aapl_server_query_bitmask,
+                                      ett_smb2_aapl_server_query_bitmask,
+                                      aapl_server_query_bitmap_fields,
+                                      ENC_LITTLE_ENDIAN);
+               offset += 8;
+
+               /* Client capabilities */
+               proto_tree_add_bitmask(sub_tree, tvb, offset,
+                                      hf_smb2_aapl_server_query_caps,
+                                      ett_smb2_aapl_server_query_caps,
+                                      aapl_server_query_caps_fields,
+                                      ENC_LITTLE_ENDIAN);
+               break;
+
+       case SMB2_AAPL_RESOLVE_ID:
+               /* file ID */
+               proto_tree_add_item(sub_tree, hf_smb2_file_id, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+               break;
+
+       default:
+               break;
+       }
+}
+
+#define SMB2_AAPL_SUPPORTS_RESOLVE_ID  0x00000001
+#define SMB2_AAPL_CASE_SENSITIVE               0x00000002
+#define SMB2_AAPL_SUPPORTS_FULL_SYNC   0x00000004
+
+static const int *aapl_server_query_volume_caps_fields[] = {
+       &hf_smb2_aapl_server_query_volume_caps_support_resolve_id,
+       &hf_smb2_aapl_server_query_volume_caps_case_sensitive,
+       &hf_smb2_aapl_server_query_volume_caps_supports_full_sync,
+       NULL
+};
+
+static void
+dissect_smb2_AAPL_buffer_response(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, smb2_info_t *si _U_)
+{
+       int         offset   = 0;
+       proto_item *item;
+       proto_item *sub_tree;
+       guint32     command_code;
+       guint64     server_query_bitmask;
+
+       item = proto_tree_get_parent(tree);
+
+       proto_item_append_text(item, ": AAPL Create Context response");
+       sub_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_smb2_aapl_create_context_response, NULL, "AAPL Create Context response");
+
+       /* Command code */
+       proto_tree_add_item_ret_uint(sub_tree, hf_smb2_aapl_command_code,
+           tvb, offset, 4, ENC_LITTLE_ENDIAN, &command_code);
+       offset += 4;
+
+       /* Reserved */
+       proto_tree_add_item(sub_tree, hf_smb2_aapl_reserved,
+           tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
+
+       switch (command_code) {
+
+       case SMB2_AAPL_SERVER_QUERY:
+               /* Reply bitmap */
+               proto_tree_add_bitmask_ret_uint64(sub_tree, tvb, offset,
+                                                 hf_smb2_aapl_server_query_bitmask,
+                                                 ett_smb2_aapl_server_query_bitmask,
+                                                 aapl_server_query_bitmap_fields,
+                                                 ENC_LITTLE_ENDIAN,
+                                                 &server_query_bitmask);
+               offset += 8;
+
+               if (server_query_bitmask & SMB2_AAPL_SERVER_CAPS) {
+                       /* Server capabilities */
+                       proto_tree_add_bitmask(sub_tree, tvb, offset,
+                                              hf_smb2_aapl_server_query_caps,
+                                              ett_smb2_aapl_server_query_caps,
+                                              aapl_server_query_caps_fields,
+                                              ENC_LITTLE_ENDIAN);
+                       offset += 8;
+               }
+               if (server_query_bitmask & SMB2_AAPL_VOLUME_CAPS) {
+                       /* Volume capabilities */
+                       proto_tree_add_bitmask(sub_tree, tvb, offset,
+                                              hf_smb2_aapl_server_query_volume_caps,
+                                              ett_smb2_aapl_server_query_volume_caps,
+                                              aapl_server_query_volume_caps_fields,
+                                              ENC_LITTLE_ENDIAN);
+                       offset += 8;
+               }
+               if (server_query_bitmask & SMB2_AAPL_MODEL_INFO) {
+                       /* Padding */
+                       offset += 4;
+
+                       /* Model string */
+                       proto_tree_add_item(sub_tree, hf_smb2_aapl_server_query_model_string,
+                                           tvb, offset, 4,
+                                           ENC_UTF_16|ENC_LITTLE_ENDIAN);
+               }
+               break;
+
+       case SMB2_AAPL_RESOLVE_ID:
+               /* NT status */
+               proto_tree_add_item(sub_tree, hf_smb2_nt_status, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+
+               /* Server path */
+               proto_tree_add_item(sub_tree, hf_smb2_aapl_server_query_server_path,
+                                   tvb, offset, 4,
+                                   ENC_UTF_16|ENC_LITTLE_ENDIAN);
+               break;
+
+       default:
+               break;
+       }
+}
+
 typedef void (*create_context_data_dissector_t)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, smb2_info_t *si);
 
 typedef struct create_context_data_dissectors {
@@ -5771,14 +6980,15 @@ struct create_context_data_tag_dissectors create_context_dissectors_array[] = {
        { "RqLs", "SMB2_CREATE_REQUEST_LEASE",
          { dissect_smb2_RqLs_buffer_request, dissect_smb2_RqLs_buffer_response } },
        { "744D142E-46FA-0890-4AF7-A7EF6AA6BC45", "SMB2_CREATE_APP_INSTANCE_ID",
-               { dissect_smb2_APP_INSTANCE_buffer_request,
-                 dissect_smb2_APP_INSTANCE_buffer_response } },
+         { dissect_smb2_APP_INSTANCE_buffer_request, dissect_smb2_APP_INSTANCE_buffer_response } },
        { "6aa6bc45-a7ef-4af7-9008-fa462e144d74", "SMB2_CREATE_APP_INSTANCE_ID",
-               { dissect_smb2_APP_INSTANCE_buffer_request,
-                 dissect_smb2_APP_INSTANCE_buffer_response } },
+         { dissect_smb2_APP_INSTANCE_buffer_request, dissect_smb2_APP_INSTANCE_buffer_response } },
        { "9ecfcb9c-c104-43e6-980e-158da1f6ec83", "SVHDX_OPEN_DEVICE_CONTEXT",
-               { dissect_smb2_svhdx_open_device_context_request,
-                 dissect_smb2_svhdx_open_device_context_response} }
+         { dissect_smb2_svhdx_open_device_context_request, dissect_smb2_svhdx_open_device_context_response} },
+       { "34263501-2921-4912-2586-447794114531", "SMB2_POSIX_V1_CAPS",
+         { dissect_smb2_posix_v1_caps_request, dissect_smb2_posix_v1_caps_response } },
+       { "AAPL", "SMB2_AAPL_CREATE_CONTEXT",
+         { dissect_smb2_AAPL_buffer_request, dissect_smb2_AAPL_buffer_response } },
 };
 
 static struct create_context_data_tag_dissectors*
@@ -5966,14 +7176,14 @@ dissect_smb2_create_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
                &hf_smb2_create_rep_flags_reparse_point,
                NULL
        };
+       gboolean continue_dissection;
 
        switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
-
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        /* oplock */
        offset = dissect_smb2_oplock(tree, tvb, offset);
@@ -6091,16 +7301,16 @@ dissect_smb2_setinfo_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
 static int
 dissect_smb2_setinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_info_t *si)
 {
+       gboolean continue_dissection;
        /* class/infolevel */
        dissect_smb2_class_infolevel(pinfo, tvb, offset, tree, si);
 
        switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
-
        /* buffer code */
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        return offset;
 }
@@ -6166,15 +7376,15 @@ static int
 dissect_smb2_break_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, smb2_info_t *si)
 {
        guint16 buffer_code;
-
-       switch (si->status) {
-       case 0x00000000: break;
-       default: return dissect_smb2_error_response(tvb, pinfo, tree, offset, si);
-       }
+       gboolean continue_dissection;
 
        /* buffer code */
        buffer_code = tvb_get_letohs(tvb, offset);
-       offset = dissect_smb2_buffercode(tree, tvb, offset, NULL);
+       switch (si->status) {
+       case 0x00000000: offset = dissect_smb2_buffercode(tree, tvb, offset, NULL); break;
+       default: offset = dissect_smb2_error_response(tvb, pinfo, tree, offset, si, &continue_dissection);
+               if (!continue_dissection) return offset;
+       }
 
        if (buffer_code == 24) {
                /* OPLOCK Break Notification */
@@ -6942,11 +8152,11 @@ dissect_smb2_transform_header(packet_info *pinfo _U_, proto_tree *tree,
 
                memcpy(&A_1[1], sti->nonce, 15 - 4);
 
-               plain_data = (guint8 *)tvb_memdup(NULL, tvb, offset, sti->size);
+               plain_data = (guint8 *)tvb_memdup(pinfo->pool, tvb, offset, sti->size);
 
                /* Open the cipher. */
                if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0)) {
-                       g_free(plain_data);
+                       wmem_free(pinfo->pool, plain_data);
                        plain_data = NULL;
                        goto done_decryption;
                }
@@ -6954,20 +8164,20 @@ dissect_smb2_transform_header(packet_info *pinfo _U_, proto_tree *tree,
                /* Set the key and initial value. */
                if (gcry_cipher_setkey(cipher_hd, decryption_key, 16)) {
                        gcry_cipher_close(cipher_hd);
-                       g_free(plain_data);
+                       wmem_free(pinfo->pool, plain_data);
                        plain_data = NULL;
                        goto done_decryption;
                }
                if (gcry_cipher_setctr(cipher_hd, A_1, 16)) {
                        gcry_cipher_close(cipher_hd);
-                       g_free(plain_data);
+                       wmem_free(pinfo->pool, plain_data);
                        plain_data = NULL;
                        goto done_decryption;
                }
 
                if (gcry_cipher_encrypt(cipher_hd, plain_data, sti->size, NULL, 0)) {
                        gcry_cipher_close(cipher_hd);
-                       g_free(plain_data);
+                       wmem_free(pinfo->pool, plain_data);
                        plain_data = NULL;
                        goto done_decryption;
                }
@@ -6981,7 +8191,6 @@ done_decryption:
 
        if (plain_data != NULL) {
                *plain_tvb = tvb_new_child_real_data(*enc_tvb, plain_data, sti->size, sti->size);
-               tvb_set_free_cb(*plain_tvb, g_free);
                add_new_data_source(pinfo, *plain_tvb, "Decrypted SMB3");
        }
 
@@ -7010,7 +8219,7 @@ dissect_smb2_command(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int of
                offset = (*cmd_dissector)(tvb, pinfo, cmd_tree, offset, si);
        } else {
                proto_tree_add_item(cmd_tree, hf_smb2_unknown, tvb, offset, -1, ENC_NA);
-               offset = tvb_length(tvb);
+               offset = tvb_captured_length(tvb);
        }
 
        proto_item_set_len(cmd_item, offset-old_offset);
@@ -7158,6 +8367,8 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea
                        smb2_saved_info_equal_unmatched);
                si->conv->sesids = g_hash_table_new(smb2_sesid_info_hash,
                        smb2_sesid_info_equal);
+               si->conv->fids = g_hash_table_new(smb2_fid_info_hash,
+                       smb2_fid_info_equal);
                si->conv->files = g_hash_table_new(smb2_eo_files_hash,smb2_eo_files_equal);
 
                /* Bit of a hack to avoid leaking the hash tables - register a
@@ -7235,6 +8446,7 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea
                                &hf_smb2_flags_async_cmd,
                                &hf_smb2_flags_chained,
                                &hf_smb2_flags_signature,
+                               &hf_smb2_flags_priority_mask,
                                &hf_smb2_flags_dfs_op,
                                &hf_smb2_flags_replay_operation,
                                NULL
@@ -7302,16 +8514,18 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea
                                        */
                                        ssi                  = wmem_new0(wmem_file_scope(), smb2_saved_info_t);
                                        ssi->msg_id          = ssi_key.msg_id;
-                                       ssi->frame_req       = pinfo->fd->num;
-                                       ssi->req_time        = pinfo->fd->abs_ts;
+                                       ssi->frame_req       = pinfo->num;
+                                       ssi->req_time        = pinfo->abs_ts;
                                        ssi->extra_info_type = SMB2_EI_NONE;
                                        g_hash_table_insert(si->conv->unmatched, ssi, ssi);
                                }
                        } else {
                                /* This is a response */
-                               if (ssi) {
+                               if (!((si->flags & SMB2_FLAGS_ASYNC_CMD)
+                                       && si->status == NT_STATUS_PENDING)
+                                       && ssi) {
                                        /* just  set the response frame and move it to the matched table */
-                                       ssi->frame_res = pinfo->fd->num;
+                                       ssi->frame_res = pinfo->num;
                                        g_hash_table_remove(si->conv->unmatched, ssi);
                                        g_hash_table_insert(si->conv->matched, ssi, ssi);
                                }
@@ -7328,7 +8542,7 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea
                }
 
                if (ssi) {
-                       if (dcerpc_fetch_polhnd_data(&ssi->policy_hnd, &fid_name, NULL, &open_frame, &close_frame, pinfo->fd->num)) {
+                       if (dcerpc_fetch_polhnd_data(&ssi->policy_hnd, &fid_name, NULL, &open_frame, &close_frame, pinfo->num)) {
                                /* If needed, create the file entry and save the policy hnd */
                                if (!si->eo_file_info) {
                                        if (si->conv) {
@@ -7359,13 +8573,18 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea
 
                                        tmp_item = proto_tree_add_uint(header_tree, hf_smb2_response_to, tvb, 0, 0, ssi->frame_req);
                                        PROTO_ITEM_SET_GENERATED(tmp_item);
-                                       t = pinfo->fd->abs_ts;
+                                       t = pinfo->abs_ts;
                                        nstime_delta(&deltat, &t, &ssi->req_time);
                                        tmp_item = proto_tree_add_time(header_tree, hf_smb2_time, tvb,
                                        0, 0, &deltat);
                                        PROTO_ITEM_SET_GENERATED(tmp_item);
                                }
                        }
+                       if (si->file != NULL) {
+                               ssi->file = si->file;
+                       } else {
+                               si->file = ssi->file;
+                       }
                }
                /* if we don't have ssi yet we must fake it */
                /*qqq*/
@@ -7419,7 +8638,7 @@ dissect_smb2_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, vo
 {
 
        /* must check that this really is a smb2 packet */
-       if (tvb_length(tvb) < 4)
+       if (tvb_captured_length(tvb) < 4)
                return FALSE;
 
        if (((tvb_get_guint8(tvb, 0) != 0xfe) && (tvb_get_guint8(tvb, 0) != 0xfd))
@@ -7459,7 +8678,7 @@ proto_register_smb2(void)
                    &NT_errors_ext, 0, "NT Status code", HFILL }},
                { &hf_smb2_msg_id,
                  { "Message ID", "smb2.msg_id", FT_INT64, BASE_DEC,
-                   NULL, 0, "SMB2 Messsage ID", HFILL }},
+                   NULL, 0, "SMB2 Message ID", HFILL }},
                { &hf_smb2_tid,
                  { "Tree Id", "smb2.tid", FT_UINT32, BASE_HEX,
                    NULL, 0, "SMB2 Tree Id", HFILL }},
@@ -7531,17 +8750,26 @@ proto_register_smb2(void)
                { &hf_smb2_flags_replay_operation,
                  { "Replay operation", "smb2.flags.replay", FT_BOOLEAN, 32,
                    TFS(&tfs_flags_replay_operation), SMB2_FLAGS_REPLAY_OPERATION, "Whether this is a replay operation", HFILL }},
+               { &hf_smb2_flags_priority_mask,
+                 { "Priority", "smb2.flags.priority_mask", FT_BOOLEAN, 32,
+                   TFS(&tfs_flags_priority_mask), SMB2_FLAGS_PRIORITY_MASK, "Priority Mask", HFILL }},
 
                { &hf_smb2_tree,
                  { "Tree", "smb2.tree", FT_STRING, BASE_NONE,
                    NULL, 0, "Name of the Tree/Share", HFILL }},
+
                { &hf_smb2_filename,
                  { "Filename", "smb2.filename", FT_STRING, BASE_NONE,
                    NULL, 0, "Name of the file", HFILL }},
+
                { &hf_smb2_filename_len,
                  { "Filename Length", "smb2.filename.len", FT_UINT32, BASE_DEC,
                    NULL, 0, "Length of the file name", HFILL }},
 
+               { &hf_smb2_replace_if,
+                 { "Replace If", "smb2.rename.replace_if", FT_BOOLEAN, 8,
+                   TFS(&tfs_replace_if_exists), 0xFF, "Whether to replace if the target exists", HFILL }},
+
                { &hf_smb2_data_offset,
                  { "Data Offset", "smb2.data_offset", FT_UINT16, BASE_HEX,
                    NULL, 0, "Offset to data", HFILL }},
@@ -7585,6 +8813,10 @@ proto_register_smb2(void)
                  { "InfoLevel", "smb2.sec_info.infolevel", FT_UINT8, BASE_HEX | BASE_EXT_STRING,
                    &smb2_sec_info_levels_ext, 0, "Sec_Info Infolevel", HFILL }},
 
+               { &hf_smb2_infolevel_posix_info,
+                 { "InfoLevel", "smb2.posix_info.infolevel", FT_UINT8, BASE_HEX | BASE_EXT_STRING,
+                   &smb2_posix_info_levels_ext, 0, "Posix_Info Infolevel", HFILL }},
+
                { &hf_smb2_write_length,
                  { "Write Length", "smb2.write_length", FT_UINT32, BASE_DEC,
                    NULL, 0, "Amount of data to write", HFILL }},
@@ -7605,6 +8837,34 @@ proto_register_smb2(void)
                  { "File Offset", "smb2.file_offset", FT_UINT64, BASE_DEC,
                    NULL, 0, NULL, HFILL }},
 
+               { &hf_smb2_fsctl_range_offset,
+                 { "File Offset", "smb2.fsctl.range_offset", FT_UINT64, BASE_DEC,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_fsctl_range_length,
+                 { "Length", "smb2.fsctl.range_length", FT_UINT64, BASE_DEC,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_qfr_length,
+                 { "Length", "smb2.qfr_length", FT_UINT64, BASE_DEC,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_qfr_usage,
+                 { "Desired Usage", "smb2.qfr_usage", FT_UINT32, BASE_HEX,
+                   VALS(file_region_usage_vals), 0, NULL, HFILL }},
+
+               { &hf_smb2_qfr_flags,
+                 { "Flags", "smb2.qfr_flags", FT_UINT32, BASE_HEX,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_qfr_total_region_entry_count,
+                 { "Total Region Entry Count", "smb2.qfr_tot_region_entry_count", FT_UINT32, BASE_HEX,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_qfr_region_entry_count,
+                 { "Region Entry Count", "smb2.qfr_region_entry_count", FT_UINT32, BASE_HEX,
+                   NULL, 0, NULL, HFILL }},
+
                { &hf_smb2_security_blob,
                  { "Security Blob", "smb2.security_blob", FT_BYTES, BASE_NONE,
                    NULL, 0, NULL, HFILL }},
@@ -8010,6 +9270,63 @@ proto_register_smb2(void)
                  { "Method", "smb2.ioctl.function.method", FT_UINT32, BASE_HEX,
                    VALS(smb2_ioctl_method_vals), 0x00000003, "Method for Ioctl", HFILL }},
 
+               { &hf_smb2_fsctl_pipe_wait_timeout,
+                 { "Timeout", "smb2.fsctl.wait.timeout", FT_INT64, BASE_DEC,
+                   NULL, 0, "Wait timeout", HFILL }},
+
+               { &hf_smb2_fsctl_pipe_wait_name,
+                 { "Name", "smb2.fsctl.wait.name", FT_STRING, BASE_NONE,
+                   NULL, 0, "Pipe name", HFILL }},
+
+               { &hf_smb2_fsctl_odx_token_type,
+                 { "TokenType", "smb2.fsctl.odx.token.type", FT_UINT32, BASE_HEX,
+                   NULL, 0, "Token Type", HFILL }},
+
+               { &hf_smb2_fsctl_odx_token_idlen,
+                 { "TokenIdLength", "smb2.fsctl.odx.token.idlen", FT_UINT16, BASE_DEC,
+                   NULL, 0, "Token ID Length", HFILL }},
+
+               { &hf_smb2_fsctl_odx_token_idraw,
+                 { "TokenId", "smb2.fsctl.odx.token.id", FT_BYTES, BASE_NONE,
+                   NULL, 0, "Token ID (opaque)", HFILL }},
+
+               { &hf_smb2_fsctl_odx_token_ttl,
+                 { "TokenTimeToLive", "smb2.fsctl.odx.token_ttl",
+                   FT_UINT32, BASE_DEC, NULL, 0,
+                   "TTL requested for the token (in milliseconds)", HFILL }},
+
+               { &hf_smb2_fsctl_odx_size,
+                 { "Size", "smb2.fsctl.odx.size", FT_UINT32, BASE_DEC,
+                   NULL, 0, "Size of this data element", HFILL }},
+
+               { &hf_smb2_fsctl_odx_flags,
+                 { "Flags", "smb2.fsctl.odx.flags", FT_UINT32, BASE_HEX,
+                   NULL, 0, "Flags for this operation", HFILL }},
+
+               { &hf_smb2_fsctl_odx_file_offset,
+                 { "FileOffset", "smb2.fsctl.odx.file_offset",
+                   FT_UINT64, BASE_DEC, NULL, 0,
+                   "File offset", HFILL }},
+
+               { &hf_smb2_fsctl_odx_copy_length,
+                 { "CopyLength", "smb2.fsctl.odx.copy_length",
+                   FT_UINT64, BASE_DEC, NULL, 0,
+                   "Copy length", HFILL }},
+
+               { &hf_smb2_fsctl_odx_xfer_length,
+                 { "TransferLength", "smb2.fsctl.odx.xfer_length",
+                   FT_UINT64, BASE_DEC, NULL, 0,
+                   "Length Transfered", HFILL }},
+
+               { &hf_smb2_fsctl_odx_token_offset,
+                 { "TokenOffset", "smb2.fsctl.odx.token_offset",
+                   FT_UINT64, BASE_DEC, NULL, 0,
+                   "Token Offset (relative to start of token)", HFILL }},
+
+               { &hf_smb2_fsctl_sparse_flag,
+                 { "SetSparse", "smb2.fsctl.set_sparse", FT_BOOLEAN, 8,
+                   NULL, 0xFF, NULL, HFILL }},
+
                { &hf_smb2_ioctl_resiliency_timeout,
                  { "Timeout", "smb2.ioctl.resiliency.timeout", FT_UINT32, BASE_DEC,
                    NULL, 0, "Resiliency timeout", HFILL }},
@@ -8401,6 +9718,19 @@ proto_register_smb2(void)
                  { "Out Data", "smb2.notify.out", FT_NONE, BASE_NONE,
                    NULL, 0, NULL, HFILL }},
 
+               { &hf_smb2_notify_info,
+                 { "Notify Info", "smb2.notify.info", FT_NONE, BASE_NONE,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_notify_next_offset,
+                 { "Next Offset", "smb2.notify.next_offset", FT_UINT32, BASE_HEX,
+                   NULL, 0, "Offset to next entry in chain or 0", HFILL }},
+
+               { &hf_smb2_notify_action,
+                 { "Action", "smb2.notify.action", FT_UINT32, BASE_HEX,
+                   VALS(notify_action_vals), 0, "Notify Action", HFILL }},
+
+
                { &hf_smb2_find_flags_restart_scans,
                  { "Restart Scans", "smb2.find.restart_scans", FT_BOOLEAN, 8,
                    NULL, SMB2_FIND_FLAG_RESTART_SCANS, NULL, HFILL }},
@@ -8489,6 +9819,14 @@ proto_register_smb2(void)
                  { "Reserved", "smb2.reserved", FT_BYTES, BASE_NONE,
                    NULL, 0, "Reserved bytes", HFILL }},
 
+               { &hf_smb2_reserved_random,
+                 { "Reserved (Random)", "smb2.reserved.random", FT_BYTES, BASE_NONE,
+                   NULL, 0, "Reserved bytes, random data", HFILL }},
+
+               { &hf_smb2_root_directory_mbz,
+                 { "Root Dir Handle (MBZ)", "smb2.root_directory", FT_BYTES, BASE_NONE,
+                   NULL, 0, "Root Directory Handle, mbz", HFILL }},
+
                { &hf_smb2_dhnq_buffer_reserved,
                  { "Reserved", "smb2.dhnq_buffer_reserved", FT_UINT64, BASE_HEX,
                    NULL, 0, NULL, HFILL}},
@@ -8561,6 +9899,118 @@ proto_register_smb2(void)
                  { "HostName", "smb2.svhdx_open_device_context.host_name", FT_STRING, BASE_NONE,
                     NULL, 0, NULL, HFILL }},
 
+               { &hf_smb2_posix_v1_version,
+                 { "Version", "smb2.posix_v1_version", FT_UINT32, BASE_DEC,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_posix_v1_request,
+                 { "Request", "smb2.posix_request", FT_UINT32, BASE_HEX,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_posix_v1_case_sensitive,
+                 { "Posix Case Sensitive File Names", "smb2.posix_case_sensitive", FT_UINT32, BASE_HEX,
+                   VALS(posix_case_sensitive_vals), 0x01, NULL, HFILL }},
+
+               { &hf_smb2_posix_v1_posix_lock,
+                 { "Posix Byte-Range Locks", "smb2.posix_locks", FT_UINT32, BASE_HEX,
+                   VALS(posix_locks_vals), 0x02, NULL, HFILL }},
+
+               { &hf_smb2_posix_v1_posix_file_semantics,
+                 { "Posix File Semantics", "smb2.posix_file_semantics", FT_UINT32, BASE_HEX,
+                   VALS(posix_file_semantics_vals), 0x04, NULL, HFILL }},
+
+               { &hf_smb2_posix_v1_posix_utf8_paths,
+                 { "Posix UTF8 Paths", "smb2.posix_utf8_paths", FT_UINT32, BASE_HEX,
+                   VALS(posix_utf8_paths_vals), 0x08, NULL, HFILL }},
+
+               { &hf_smb2_posix_v1_posix_will_convert_nt_acls,
+                 { "Posix Will Convert NT ACLs", "smb2.will_convert_NTACLs", FT_UINT32, BASE_HEX,
+                   VALS(posix_will_convert_ntacls_vals), 0x10, NULL, HFILL }},
+
+               { &hf_smb2_posix_v1_posix_fileinfo,
+                 { "Posix Fileinfo", "smb2.posix_fileinfo", FT_UINT32, BASE_HEX,
+                   VALS(posix_fileinfo_vals), 0x20, NULL, HFILL }},
+
+               { &hf_smb2_posix_v1_posix_acls,
+                 { "Posix ACLs", "smb2.posix_acls", FT_UINT32, BASE_HEX,
+                   VALS(posix_acls_vals), 0x40, NULL, HFILL }},
+
+               { &hf_smb2_posix_v1_rich_acls,
+                 { "Rich ACLs", "smb2.rich_acls", FT_UINT32, BASE_HEX,
+                   VALS(posix_rich_acls_vals), 0x80, NULL, HFILL }},
+
+               { &hf_smb2_posix_v1_supported_features,
+                 { "Supported Features", "smb2.posix_supported_features", FT_UINT32, BASE_HEX,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_aapl_command_code,
+                 { "Command code", "smb2.aapl.command_code", FT_UINT32, BASE_DEC,
+                   VALS(aapl_command_code_vals), 0, NULL, HFILL }},
+
+               { &hf_smb2_aapl_reserved,
+                 { "Reserved", "smb2.aapl.reserved", FT_UINT32, BASE_HEX,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_bitmask,
+                 { "Query bitmask", "smb2.aapl.query_bitmask", FT_UINT64, BASE_HEX,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_bitmask_server_caps,
+                 { "Server capabilities", "smb2.aapl.bitmask.server_caps", FT_BOOLEAN, 64,
+                   NULL, SMB2_AAPL_SERVER_CAPS, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_bitmask_volume_caps,
+                 { "Volume capabilities", "smb2.aapl.bitmask.volume_caps", FT_BOOLEAN, 64,
+                   NULL, SMB2_AAPL_VOLUME_CAPS, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_bitmask_model_info,
+                 { "Model information", "smb2.aapl.bitmask.model_info", FT_BOOLEAN, 64,
+                   NULL, SMB2_AAPL_MODEL_INFO, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_caps,
+                 { "Client/Server capabilities", "smb2.aapl.caps", FT_UINT64, BASE_HEX,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_caps_supports_read_dir_attr,
+                 { "Supports READDIRATTR", "smb2.aapl.caps.supports_read_dir_addr", FT_BOOLEAN, 64,
+                   NULL, SMB2_AAPL_SUPPORTS_READ_DIR_ATTR, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_caps_supports_osx_copyfile,
+                 { "Supports OS X copyfile", "smb2.aapl.caps.supports_osx_copyfile", FT_BOOLEAN, 64,
+                   NULL, SMB2_AAPL_SUPPORTS_OSX_COPYFILE, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_caps_unix_based,
+                 { "UNIX-based", "smb2.aapl.caps.unix_based", FT_BOOLEAN, 64,
+                   NULL, SMB2_AAPL_UNIX_BASED, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_caps_supports_nfs_ace,
+                 { "Supports NFS ACE", "smb2.aapl.supports_nfs_ace", FT_BOOLEAN, 64,
+                   NULL, SMB2_AAPL_SUPPORTS_NFS_ACE, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_volume_caps,
+                 { "Volume capabilities", "smb2.aapl.volume_caps", FT_UINT64, BASE_HEX,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_volume_caps_support_resolve_id,
+                 { "Supports Resolve ID", "smb2.aapl.volume_caps.supports_resolve_id", FT_BOOLEAN, 64,
+                   NULL, SMB2_AAPL_SUPPORTS_RESOLVE_ID, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_volume_caps_case_sensitive,
+                 { "Case sensitive", "smb2.aapl.volume_caps.case_sensitive", FT_BOOLEAN, 64,
+                   NULL, SMB2_AAPL_CASE_SENSITIVE, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_volume_caps_supports_full_sync,
+                 { "Supports full sync", "smb2.aapl.volume_caps.supports_full_sync", FT_BOOLEAN, 64,
+                   NULL, SMB2_AAPL_SUPPORTS_FULL_SYNC, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_model_string,
+                 { "Model string", "smb2.aapl.model_string", FT_UINT_STRING, STR_UNICODE,
+                   NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_aapl_server_query_server_path,
+                 { "Server path", "smb2.aapl.server_path", FT_UINT_STRING, STR_UNICODE,
+                   NULL, 0, NULL, HFILL }},
+
                { &hf_smb2_transform_signature,
                  { "Signature", "smb2.header.transform.signature", FT_BYTES, BASE_NONE,
                    NULL, 0, NULL, HFILL }},
@@ -8600,6 +10050,64 @@ proto_register_smb2(void)
                { &hf_smb2_truncated,
                  { "Truncated...", "smb2.truncated", FT_NONE, BASE_NONE,
                    NULL, 0, NULL, HFILL }},
+
+               { &hf_smb2_pipe_fragment_overlap,
+                       { "Fragment overlap", "smb2.pipe.fragment.overlap", FT_BOOLEAN, BASE_NONE,
+                       NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
+               { &hf_smb2_pipe_fragment_overlap_conflict,
+                       { "Conflicting data in fragment overlap", "smb2.pipe.fragment.overlap.conflict", FT_BOOLEAN,
+                       BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
+               { &hf_smb2_pipe_fragment_multiple_tails,
+                       { "Multiple tail fragments found", "smb2.pipe.fragment.multipletails", FT_BOOLEAN,
+                       BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
+               { &hf_smb2_pipe_fragment_too_long_fragment,
+                       { "Fragment too long", "smb2.pipe.fragment.toolongfragment", FT_BOOLEAN,
+                       BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
+               { &hf_smb2_pipe_fragment_error,
+                       { "Defragmentation error", "smb2.pipe.fragment.error", FT_FRAMENUM,
+                       BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
+               { &hf_smb2_pipe_fragment_count,
+                       { "Fragment count", "smb2.pipe.fragment.count", FT_UINT32,
+                       BASE_DEC, NULL, 0x0, NULL, HFILL }},
+               { &hf_smb2_pipe_fragment,
+                       { "Fragment SMB2 Named Pipe", "smb2.pipe.fragment", FT_FRAMENUM,
+                       BASE_NONE, NULL, 0x0, "SMB2 Named Pipe Fragment", HFILL }},
+               { &hf_smb2_pipe_fragments,
+                       { "Reassembled SMB2 Named Pipe fragments", "smb2.pipe.fragments", FT_NONE,
+                       BASE_NONE, NULL, 0x0, "SMB2 Named Pipe Fragments", HFILL }},
+               { &hf_smb2_pipe_reassembled_in,
+                       { "This SMB2 Named Pipe payload is reassembled in frame", "smb2.pipe.reassembled_in", FT_FRAMENUM,
+                       BASE_NONE, NULL, 0x0, "The Named Pipe PDU is completely reassembled in this frame", HFILL }},
+               { &hf_smb2_pipe_reassembled_length,
+                       { "Reassembled SMB2 Named Pipe length", "smb2.pipe.reassembled.length", FT_UINT32,
+                       BASE_DEC, NULL, 0x0, "The total length of the reassembled payload", HFILL }},
+               { &hf_smb2_pipe_reassembled_data,
+                       { "Reassembled SMB2 Named Pipe Data", "smb2.pipe.reassembled.data", FT_BYTES,
+                       BASE_NONE, NULL, 0x0, "The reassembled payload", HFILL }},
+               { &hf_smb2_cchunk_resume_key,
+                       { "ResumeKey", "smb2.fsctl.cchunk.resume_key", FT_BYTES,
+                       BASE_NONE, NULL, 0x0, "Opaque data representing source of copy", HFILL }},
+               { &hf_smb2_cchunk_count,
+                       { "Chunk Count", "smb2.fsctl.cchunk.count", FT_UINT32,
+                       BASE_DEC, NULL, 0x0, NULL, HFILL }},
+               { &hf_smb2_cchunk_src_offset,
+                       { "Source Offset", "smb2.fsctl.cchunk.src_offset", FT_UINT64,
+                       BASE_DEC, NULL, 0x0, NULL, HFILL }},
+               { &hf_smb2_cchunk_dst_offset,
+                       { "Target Offset", "smb2.fsctl.cchunk.dst_offset", FT_UINT64,
+                       BASE_DEC, NULL, 0x0, NULL, HFILL }},
+               { &hf_smb2_cchunk_xfer_len,
+                       { "Transfer Length", "smb2.fsctl.cchunk.xfer_len", FT_UINT32,
+                       BASE_DEC, NULL, 0x0, NULL, HFILL }},
+               { &hf_smb2_cchunk_chunks_written,
+                       { "Chunks Written", "smb2.fsctl.cchunk.chunks_written", FT_UINT32,
+                       BASE_DEC, NULL, 0x0, NULL, HFILL }},
+               { &hf_smb2_cchunk_bytes_written,
+                       { "Chunk Bytes Written", "smb2.fsctl.cchunk.bytes_written", FT_UINT32,
+                       BASE_DEC, NULL, 0x0, NULL, HFILL }},
+               { &hf_smb2_cchunk_total_written,
+                       { "Total Bytes Written", "smb2.fsctl.cchunk.total_written", FT_UINT32,
+                       BASE_DEC, NULL, 0x0, NULL, HFILL }},
        };
 
        static gint *ett[] = {
@@ -8659,8 +10167,10 @@ proto_register_smb2(void)
                &ett_smb2_share_caps,
                &ett_smb2_ioctl_flags,
                &ett_smb2_ioctl_network_interface,
+               &ett_smb2_fsctl_range_data,
                &ett_windows_sockaddr,
                &ett_smb2_close_flags,
+               &ett_smb2_notify_info,
                &ett_smb2_notify_flags,
                &ett_smb2_rdma_v1,
                &ett_smb2_write_flags,
@@ -8677,10 +10187,23 @@ proto_register_smb2(void)
                &ett_smb2_dh2x_flags,
                &ett_smb2_APP_INSTANCE_buffer,
                &ett_smb2_svhdx_open_device_context,
+               &ett_smb2_posix_v1_request,
+               &ett_smb2_posix_v1_response,
+               &ett_smb2_posix_v1_supported_features,
+               &ett_smb2_aapl_create_context_request,
+               &ett_smb2_aapl_server_query_bitmask,
+               &ett_smb2_aapl_server_query_caps,
+               &ett_smb2_aapl_create_context_response,
+               &ett_smb2_aapl_server_query_volume_caps,
                &ett_smb2_integrity_flags,
                &ett_smb2_transform_enc_alg,
                &ett_smb2_buffercode,
                &ett_smb2_ioctl_network_interface_capabilities,
+               &ett_qfr_entry,
+               &ett_smb2_pipe_fragment,
+               &ett_smb2_pipe_fragments,
+               &ett_smb2_cchunk_entry,
+               &ett_smb2_fsctl_odx_token,
        };
 
        static ei_register_info ei[] = {
@@ -8703,20 +10226,27 @@ proto_register_smb2(void)
                                       "Whether the export object functionality will take the full path file name as file identifier",
                                       &eosmb2_take_name_as_fid);
 
-       smb2_heur_subdissector_list = register_heur_dissector_list("smb2_heur_subdissectors");
+       prefs_register_bool_preference(smb2_module, "pipe_reassembly",
+               "Reassemble Named Pipes over SMB2",
+               "Whether the dissector should reassemble Named Pipes over SMB2 commands",
+               &smb2_pipe_reassembly);
+       smb2_pipe_subdissector_list = register_heur_dissector_list("smb2_pipe_subdissectors", proto_smb2);
+       register_init_routine(smb2_pipe_reassembly_init);
+
        smb2_tap = register_tap("smb2");
        smb2_eo_tap = register_tap("smb_eo"); /* SMB Export Object tap */
 
+       register_srt_table(proto_smb2, NULL, 1, smb2stat_packet, smb2stat_init, NULL);
 }
 
 void
 proto_reg_handoff_smb2(void)
 {
-       gssapi_handle  = find_dissector("gssapi");
-       ntlmssp_handle = find_dissector("ntlmssp");
-       rsvd_handle    = find_dissector("rsvd");
-       heur_dissector_add("netbios", dissect_smb2_heur, proto_smb2);
-       heur_dissector_add("smb_direct", dissect_smb2_heur, proto_smb2);
+       gssapi_handle  = find_dissector_add_dependency("gssapi", proto_smb2);
+       ntlmssp_handle = find_dissector_add_dependency("ntlmssp", proto_smb2);
+       rsvd_handle    = find_dissector_add_dependency("rsvd", proto_smb2);
+       heur_dissector_add("netbios", dissect_smb2_heur, "SMB2 over Netbios", "smb2_netbios", proto_smb2, HEURISTIC_ENABLE);
+       heur_dissector_add("smb_direct", dissect_smb2_heur, "SMB2 over SMB Direct", "smb2_smb_direct", proto_smb2, HEURISTIC_ENABLE);
 }
 
 /*