Removed trailing whitespaces from .h and .c files using the
[obnox/wireshark/wip.git] / packet-ndmp.c
index bb15ff6cae6836effe39f916de045fabcbcbccea..8dfe01c461a7ba90d07bf3b0f62c610500a28a78 100644 (file)
@@ -1,18 +1,8 @@
-/* XXX TODO:
-   Someone should take packet-iscsi.c apart and break all the SCSI-CDB stuff
-   out and put SCSI-CDB in packet-scsi.c instead.
-   Then packet-iscsi.c only contains the iscsi layer and it will call
-   packet-scsi.c to dissect the cdb's.
-   Then we can call packet-scsi.c to dissect the scsi cdb's 
-   from here as well.
-
-   volunteers?
-*/
 /* packet-ndmp.c
  * Routines for NDMP dissection
  * 2001 Ronnie Sahlberg (see AUTHORS for email)
  *
- * $Id: packet-ndmp.c,v 1.6 2002/01/15 10:01:19 guy Exp $
+ * $Id: packet-ndmp.c,v 1.22 2002/08/20 22:33:16 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
 #include <stdio.h>
 #include <string.h>
 #include <glib.h>
 
-#include "packet.h"
+#include <epan/packet.h>
+#include <epan/conversation.h>
 #include "packet-rpc.h"
+#include "packet-scsi.h"
+#include "packet-frame.h"
 #include "prefs.h"
+#include "reassemble.h"
+#include "rpc_defrag.h"
 
 #define TCP_PORT_NDMP 10000
 
-#define NDMP_FRAGLEN 0x7fffffffL
-
 static int proto_ndmp = -1;
 static int hf_ndmp_version = -1;
-static int hf_ndmp_size = -1;
 static int hf_ndmp_header = -1;
 static int hf_ndmp_sequence = -1;
 static int hf_ndmp_reply_sequence = -1;
@@ -130,6 +118,16 @@ static int hf_ndmp_scsi_device = -1;
 static int hf_ndmp_scsi_controller = -1;
 static int hf_ndmp_scsi_id = -1;
 static int hf_ndmp_scsi_lun = -1;
+static int hf_ndmp_execute_cdb_flags_data_in = -1;
+static int hf_ndmp_execute_cdb_flags_data_out = -1;
+static int hf_ndmp_execute_cdb_timeout = -1;
+static int hf_ndmp_execute_cdb_datain_len = -1;
+static int hf_ndmp_execute_cdb_cdb_len = -1;
+static int hf_ndmp_execute_cdb_dataout = -1;
+static int hf_ndmp_execute_cdb_status = -1;
+static int hf_ndmp_execute_cdb_dataout_len = -1;
+static int hf_ndmp_execute_cdb_datain = -1;
+static int hf_ndmp_execute_cdb_sns_len = -1;
 static int hf_ndmp_tape_invalid_file_num = -1;
 static int hf_ndmp_tape_invalid_soft_errors = -1;
 static int hf_ndmp_tape_invalid_block_size = -1;
@@ -216,6 +214,10 @@ static gint ett_ndmp_header = -1;
 static gint ett_ndmp_butype_attrs = -1;
 static gint ett_ndmp_fs_invalid = -1;
 static gint ett_ndmp_tape_attr = -1;
+static gint ett_ndmp_execute_cdb_flags = -1;
+static gint ett_ndmp_execute_cdb_cdb = -1;
+static gint ett_ndmp_execute_cdb_sns = -1;
+static gint ett_ndmp_execute_cdb_payload = -1;
 static gint ett_ndmp_tape_invalid = -1;
 static gint ett_ndmp_tape_flags = -1;
 static gint ett_ndmp_addr = -1;
@@ -235,9 +237,10 @@ struct ndmp_header {
 };
 
 /* desegmentation of NDMP packets */
-static gboolean ndmp_desegment = FALSE;
-
+static gboolean ndmp_desegment = TRUE;
 
+/* defragmentation of fragmented NDMP records */
+static gboolean ndmp_defragment = FALSE;
 
 #define NDMP_MESSAGE_REQUEST   0x00
 #define NDMP_MESSAGE_REPLY     0x01
@@ -418,9 +421,9 @@ static const value_string msg_vals[] = {
        {0, NULL}
 };
 
-
 static int
-dissect_connect_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_connect_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* version number */
        proto_tree_add_item(tree, hf_ndmp_version, tvb, offset, 4, FALSE);
@@ -430,7 +433,8 @@ dissect_connect_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo, prot
 }
 
 static int
-dissect_error(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_error(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -440,26 +444,27 @@ dissect_error(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 }
 
 static int
-dissect_ndmp_get_host_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_ndmp_get_host_info_reply(tvbuff_t *tvb, int offset,
+    packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
        offset += 4;
 
        /* hostname */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_hostname, offset, NULL);
 
        /* os type */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_os_type, offset, NULL);
 
        /* os version */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_os_vers, offset, NULL);
 
        /* hostid */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_hostid, offset, NULL);
 
        return offset;
@@ -478,9 +483,9 @@ static const value_string addr_type_vals[] = {
 };
 
 static int
-dissect_ndmp_addr_type(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_ndmp_addr_type(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree)
 {
-       /*address type*/
        proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, FALSE);
        offset += 4;
 
@@ -488,7 +493,16 @@ dissect_ndmp_addr_type(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree
 }
 
 static int
-dissect_ndmp_config_get_connection_type_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_ndmp_addr_msg(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
+{
+       /*address type*/
+       return dissect_ndmp_addr_type(tvb, offset, pinfo, tree);
+}
+
+static int
+dissect_ndmp_config_get_connection_type_reply(tvbuff_t *tvb, int offset,
+    packet_info *pinfo, proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -511,9 +525,9 @@ static const value_string auth_type_vals[] = {
        {0,NULL}
 };
 static int
-dissect_auth_type(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_auth_type(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree)
 {
-       /* auth type */
        proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, FALSE);
        offset += 4;
 
@@ -521,7 +535,16 @@ dissect_auth_type(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tre
 }
 
 static int
-dissect_auth_attr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_get_auth_type_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
+{
+       /* auth type */
+       return dissect_auth_type(tvb, offset, pinfo, tree);
+}
+
+static int
+dissect_auth_attr_msg(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        guint type;
        
@@ -546,14 +569,15 @@ dissect_auth_attr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tre
 }
 
 static int
-dissect_default_env(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_default_env(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree)
 {
        /* name */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_butype_env_name, offset, NULL);
 
        /* value */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_butype_env_value, offset, NULL);
 
        return offset;
@@ -597,7 +621,8 @@ static const true_false_string tfs_butype_attr_recover_utf8 = {
        "Normal recover. Do NOT use utf8"
 };
 static int
-dissect_butype_attrs(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
+dissect_butype_attrs(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *parent_tree)
 {
        proto_item* item = NULL;
        proto_tree* tree = NULL;
@@ -606,7 +631,7 @@ dissect_butype_attrs(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *
        flags=tvb_get_ntohl(tvb, offset);
        if (parent_tree) {
                item = proto_tree_add_text(parent_tree, tvb, offset, 4,
-                               "Attributes: 0x%08x ", flags);
+                               "Attributes: 0x%08x", flags);
                tree = proto_item_add_subtree(item, ett_ndmp_butype_attrs);
        }
 
@@ -637,7 +662,7 @@ static int
 dissect_butype_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 {
        /*butype name*/
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_butype_name, offset, NULL);
 
        /* default env */
@@ -651,7 +676,8 @@ dissect_butype_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *t
 }
 
 static int
-dissect_get_butype_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_get_butype_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -685,7 +711,8 @@ static const true_false_string tfs_fs_invalid_used_inodes = {
        "Used inode count is VALID"
 };
 static int
-dissect_fs_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
+dissect_fs_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *parent_tree)
 {
        proto_item* item = NULL;
        proto_tree* tree = NULL;
@@ -694,7 +721,7 @@ dissect_fs_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *pa
        flags=tvb_get_ntohl(tvb, offset);
        if (parent_tree) {
                item = proto_tree_add_text(parent_tree, tvb, offset, 4,
-                               "Invalids: 0x%08x ", flags);
+                               "Invalids: 0x%08x", flags);
                tree = proto_item_add_subtree(item, ett_ndmp_fs_invalid);
        }
 
@@ -714,14 +741,15 @@ dissect_fs_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *pa
 }
 
 static int
-dissect_fs_env(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_fs_env(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree)
 {
        /* name */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_fs_env_name, offset, NULL);
 
        /* value */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_fs_env_value, offset, NULL);
 
        return offset;
@@ -734,35 +762,35 @@ dissect_fs_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
        offset=dissect_fs_invalid(tvb, offset, pinfo, tree);
 
        /* fs type */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_fs_fs_type, offset, NULL);
 
        /* fs logical device */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_fs_logical_device, offset, NULL);
 
        /* fs physical device */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_fs_physical_device, offset, NULL);
 
        /*total_size*/
-       offset = dissect_rpc_uint64(tvb, pinfo, tree, hf_ndmp_fs_total_size,
+       offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_total_size,
                        offset);
 
        /*used_size*/
-       offset = dissect_rpc_uint64(tvb, pinfo, tree, hf_ndmp_fs_used_size,
+       offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_used_size,
                        offset);
 
        /*avail_size*/
-       offset = dissect_rpc_uint64(tvb, pinfo, tree, hf_ndmp_fs_avail_size,
+       offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_avail_size,
                        offset);
 
        /*total_inodes*/
-       offset = dissect_rpc_uint64(tvb, pinfo, tree, hf_ndmp_fs_total_inodes,
+       offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_total_inodes,
                        offset);
 
        /*used_inodes*/
-       offset = dissect_rpc_uint64(tvb, pinfo, tree, hf_ndmp_fs_used_inodes,
+       offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_used_inodes,
                        offset);
 
        /* env */
@@ -770,14 +798,15 @@ dissect_fs_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
                        dissect_fs_env, hf_ndmp_fs_env);
 
        /* status */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_fs_status, offset, NULL);
 
        return offset;
 }
 
 static int
-dissect_get_fs_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_get_fs_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -799,7 +828,8 @@ static const true_false_string tfs_tape_attr_unload = {
        "Device does NOT support unload"
 };
 static int
-dissect_tape_attr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
+dissect_tape_attr(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *parent_tree)
 {
        proto_item* item = NULL;
        proto_tree* tree = NULL;
@@ -808,7 +838,7 @@ dissect_tape_attr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *par
        flags=tvb_get_ntohl(tvb, offset);
        if (parent_tree) {
                item = proto_tree_add_text(parent_tree, tvb, offset, 4,
-                               "Attributes: 0x%08x ", flags);
+                               "Attributes: 0x%08x", flags);
                tree = proto_item_add_subtree(item, ett_ndmp_tape_attr);
        }
 
@@ -822,14 +852,15 @@ dissect_tape_attr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *par
 }
 
 static int
-dissect_tape_capability(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_tape_capability(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree)
 {
        /* name */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_tape_capability_name, offset, NULL);
 
        /* value */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_tape_capability_value, offset, NULL);
 
        return offset;
@@ -839,7 +870,7 @@ static int
 dissect_tape_dev_cap(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 {
        /* device */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_tape_device, offset, NULL);
 
        /* tape attributes */
@@ -856,7 +887,7 @@ static int
 dissect_tape_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 {
        /* model */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_tape_model, offset, NULL);
 
        /* device capabilites */
@@ -867,7 +898,8 @@ dissect_tape_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tre
 }
 
 static int
-dissect_get_tape_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_get_tape_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -884,7 +916,7 @@ static int
 dissect_scsi_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 {
        /* model */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_scsi_model, offset, NULL);
 
        /* device capabilites */
@@ -895,7 +927,8 @@ dissect_scsi_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tre
 }
 
 static int
-dissect_get_scsi_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_get_scsi_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -909,22 +942,23 @@ dissect_get_scsi_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto
 }
 
 static int
-dissect_get_server_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_get_server_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
        offset += 4;
 
        /* vendor */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_server_vendor, offset, NULL);
 
        /* product */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_server_product, offset, NULL);
 
        /* revision */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_server_revision, offset, NULL);
 
 
@@ -936,17 +970,19 @@ dissect_get_server_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, pro
 }
 
 static int
-dissect_scsi_device(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_scsi_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* device */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_scsi_device, offset, NULL);
 
        return offset;
 }
 
 static int
-dissect_scsi_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_scsi_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -968,10 +1004,11 @@ dissect_scsi_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, prot
 }
 
 static int
-dissect_scsi_set_state_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_scsi_set_state_request(tvbuff_t *tvb, int offset,
+    packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
 {
        /* device */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_scsi_device, offset, NULL);
 
        /* controller */
@@ -989,6 +1026,241 @@ dissect_scsi_set_state_request(tvbuff_t *tvb, int offset, packet_info *pinfo, pr
        return offset;
 }
 
+static int
+dissect_execute_cdb_flags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *parent_tree)
+{
+       proto_item* item = NULL;
+       proto_tree* tree = NULL;
+       guint32 flags;
+
+       flags = tvb_get_ntohl(tvb, offset);
+       if (parent_tree) {
+               item = proto_tree_add_text(parent_tree, tvb, offset, 4,
+                               "Flags: 0x%08x", flags);
+               tree = proto_item_add_subtree(item, ett_ndmp_execute_cdb_flags);
+       }
+       
+       proto_tree_add_boolean(tree, hf_ndmp_execute_cdb_flags_data_in,
+                               tvb, offset, 4, flags);
+       proto_tree_add_boolean(tree, hf_ndmp_execute_cdb_flags_data_out,
+                               tvb, offset, 4, flags);
+       offset += 4;
+       return offset;
+}
+
+static int
+dissect_execute_cdb_cdb(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *parent_tree, gint devtype)
+{
+       proto_item* item = NULL;
+       proto_tree* tree = NULL;
+       guint32 cdb_len;
+       guint32 cdb_len_full;
+
+       cdb_len = tvb_get_ntohl(tvb, offset);
+       cdb_len_full = rpc_roundup(cdb_len);
+       
+       if (parent_tree) {
+               item = proto_tree_add_text(parent_tree, tvb, offset,
+                               4+cdb_len_full, "CDB");
+               tree = proto_item_add_subtree(item, ett_ndmp_execute_cdb_cdb);
+       }
+
+       proto_tree_add_uint(tree, hf_ndmp_execute_cdb_cdb_len, tvb, offset, 4,
+                       cdb_len);
+       offset += 4;
+
+       if (cdb_len != 0) {
+               dissect_scsi_cdb(tvb, pinfo, tree, offset, cdb_len, devtype);
+               offset += cdb_len_full;
+       }
+
+       return offset;
+}
+
+
+static int
+dissect_execute_cdb_payload(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree,
+    char *name, int hf_len, gboolean isreq)
+{
+       proto_item* item = NULL;
+       proto_tree* tree = NULL;
+       guint32 payload_len;
+       guint32 payload_len_full;
+
+       payload_len = tvb_get_ntohl(tvb, offset);
+       payload_len_full = rpc_roundup(payload_len);
+       
+       if (parent_tree) {
+               item = proto_tree_add_text(parent_tree, tvb, offset,
+                               4+payload_len_full, "%s", name);
+               tree = proto_item_add_subtree(item,
+                   ett_ndmp_execute_cdb_payload);
+       }
+
+       proto_tree_add_uint(tree, hf_len, tvb, offset, 4, payload_len);
+       offset += 4;
+
+       if (payload_len != 0) {
+               dissect_scsi_payload(tvb, pinfo, tree, offset, isreq,
+                   payload_len);
+               offset += payload_len_full;
+       }
+
+       return offset;
+}
+
+/*
+ * XXX - we assume that NDMP_SCSI_EXECUTE_CDB requests only go to SCSI Media
+ * Changer devices and NDMP_TAPE_EXECUTE_CDB only go to SCSI Sequential
+ * Access devices.
+ *
+ * If that's not the case, we'll have to use the SCSI dissector's mechanisms
+ * for saving inquiry data for devices, and use inquiry data when available.
+ * Unfortunately, that means we need to save the name of the device, and
+ * use it as a device identifier; as the name isn't available in the
+ * NDMP_SCSI_EXECUTE_CDB or NDMP_TAPE_EXECUTE_CDB messages, that means
+ * we need to remember the currently-opened "SCSI" and "TAPE" devices
+ * from NDMP_SCSI_OPEN and NDMP_TAPE_OPEN, and attach to all frames
+ * that are the ones that trigger the dissection of NDMP_SCSI_EXECUTE_CDB
+ * or NDMP_TAPE_EXECUTE_CDB requests pointers to those names.
+ */
+static int
+dissect_execute_cdb_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq, gint devtype)
+{
+       conversation_t *conversation;
+       scsi_task_id_t task_key;
+
+       /*
+        * We need to provide SCSI task information to the SCSI
+        * dissection routines.  We use a conversation plus the
+        * sequence number in requests and the reply sequence
+        * number in replies to identify SCSI tasks.
+        */
+       conversation = find_conversation(&pinfo->src, &pinfo->dst,
+           pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+       if (conversation == NULL) {
+               conversation = conversation_new(&pinfo->src, &pinfo->dst,
+                   pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+       }
+       task_key.conv_id = conversation->index;
+       task_key.task_id = seq;
+       pinfo->private_data = &task_key;
+        
+       /* flags */
+       offset = dissect_execute_cdb_flags(tvb, offset, pinfo, tree);
+
+       /* timeout */
+       proto_tree_add_item(tree, hf_ndmp_execute_cdb_timeout, tvb, offset, 4, FALSE);
+       offset += 4;
+
+       /* datain_len */
+       proto_tree_add_item(tree, hf_ndmp_execute_cdb_datain_len, tvb, offset, 4, FALSE);
+       offset += 4;
+
+       /* CDB */
+       offset = dissect_execute_cdb_cdb(tvb, offset, pinfo, tree, devtype);
+
+       /* dataout */
+       offset = dissect_execute_cdb_payload(tvb, offset, pinfo, tree,
+           "Data out", hf_ndmp_execute_cdb_dataout_len, TRUE);
+
+       return offset;
+}
+
+static int
+dissect_execute_cdb_request_mc(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq)
+{
+       return dissect_execute_cdb_request(tvb, offset, pinfo, tree, seq,
+           SCSI_DEV_SMC);
+}
+
+static int
+dissect_execute_cdb_request_tape(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq)
+{
+       return dissect_execute_cdb_request(tvb, offset, pinfo, tree, seq,
+           SCSI_DEV_SSC);
+}
+
+static int
+dissect_execute_cdb_sns(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
+{
+       proto_item* item = NULL;
+       proto_tree* tree = NULL;
+       guint32 sns_len;
+       guint32 sns_len_full;
+
+       sns_len = tvb_get_ntohl(tvb, offset);
+       sns_len_full = rpc_roundup(sns_len);
+       
+       if (parent_tree) {
+               item = proto_tree_add_text(parent_tree, tvb, offset,
+                               4+sns_len_full, "Sense data");
+               tree = proto_item_add_subtree(item, ett_ndmp_execute_cdb_sns);
+       }
+
+       proto_tree_add_uint(tree, hf_ndmp_execute_cdb_sns_len, tvb, offset, 4,
+                       sns_len);
+       offset += 4;
+
+       if (sns_len != 0) {
+               dissect_scsi_snsinfo(tvb, pinfo, tree, offset, sns_len);
+               offset += sns_len_full;
+       }
+
+       return offset;
+}
+
+static int
+dissect_execute_cdb_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq)
+{
+       conversation_t *conversation;
+       scsi_task_id_t task_key;
+
+       /*
+        * We need to provide SCSI task information to the SCSI
+        * dissection routines.  We use a conversation plus the
+        * sequence number in requests and the reply sequence
+        * number in replies to identify SCSI tasks.
+        */
+       conversation = find_conversation(&pinfo->src, &pinfo->dst,
+           pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+       if (conversation != NULL) {
+               task_key.conv_id = conversation->index;
+               task_key.task_id = seq;
+               pinfo->private_data = &task_key;
+       } else {
+               /* no conversation, meaning we didn't see the request */
+               pinfo->private_data = NULL;
+       }
+        
+       /* error */
+       proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
+       offset += 4;
+
+       /* status */
+       proto_tree_add_item(tree, hf_ndmp_execute_cdb_status, tvb, offset, 4, FALSE);
+       offset += 4;
+
+       /* dataout_len */
+       proto_tree_add_item(tree, hf_ndmp_execute_cdb_dataout_len, tvb, offset, 4, FALSE);
+       offset += 4;
+
+       /* datain */
+       offset = dissect_execute_cdb_payload(tvb, offset, pinfo, tree,
+           "Data in", hf_ndmp_execute_cdb_datain_len, FALSE);
+
+       /* ext_sense */
+       offset = dissect_execute_cdb_sns(tvb, offset, pinfo, tree);
+
+       return offset;
+}
+
 #define NDMP_TAPE_OPEN_MODE_READ       0
 #define NDMP_TAPE_OPEN_MODE_RDWR       1
 static const value_string tape_open_mode_vals[] = {
@@ -998,10 +1270,11 @@ static const value_string tape_open_mode_vals[] = {
 };
 
 static int
-dissect_tape_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_tape_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* device */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_tape_device, offset, NULL);
 
        /* open mode */
@@ -1041,7 +1314,8 @@ static const true_false_string tfs_ndmp_tape_invalid_partition = {
        "Partition is valid"
 };
 static int
-dissect_tape_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
+dissect_tape_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *parent_tree)
 {
        proto_item* item = NULL;
        proto_tree* tree = NULL;
@@ -1050,7 +1324,7 @@ dissect_tape_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *
        flags=tvb_get_ntohl(tvb, offset);
        if (parent_tree) {
                item = proto_tree_add_text(parent_tree, tvb, offset, 4,
-                               "Invalids: 0x%08x ", flags);
+                               "Invalids: 0x%08x", flags);
                tree = proto_item_add_subtree(item, ett_ndmp_tape_invalid);
        }
 
@@ -1090,7 +1364,8 @@ static const true_false_string tfs_ndmp_tape_flags_unload = {
        "This device does NOT support unload"
 };
 static int
-dissect_tape_flags(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
+dissect_tape_flags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *parent_tree)
 {
        proto_item* item = NULL;
        proto_tree* tree = NULL;
@@ -1099,7 +1374,7 @@ dissect_tape_flags(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *pa
        flags=tvb_get_ntohl(tvb, offset);
        if (parent_tree) {
                item = proto_tree_add_text(parent_tree, tvb, offset, 4,
-                               "Flags: 0x%08x ", flags);
+                               "Flags: 0x%08x", flags);
                tree = proto_item_add_subtree(item, ett_ndmp_tape_flags);
        }
 
@@ -1118,7 +1393,8 @@ dissect_tape_flags(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *pa
 }
 
 static int
-dissect_tape_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_tape_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* invalid bits */
        offset=dissect_tape_invalid(tvb, offset, pinfo, tree);
@@ -1147,11 +1423,11 @@ dissect_tape_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, prot
        offset += 4;
 
        /* total_space */
-       offset = dissect_rpc_uint64(tvb, pinfo, tree,hf_ndmp_tape_total_space,
+       offset = dissect_rpc_uint64(tvb, tree,hf_ndmp_tape_total_space,
                        offset);
 
        /* space_remain */
-       offset = dissect_rpc_uint64(tvb, pinfo, tree,hf_ndmp_tape_space_remain,
+       offset = dissect_rpc_uint64(tvb, tree,hf_ndmp_tape_space_remain,
                        offset);
 
        /* partition */
@@ -1180,7 +1456,8 @@ static const value_string tape_mtio_vals[] = {
 };
 
 static int
-dissect_tape_mtio_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_tape_mtio_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* op */
        proto_tree_add_item(tree, hf_ndmp_tape_mtio_op, tvb, offset, 4, FALSE);
@@ -1194,7 +1471,8 @@ dissect_tape_mtio_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_t
 }
 
 static int
-dissect_tape_mtio_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_tape_mtio_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -1252,7 +1530,8 @@ static const value_string halt_vals[] = {
 };
 
 static int
-dissect_ndmp_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
+dissect_ndmp_addr(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *parent_tree)
 {
        proto_item* item = NULL;
        proto_tree* tree = NULL;
@@ -1291,7 +1570,7 @@ dissect_ndmp_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *par
                break;
        case NDMP_ADDR_IPC:
                /* IPC address */
-               offset = dissect_rpc_data(tvb, pinfo, tree, hf_ndmp_addr_ipc, offset);
+               offset = dissect_rpc_data(tvb, tree, hf_ndmp_addr_ipc, offset);
                break;
        }
 
@@ -1299,7 +1578,8 @@ dissect_ndmp_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *par
 }
                
 static int
-dissect_mover_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_mover_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -1360,7 +1640,8 @@ static const value_string mover_mode_vals[] = {
 };
 
 static int
-dissect_mover_listen_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_mover_listen_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* mode */
        proto_tree_add_item(tree, hf_ndmp_mover_mode, tvb, offset, 4, FALSE);
@@ -1374,7 +1655,8 @@ dissect_mover_listen_request(tvbuff_t *tvb, int offset, packet_info *pinfo, prot
 }
 
 static int
-dissect_mover_listen_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_mover_listen_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -1387,7 +1669,8 @@ dissect_mover_listen_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_
 }
 
 static int
-dissect_mover_set_window_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_mover_set_window_request(tvbuff_t *tvb, int offset,
+    packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
 {
        /* window offset */
        proto_tree_add_item(tree, hf_ndmp_window_offset, tvb, offset, 8, FALSE);
@@ -1401,7 +1684,8 @@ dissect_mover_set_window_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
 }
 
 static int
-dissect_mover_set_record_size_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_mover_set_record_size_request(tvbuff_t *tvb, int offset,
+    packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
 {
        /* record size */
        proto_tree_add_item(tree, hf_ndmp_record_size, tvb, offset, 4, FALSE);
@@ -1411,7 +1695,8 @@ dissect_mover_set_record_size_request(tvbuff_t *tvb, int offset, packet_info *pi
 }
 
 static int
-dissect_mover_connect_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_mover_connect_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* mode */
        proto_tree_add_item(tree, hf_ndmp_mover_mode, tvb, offset, 4, FALSE);
@@ -1424,10 +1709,11 @@ dissect_mover_connect_request(tvbuff_t *tvb, int offset, packet_info *pinfo, pro
 }
 
 static int
-dissect_log_file_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_log_file_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* file */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_file_name, offset, NULL);
 
        /* error */
@@ -1450,7 +1736,8 @@ static const value_string log_type_vals[] = {
 };
 
 static int
-dissect_log_message_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_log_message_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* type */
        proto_tree_add_item(tree, hf_ndmp_log_type, tvb, offset, 4, FALSE);
@@ -1461,21 +1748,22 @@ dissect_log_message_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto
        offset += 4;
 
        /* message */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_log_message, offset, NULL);
 
        return offset;
 }
 
 static int
-dissect_notify_data_halted_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_notify_data_halted_request(tvbuff_t *tvb, int offset,
+    packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
 {
        /* halt */
        proto_tree_add_item(tree, hf_ndmp_halt, tvb, offset, 4, FALSE);
        offset += 4;
 
        /* reason */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_halt_reason, offset, NULL);
 
        return offset;
@@ -1492,7 +1780,8 @@ static const value_string connected_vals[] = {
 };
 
 static int
-dissect_notify_connected_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_notify_connected_request(tvbuff_t *tvb, int offset,
+    packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
 {
        /* connected */
        proto_tree_add_item(tree, hf_ndmp_connected, tvb, offset, 4, FALSE);
@@ -1503,7 +1792,7 @@ dissect_notify_connected_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
        offset += 4;
 
        /* reason */
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_connected_reason, offset, NULL);
 
        return offset;
@@ -1511,7 +1800,8 @@ dissect_notify_connected_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
 
 
 static int
-dissect_notify_mover_paused_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_notify_mover_paused_request(tvbuff_t *tvb, int offset,
+    packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
 {
        /* mover pause */
        proto_tree_add_item(tree, hf_ndmp_mover_pause, tvb, offset, 4, FALSE);
@@ -1525,7 +1815,8 @@ dissect_notify_mover_paused_request(tvbuff_t *tvb, int offset, packet_info *pinf
 }
 
 static int
-dissect_auth_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_auth_data(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree)
 {
        guint type;
        
@@ -1540,18 +1831,18 @@ dissect_auth_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tre
                break;
        case NDMP_AUTH_TEXT:
                /* auth id */
-               offset = dissect_rpc_string(tvb, pinfo, tree,
+               offset = dissect_rpc_string(tvb, tree,
                                hf_ndmp_auth_id, offset, NULL);
 
                /* auth password */
-               offset = dissect_rpc_string(tvb, pinfo, tree,
+               offset = dissect_rpc_string(tvb, tree,
                                hf_ndmp_auth_password, offset, NULL);
 
                
                break;
        case NDMP_AUTH_MD5:
                /* auth id */
-               offset = dissect_rpc_string(tvb, pinfo, tree,
+               offset = dissect_rpc_string(tvb, tree,
                                hf_ndmp_auth_id, offset, NULL);
 
                /* digest */
@@ -1563,9 +1854,16 @@ dissect_auth_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tre
        return offset;
 }
 
+static int
+dissect_connect_client_auth_request(tvbuff_t *tvb, int offset,
+    packet_info *pinfo, proto_tree *tree, guint32 seq _U_)
+{
+       return dissect_auth_data(tvb, offset, pinfo, tree);
+}
 
 static int
-dissect_connect_server_auth_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_connect_server_auth_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -1578,16 +1876,18 @@ dissect_connect_server_auth_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
 }
 
 static int
-dissect_tape_write_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_tape_write_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* data */
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_ndmp_data, offset);
+       offset = dissect_rpc_data(tvb, tree, hf_ndmp_data, offset);
 
        return offset;
 }
 
 static int
-dissect_tape_write_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_tape_write_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -1601,7 +1901,8 @@ dissect_tape_write_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tr
 }
 
 static int
-dissect_tape_read_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_tape_read_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* count */
        proto_tree_add_item(tree, hf_ndmp_count, tvb, offset, 4, FALSE);
@@ -1611,14 +1912,15 @@ dissect_tape_read_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_t
 }
 
 static int
-dissect_tape_read_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_tape_read_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
        offset += 4;
 
        /* data */
-       offset = dissect_rpc_data(tvb, pinfo, tree, hf_ndmp_data, offset);
+       offset = dissect_rpc_data(tvb, tree, hf_ndmp_data, offset);
 
        return offset;
 }
@@ -1643,8 +1945,8 @@ dissect_file_name(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *par
        char *name;
 
        if (parent_tree) {
-               item = proto_tree_add_text(parent_tree, tvb, offset, 0,
-                               "File ");
+               item = proto_tree_add_text(parent_tree, tvb, offset, -1,
+                               "File");
                tree = proto_item_add_subtree(item, ett_ndmp_file_name);
        }
 
@@ -1656,7 +1958,7 @@ dissect_file_name(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *par
        switch(type){
        case NDMP_FS_UNIX:
                /* file */
-               offset = dissect_rpc_string(tvb, pinfo, tree,
+               offset = dissect_rpc_string(tvb, tree,
                                hf_ndmp_file_name, offset, &name);
                if (check_col(pinfo->cinfo, COL_INFO)){
                        col_append_fstr(pinfo->cinfo, COL_INFO, " %s ", name);
@@ -1664,19 +1966,19 @@ dissect_file_name(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *par
                break;
        case NDMP_FS_NT:
                /* nt file */
-               offset = dissect_rpc_string(tvb, pinfo, tree,
+               offset = dissect_rpc_string(tvb, tree,
                                hf_ndmp_nt_file_name, offset, &name);
                if (check_col(pinfo->cinfo, COL_INFO)){
                        col_append_fstr(pinfo->cinfo, COL_INFO, " %s ", name);
                }
 
                /* dos file */
-               offset = dissect_rpc_string(tvb, pinfo, tree,
+               offset = dissect_rpc_string(tvb, tree,
                                hf_ndmp_dos_file_name, offset, NULL);
                break;
        default:
                /* file */
-               offset = dissect_rpc_string(tvb, pinfo, tree,
+               offset = dissect_rpc_string(tvb, tree,
                                hf_ndmp_file_name, offset, &name);
                if (check_col(pinfo->cinfo, COL_INFO)){
                        col_append_fstr(pinfo->cinfo, COL_INFO, " %s ", name);
@@ -1706,7 +2008,8 @@ static const true_false_string tfs_ndmp_file_invalid_group = {
        "Group is valid"
 };
 static int
-dissect_file_invalids(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
+dissect_file_invalids(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *parent_tree)
 {
        proto_item* item = NULL;
        proto_tree* tree = NULL;
@@ -1715,7 +2018,7 @@ dissect_file_invalids(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree
        flags=tvb_get_ntohl(tvb, offset);
        if (parent_tree) {
                item = proto_tree_add_text(parent_tree, tvb, offset, 4,
-                               "Invalids: 0x%08x ", flags);
+                               "Invalids: 0x%08x", flags);
                tree = proto_item_add_subtree(item, ett_ndmp_file_invalids);
        }
 
@@ -1761,7 +2064,7 @@ dissect_file_stats(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *pa
        nstime_t ns;
 
        if (parent_tree) {
-               item = proto_tree_add_text(parent_tree, tvb, offset, 0,
+               item = proto_tree_add_text(parent_tree, tvb, offset, -1,
                                "Stats:");
                tree = proto_item_add_subtree(item, ett_ndmp_file_stats);
        }
@@ -1810,7 +2113,7 @@ dissect_file_stats(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *pa
        offset += 4;
 
        /*file size*/
-       offset = dissect_rpc_uint64(tvb, pinfo, tree, hf_ndmp_file_size,
+       offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_file_size,
                        offset);
 
        /* links */
@@ -1830,7 +2133,7 @@ dissect_file(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_t
        int old_offset=offset;
 
        if (parent_tree) {
-               item = proto_tree_add_text(parent_tree, tvb, offset, 0,
+               item = proto_tree_add_text(parent_tree, tvb, offset, -1,
                                "File:");
                tree = proto_item_add_subtree(item, ett_ndmp_file);
        }
@@ -1856,7 +2159,8 @@ dissect_file(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_t
 }
 
 static int
-dissect_fh_add_file_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_fh_add_file_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* files */
        offset = dissect_rpc_array(tvb, pinfo, tree, offset,
@@ -1884,7 +2188,8 @@ dissect_dir(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 }
 
 static int
-dissect_fh_add_dir_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_fh_add_dir_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* dirs */
        offset = dissect_rpc_array(tvb, pinfo, tree, offset,
@@ -1913,7 +2218,8 @@ dissect_node(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 
 
 static int
-dissect_fh_add_node_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_fh_add_node_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* node */
        offset = dissect_rpc_array(tvb, pinfo, tree, offset,
@@ -1923,10 +2229,11 @@ dissect_fh_add_node_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto
 }
 
 static int
-dissect_data_start_backup_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_data_start_backup_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /*butype name*/
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_butype_name, offset, NULL);
 
        /* default env */
@@ -1937,22 +2244,23 @@ dissect_data_start_backup_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
 }
 
 static int
-dissect_nlist(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_nlist(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *tree)
 {
        /*original path*/
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_bu_original_path, offset, NULL);
 
        /*destination dir*/
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_bu_destination_dir, offset, NULL);
 
        /*new name*/
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_bu_new_name, offset, NULL);
 
        /*other name*/
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_bu_other_name, offset, NULL);
 
        /* node */
@@ -1968,7 +2276,8 @@ dissect_nlist(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 
 
 static int
-dissect_data_start_recover_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_data_start_recover_request(tvbuff_t *tvb, int offset,
+    packet_info *pinfo, proto_tree *tree, guint32 seq _U_)
 {
        /* default env */
        offset = dissect_rpc_array(tvb, pinfo, tree, offset,
@@ -1979,14 +2288,15 @@ dissect_data_start_recover_request(tvbuff_t *tvb, int offset, packet_info *pinfo
                        dissect_nlist, hf_ndmp_nlist);
 
        /*butype name*/
-       offset = dissect_rpc_string(tvb, pinfo, tree,
+       offset = dissect_rpc_string(tvb, tree,
                        hf_ndmp_butype_name, offset, NULL);
 
        return offset;
 }
 
 static int
-dissect_data_get_env_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_data_get_env_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        /* error */
        proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
@@ -2009,7 +2319,8 @@ static const true_false_string tfs_ndmp_state_invalid_etr = {
        "Estimated Time Remaining is valid"
 };
 static int
-dissect_state_invalids(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
+dissect_state_invalids(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+    proto_tree *parent_tree)
 {
        proto_item* item = NULL;
        proto_tree* tree = NULL;
@@ -2018,7 +2329,7 @@ dissect_state_invalids(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree
        flags=tvb_get_ntohl(tvb, offset);
        if (parent_tree) {
                item = proto_tree_add_text(parent_tree, tvb, offset, 4,
-                               "Invalids: 0x%08x ", flags);
+                               "Invalids: 0x%08x", flags);
                tree = proto_item_add_subtree(item, ett_ndmp_state_invalids);
        }
 
@@ -2070,7 +2381,8 @@ static const value_string data_halted_vals[] = {
 };
 
 static int
-dissect_data_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_data_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
+    proto_tree *tree, guint32 seq _U_)
 {
        nstime_t ns;
 
@@ -2094,11 +2406,11 @@ dissect_data_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, prot
        offset += 4;
 
        /*bytes processed*/
-       offset = dissect_rpc_uint64(tvb, pinfo, tree, hf_ndmp_data_bytes_processed,
+       offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_data_bytes_processed,
                        offset);
 
        /*est bytes remain*/
-       offset = dissect_rpc_uint64(tvb, pinfo, tree, hf_ndmp_data_est_bytes_remain,
+       offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_data_est_bytes_remain,
                        offset);
 
        /* est time remain */
@@ -2124,8 +2436,10 @@ dissect_data_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, prot
 
 typedef struct _ndmp_command {
        guint32 cmd;
-       int (*request) (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
-       int (*response)(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
+       int (*request) (tvbuff_t *tvb, int offset, packet_info *pinfo,
+           proto_tree *tree, guint32 seq);
+       int (*response)(tvbuff_t *tvb, int offset, packet_info *pinfo,
+           proto_tree *tree, guint32 seq);
 } ndmp_command;
 
 static const ndmp_command ndmp_commands[] = {
@@ -2134,7 +2448,7 @@ static const ndmp_command ndmp_commands[] = {
        {NDMP_CONFIG_GET_CONNECTION_TYPE, 
                NULL, dissect_ndmp_config_get_connection_type_reply},
        {NDMP_CONFIG_GET_AUTH_ATTR, 
-               dissect_auth_type, dissect_auth_attr},
+               dissect_get_auth_type_request, dissect_auth_attr_msg},
        {NDMP_CONFIG_GET_BUTYPE_INFO,   
                NULL, dissect_get_butype_info_reply},
        {NDMP_CONFIG_GET_FS_INFO,       
@@ -2146,7 +2460,7 @@ static const ndmp_command ndmp_commands[] = {
        {NDMP_CONFIG_GET_SERVER_INFO,   
                NULL, dissect_get_server_info_reply},
        {NDMP_SCSI_OPEN,                
-               dissect_scsi_device, dissect_error},
+               dissect_scsi_open_request, dissect_error},
        {NDMP_SCSI_CLOSE,               
                NULL, dissect_error},
        {NDMP_SCSI_GET_STATE,           
@@ -2157,7 +2471,8 @@ static const ndmp_command ndmp_commands[] = {
                NULL, dissect_error},
        {NDMP_SCSI_RESET_BUS,           
                NULL, dissect_error},
-       {NDMP_SCSI_EXECUTE_CDB,         NULL,NULL},
+       {NDMP_SCSI_EXECUTE_CDB,
+               dissect_execute_cdb_request_mc, dissect_execute_cdb_reply},
        {NDMP_TAPE_OPEN,                
                dissect_tape_open_request, dissect_error},
        {NDMP_TAPE_CLOSE,               
@@ -2170,7 +2485,8 @@ static const ndmp_command ndmp_commands[] = {
                dissect_tape_write_request, dissect_tape_write_reply},
        {NDMP_TAPE_READ,        
                dissect_tape_read_request, dissect_tape_read_reply},
-       {NDMP_TAPE_EXECUTE_CDB,         NULL,NULL},
+       {NDMP_TAPE_EXECUTE_CDB,
+               dissect_execute_cdb_request_tape, dissect_execute_cdb_reply},
        {NDMP_DATA_GET_STATE,           
                NULL, dissect_data_get_state_reply},
        {NDMP_DATA_START_BACKUP,
@@ -2184,9 +2500,9 @@ static const ndmp_command ndmp_commands[] = {
        {NDMP_DATA_STOP, 
                NULL, dissect_error},
        {NDMP_DATA_LISTEN, 
-               dissect_ndmp_addr_type, dissect_mover_listen_reply},
+               dissect_ndmp_addr_msg, dissect_mover_listen_reply},
        {NDMP_DATA_CONNECT,             
-               dissect_ndmp_addr, dissect_error},
+               dissect_ndmp_addr_msg, dissect_error},
        {NDMP_NOTIFY_DATA_HALTED,       
                dissect_notify_data_halted_request, NULL},
        {NDMP_NOTIFY_CONNECTED,         
@@ -2210,11 +2526,11 @@ static const ndmp_command ndmp_commands[] = {
        {NDMP_CONNECT_OPEN,             
                dissect_connect_open_request, dissect_error},
        {NDMP_CONNECT_CLIENT_AUTH, 
-               dissect_auth_data, dissect_error},
+               dissect_connect_client_auth_request, dissect_error},
        {NDMP_CONNECT_CLOSE,            
                NULL,NULL},
        {NDMP_CONNECT_SERVER_AUTH, 
-               dissect_auth_attr, dissect_connect_server_auth_reply},
+               dissect_auth_attr_msg, dissect_connect_server_auth_reply},
        {NDMP_MOVER_GET_STATE,          
                NULL, dissect_mover_get_state_reply},
        {NDMP_MOVER_LISTEN,             
@@ -2295,12 +2611,6 @@ dissect_ndmp_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree
        int i;
        proto_item *cmd_item=NULL;
        proto_tree *cmd_tree=NULL;
-       guint32 size;
-
-       /* the size of the current PDU */
-       size = tvb_get_ntohl(tvb, offset);      
-       proto_tree_add_uint(tree, hf_ndmp_size, tvb, offset, 4, size&NDMP_FRAGLEN);
-       offset += 4;
 
        offset=dissect_ndmp_header(tvb, offset, pinfo, tree, nh);
 
@@ -2313,120 +2623,143 @@ dissect_ndmp_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree
 
        if(ndmp_commands[i].cmd==0){
                /* we do not know this message */
-               proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset), "Unknown type of NDMP message: 0x%02x", nh->msg);
+               proto_tree_add_text(tree, tvb, offset, -1, "Unknown type of NDMP message: 0x%02x", nh->msg);
                offset+=tvb_length_remaining(tvb, offset);
                return offset;
        }
 
        if(tree){
-               cmd_item = proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset)
+               cmd_item = proto_tree_add_text(tree, tvb, offset, -1
                        msg_vals[i].strptr);
                cmd_tree = proto_item_add_subtree(cmd_item, ett_ndmp);
        }
 
        if(nh->type==NDMP_MESSAGE_REQUEST){
                if(ndmp_commands[i].request){
-                       offset=ndmp_commands[i].request(tvb, offset, pinfo, cmd_tree);
+                       offset=ndmp_commands[i].request(tvb, offset, pinfo, cmd_tree,
+                           nh->seq);
                }
        } else {
                if(ndmp_commands[i].response){
-                       offset=ndmp_commands[i].response(tvb, offset, pinfo, cmd_tree);
+                       offset=ndmp_commands[i].response(tvb, offset, pinfo, cmd_tree,
+                           nh->rep_seq);
                }
        }
 
        return offset;
 }
 
-static void
-dissect_ndmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
+static gboolean
+dissect_ndmp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+    tvbuff_t *frag_tvb, fragment_data *ipfd_head, gboolean is_tcp,
+    guint32 rpc_rm)
 {
-       int offset = 0;
-       guint32 size, available_bytes;
+       int offset = (is_tcp && tvb == frag_tvb) ? 4 : 0;
+       guint32 size;
        struct ndmp_header nh;
-       proto_item *item=NULL;
-       proto_tree *tree=NULL;
-
+       proto_item *ndmp_item = NULL;
+       proto_tree *ndmp_tree = NULL;
+
+       /* size of this NDMP PDU */
+       size = tvb_length_remaining(tvb, offset);
+       if (size < 24) {
+               /* too short to be NDMP */
+               return FALSE;
+       }
 
-       if(parent_tree){
-               item = proto_tree_add_item(parent_tree, proto_ndmp, tvb, offset, 0, FALSE);
-               tree = proto_item_add_subtree(item, ett_ndmp);
+       /*
+        * Check the NDMP header, if we have it.
+        */
+       nh.seq = tvb_get_ntohl(tvb, offset);
+       nh.time = tvb_get_ntohl(tvb, offset+4);
+       nh.type = tvb_get_ntohl(tvb, offset+8);
+       nh.msg = tvb_get_ntohl(tvb, offset+12);
+       nh.rep_seq = tvb_get_ntohl(tvb, offset+16);
+       nh.err = tvb_get_ntohl(tvb, offset+20);
+
+       if (nh.type > 1)
+               return FALSE;
+       if (nh.msg > 0xa09 || nh.msg == 0)
+               return FALSE;
+       if (nh.err > 0x17)
+               return FALSE;
+
+       /*
+        * Check if this is the last fragment.
+        */
+       if (!(rpc_rm & RPC_RM_LASTFRAG)) {
+               /*
+                * This isn't the last fragment.
+                * If we're doing reassembly, just return
+                * TRUE to indicate that this looks like
+                * the beginning of an NDMP message,
+                * and let them do reassembly.
+                */
+               if (ndmp_defragment)
+                       return TRUE;
        }
 
        if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
-               col_add_str(pinfo->cinfo, COL_PROTOCOL, "NDMP");
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDMP");
        if (check_col(pinfo->cinfo, COL_INFO)) 
                col_clear(pinfo->cinfo, COL_INFO);
 
+       if (tree) {
+               ndmp_item = proto_tree_add_item(tree, proto_ndmp,
+                   tvb, 0, -1, FALSE);
+               ndmp_tree = proto_item_add_subtree(ndmp_item, ett_ndmp);
 
-       /* loop through the packet, dissecting multiple NDMP pdus*/
-       do {
-               available_bytes = tvb_length_remaining(tvb, offset);
-
-               /* size of this NDMP PDU */
-               size = (tvb_get_ntohl(tvb, offset)&NDMP_FRAGLEN) + 4;   
-               if(size<28){
-                       /* too short to be NDMP */
-                       return;
-               }
-
-               /* check the ndmp header, if we have it */
-               if(available_bytes>=28){
-                       nh.seq=tvb_get_ntohl(tvb, offset+4);
-                       nh.time=tvb_get_ntohl(tvb, offset+8);
-                       nh.type=tvb_get_ntohl(tvb, offset+12);
-                       nh.msg=tvb_get_ntohl(tvb, offset+16);
-                       nh.rep_seq=tvb_get_ntohl(tvb, offset+20);
-                       nh.err=tvb_get_ntohl(tvb, offset+24);
-
-                       if(nh.type>1){
-                               return;
-                       }
-                       if((nh.msg>0xa09)||(nh.msg==0)){
-                               return;
-                       }
-                       if(nh.err>0x17){
-                               return;
-                       }
+               if (is_tcp) {
+                       show_rpc_fraginfo(tvb, frag_tvb, ndmp_tree, rpc_rm,
+                           ipfd_head, pinfo);
                }
+       }
 
-               /* desegmentation */
-               if(ndmp_desegment){
-                       if(pinfo->can_desegment
-                       && size>available_bytes) {
-                               pinfo->desegment_offset = offset;
-                               pinfo->desegment_len = size-available_bytes;
-                               return;
-                       }
-               }
+       /*
+        * We cannot trust what dissect_ndmp_cmd() tells us, as there
+        * are implementations which pad some additional data after
+        * the PDU.  We MUST use size.
+        */
+       dissect_ndmp_cmd(tvb, offset, pinfo, ndmp_tree, &nh);
+       return TRUE;
+}
 
-               if(available_bytes<28){
-                       /* too short to be a NDMP packet */
+static void
+dissect_ndmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       int offset = 0;
+       int len;
+
+       while (tvb_reported_length_remaining(tvb, offset) != 0) {
+               /*
+                * Process this fragment.
+                */
+               len = dissect_rpc_fragment(tvb, offset, pinfo, tree,
+                   dissect_ndmp_message, FALSE, proto_ndmp, ett_ndmp,
+                   ndmp_defragment);
+               if (len < 0) {
+                       /*
+                        * We need more data from the TCP stream for
+                        * this fragment.
+                        */
                        return;
                }
+               if (len == 0) {
+                       /*
+                        * It's not NDMP.  Stop processing.
+                        */
+                       break;
+               }
 
-               /* We can not trust what dissect_ndmp_cmd() tells us since
-                  there are implementations which pads some additional data
-                  after the PDU. We MUST use size.
-               */
-               dissect_ndmp_cmd(tvb, offset, pinfo, tree, &nh);
-               offset += size;
-       } while(offset<(int)tvb_reported_length(tvb));
-
-       proto_item_set_len(item, offset);
+               offset += len;
+       }
 }
 
-
-
-
 void
 proto_register_ndmp(void)
 {
 
   static hf_register_info hf_ndmp[] = {
-       { &hf_ndmp_size, {
-               "Size", "ndmp.size", FT_UINT32, BASE_DEC,
-               NULL, 0, "Size of this NDMP PDU", HFILL }},
-
        { &hf_ndmp_header, {
                "NDMP Header", "ndmp.header", FT_NONE, 0,
                NULL, 0, "NDMP Header", HFILL }},
@@ -2699,6 +3032,46 @@ proto_register_ndmp(void)
                "LUN", "ndmp.scsi.lun", FT_UINT32, BASE_DEC,
                NULL, 0, "Target LUN", HFILL }},
 
+       { &hf_ndmp_execute_cdb_flags_data_in, {
+               "DATA_IN", "ndmp.execute_cdb.flags.data_in", FT_BOOLEAN, 32,
+               NULL, 0x00000001, "DATA_IN", HFILL }},
+
+       { &hf_ndmp_execute_cdb_flags_data_out, {
+               "DATA_OUT", "ndmp.execute_cdb.flags.data_out", FT_BOOLEAN, 32,
+               NULL, 0x00000002, "DATA_OUT", HFILL }},
+
+       { &hf_ndmp_execute_cdb_timeout, {
+               "Timeout", "ndmp.execute_cdb.timeout", FT_UINT32, BASE_DEC,
+               NULL, 0, "Reselect timeout, in milliseconds", HFILL }},
+
+       { &hf_ndmp_execute_cdb_datain_len, {
+               "Data in length", "ndmp.execute_cdb.datain_len", FT_UINT32, BASE_DEC,
+               NULL, 0, "Expected length of data bytes to read", HFILL }},
+
+       { &hf_ndmp_execute_cdb_cdb_len, {
+               "CDB length", "ndmp.execute_cdb.cdb_len", FT_UINT32, BASE_DEC,
+               NULL, 0, "Length of CDB", HFILL }},
+
+       { &hf_ndmp_execute_cdb_dataout, {
+               "Data out", "ndmp.execute_cdb.dataout", FT_BYTES, BASE_NONE,
+               NULL, 0, "Data to be transferred to the SCSI device", HFILL }},
+
+       { &hf_ndmp_execute_cdb_status, {
+               "Status", "ndmp.execute_cdb.status", FT_UINT8, BASE_DEC,
+               VALS(scsi_status_val), 0, "SCSI status", HFILL }},
+
+       { &hf_ndmp_execute_cdb_dataout_len, {
+               "Data out length", "ndmp.execute_cdb.dataout_len", FT_UINT32, BASE_DEC,
+               NULL, 0, "Number of bytes transferred to the device", HFILL }},
+
+       { &hf_ndmp_execute_cdb_datain, {
+               "Data in", "ndmp.execute_cdb.datain", FT_BYTES, BASE_NONE,
+               NULL, 0, "Data transferred from the SCSI device", HFILL }},
+
+       { &hf_ndmp_execute_cdb_sns_len, {
+               "Sense data length", "ndmp.execute_cdb.sns_len", FT_UINT32, BASE_DEC,
+               NULL, 0, "Length of sense data", HFILL }},
+
        { &hf_ndmp_tape_open_mode, {
                "Mode", "ndmp.tape.open_mode", FT_UINT32, BASE_DEC,
                VALS(tape_open_mode_vals), 0, "Mode to open tape in", HFILL }},
@@ -3030,9 +3403,6 @@ proto_register_ndmp(void)
        { &hf_ndmp_data_est_time_remain, {
                "Est Time Remain", "ndmp.data.est_time_remain", FT_RELATIVE_TIME, BASE_DEC,
                NULL, 0, "Estimated time remaining", HFILL }},
-
-
-
   };
 
   static gint *ett[] = {
@@ -3041,11 +3411,16 @@ proto_register_ndmp(void)
     &ett_ndmp_butype_attrs,
     &ett_ndmp_fs_invalid,
     &ett_ndmp_tape_attr,
+    &ett_ndmp_execute_cdb_flags,
+    &ett_ndmp_execute_cdb_cdb,
+    &ett_ndmp_execute_cdb_sns,
+    &ett_ndmp_execute_cdb_payload,
     &ett_ndmp_tape_invalid,
     &ett_ndmp_tape_flags,
     &ett_ndmp_addr,
     &ett_ndmp_file,
     &ett_ndmp_file_name,
+    &ett_ndmp_file_stats,
     &ett_ndmp_file_invalids,
     &ett_ndmp_state_invalids,
   };
@@ -3059,8 +3434,14 @@ proto_register_ndmp(void)
 
   /* desegmentation */
   ndmp_module = prefs_register_protocol(proto_ndmp, NULL);
-  prefs_register_bool_preference(ndmp_module, "desegment", "Desegment all NDMP messages spanning multiple TCP segments", "Whether the dissector should desegment NDMP over TCP PDUs or not", &ndmp_desegment);
-
+  prefs_register_bool_preference(ndmp_module, "desegment",
+       "Desegment all NDMP messages spanning multiple TCP segments",
+       "Whether the dissector should desegment NDMP messages",
+       &ndmp_desegment);
+  prefs_register_bool_preference(ndmp_module, "defragment",
+       "Defragment all multi-fragment NDMP messages",
+       "Whether the dissector should defragment multi-fragment NDMP messages",
+       &ndmp_defragment);
 }
 
 void