smb-direct fragmentation
authorStefan Metzmacher <metze@samba.org>
Wed, 3 Oct 2012 21:01:12 +0000 (23:01 +0200)
committerStefan Metzmacher <metze@samba.org>
Wed, 29 Jan 2014 08:18:24 +0000 (09:18 +0100)
epan/dissectors/packet-smb-direct.c

index b60b5556427f93913bd40a9c561862b2dd09fdb6..d42046490de7b9b55c21ff9c02aa87c9217db5ca 100644 (file)
@@ -33,7 +33,7 @@
 #include <glib.h>
 
 #include <epan/packet.h>
-#include <epan/llcsaps.h>
+#include <epan/conversation.h>
 #include <epan/reassemble.h>
 #include <epan/prefs.h>
 #include "packet-windows-common.h"
@@ -43,6 +43,8 @@ static int proto_smb_direct = -1;
 static gint ett_smb_direct = -1;
 static gint ett_smb_direct_hdr = -1;
 static gint ett_smb_direct_flags = -1;
+static gint ett_smb_direct_fragment = -1;
+static gint ett_smb_direct_fragments = -1;
 
 static int hf_smb_direct_min_version = -1;
 static int hf_smb_direct_max_version = -1;
@@ -59,6 +61,34 @@ static int hf_smb_direct_flags_response_requested = -1;
 static int hf_smb_direct_remaining_length = -1;
 static int hf_smb_direct_data_offset = -1;
 static int hf_smb_direct_data_length = -1;
+static int hf_smb_direct_fragments = -1;
+static int hf_smb_direct_fragment = -1;
+static int hf_smb_direct_fragment_overlap = -1;
+static int hf_smb_direct_fragment_overlap_conflict = -1;
+static int hf_smb_direct_fragment_multiple_tails = -1;
+static int hf_smb_direct_fragment_too_long_fragment = -1;
+static int hf_smb_direct_fragment_error = -1;
+static int hf_smb_direct_fragment_count = -1;
+static int hf_smb_direct_reassembled_in = -1;
+static int hf_smb_direct_reassembled_length = -1;
+static int hf_smb_direct_reassembled_data = -1;
+
+static const fragment_items smb_direct_frag_items = {
+        &ett_smb_direct_fragment,
+        &ett_smb_direct_fragments,
+        &hf_smb_direct_fragments,
+        &hf_smb_direct_fragment,
+        &hf_smb_direct_fragment_overlap,
+        &hf_smb_direct_fragment_overlap_conflict,
+        &hf_smb_direct_fragment_multiple_tails,
+        &hf_smb_direct_fragment_too_long_fragment,
+        &hf_smb_direct_fragment_error,
+        &hf_smb_direct_fragment_count,
+        &hf_smb_direct_reassembled_in,
+        &hf_smb_direct_reassembled_length,
+        &hf_smb_direct_reassembled_data,
+        "SMB Direct fragments"
+};
 
 enum SMB_DIRECT_HDR_TYPE {
        SMB_DIRECT_HDR_UNKNOWN = -1,
@@ -70,12 +100,68 @@ enum SMB_DIRECT_HDR_TYPE {
 static heur_dissector_list_t smb_direct_heur_subdissector_list;
 static dissector_handle_t data_handle;
 
+static gboolean smb_direct_reassemble = TRUE;
+static GHashTable *smb_direct_fragment_table = NULL;
+static GHashTable *smb_direct_reassemble_table = NULL;
+
 static void
-dissect_smb_direct_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+smb_direct_reassemble_init(void)
 {
-       if (!dissector_try_heuristic(smb_direct_heur_subdissector_list,
-                                   tvb, pinfo, tree, NULL))
-               call_dissector(data_handle,tvb, pinfo, tree);
+       fragment_table_init(&smb_direct_fragment_table);
+       reassembled_table_init(&smb_direct_reassemble_table);
+}
+
+static void
+dissect_smb_direct_payload(tvbuff_t *tvb, packet_info *pinfo,
+                          proto_tree *tree, guint32 remaining_length _U_)
+{
+       gboolean save_fragmented = pinfo->fragmented;
+       int visited = pinfo->fd->flags.visited;
+       conversation_t *conversation = NULL;
+       fragment_data *fd_head = NULL;
+       tvbuff_t *next_tvb = NULL;
+
+       if (!smb_direct_reassemble) {
+               pinfo->fragmented = FALSE;
+               if (!dissector_try_heuristic(smb_direct_heur_subdissector_list,
+                                            tvb, pinfo, tree, NULL)) {
+                       call_dissector(data_handle,tvb, pinfo, tree);
+               }
+               pinfo->fragmented = save_fragmented;
+               pinfo->fd->flags.visited = visited;
+               return;
+       }
+
+       conversation = find_or_create_conversation(pinfo);
+
+       pinfo->fd->flags.visited = 0;
+       fd_head = fragment_add_seq_next(tvb, 0, pinfo,
+                                       conversation->index,
+                                       smb_direct_fragment_table,
+                                       smb_direct_reassemble_table,
+                                       tvb_length(tvb),
+                                       remaining_length > 0 ? TRUE : FALSE /* more_frags */);
+
+       next_tvb = process_reassembled_data(tvb, 0, pinfo,
+                                           "Reassembled SMB Direct",
+                                           fd_head,
+                                           &smb_direct_frag_items,
+                                           NULL, /* update_col_info*/
+                                           tree);
+
+       if (next_tvb != NULL) {
+               pinfo->fragmented = FALSE;
+               if (!dissector_try_heuristic(smb_direct_heur_subdissector_list,
+                                            next_tvb, pinfo, tree, NULL)) {
+                       call_dissector(data_handle,tvb, pinfo, tree);
+               }
+               pinfo->fragmented = save_fragmented;
+               pinfo->fd->flags.visited = visited;
+               return;
+       }
+
+       pinfo->fragmented = save_fragmented;
+       pinfo->fd->flags.visited = visited;
 }
 
 static void
@@ -227,6 +313,7 @@ dissect_smb_direct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
                guint16 flags;
                proto_tree *flags_tree = NULL;
                proto_item *item = NULL;
+               guint32 remaining_length;
                guint32 data_offset;
                guint32 data_length;
                gint len = 0;
@@ -251,6 +338,7 @@ dissect_smb_direct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
                /* 2 bytes reserved */
                offset += 2;
 
+               remaining_length = tvb_get_letohl(tvb, offset);
                proto_tree_add_item(data_tree, hf_smb_direct_remaining_length,
                                    tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;
@@ -278,7 +366,8 @@ dissect_smb_direct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
                }
 
                if (next_tvb) {
-                       dissect_smb_direct_payload(next_tvb, pinfo, parent_tree);
+                       dissect_smb_direct_payload(next_tvb, pinfo,
+                                                  parent_tree, remaining_length);
                }
                offset = data_offset + data_length;
        }
@@ -387,69 +476,120 @@ void proto_register_smb_direct(void)
                &ett_smb_direct,
                &ett_smb_direct_hdr,
                &ett_smb_direct_flags,
+               &ett_smb_direct_fragment,
+               &ett_smb_direct_fragments,
        };
 
        static hf_register_info hf[] = {
        { &hf_smb_direct_min_version,
-               { "MinVersion", "smb_direct.version.min", FT_UINT16, BASE_HEX,
-               NULL, 0, NULL, HFILL }},
+               { "MinVersion", "smb_direct.version.min",
+               FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
+
        { &hf_smb_direct_max_version,
-               { "MaxVersion", "smb_direct.version.max", FT_UINT16, BASE_HEX,
-               NULL, 0, NULL, HFILL }},
+               { "MaxVersion", "smb_direct.version.max",
+               FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
+
        { &hf_smb_direct_negotiated_version,
-               { "NegotiatedVersion", "smb_direct.version.negotiated", FT_UINT16, BASE_HEX,
-               NULL, 0, NULL, HFILL }},
+               { "NegotiatedVersion", "smb_direct.version.negotiated",
+               FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
 
        { &hf_smb_direct_credits_requested,
-               { "CreditsRequested", "smb_direct.credits.requested", FT_UINT16, BASE_DEC,
-               NULL, 0, NULL, HFILL }},
+               { "CreditsRequested", "smb_direct.credits.requested",
+               FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
+
        { &hf_smb_direct_credits_granted,
-               { "CreditsGranted", "smb_direct.credits.granted", FT_UINT16, BASE_DEC,
-               NULL, 0, NULL, HFILL }},
+               { "CreditsGranted", "smb_direct.credits.granted",
+               FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
 
        { &hf_smb_direct_status,
-               { "Status", "smb_direct.status", FT_UINT32, BASE_HEX,
-               VALS(NT_errors), 0, "NT Status code", HFILL }},
+               { "Status", "smb_direct.status",
+               FT_UINT32, BASE_HEX, VALS(NT_errors), 0,
+               "NT Status code", HFILL }},
 
        { &hf_smb_direct_max_read_write_size,
-               { "MaxReadWriteSize", "smb_direct.max_read_write_size", FT_UINT32, BASE_DEC,
-               NULL, 0, NULL, HFILL }},
+               { "MaxReadWriteSize", "smb_direct.max_read_write_size",
+               FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
 
        { &hf_smb_direct_preferred_send_size,
-               { "PreferredSendSize", "smb_direct.preferred_send_size", FT_UINT32, BASE_DEC,
-               NULL, 0, NULL, HFILL }},
+               { "PreferredSendSize", "smb_direct.preferred_send_size",
+               FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
 
        { &hf_smb_direct_max_receive_size,
-               { "MaxReceiveSize", "smb_direct.max_receive_size", FT_UINT32, BASE_DEC,
-               NULL, 0, NULL, HFILL }},
+               { "MaxReceiveSize", "smb_direct.max_receive_size",
+               FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
 
        { &hf_smb_direct_max_fragmented_size,
-               { "MaxFragmentedSize", "smb_direct.max_fragmented_size", FT_UINT32, BASE_DEC,
-               NULL, 0, NULL, HFILL }},
+               { "MaxFragmentedSize", "smb_direct.max_fragmented_size",
+               FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
 
        { &hf_smb_direct_flags,
-               { "Flags", "smb_direct.flags", FT_UINT16, BASE_HEX,
-               NULL, 0, NULL, HFILL }},
+               { "Flags", "smb_direct.flags",
+               FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
 
 #define SMB_DIRECT_RESPONSE_REQUESTED 0x0001
 
        { &hf_smb_direct_flags_response_requested,
-               { "ResponseRequested", "smb_direct.flags.response_requested", FT_BOOLEAN, 16,
-               NULL, SMB_DIRECT_RESPONSE_REQUESTED, NULL, HFILL }},
+               { "ResponseRequested", "smb_direct.flags.response_requested",
+               FT_BOOLEAN, 16, NULL, SMB_DIRECT_RESPONSE_REQUESTED,
+               NULL, HFILL }},
 
        { &hf_smb_direct_remaining_length,
-               { "RemainingLength", "smb_direct.remaining_length", FT_UINT32, BASE_DEC,
-               NULL, 0, NULL, HFILL }},
+               { "RemainingLength", "smb_direct.remaining_length",
+               FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
 
        { &hf_smb_direct_data_offset,
-               { "DataOffset", "smb_direct.data_offset", FT_UINT32, BASE_DEC,
-               NULL, 0, NULL, HFILL }},
+               { "DataOffset", "smb_direct.data_offset",
+               FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
 
        { &hf_smb_direct_data_length,
-               { "DataLength", "smb_direct.data_length", FT_UINT32, BASE_DEC,
-               NULL, 0, NULL, HFILL }},
+               { "DataLength", "smb_direct.data_length",
+               FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
+
+       { &hf_smb_direct_fragments,
+               { "Reassembled SMB Direct Fragments", "smb_direct.fragments",
+               FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+
+       { &hf_smb_direct_fragment,
+               { "SMB Direct Fragment", "smb_direct.fragment",
+               FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }},
+       { &hf_smb_direct_fragment_overlap,
+               { "Fragment overlap", "smb_direct.fragment.overlap",
+               FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL }},
+
+       { &hf_smb_direct_fragment_overlap_conflict,
+               { "Conflicting data in fragment overlap", "smb_direct.fragment.overlap.conflict",
+               FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL }},
+
+       { &hf_smb_direct_fragment_multiple_tails,
+               { "Multiple tail fragments found", "smb_direct.fragment.multipletails",
+               FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL }},
+
+       { &hf_smb_direct_fragment_too_long_fragment,
+               { "Fragment too long", "smb_direct.fragment.toolongfragment",
+               FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL }},
+
+       { &hf_smb_direct_fragment_error,
+               { "Defragmentation error", "smb_direct.fragment.error",
+               FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }},
+
+       { &hf_smb_direct_fragment_count,
+               { "Fragment count", "smb_direct.fragment.count",
+               FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+
+       { &hf_smb_direct_reassembled_in,
+               { "Reassembled PDU in frame", "smb_direct.reassembled_in",
+               FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }},
+
+       { &hf_smb_direct_reassembled_length,
+               { "Reassembled SMB Direct length", "smb_direct.reassembled.length",
+               FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
+
+       { &hf_smb_direct_reassembled_data,
+               { "Reassembled SMB Direct data", "smb_direct.reassembled.data",
+               FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
 
        };
+       module_t *smb_direct_module;
 
        proto_smb_direct = proto_register_protocol("SMB-Direct (SMB RDMA Transport)",
                                                   "SMBDirect", "smb_direct");
@@ -458,6 +598,14 @@ void proto_register_smb_direct(void)
 
        register_heur_dissector_list("smb_direct",
                                     &smb_direct_heur_subdissector_list);
+
+       smb_direct_module = prefs_register_protocol(proto_smb_direct, NULL);
+       prefs_register_bool_preference(smb_direct_module,
+                                      "reassemble_smb_direct",
+                                      "Reassemble SMB Direct fragments",
+                                      "Whether the SMB Direct dissector should reassemble fragmented payloads",
+                                      &smb_direct_reassemble);
+       register_init_routine(smb_direct_reassemble_init);
 }
 
 void