Removed trailing whitespaces from .h and .c files using the
[obnox/wireshark/wip.git] / packet-ndmp.c
index 0e605783b3e78a3eda965b67b856eb93741d00ae..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.2 2002/01/04 19:55:03 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
 
 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;
@@ -128,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;
@@ -214,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;
@@ -223,9 +227,20 @@ static gint ett_ndmp_file_stats = -1;
 static gint ett_ndmp_file_invalids = -1;
 static gint ett_ndmp_state_invalids = -1;
 
+struct ndmp_header {
+       guint32 seq;
+       guint32 time;
+       guint32 type;
+       guint32 msg;
+       guint32 rep_seq;
+       guint32 err;
+};
+
 /* 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
@@ -406,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);
@@ -418,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);
@@ -428,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;
@@ -466,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;
 
@@ -476,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);
@@ -499,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;
 
@@ -509,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;
        
@@ -534,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;
@@ -585,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;
@@ -594,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);
        }
 
@@ -625,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 */
@@ -639,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);
@@ -673,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;
@@ -682,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);
        }
 
@@ -702,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;
@@ -722,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 */
@@ -758,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);
@@ -787,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;
@@ -796,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);
        }
 
@@ -810,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;
@@ -827,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 */
@@ -844,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 */
@@ -855,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);
@@ -872,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 */
@@ -883,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);
@@ -897,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);
 
 
@@ -924,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);
@@ -956,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 */
@@ -977,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[] = {
@@ -986,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 */
@@ -1029,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;
@@ -1038,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);
        }
 
@@ -1078,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;
@@ -1087,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);
        }
 
@@ -1106,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);
@@ -1135,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 */
@@ -1168,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);
@@ -1182,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);
@@ -1240,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;
@@ -1279,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;
        }
 
@@ -1287,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);
@@ -1348,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);
@@ -1362,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);
@@ -1375,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);
@@ -1389,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);
@@ -1399,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);
@@ -1412,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 */
@@ -1438,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);
@@ -1449,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;
@@ -1480,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);
@@ -1491,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;
@@ -1499,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);
@@ -1513,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;
        
@@ -1528,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 */
@@ -1551,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);
@@ -1566,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);
@@ -1589,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);
@@ -1599,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;
 }
@@ -1631,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);
        }
 
@@ -1644,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);
@@ -1652,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);
@@ -1694,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;
@@ -1703,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);
        }
 
@@ -1746,9 +2061,10 @@ dissect_file_stats(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *pa
        proto_item* item = NULL;
        proto_tree* tree = NULL;
        int old_offset=offset;
+       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);
        }
@@ -1765,15 +2081,21 @@ dissect_file_stats(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *pa
        offset += 4;
 
        /* mtime */
-       proto_tree_add_item(tree, hf_ndmp_file_mtime, tvb, offset, 4, FALSE);
+       ns.secs=tvb_get_ntohl(tvb, offset);
+       ns.nsecs=0;
+       proto_tree_add_time(tree, hf_ndmp_file_mtime, tvb, offset, 4, &ns);
        offset += 4;
 
        /* atime */
-       proto_tree_add_item(tree, hf_ndmp_file_atime, tvb, offset, 4, FALSE);
+       ns.secs=tvb_get_ntohl(tvb, offset);
+       ns.nsecs=0;
+       proto_tree_add_time(tree, hf_ndmp_file_atime, tvb, offset, 4, &ns);
        offset += 4;
 
        /* ctime */
-       proto_tree_add_item(tree, hf_ndmp_file_ctime, tvb, offset, 4, FALSE);
+       ns.secs=tvb_get_ntohl(tvb, offset);
+       ns.nsecs=0;
+       proto_tree_add_time(tree, hf_ndmp_file_ctime, tvb, offset, 4, &ns);
        offset += 4;
 
        /* owner */
@@ -1791,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 */
@@ -1811,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);
        }
@@ -1837,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,
@@ -1865,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,
@@ -1894,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,
@@ -1904,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 */
@@ -1918,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 */
@@ -1949,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,
@@ -1960,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);
@@ -1990,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;
@@ -1999,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);
        }
 
@@ -2051,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;
 
@@ -2075,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 */
@@ -2105,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[] = {
@@ -2115,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,       
@@ -2127,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,           
@@ -2138,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,               
@@ -2151,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,
@@ -2165,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,         
@@ -2191,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,             
@@ -2221,49 +2556,48 @@ static const ndmp_command ndmp_commands[] = {
 
 
 static int
-dissect_ndmp_header(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
+dissect_ndmp_header(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, struct ndmp_header *nh)
 {
        proto_item* item = NULL;
        proto_tree* tree = NULL;
-       guint32 msgtype, msg;
+       nstime_t ns;
 
        if (parent_tree) {
-               item = proto_tree_add_item(tree, hf_ndmp_header, tvb,
+               item = proto_tree_add_item(parent_tree, hf_ndmp_header, tvb,
                                offset, 24, FALSE);
                tree = proto_item_add_subtree(item, ett_ndmp_header);
        }
 
        /* sequence number */
-       proto_tree_add_item(tree, hf_ndmp_sequence, tvb, offset, 4, FALSE);
+       proto_tree_add_uint(tree, hf_ndmp_sequence, tvb, offset, 4, nh->seq);
        offset += 4;
 
        /* timestamp */
-       proto_tree_add_item(tree, hf_ndmp_timestamp, tvb, offset, 4, FALSE);
+       ns.secs=nh->time;
+       ns.nsecs=0;
+       proto_tree_add_time(tree, hf_ndmp_timestamp, tvb, offset, 4, &ns);
        offset += 4;
 
        /* Message Type */
-       msgtype = tvb_get_ntohl(tvb, offset);
-       proto_tree_add_item(tree, hf_ndmp_msgtype, tvb, offset, 4, FALSE);
+       proto_tree_add_uint(tree, hf_ndmp_msgtype, tvb, offset, 4, nh->type);
        offset += 4;
 
        /* Message */
-       msg = tvb_get_ntohl(tvb, offset);
-       proto_tree_add_item(tree, hf_ndmp_msg, tvb, offset, 4, FALSE);
+       proto_tree_add_uint(tree, hf_ndmp_msg, tvb, offset, 4, nh->msg);
        offset += 4;
 
        /* Reply sequence number */
-       proto_tree_add_item(tree, hf_ndmp_reply_sequence, tvb, offset, 4, FALSE);
+       proto_tree_add_uint(tree, hf_ndmp_reply_sequence, tvb, offset, 4, nh->rep_seq);
        offset += 4;
 
        /* error */
-       proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
+       proto_tree_add_uint(tree, hf_ndmp_error, tvb, offset, 4, nh->err);
        offset += 4;
 
        if (check_col(pinfo->cinfo, COL_INFO)){
-               col_clear(pinfo->cinfo, COL_INFO);
-               col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s",
-                       val_to_str(msg, msg_vals, "Unknown Message (0x%02x)"),
-                       val_to_str(msgtype, msg_type_vals, "Unknown Type (0x%02x)")
+               col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s  ",
+                       val_to_str(nh->msg, msg_vals, "Unknown Message (0x%02x)"),
+                       val_to_str(nh->type, msg_type_vals, "Unknown Type (0x%02x)")
                        );
        }
 
@@ -2272,19 +2606,16 @@ dissect_ndmp_header(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *p
 
 
 static int
-dissect_ndmp_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_ndmp_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, struct ndmp_header *nh)
 {
        int i;
-       guint32 msg, msgtype;
-
-       msg=tvb_get_ntohl(tvb, offset+12);
-       msgtype=tvb_get_ntohl(tvb, offset+8);
-
-       offset=dissect_ndmp_header(tvb, offset, pinfo, tree);
+       proto_item *cmd_item=NULL;
+       proto_tree *cmd_tree=NULL;
 
+       offset=dissect_ndmp_header(tvb, offset, pinfo, tree, nh);
 
        for(i=0;ndmp_commands[i].cmd!=0;i++){
-               if(ndmp_commands[i].cmd==msg){
+               if(ndmp_commands[i].cmd==nh->msg){
                        break;
                }
        }
@@ -2292,65 +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", 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, -1, 
+                       msg_vals[i].strptr);
+               cmd_tree = proto_item_add_subtree(cmd_item, ett_ndmp);
+       }
 
-       if(msgtype==NDMP_MESSAGE_REQUEST){
-               offset=ndmp_commands[i].request(tvb, offset, pinfo, tree);
+       if(nh->type==NDMP_MESSAGE_REQUEST){
+               if(ndmp_commands[i].request){
+                       offset=ndmp_commands[i].request(tvb, offset, pinfo, cmd_tree,
+                           nh->seq);
+               }
        } else {
-               offset=ndmp_commands[i].response(tvb, offset, pinfo, tree);
+               if(ndmp_commands[i].response){
+                       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 *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;
-
-       /* 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);      
-
-               /* desegmentation */
-               if(ndmp_desegment){
-                       if(pinfo->can_desegment
-                       && size>available_bytes) {
-                               pinfo->desegment_offset = offset;
-                               pinfo->desegment_len = size-available_bytes;
-                               return;
-                       }
-               }
+       int offset = (is_tcp && tvb == frag_tvb) ? 4 : 0;
+       guint32 size;
+       struct ndmp_header nh;
+       proto_item *ndmp_item = NULL;
+       proto_tree *ndmp_tree = NULL;
 
-               /* the size of the current PDU */
-               proto_tree_add_item(tree, hf_ndmp_size, tvb, offset, 4, size);
-               offset += 4;
+       /* size of this NDMP PDU */
+       size = tvb_length_remaining(tvb, offset);
+       if (size < 24) {
+               /* too short to be NDMP */
+               return FALSE;
+       }
 
-               offset = dissect_ndmp_cmd(tvb, offset, pinfo, tree);
-       } while(offset<(int)tvb_reported_length(tvb));
+       /*
+        * 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_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);
 
+               if (is_tcp) {
+                       show_rpc_fraginfo(tvb, frag_tvb, ndmp_tree, rpc_rm,
+                           ipfd_head, pinfo);
+               }
+       }
 
+       /*
+        * 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;
+}
+
+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;
+               }
+
+               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 }},
@@ -2372,7 +2781,7 @@ proto_register_ndmp(void)
                VALS(msg_type_vals), 0, "Is this a Request or Response?", HFILL }},
 
        { &hf_ndmp_msg, {
-               "Message", "ndmp.msg", FT_UINT32, BASE_DEC,
+               "Message", "ndmp.msg", FT_UINT32, BASE_HEX,
                VALS(msg_vals), 0, "Type of NDMP PDU", HFILL }},
 
        { &hf_ndmp_error, {
@@ -2623,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 }},
@@ -2932,15 +3381,15 @@ proto_register_ndmp(void)
                TFS(&tfs_ndmp_state_invalid_etr), 0x00000002, "Whether EstimatedTimeLeft is valid or not", HFILL, }},
 
        { &hf_ndmp_bu_operation, {
-               "", "ndmp.bu.operation", FT_UINT32, BASE_DEC,
+               "Operation", "ndmp.bu.operation", FT_UINT32, BASE_DEC,
                VALS(bu_operation_vals), 0, "BU Operation", HFILL, }},
 
        { &hf_ndmp_data_state, {
-               "", "ndmp.data.state", FT_UINT32, BASE_DEC,
+               "State", "ndmp.data.state", FT_UINT32, BASE_DEC,
                VALS(data_state_vals), 0, "Data state", HFILL, }},
 
        { &hf_ndmp_data_halted, {
-               "", "ndmp.data.halted", FT_UINT32, BASE_DEC,
+               "Halted Reason", "ndmp.data.halted", FT_UINT32, BASE_DEC,
                VALS(data_halted_vals), 0, "Data halted reason", HFILL, }},
 
        { &hf_ndmp_data_bytes_processed, {
@@ -2954,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[] = {
@@ -2965,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,
   };
@@ -2983,8 +3434,14 @@ proto_register_ndmp(void)
 
   /* desegmentation */
   ndmp_module = prefs_register_protocol(proto_ndmp, NULL);
-  prefs_register_bool_preference(ndmp_module, "ndmp.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