-/* 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.7 2002/01/18 21:16:39 guy Exp $
+ * $Id: packet-ndmp.c,v 1.16 2002/02/18 23:51:55 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#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;
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;
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;
/* desegmentation of NDMP packets */
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
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,
+ proto_tree *tree, guint32 seq)
{
/* version number */
proto_tree_add_item(tree, hf_ndmp_version, tvb, offset, 4, FALSE);
}
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, proto_tree *tree,
+ guint32 seq)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
}
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,
+ proto_tree *tree, guint32 seq)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
static int
dissect_ndmp_addr_type(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
{
- /*address type*/
proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, FALSE);
offset += 4;
}
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)
+{
+ /*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)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
static int
dissect_auth_type(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
{
- /* auth type */
proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, FALSE);
offset += 4;
}
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)
+{
+ /* auth type */
+ return dissect_auth_type(tvb, offset, pinfo, tree);
+}
+
+static int
+dissect_auth_attr_msg(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, guint32 seq)
{
guint type;
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);
}
}
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)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
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);
}
}
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)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
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);
}
}
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)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
}
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)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
}
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)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
}
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,
+ proto_tree *tree, guint32 seq)
{
/* device */
offset = dissect_rpc_string(tvb, pinfo, tree,
}
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,
+ proto_tree *tree, guint32 seq)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
}
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,
+ proto_tree *tree, guint32 seq)
{
/* device */
offset = dissect_rpc_string(tvb, pinfo, tree,
return offset;
}
+static int
+dissect_execute_cdb_flags(tvbuff_t *tvb, int offset, packet_info *pinfo, 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)
+{
+ 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);
+ 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;
+}
+
+static int
+dissect_execute_cdb_request(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) {
+ 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);
+
+ /* 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_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[] = {
};
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,
+ proto_tree *tree, guint32 seq)
{
/* device */
offset = dissect_rpc_string(tvb, pinfo, 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);
}
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);
}
}
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)
{
/* invalid bits */
offset=dissect_tape_invalid(tvb, offset, pinfo, tree);
};
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,
+ proto_tree *tree, guint32 seq)
{
/* op */
proto_tree_add_item(tree, hf_ndmp_tape_mtio_op, tvb, offset, 4, FALSE);
}
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,
+ proto_tree *tree, guint32 seq)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
}
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)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
};
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,
+ proto_tree *tree, guint32 seq)
{
/* mode */
proto_tree_add_item(tree, hf_ndmp_mover_mode, tvb, offset, 4, FALSE);
}
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)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
}
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,
+ proto_tree *tree, guint32 seq)
{
/* window offset */
proto_tree_add_item(tree, hf_ndmp_window_offset, tvb, offset, 8, FALSE);
}
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,
+ proto_tree *tree, guint32 seq)
{
/* record size */
proto_tree_add_item(tree, hf_ndmp_record_size, tvb, offset, 4, FALSE);
}
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)
{
/* mode */
proto_tree_add_item(tree, hf_ndmp_mover_mode, tvb, offset, 4, FALSE);
}
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,
+ proto_tree *tree, guint32 seq)
{
/* file */
offset = dissect_rpc_string(tvb, pinfo, tree,
};
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,
+ proto_tree *tree, guint32 seq)
{
/* type */
proto_tree_add_item(tree, hf_ndmp_log_type, tvb, offset, 4, FALSE);
}
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, proto_tree *tree, guint32 seq)
{
/* halt */
proto_tree_add_item(tree, hf_ndmp_halt, tvb, offset, 4, FALSE);
};
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,
+ proto_tree *tree, guint32 seq)
{
/* connected */
proto_tree_add_item(tree, hf_ndmp_connected, tvb, offset, 4, FALSE);
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, proto_tree *tree, guint32 seq)
{
/* mover pause */
proto_tree_add_item(tree, hf_ndmp_mover_pause, tvb, offset, 4, FALSE);
return offset;
}
+static int
+dissect_connect_client_auth_request(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint32 seq)
+{
+ 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)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
}
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,
+ proto_tree *tree, guint32 seq)
{
/* data */
offset = dissect_rpc_data(tvb, pinfo, tree, hf_ndmp_data, 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,
+ proto_tree *tree, guint32 seq)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
}
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,
+ proto_tree *tree, guint32 seq)
{
/* count */
proto_tree_add_item(tree, hf_ndmp_count, tvb, offset, 4, FALSE);
}
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,
+ proto_tree *tree, guint32 seq)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
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);
}
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);
}
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);
}
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);
}
}
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)
{
/* files */
offset = dissect_rpc_array(tvb, pinfo, tree, offset,
}
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)
{
/* dirs */
offset = dissect_rpc_array(tvb, pinfo, tree, offset,
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)
{
/* node */
offset = dissect_rpc_array(tvb, pinfo, tree, offset,
}
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)
{
/*butype name*/
offset = dissect_rpc_string(tvb, pinfo, 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)
{
/* default env */
offset = dissect_rpc_array(tvb, pinfo, tree, 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)
{
/* error */
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
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);
}
};
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)
{
nstime_t ns;
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[] = {
{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,
{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,
NULL, dissect_error},
{NDMP_SCSI_RESET_BUS,
NULL, dissect_error},
- {NDMP_SCSI_EXECUTE_CDB, NULL,NULL},
+ {NDMP_SCSI_EXECUTE_CDB,
+ dissect_execute_cdb_request, dissect_execute_cdb_reply},
{NDMP_TAPE_OPEN,
dissect_tape_open_request, dissect_error},
{NDMP_TAPE_CLOSE,
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, dissect_execute_cdb_reply},
{NDMP_DATA_GET_STATE,
NULL, dissect_data_get_state_reply},
{NDMP_DATA_START_BACKUP,
{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,
{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,
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);
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);
}
+ }
- /* 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;
+ proto_item *ndmp_item = NULL;
+ proto_tree *ndmp_tree = NULL;
+
+ 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 }},
"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 }},
{ &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[] = {
&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,
};
/* 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