X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=packet-ndmp.c;h=4aad9397a3085b6ee76e1eed185702a9d3a18422;hb=86096927fc628e8073b812fbac1193c56363585f;hp=ecee3927d5825ebd3880c956e9051178ecc789fb;hpb=528f79538433ade821ccb33d504f819ac1982b38;p=obnox%2Fwireshark%2Fwip.git diff --git a/packet-ndmp.c b/packet-ndmp.c index ecee3927d5..4aad9397a3 100644 --- a/packet-ndmp.c +++ b/packet-ndmp.c @@ -1,52 +1,53 @@ /* packet-ndmp.c - * Routines for NDMP - * Ronnie Sahlberg (see AUTHORS for email) + * Routines for NDMP dissection + * 2001 Ronnie Sahlberg (see AUTHORS for email) * - * $Id: packet-ndmp.c,v 1.1 2001/12/23 21:36:57 guy Exp $ + * $Id: packet-ndmp.c,v 1.28 2004/05/24 02:25:19 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* see www.ndmp.org for protocol specifications. - this file implements version 3 of ndmp + this file implements version 3 of ndmp */ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif - #include #include #include -#include "packet.h" +#include +#include +#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; @@ -54,13 +55,210 @@ static int hf_ndmp_timestamp = -1; static int hf_ndmp_msgtype = -1; static int hf_ndmp_msg = -1; static int hf_ndmp_error = -1; +static int hf_ndmp_hostname = -1; +static int hf_ndmp_os_type = -1; +static int hf_ndmp_os_vers = -1; +static int hf_ndmp_hostid = -1; +static int hf_ndmp_addr_types = -1; +static int hf_ndmp_addr_type = -1; +static int hf_ndmp_auth_type = -1; +static int hf_ndmp_auth_types = -1; +static int hf_ndmp_auth_challenge = -1; +static int hf_ndmp_auth_digest = -1; +static int hf_ndmp_auth_id = -1; +static int hf_ndmp_auth_password = -1; +static int hf_ndmp_butype_info = -1; +static int hf_ndmp_butype_name = -1; +static int hf_ndmp_butype_default_env = -1; +static int hf_ndmp_butype_attr_backup_file_history = -1; +static int hf_ndmp_butype_attr_backup_filelist = -1; +static int hf_ndmp_butype_attr_recover_filelist = -1; +static int hf_ndmp_butype_attr_backup_direct = -1; +static int hf_ndmp_butype_attr_recover_direct = -1; +static int hf_ndmp_butype_attr_backup_incremental = -1; +static int hf_ndmp_butype_attr_recover_incremental = -1; +static int hf_ndmp_butype_attr_backup_utf8 = -1; +static int hf_ndmp_butype_attr_recover_utf8 = -1; +static int hf_ndmp_butype_env_name = -1; +static int hf_ndmp_butype_env_value = -1; +static int hf_ndmp_fs_info = -1; +static int hf_ndmp_fs_invalid_total_size = -1; +static int hf_ndmp_fs_invalid_used_size = -1; +static int hf_ndmp_fs_invalid_avail_size = -1; +static int hf_ndmp_fs_invalid_total_inodes = -1; +static int hf_ndmp_fs_invalid_used_inodes = -1; +static int hf_ndmp_fs_fs_type = -1; +static int hf_ndmp_fs_logical_device = -1; +static int hf_ndmp_fs_physical_device = -1; +static int hf_ndmp_fs_total_size = -1; +static int hf_ndmp_fs_used_size = -1; +static int hf_ndmp_fs_avail_size = -1; +static int hf_ndmp_fs_total_inodes = -1; +static int hf_ndmp_fs_used_inodes = -1; +static int hf_ndmp_fs_env = -1; +static int hf_ndmp_fs_env_name = -1; +static int hf_ndmp_fs_env_value = -1; +static int hf_ndmp_fs_status = -1; +static int hf_ndmp_tape_info = -1; +static int hf_ndmp_tape_model = -1; +static int hf_ndmp_tape_dev_cap = -1; +static int hf_ndmp_tape_device = -1; +static int hf_ndmp_tape_open_mode = -1; +static int hf_ndmp_tape_attr_rewind = -1; +static int hf_ndmp_tape_attr_unload = -1; +static int hf_ndmp_tape_capability = -1; +static int hf_ndmp_tape_capability_name = -1; +static int hf_ndmp_tape_capability_value = -1; +static int hf_ndmp_scsi_info = -1; +static int hf_ndmp_scsi_model = -1; +static int hf_ndmp_server_vendor = -1; +static int hf_ndmp_server_product = -1; +static int hf_ndmp_server_revision = -1; +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; +static int hf_ndmp_tape_invalid_block_no = -1; +static int hf_ndmp_tape_invalid_total_space = -1; +static int hf_ndmp_tape_invalid_space_remain = -1; +static int hf_ndmp_tape_invalid_partition = -1; +static int hf_ndmp_tape_flags_no_rewind = -1; +static int hf_ndmp_tape_flags_write_protect = -1; +static int hf_ndmp_tape_flags_error = -1; +static int hf_ndmp_tape_flags_unload = -1; +static int hf_ndmp_tape_file_num = -1; +static int hf_ndmp_tape_soft_errors = -1; +static int hf_ndmp_tape_block_size = -1; +static int hf_ndmp_tape_block_no = -1; +static int hf_ndmp_tape_total_space = -1; +static int hf_ndmp_tape_space_remain = -1; +static int hf_ndmp_tape_partition = -1; +static int hf_ndmp_tape_mtio_op = -1; +static int hf_ndmp_count = -1; +static int hf_ndmp_resid_count = -1; +static int hf_ndmp_mover_state = -1; +static int hf_ndmp_mover_pause = -1; +static int hf_ndmp_halt = -1; +static int hf_ndmp_halt_reason = -1; +static int hf_ndmp_record_size = -1; +static int hf_ndmp_record_num = -1; +static int hf_ndmp_data_written = -1; +static int hf_ndmp_seek_position = -1; +static int hf_ndmp_bytes_left_to_read = -1; +static int hf_ndmp_window_offset = -1; +static int hf_ndmp_window_length = -1; +static int hf_ndmp_addr_ip = -1; +static int hf_ndmp_addr_tcp = -1; +static int hf_ndmp_addr_fcal_loop_id = -1; +static int hf_ndmp_addr_ipc = -1; +static int hf_ndmp_mover_mode = -1; +static int hf_ndmp_file_name = -1; +static int hf_ndmp_nt_file_name = -1; +static int hf_ndmp_dos_file_name = -1; +static int hf_ndmp_log_type = -1; +static int hf_ndmp_log_message_id = -1; +static int hf_ndmp_log_message = -1; +static int hf_ndmp_connected = -1; +static int hf_ndmp_connected_reason = -1; +static int hf_ndmp_data = -1; +static int hf_ndmp_files = -1; +static int hf_ndmp_file_fs_type = -1; +static int hf_ndmp_file_names = -1; +static int hf_ndmp_file_stats = -1; +static int hf_ndmp_file_node = -1; +static int hf_ndmp_file_parent = -1; +static int hf_ndmp_file_fh_info = -1; +static int hf_ndmp_file_invalid_atime = -1; +static int hf_ndmp_file_invalid_ctime = -1; +static int hf_ndmp_file_invalid_group = -1; +static int hf_ndmp_file_type = -1; +static int hf_ndmp_file_mtime = -1; +static int hf_ndmp_file_atime = -1; +static int hf_ndmp_file_ctime = -1; +static int hf_ndmp_file_owner = -1; +static int hf_ndmp_file_group = -1; +static int hf_ndmp_file_fattr = -1; +static int hf_ndmp_file_size = -1; +static int hf_ndmp_file_links = -1; +static int hf_ndmp_dirs = -1; +static int hf_ndmp_nodes = -1; +static int hf_ndmp_nlist = -1; +static int hf_ndmp_bu_original_path = -1; +static int hf_ndmp_bu_destination_dir = -1; +static int hf_ndmp_bu_new_name = -1; +static int hf_ndmp_bu_other_name = -1; +static int hf_ndmp_state_invalid_ebr = -1; +static int hf_ndmp_state_invalid_etr = -1; +static int hf_ndmp_bu_operation = -1; +static int hf_ndmp_data_state = -1; +static int hf_ndmp_data_halted = -1; +static int hf_ndmp_data_bytes_processed = -1; +static int hf_ndmp_data_est_bytes_remain = -1; +static int hf_ndmp_data_est_time_remain = -1; static gint ett_ndmp = -1; 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; +static gint ett_ndmp_file = -1; +static gint ett_ndmp_file_name = -1; +static gint ett_ndmp_file_stats = -1; +static gint ett_ndmp_file_invalids = -1; +static gint ett_ndmp_state_invalids = -1; + + +/* XXX someone should start adding the new stuff from v3, v4 and v5*/ +#define NDMP_PROTOCOL_V2 1 +#define NDMP_PROTOCOL_V3 2 +#define NDMP_PROTOCOL_V4 3 +#define NDMP_PROTOCOL_V5 4 + +static enum_val_t ndmp_protocol_versions[] = { + { "version2", "Version 2", NDMP_PROTOCOL_V2 }, + { "version3", "Version 3", NDMP_PROTOCOL_V3 }, + { "version4", "Version 4", NDMP_PROTOCOL_V4 }, + { "version5", "Version 5", NDMP_PROTOCOL_V5 }, + { NULL, NULL, 0 } +}; + +static gint ndmp_protocol_version = NDMP_PROTOCOL_V2; + + +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 @@ -241,9 +439,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); @@ -253,263 +451,3036 @@ 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, + proto_tree *tree, guint32 seq _U_) { + guint32 err; + /* error */ + err=tvb_get_ntohl(tvb, offset); proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE); + if(err && check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, + " NDMP Error:%s", + val_to_str(err, error_vals, + "Unknown NDMP error code %#x")); + } + offset += 4; return offset; } +static int +dissect_ndmp_get_host_info_reply(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* hostname */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_hostname, offset, NULL); -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); -} ndmp_command; + /* os type */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_os_type, offset, NULL); -static const ndmp_command ndmp_commands[] = { - {NDMP_CONFIG_GET_HOST_INFO, NULL,NULL}, - {NDMP_CONFIG_GET_CONNECTION_TYPE, NULL,NULL}, - {NDMP_CONFIG_GET_AUTH_ATTR, NULL,NULL}, - {NDMP_CONFIG_GET_BUTYPE_INFO, NULL,NULL}, - {NDMP_CONFIG_GET_FS_INFO, NULL,NULL}, - {NDMP_CONFIG_GET_TAPE_INFO, NULL,NULL}, - {NDMP_CONFIG_GET_SCSI_INFO, NULL,NULL}, - {NDMP_CONFIG_GET_SERVER_INFO, NULL,NULL}, - {NDMP_SCSI_OPEN, NULL,NULL}, - {NDMP_SCSI_CLOSE, NULL,NULL}, - {NDMP_SCSI_GET_STATE, NULL,NULL}, - {NDMP_SCSI_SET_TARGET, NULL,NULL}, - {NDMP_SCSI_RESET_DEVICE, NULL,NULL}, - {NDMP_SCSI_RESET_BUS, NULL,NULL}, - {NDMP_SCSI_EXECUTE_CDB, NULL,NULL}, - {NDMP_TAPE_OPEN, NULL,NULL}, - {NDMP_TAPE_CLOSE, NULL,NULL}, - {NDMP_TAPE_GET_STATE, NULL,NULL}, - {NDMP_TAPE_MTIO, NULL,NULL}, - {NDMP_TAPE_WRITE, NULL,NULL}, - {NDMP_TAPE_READ, NULL,NULL}, - {NDMP_TAPE_EXECUTE_CDB, NULL,NULL}, - {NDMP_DATA_GET_STATE, NULL,NULL}, - {NDMP_DATA_START_BACKUP, NULL,NULL}, - {NDMP_DATA_START_RECOVER, NULL,NULL}, - {NDMP_DATA_ABORT, NULL,NULL}, - {NDMP_DATA_GET_ENV, NULL,NULL}, - {NDMP_DATA_STOP, NULL,NULL}, - {NDMP_DATA_LISTEN, NULL,NULL}, - {NDMP_DATA_CONNECT, NULL,NULL}, - {NDMP_NOTIFY_DATA_HALTED, NULL,NULL}, - {NDMP_NOTIFY_CONNECTED, NULL,NULL}, - {NDMP_NOTIFY_MOVER_HALTED, NULL,NULL}, - {NDMP_NOTIFY_MOVER_PAUSED, NULL,NULL}, - {NDMP_NOTIFY_DATA_READ, NULL,NULL}, - {NDMP_LOG_FILE, NULL,NULL}, - {NDMP_LOG_MESSAGE, NULL,NULL}, - {NDMP_FH_ADD_FILE, NULL,NULL}, - {NDMP_FH_ADD_DIR, NULL,NULL}, - {NDMP_FH_ADD_NODE, NULL,NULL}, - {NDMP_CONNECT_OPEN, dissect_connect_open_request, dissect_error}, - {NDMP_CONNECT_CLIENT_AUTH, NULL,NULL}, - {NDMP_CONNECT_CLOSE, NULL,NULL}, - {NDMP_CONNECT_SERVER_AUTH, NULL,NULL}, - {NDMP_MOVER_GET_STATE, NULL,NULL}, - {NDMP_MOVER_LISTEN, NULL,NULL}, - {NDMP_MOVER_CONTINUE, NULL,NULL}, - {NDMP_MOVER_ABORT, NULL,NULL}, - {NDMP_MOVER_STOP, NULL,NULL}, - {NDMP_MOVER_SET_WINDOW, NULL,NULL}, - {NDMP_MOVER_READ, NULL,NULL}, - {NDMP_MOVER_CLOSE, NULL,NULL}, - {NDMP_MOVER_SET_RECORD_SIZE, NULL,NULL}, - {NDMP_MOVER_CONNECT, NULL,NULL}, - {0, NULL,NULL} + /* os version */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_os_vers, offset, NULL); + + /* hostid */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_hostid, offset, NULL); + + return offset; +} + +#define NDMP_ADDR_LOCAL 0 +#define NDMP_ADDR_TCP 1 +#define NDMP_ADDR_FC 2 +#define NDMP_ADDR_IPC 3 +static const value_string addr_type_vals[] = { + {NDMP_ADDR_LOCAL, "Local"}, + {NDMP_ADDR_TCP, "TCP"}, + {NDMP_ADDR_FC, "FC"}, + {NDMP_ADDR_IPC, "IPC"}, + {0,NULL} +}; + +static int +dissect_ndmp_addr_type(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree) +{ + proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, FALSE); + offset += 4; + + return offset; +} + +static int +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) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* addr types */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_ndmp_addr_type, hf_ndmp_addr_types); + + return offset; +} + +#define NDMP_AUTH_NONE 0 +#define NDMP_AUTH_TEXT 1 +#define NDMP_AUTH_MD5 2 +static const value_string auth_type_vals[] = { + {NDMP_AUTH_NONE, "None"}, + {NDMP_AUTH_TEXT, "Text"}, + {NDMP_AUTH_MD5, "MD5"}, + {0,NULL} }; +static int +dissect_auth_type(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree) +{ + proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, FALSE); + offset += 4; + + return offset; +} + +static int +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; + + type=tvb_get_ntohl(tvb,offset); + + /* auth type */ + proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, FALSE); + offset += 4; + switch(type){ + case NDMP_AUTH_NONE: + break; + case NDMP_AUTH_TEXT: + break; + case NDMP_AUTH_MD5: + proto_tree_add_item(tree, hf_ndmp_auth_challenge, + tvb, offset, 64, FALSE); + offset+=64; + } + + return offset; +} + +static int +dissect_default_env(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree) +{ + /* name */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_butype_env_name, offset, NULL); + + /* value */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_butype_env_value, offset, NULL); + return offset; +} + + +static const true_false_string tfs_butype_attr_backup_file_history = { + "Backup FILE HISTORY", + "Do NOT backup file history" +}; +static const true_false_string tfs_butype_attr_backup_filelist = { + "Backup FILELIST", + "Do NOT backup filelist" +}; +static const true_false_string tfs_butype_attr_recover_filelist = { + "Recover FILELIST", + "Do NOT recover filelist" +}; +static const true_false_string tfs_butype_attr_backup_direct = { + "Perform DIRECT backup", + "Do NOT perform direct backup" +}; +static const true_false_string tfs_butype_attr_recover_direct = { + "Perform DIRECT recovery", + "Do NOT perform direct recovery" +}; +static const true_false_string tfs_butype_attr_backup_incremental = { + "Perform INCREMENTAL backup", + "Perform FULL backup" +}; +static const true_false_string tfs_butype_attr_recover_incremental = { + "Perform INCREMENTAL revocery", + "Perform FULL recovery" +}; +static const true_false_string tfs_butype_attr_backup_utf8 = { + "Backup using UTF8", + "Normal backup. Do NOT use utf8" +}; +static const true_false_string tfs_butype_attr_recover_utf8 = { + "Recover using UTF8", + "Normal recover. Do NOT use utf8" +}; static int -dissect_ndmp_header(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; - guint32 msgtype, msg; + guint32 flags; + flags=tvb_get_ntohl(tvb, offset); if (parent_tree) { - item = proto_tree_add_item(tree, hf_ndmp_header, tvb, - offset, 24, FALSE); - tree = proto_item_add_subtree(item, ett_ndmp_header); + item = proto_tree_add_text(parent_tree, tvb, offset, 4, + "Attributes: 0x%08x", flags); + tree = proto_item_add_subtree(item, ett_ndmp_butype_attrs); } - /* sequence number */ - proto_tree_add_item(tree, hf_ndmp_sequence, tvb, offset, 4, FALSE); - offset += 4; + proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_utf8, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_utf8, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_incremental, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_incremental, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_direct, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_direct, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_filelist, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_filelist, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_file_history, + tvb, offset, 4, flags); - /* timestamp */ - proto_tree_add_item(tree, hf_ndmp_timestamp, tvb, offset, 4, FALSE); offset += 4; + return offset; +} - /* Message Type */ - msgtype = tvb_get_ntohl(tvb, offset); - proto_tree_add_item(tree, hf_ndmp_msgtype, tvb, offset, 4, FALSE); - offset += 4; +static int +dissect_butype_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) +{ + /*butype name*/ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_butype_name, offset, NULL); - /* Message */ - msg = tvb_get_ntohl(tvb, offset); - proto_tree_add_item(tree, hf_ndmp_msg, tvb, offset, 4, FALSE); - offset += 4; + /* default env */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_default_env, hf_ndmp_butype_default_env); - /* Reply sequence number */ - proto_tree_add_item(tree, hf_ndmp_reply_sequence, tvb, offset, 4, FALSE); - offset += 4; + /* attrs */ + offset = dissect_butype_attrs(tvb, offset, pinfo, tree); + return offset; +} + +static int +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); - offset += 4; + offset=dissect_error(tvb, offset, pinfo, tree, seq); - 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)") - ); + /* butype */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_butype_info, hf_ndmp_butype_info); + + return offset; +} + +static const true_false_string tfs_fs_invalid_total_size = { + "Total size is INVALID", + "Total size is VALID" +}; +static const true_false_string tfs_fs_invalid_used_size = { + "Used size is INVALID", + "Used size is VALID" +}; +static const true_false_string tfs_fs_invalid_avail_size = { + "Available size is INVALID", + "Available size is VALID" +}; +static const true_false_string tfs_fs_invalid_total_inodes = { + "Total inode count is INVALID", + "Total inode count is VALID" +}; +static const true_false_string tfs_fs_invalid_used_inodes = { + "Used inode count is INVALID", + "Used inode count is VALID" +}; +static int +dissect_fs_invalid(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, + "Invalids: 0x%08x", flags); + tree = proto_item_add_subtree(item, ett_ndmp_fs_invalid); } + proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_used_inodes, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_total_inodes, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_avail_size, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_used_size, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_total_size, + tvb, offset, 4, flags); + + offset+=4; + return offset; +} + +static int +dissect_fs_env(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree) +{ + /* name */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_fs_env_name, offset, NULL); + + /* value */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_fs_env_value, offset, NULL); + return offset; } +static int +dissect_fs_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) +{ + /* invalid bits */ + offset=dissect_fs_invalid(tvb, offset, pinfo, tree); + + /* fs type */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_fs_fs_type, offset, NULL); + + /* fs logical device */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_fs_logical_device, offset, NULL); + + /* fs physical device */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_fs_physical_device, offset, NULL); + + /*total_size*/ + offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_total_size, + offset); + + /*used_size*/ + offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_used_size, + offset); + + /*avail_size*/ + offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_avail_size, + offset); + + /*total_inodes*/ + offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_total_inodes, + offset); + + /*used_inodes*/ + offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_used_inodes, + offset); + + /* env */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_fs_env, hf_ndmp_fs_env); + + /* status */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_fs_status, offset, NULL); + + return offset; +} static int -dissect_ndmp_cmd(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) { - int i; - guint32 msg, msgtype; + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); - msg=tvb_get_ntohl(tvb, offset+12); - msgtype=tvb_get_ntohl(tvb, offset+8); + /* fs */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_fs_info, hf_ndmp_fs_info); - offset=dissect_ndmp_header(tvb, offset, pinfo, tree); + return offset; +} +static const true_false_string tfs_tape_attr_rewind = { + "Device supports REWIND", + "Device does NOT support rewind" +}; +static const true_false_string tfs_tape_attr_unload = { + "Device supports UNLOAD", + "Device does NOT support unload" +}; +static int +dissect_tape_attr(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *parent_tree) +{ + proto_item* item = NULL; + proto_tree* tree = NULL; + guint32 flags; - for(i=0;ndmp_commands[i].cmd!=0;i++){ - if(ndmp_commands[i].cmd==msg){ - break; - } + flags=tvb_get_ntohl(tvb, offset); + if (parent_tree) { + item = proto_tree_add_text(parent_tree, tvb, offset, 4, + "Attributes: 0x%08x", flags); + tree = proto_item_add_subtree(item, ett_ndmp_tape_attr); } + proto_tree_add_boolean(tree, hf_ndmp_tape_attr_unload, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_tape_attr_rewind, + tvb, offset, 4, flags); - 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); - offset+=tvb_length_remaining(tvb, offset); - return offset; - } + offset+=4; + return offset; +} +static int +dissect_tape_capability(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree) +{ + /* name */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_tape_capability_name, offset, NULL); - if(msgtype==NDMP_MESSAGE_REQUEST){ - offset=ndmp_commands[i].request(tvb, offset, pinfo, tree); - } else { - offset=ndmp_commands[i].response(tvb, offset, pinfo, tree); - } + /* value */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_tape_capability_value, offset, NULL); return offset; } -static void -dissect_ndmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +static int +dissect_tape_dev_cap(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { - 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; - } - } + /* device */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_tape_device, offset, NULL); - /* the size of the current PDU */ - proto_tree_add_item(tree, hf_ndmp_size, tvb, offset, 4, size); - offset += 4; + /* tape attributes */ + offset = dissect_tape_attr(tvb, offset, pinfo, tree); - offset = dissect_ndmp_cmd(tvb, offset, pinfo, tree); - } while(offset<(int)tvb_reported_length(tvb)); + /* capability */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_tape_capability, hf_ndmp_tape_capability); + return offset; } +static int +dissect_tape_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) +{ + /* model */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_tape_model, offset, NULL); + /* device capabilites */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_tape_dev_cap, hf_ndmp_tape_dev_cap); + return offset; +} -void -proto_register_ndmp(void) +static int +dissect_get_tape_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 seq) { + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); - static hf_register_info hf_ndmp[] = { - { &hf_ndmp_size, { - "Size", "ndmp.size", FT_UINT32, BASE_DEC, - NULL, 0, "Size of this NDMP PDU", HFILL }}, + /* tape */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_tape_info, hf_ndmp_tape_info); - { &hf_ndmp_header, { - "NDMP Header", "ndmp.header", FT_NONE, 0, - NULL, 0, "NDMP Header", HFILL }}, + return offset; +} - { &hf_ndmp_sequence, { - "Sequence", "ndmp.sequence", FT_UINT32, BASE_DEC, - NULL, 0, "Sequence number for NDMP PDU", HFILL }}, +static int +dissect_scsi_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) +{ + /* model */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_scsi_model, offset, NULL); - { &hf_ndmp_reply_sequence, { - "Reply Sequence", "ndmp.reply_sequence", FT_UINT32, BASE_DEC, - NULL, 0, "Reply Sequence number for NDMP PDU", HFILL }}, + /* device capabilites */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_tape_dev_cap, hf_ndmp_tape_dev_cap); - { &hf_ndmp_timestamp, { - "Time", "ndmp.timestamp", FT_ABSOLUTE_TIME, BASE_NONE, - NULL, 0, "Timestamp for this NDMP PDU", HFILL }}, + return offset; +} - { &hf_ndmp_msgtype, { - "Type", "ndmp.msg_type", FT_UINT32, BASE_DEC, - VALS(msg_type_vals), 0, "Is this a Request or Response?", HFILL }}, +static int +dissect_get_scsi_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); - { &hf_ndmp_msg, { - "Message", "ndmp.msg", FT_UINT32, BASE_DEC, - VALS(msg_vals), 0, "Type of NDMP PDU", HFILL }}, + /* scsi */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_scsi_info, hf_ndmp_scsi_info); - { &hf_ndmp_error, { - "Error", "ndmp.error", FT_UINT32, BASE_DEC, - VALS(error_vals), 0, "Error code for this NDMP PDU", HFILL }}, + return offset; +} - { &hf_ndmp_version, { - "Version", "ndmp.version", FT_UINT32, BASE_DEC, - NULL, 0, "Version of NDMP protocol", HFILL }}, +static int +dissect_get_server_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + /* vendor */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_server_vendor, offset, NULL); - }; + /* product */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_server_product, offset, NULL); - static gint *ett[] = { - &ett_ndmp, - &ett_ndmp_header, - }; + /* revision */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_server_revision, offset, NULL); - module_t *ndmp_module; - proto_ndmp = proto_register_protocol("Network Data Management Protocol", "NDMP", "ndmp"); - proto_register_field_array(proto_ndmp, hf_ndmp, array_length(hf_ndmp)); - - proto_register_subtree_array(ett, array_length(ett)); + /* server */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_auth_type, hf_ndmp_auth_types); - /* 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); + return offset; +} + +static int +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, 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, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + /* controller */ + proto_tree_add_item(tree, hf_ndmp_scsi_controller, tvb, offset, 4, FALSE); + offset += 4; + + /* id */ + proto_tree_add_item(tree, hf_ndmp_scsi_id, tvb, offset, 4, FALSE); + offset += 4; + + /* lun */ + proto_tree_add_item(tree, hf_ndmp_scsi_lun, tvb, offset, 4, FALSE); + offset += 4; + + return offset; +} + +static int +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, tree, + hf_ndmp_scsi_device, offset, NULL); + + /* controller */ + proto_tree_add_item(tree, hf_ndmp_scsi_controller, tvb, offset, 4, FALSE); + offset += 4; + + /* id */ + proto_tree_add_item(tree, hf_ndmp_scsi_id, tvb, offset, 4, FALSE); + offset += 4; + + /* lun */ + proto_tree_add_item(tree, hf_ndmp_scsi_lun, tvb, offset, 4, FALSE); + offset += 4; + + 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 */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* 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[] = { + {NDMP_TAPE_OPEN_MODE_READ, "Read"}, + {NDMP_TAPE_OPEN_MODE_RDWR, "Read/Write"}, + {0, NULL} +}; + +static int +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, tree, + hf_ndmp_tape_device, offset, NULL); + + /* open mode */ + proto_tree_add_item(tree, hf_ndmp_tape_open_mode, tvb, offset, 4, FALSE); + offset += 4; + + return offset; +} + + +static const true_false_string tfs_ndmp_tape_invalid_file_num = { + "File num is valid", + "File num is INVALID" +}; +static const true_false_string tfs_ndmp_tape_invalid_soft_errors = { + "Soft errors is valid", + "Soft errors is INVALID" +}; +static const true_false_string tfs_ndmp_tape_invalid_block_size = { + "Block size is valid", + "Block size is INVALID" +}; +static const true_false_string tfs_ndmp_tape_invalid_block_no = { + "Block no is valid", + "Block no is INVALID" +}; +static const true_false_string tfs_ndmp_tape_invalid_total_space = { + "Total space is valid", + "Total space is INVALID" +}; +static const true_false_string tfs_ndmp_tape_invalid_space_remain = { + "Space remaining is INVALID", + "Space remaining is valid" +}; +static const true_false_string tfs_ndmp_tape_invalid_partition = { + "Partition is INVALID", + "Partition is valid" +}; +static int +dissect_tape_invalid(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, + "Invalids: 0x%08x", flags); + tree = proto_item_add_subtree(item, ett_ndmp_tape_invalid); + } + + proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_partition, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_space_remain, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_total_space, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_block_no, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_block_size, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_soft_errors, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_file_num, + tvb, offset, 4, flags); + + offset+=4; + return offset; +} + +static const true_false_string tfs_ndmp_tape_flags_no_rewind = { + "This is a NON-REWINDING device", + "This device supports rewind" +}; +static const true_false_string tfs_ndmp_tape_flags_write_protect = { + "This device is WRITE-PROTECTED", + "This device is NOT write-protected" +}; +static const true_false_string tfs_ndmp_tape_flags_error = { + "This device shows ERROR", + "This device shows NO errors" +}; +static const true_false_string tfs_ndmp_tape_flags_unload = { + "This device supports UNLOAD", + "This device does NOT support unload" +}; +static int +dissect_tape_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_tape_flags); + } + + + proto_tree_add_boolean(tree, hf_ndmp_tape_flags_unload, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_tape_flags_error, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_tape_flags_write_protect, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_tape_flags_no_rewind, + tvb, offset, 4, flags); + + offset+=4; + return offset; +} + +static int +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); + + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* flags */ + offset=dissect_tape_flags(tvb, offset, pinfo, tree); + + /* file_num */ + proto_tree_add_item(tree, hf_ndmp_tape_file_num, tvb, offset, 4, FALSE); + offset += 4; + + /* soft_errors */ + proto_tree_add_item(tree, hf_ndmp_tape_soft_errors, tvb, offset, 4, FALSE); + offset += 4; + + /* block_size */ + proto_tree_add_item(tree, hf_ndmp_tape_block_size, tvb, offset, 4, FALSE); + offset += 4; + + /* block_no */ + proto_tree_add_item(tree, hf_ndmp_tape_block_no, tvb, offset, 4, FALSE); + offset += 4; + + /* total_space */ + offset = dissect_rpc_uint64(tvb, tree,hf_ndmp_tape_total_space, + offset); + + /* space_remain */ + offset = dissect_rpc_uint64(tvb, tree,hf_ndmp_tape_space_remain, + offset); + + /* partition */ + proto_tree_add_item(tree, hf_ndmp_tape_partition, tvb, offset, 4, FALSE); + offset += 4; + + return offset; +} + +#define NDMP_TAPE_MTIO_FSF 0 +#define NDMP_TAPE_MTIO_BSF 1 +#define NDMP_TAPE_MTIO_FSR 2 +#define NDMP_TAPE_MTIO_BSR 3 +#define NDMP_TAPE_MTIO_REW 4 +#define NDMP_TAPE_MTIO_EOF 5 +#define NDMP_TAPE_MTIO_OFF 6 +static const value_string tape_mtio_vals[] = { + {NDMP_TAPE_MTIO_FSF, "FSF"}, + {NDMP_TAPE_MTIO_BSF, "BSF"}, + {NDMP_TAPE_MTIO_FSR, "FSR"}, + {NDMP_TAPE_MTIO_BSR, "BSR"}, + {NDMP_TAPE_MTIO_REW, "REW"}, + {NDMP_TAPE_MTIO_EOF, "EOF"}, + {NDMP_TAPE_MTIO_OFF, "OFF"}, + {0, NULL} +}; + +static int +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); + offset += 4; + + /* count */ + proto_tree_add_item(tree, hf_ndmp_count, tvb, offset, 4, FALSE); + offset += 4; + + return offset; +} + +static int +dissect_tape_mtio_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* resid count */ + proto_tree_add_item(tree, hf_ndmp_resid_count, tvb, offset, 4, FALSE); + offset += 4; + + return offset; +} + +#define NDMP_MOVER_STATE_IDLE 0 +#define NDMP_MOVER_STATE_LISTEN 1 +#define NDMP_MOVER_STATE_ACTIVE 2 +#define NDMP_MOVER_STATE_PAUSED 3 +#define NDMP_MOVER_STATE_HALTED 4 +static const value_string mover_state_vals[] = { + {NDMP_MOVER_STATE_IDLE, "MOVER_STATE_IDLE"}, + {NDMP_MOVER_STATE_LISTEN, "MOVER_STATE_LISTEN"}, + {NDMP_MOVER_STATE_ACTIVE, "MOVER_STATE_ACTIVE"}, + {NDMP_MOVER_STATE_PAUSED, "MOVER_STATE_PAUSED"}, + {NDMP_MOVER_STATE_HALTED, "MOVER_STATE_HALTED"}, + {0, NULL} +}; + +#define NDMP_MOVER_PAUSE_NA 0 +#define NDMP_MOVER_PAUSE_EOM 1 +#define NDMP_MOVER_PAUSE_EOF 2 +#define NDMP_MOVER_PAUSE_SEEK 3 +#define NDMP_MOVER_PAUSE_MEDIA_ERROR 4 +#define NDMP_MOVER_PAUSE_EOW 5 +static const value_string mover_pause_vals[] = { + {NDMP_MOVER_PAUSE_NA, "MOVER_PAUSE_NA"}, + {NDMP_MOVER_PAUSE_EOM, "MOVER_PAUSE_EOM"}, + {NDMP_MOVER_PAUSE_EOF, "MOVER_PAUSE_EOF"}, + {NDMP_MOVER_PAUSE_SEEK, "MOVER_PAUSE_SEEK"}, + {NDMP_MOVER_PAUSE_MEDIA_ERROR, "MOVER_PAUSE_MEDIA_ERROR"}, + {NDMP_MOVER_PAUSE_EOW, "MOVER_PAUSE_EOW"}, + {0, NULL} +}; + +#define NDMP_HALT_NA 0 +#define NDMP_HALT_CONNECT_CLOSE 1 +#define NDMP_HALT_ABORTED 2 +#define NDMP_HALT_INTERNAL_ERROR 3 +#define NDMP_HALT_CONNECT_ERROR 4 +static const value_string halt_vals[] = { + {NDMP_HALT_NA, "HALT_NA"}, + {NDMP_HALT_CONNECT_CLOSE, "HALT_CONNECT_CLOSE"}, + {NDMP_HALT_ABORTED, "HALT_ABORTED"}, + {NDMP_HALT_INTERNAL_ERROR, "HALT_INTERNAL_ERROR"}, + {NDMP_HALT_CONNECT_ERROR, "HALT_CONNECT_ERROR"}, + {0, NULL} +}; + +static int +dissect_ndmp_addr(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *parent_tree) +{ + proto_item* item = NULL; + proto_tree* tree = NULL; + guint32 type; + + type=tvb_get_ntohl(tvb, offset); + if (parent_tree) { + item = proto_tree_add_text(parent_tree, tvb, offset, 4, + "Type: %s ", val_to_str(type, addr_type_vals,"Unknown addr type (0x%02x)") ); + tree = proto_item_add_subtree(item, ett_ndmp_addr); + } + + /*address type*/ + proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, FALSE); + offset += 4; + + + switch(type){ + case NDMP_ADDR_LOCAL: + break; + case NDMP_ADDR_TCP: + /* IP addr */ + proto_tree_add_item(tree, hf_ndmp_addr_ip, tvb, offset, 4, FALSE); + offset+=4; + + /* TCP port */ + proto_tree_add_item(tree, hf_ndmp_addr_tcp, tvb, offset, 4, FALSE); + offset+=4; + + break; + case NDMP_ADDR_FC: + /* FCAL loop id */ + proto_tree_add_item(tree, hf_ndmp_addr_fcal_loop_id, tvb, offset, 4, FALSE); + offset+=4; + + break; + case NDMP_ADDR_IPC: + /* IPC address */ + offset = dissect_rpc_data(tvb, tree, hf_ndmp_addr_ipc, offset); + break; + } + + return offset; +} + +static int +dissect_mover_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* mover state */ + proto_tree_add_item(tree, hf_ndmp_mover_state, tvb, offset, 4, FALSE); + offset += 4; + + /* mover pause */ + proto_tree_add_item(tree, hf_ndmp_mover_pause, tvb, offset, 4, FALSE); + offset += 4; + + /* halt */ + proto_tree_add_item(tree, hf_ndmp_halt, tvb, offset, 4, FALSE); + offset += 4; + + /* record size */ + proto_tree_add_item(tree, hf_ndmp_record_size, tvb, offset, 4, FALSE); + offset += 4; + + /* record num */ + proto_tree_add_item(tree, hf_ndmp_record_num, tvb, offset, 4, FALSE); + offset += 4; + + /* data written */ + proto_tree_add_item(tree, hf_ndmp_data_written, tvb, offset, 8, FALSE); + offset += 8; + + /* seek position */ + proto_tree_add_item(tree, hf_ndmp_seek_position, tvb, offset, 8, FALSE); + offset += 8; + + /* bytes left to read */ + proto_tree_add_item(tree, hf_ndmp_bytes_left_to_read, tvb, offset, 8, FALSE); + offset += 8; + + /* window offset */ + proto_tree_add_item(tree, hf_ndmp_window_offset, tvb, offset, 8, FALSE); + offset += 8; + + /* window length */ + proto_tree_add_item(tree, hf_ndmp_window_length, tvb, offset, 8, FALSE); + offset += 8; + + /* this is where v2 ends */ + if(ndmp_protocol_version==NDMP_PROTOCOL_V2){ + return offset; + } + + + /* ndmp addr */ + offset=dissect_ndmp_addr(tvb, offset, pinfo, tree); + + return offset; +} + +#define NDMP_MOVER_MODE_READ 0 +#define NDMP_MOVER_MODE_WRITE 1 +static const value_string mover_mode_vals[] = { + {NDMP_MOVER_MODE_READ, "MODE_READ"}, + {NDMP_MOVER_MODE_WRITE, "MOVER_MODE_WRITE"}, + {0, NULL} +}; + +static int +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); + offset += 4; + + /*address type*/ + proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, FALSE); + offset += 4; + + return offset; +} + +static int +dissect_mover_listen_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* ndmp addr */ + offset=dissect_ndmp_addr(tvb, offset, pinfo, tree); + + return offset; +} + +static int +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); + offset += 8; + + /* window length */ + proto_tree_add_item(tree, hf_ndmp_window_length, tvb, offset, 8, FALSE); + offset += 8; + + return offset; +} + +static int +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); + offset += 4; + + return offset; +} + +static int +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); + offset += 4; + + /* ndmp addr */ + offset=dissect_ndmp_addr(tvb, offset, pinfo, tree); + + return offset; +} + +static int +dissect_log_file_request(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 seq) +{ + /* file */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_file_name, offset, NULL); + + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + return offset; +} + +#define NDMP_LOG_TYPE_NORMAL 0 +#define NDMP_LOG_TYPE_DEBUG 1 +#define NDMP_LOG_TYPE_ERROR 2 +#define NDMP_LOG_TYPE_WARNING 3 +static const value_string log_type_vals[] = { + {NDMP_LOG_TYPE_NORMAL, "NORMAL"}, + {NDMP_LOG_TYPE_DEBUG, "DEBUG"}, + {NDMP_LOG_TYPE_ERROR, "ERROR"}, + {NDMP_LOG_TYPE_WARNING, "WARNING"}, + {0, NULL} +}; + +static int +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); + offset += 4; + + /* message id */ + proto_tree_add_item(tree, hf_ndmp_log_message_id, tvb, offset, 4, FALSE); + offset += 4; + + /* message */ + 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 _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, tree, + hf_ndmp_halt_reason, offset, NULL); + + return offset; +} + +#define NDMP_CONNECTED_CONNECTED 0 +#define NDMP_CONNECTED_SHUTDOWN 1 +#define NDMP_CONNECTED_REFUSED 2 +static const value_string connected_vals[] = { + {NDMP_CONNECTED_CONNECTED, "CONNECTED"}, + {NDMP_CONNECTED_SHUTDOWN, "SHUTDOWN"}, + {NDMP_CONNECTED_REFUSED, "REFUSED"}, + {0, NULL} +}; + +static int +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); + offset += 4; + + /* version number */ + proto_tree_add_item(tree, hf_ndmp_version, tvb, offset, 4, FALSE); + offset += 4; + + /* reason */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_connected_reason, offset, NULL); + + return offset; +} + + +static int +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); + offset += 4; + + /* seek position */ + proto_tree_add_item(tree, hf_ndmp_seek_position, tvb, offset, 8, FALSE); + offset += 8; + + return offset; +} + +static int +dissect_auth_data(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree) +{ + guint type; + + type=tvb_get_ntohl(tvb,offset); + + /* auth type */ + proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, FALSE); + offset += 4; + + switch(type){ + case NDMP_AUTH_NONE: + break; + case NDMP_AUTH_TEXT: + /* auth id */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_auth_id, offset, NULL); + + /* auth password */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_auth_password, offset, NULL); + + + break; + case NDMP_AUTH_MD5: + /* auth id */ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_auth_id, offset, NULL); + + /* digest */ + proto_tree_add_item(tree, hf_ndmp_auth_digest, + tvb, offset, 16, FALSE); + offset+=16; + } + + 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, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* auth data */ + offset = dissect_auth_data(tvb, offset, pinfo, tree); + + return offset; +} + +static int +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, tree, hf_ndmp_data, offset); + + return offset; +} + +static int +dissect_tape_write_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* count */ + proto_tree_add_item(tree, hf_ndmp_count, tvb, offset, 4, FALSE); + offset += 4; + + return offset; +} + +static int +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); + offset += 4; + + return offset; +} + +static int +dissect_tape_read_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* data */ + offset = dissect_rpc_data(tvb, tree, hf_ndmp_data, offset); + + return offset; +} + +#define NDMP_FS_UNIX 0 +#define NDMP_FS_NT 1 +#define NDMP_FS_OTHER 2 +static const value_string file_fs_type_vals[] = { + {NDMP_FS_UNIX, "UNIX"}, + {NDMP_FS_NT, "NT"}, + {NDMP_FS_OTHER, "OTHER"}, + {0, NULL} +}; + +static int +dissect_file_name(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree) +{ + proto_item* item = NULL; + proto_tree* tree = NULL; + int old_offset=offset; + guint32 type; + char *name; + + if (parent_tree) { + item = proto_tree_add_text(parent_tree, tvb, offset, -1, + "File"); + tree = proto_item_add_subtree(item, ett_ndmp_file_name); + } + + /* file type */ + type=tvb_get_ntohl(tvb, offset); + proto_tree_add_item(tree, hf_ndmp_file_fs_type, tvb, offset, 4, FALSE); + offset += 4; + + switch(type){ + case NDMP_FS_UNIX: + /* file */ + 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); + } + break; + case NDMP_FS_NT: + /* nt file */ + 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, tree, + hf_ndmp_dos_file_name, offset, NULL); + break; + default: + /* file */ + 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); + } + } + + if (check_col(pinfo->cinfo, COL_INFO)){ + col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", + val_to_str(type, file_fs_type_vals, "Unknown type") ); + } + + proto_item_set_len(item, offset-old_offset); + return offset; +} + + +static const true_false_string tfs_ndmp_file_invalid_atime = { + "Atime is INVALID", + "Atime is valid" +}; +static const true_false_string tfs_ndmp_file_invalid_ctime = { + "Ctime is INVALID", + "Ctime is valid" +}; +static const true_false_string tfs_ndmp_file_invalid_group = { + "Group is INVALID", + "Group is valid" +}; +static int +dissect_file_invalids(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, + "Invalids: 0x%08x", flags); + tree = proto_item_add_subtree(item, ett_ndmp_file_invalids); + } + + proto_tree_add_boolean(tree, hf_ndmp_file_invalid_group, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_file_invalid_ctime, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_file_invalid_atime, + tvb, offset, 4, flags); + + offset+=4; + return offset; +} + +#define NDMP_FILE_TYPE_DIR 0 +#define NDMP_FILE_TYPE_FIFO 1 +#define NDMP_FILE_TYPE_CSPEC 2 +#define NDMP_FILE_TYPE_BSPEC 3 +#define NDMP_FILE_TYPE_REG 4 +#define NDMP_FILE_TYPE_SLINK 5 +#define NDMP_FILE_TYPE_SOCK 6 +#define NDMP_FILE_TYPE_REGISTRY 7 +#define NDMP_FILE_TYPE_OTHER 8 +static const value_string file_type_vals[] = { + {NDMP_FILE_TYPE_DIR, "DIR"}, + {NDMP_FILE_TYPE_FIFO, "FIFO"}, + {NDMP_FILE_TYPE_CSPEC, "CSPEC"}, + {NDMP_FILE_TYPE_BSPEC, "BSPEC"}, + {NDMP_FILE_TYPE_REG, "REG"}, + {NDMP_FILE_TYPE_SLINK, "SLINK"}, + {NDMP_FILE_TYPE_SOCK, "SOCK"}, + {NDMP_FILE_TYPE_REGISTRY, "REGISTRY"}, + {NDMP_FILE_TYPE_OTHER, "OTHER"}, + {0, NULL} +}; + +static int +dissect_file_stats(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree) +{ + 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, -1, + "Stats:"); + tree = proto_item_add_subtree(item, ett_ndmp_file_stats); + } + + /* invalids */ + offset = dissect_file_invalids(tvb, offset, pinfo, tree); + + /* file fs type */ + proto_tree_add_item(tree, hf_ndmp_file_fs_type, tvb, offset, 4, FALSE); + offset += 4; + + /* file type */ + proto_tree_add_item(tree, hf_ndmp_file_type, tvb, offset, 4, FALSE); + offset += 4; + + /* mtime */ + 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 */ + 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 */ + 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 */ + proto_tree_add_item(tree, hf_ndmp_file_owner, tvb, offset, 4, FALSE); + offset += 4; + + /* group */ + proto_tree_add_item(tree, hf_ndmp_file_group, tvb, offset, 4, FALSE); + offset += 4; + + /*XXX here we should do proper dissection of mode for unix or + fattr for nt, call appropriate functions in nfs/smb*/ + /* fattr */ + proto_tree_add_item(tree, hf_ndmp_file_fattr, tvb, offset, 4, FALSE); + offset += 4; + + /*file size*/ + offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_file_size, + offset); + + /* links */ + proto_tree_add_item(tree, hf_ndmp_file_links, tvb, offset, 4, FALSE); + offset += 4; + + proto_item_set_len(item, offset-old_offset); + return offset; +} + + +static int +dissect_file(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree) +{ + proto_item* item = NULL; + proto_tree* tree = NULL; + int old_offset=offset; + + if (parent_tree) { + item = proto_tree_add_text(parent_tree, tvb, offset, -1, + "File:"); + tree = proto_item_add_subtree(item, ett_ndmp_file); + } + + /* file names */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_file_name, hf_ndmp_file_names); + + /* file stats */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_file_stats, hf_ndmp_file_stats); + + /* node */ + proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, FALSE); + offset += 8; + + /* fh_info */ + proto_tree_add_item(tree, hf_ndmp_file_fh_info, tvb, offset, 8, FALSE); + offset += 8; + + proto_item_set_len(item, offset-old_offset); + return offset; +} + +static int +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, + dissect_file, hf_ndmp_files); + + return offset; +} + +static int +dissect_dir(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) +{ + /* file names */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_file_name, hf_ndmp_file_names); + + /* node */ + proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, FALSE); + offset += 8; + + /* parent */ + proto_tree_add_item(tree, hf_ndmp_file_parent, tvb, offset, 8, FALSE); + offset += 8; + + return offset; +} + +static int +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, + dissect_dir, hf_ndmp_dirs); + + return offset; +} + +static int +dissect_node(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) +{ + /* file stats */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_file_stats, hf_ndmp_file_stats); + + /* node */ + proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, FALSE); + offset += 8; + + /* fh_info */ + proto_tree_add_item(tree, hf_ndmp_file_fh_info, tvb, offset, 8, FALSE); + offset += 8; + + return offset; +} + + +static int +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, + dissect_node, hf_ndmp_nodes); + + return offset; +} + +static int +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, tree, + hf_ndmp_butype_name, offset, NULL); + + /* default env */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_default_env, hf_ndmp_butype_default_env); + + return offset; +} + +static int +dissect_nlist(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree) +{ + /*original path*/ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_bu_original_path, offset, NULL); + + /*destination dir*/ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_bu_destination_dir, offset, NULL); + + if(ndmp_protocol_version==NDMP_PROTOCOL_V2){ + /* just 2 reserved bytes (4 with padding) */ + offset += 4; + } else { + /*new name*/ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_bu_new_name, offset, NULL); + + /*other name*/ + offset = dissect_rpc_string(tvb, tree, + hf_ndmp_bu_other_name, offset, NULL); + + /* node */ + proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, FALSE); + offset += 8; + } + + /* fh_info */ + proto_tree_add_item(tree, hf_ndmp_file_fh_info, tvb, offset, 8, FALSE); + offset += 8; + + return offset; +} + + +static int +dissect_data_start_recover_request(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint32 seq _U_) +{ + if(ndmp_protocol_version==NDMP_PROTOCOL_V2){ + /* ndmp addr */ + offset=dissect_ndmp_addr(tvb, offset, pinfo, tree); + } + + /* default env */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_default_env, hf_ndmp_butype_default_env); + + /* nlist */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_nlist, hf_ndmp_nlist); + + /*butype name*/ + 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, guint32 seq) +{ + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* default env */ + offset = dissect_rpc_array(tvb, pinfo, tree, offset, + dissect_default_env, hf_ndmp_butype_default_env); + + return offset; +} + + +static const true_false_string tfs_ndmp_state_invalid_ebr = { + "Estimated Bytes Remaining is INVALID", + "Estimated Bytes Remaining is valid" +}; +static const true_false_string tfs_ndmp_state_invalid_etr = { + "Estimated Time Remaining is INVALID", + "Estimated Time Remaining is valid" +}; +static int +dissect_state_invalids(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, + "Invalids: 0x%08x", flags); + tree = proto_item_add_subtree(item, ett_ndmp_state_invalids); + } + + proto_tree_add_boolean(tree, hf_ndmp_state_invalid_etr, + tvb, offset, 4, flags); + proto_tree_add_boolean(tree, hf_ndmp_state_invalid_ebr, + tvb, offset, 4, flags); + + offset+=4; + return offset; +} + +#define NDMP_DATA_OP_NOACTION 0 +#define NDMP_DATA_OP_BACKUP 1 +#define NDMP_DATA_OP_RESTORE 2 +static const value_string bu_operation_vals[] = { + {NDMP_DATA_OP_NOACTION, "NOACTION"}, + {NDMP_DATA_OP_BACKUP, "BACKUP"}, + {NDMP_DATA_OP_RESTORE, "RESTORE"}, + {0, NULL} +}; + +#define NDMP_DATA_STATE_IDLE 0 +#define NDMP_DATA_STATE_ACTIVE 1 +#define NDMP_DATA_STATE_HALTED 2 +#define NDMP_DATA_STATE_LISTEN 3 +#define NDMP_DATA_STATE_CONNECTED 4 +static const value_string data_state_vals[] = { + {NDMP_DATA_STATE_IDLE, "IDLE"}, + {NDMP_DATA_STATE_ACTIVE, "ACTIVE"}, + {NDMP_DATA_STATE_HALTED, "HALTED"}, + {NDMP_DATA_STATE_LISTEN, "LISTEN"}, + {NDMP_DATA_STATE_CONNECTED, "CONNECTED"}, + {0, NULL} +}; + +#define NDMP_DATA_HALTED_NA 0 +#define NDMP_DATA_HALTED_SUCCESSFUL 1 +#define NDMP_DATA_HALTED_ABORTED 2 +#define NDMP_DATA_HALTED_INTERNAL_ERROR 3 +#define NDMP_DATA_HALTED_CONNECT_ERROR 4 +static const value_string data_halted_vals[] = { + {NDMP_DATA_HALTED_NA, "HALTED_NA"}, + {NDMP_DATA_HALTED_SUCCESSFUL, "HALTED_SUCCESSFUL"}, + {NDMP_DATA_HALTED_ABORTED, "HALTED_ABORTED"}, + {NDMP_DATA_HALTED_INTERNAL_ERROR, "HALTED_INTERNAL_ERROR"}, + {NDMP_DATA_HALTED_CONNECT_ERROR, "HALTED_CONNECT_ERROR"}, + {0, NULL} +}; + +static int +dissect_data_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 seq) +{ + nstime_t ns; + + /* invalids */ + offset = dissect_state_invalids(tvb, offset, pinfo, tree); + + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, seq); + + /* operation */ + proto_tree_add_item(tree, hf_ndmp_bu_operation, tvb, offset, 4, FALSE); + offset += 4; + + /* state */ + proto_tree_add_item(tree, hf_ndmp_data_state, tvb, offset, 4, FALSE); + offset += 4; + + /* halted reason */ + proto_tree_add_item(tree, hf_ndmp_data_halted, tvb, offset, 4, FALSE); + offset += 4; + + /*bytes processed*/ + offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_data_bytes_processed, + offset); + + /*est bytes remain*/ + offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_data_est_bytes_remain, + offset); + + /* est time remain */ + ns.secs=tvb_get_ntohl(tvb, offset); + ns.nsecs=0; + proto_tree_add_time(tree, hf_ndmp_data_est_time_remain, tvb, offset, 4, &ns); + offset += 4; + + /* ndmp addr */ + offset=dissect_ndmp_addr(tvb, offset, pinfo, tree); + + /* window offset */ + proto_tree_add_item(tree, hf_ndmp_window_offset, tvb, offset, 8, FALSE); + offset += 8; + + /* window length */ + proto_tree_add_item(tree, hf_ndmp_window_length, tvb, offset, 8, FALSE); + offset += 8; + + return offset; +} + + +typedef struct _ndmp_command { + guint32 cmd; + 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_HOST_INFO, + NULL, dissect_ndmp_get_host_info_reply}, + {NDMP_CONFIG_GET_CONNECTION_TYPE, + NULL, dissect_ndmp_config_get_connection_type_reply}, + {NDMP_CONFIG_GET_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, + NULL, dissect_get_fs_info_reply}, + {NDMP_CONFIG_GET_TAPE_INFO, + NULL, dissect_get_tape_info_reply}, + {NDMP_CONFIG_GET_SCSI_INFO, + NULL, dissect_get_scsi_info_reply}, + {NDMP_CONFIG_GET_SERVER_INFO, + NULL, dissect_get_server_info_reply}, + {NDMP_SCSI_OPEN, + dissect_scsi_open_request, dissect_error}, + {NDMP_SCSI_CLOSE, + NULL, dissect_error}, + {NDMP_SCSI_GET_STATE, + NULL, dissect_scsi_get_state_reply}, + {NDMP_SCSI_SET_TARGET, + dissect_scsi_set_state_request, dissect_error}, + {NDMP_SCSI_RESET_DEVICE, + NULL, dissect_error}, + {NDMP_SCSI_RESET_BUS, + NULL, dissect_error}, + {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, + NULL, dissect_error}, + {NDMP_TAPE_GET_STATE, + NULL, dissect_tape_get_state_reply}, + {NDMP_TAPE_MTIO, + dissect_tape_mtio_request, dissect_tape_mtio_reply}, + {NDMP_TAPE_WRITE, + dissect_tape_write_request, dissect_tape_write_reply}, + {NDMP_TAPE_READ, + dissect_tape_read_request, dissect_tape_read_reply}, + {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, + dissect_data_start_backup_request, dissect_error }, + {NDMP_DATA_START_RECOVER, + dissect_data_start_recover_request, dissect_error }, + {NDMP_DATA_ABORT, + NULL, dissect_error}, + {NDMP_DATA_GET_ENV, + NULL, dissect_data_get_env_reply}, + {NDMP_DATA_STOP, + NULL, dissect_error}, + {NDMP_DATA_LISTEN, + dissect_ndmp_addr_msg, dissect_mover_listen_reply}, + {NDMP_DATA_CONNECT, + dissect_ndmp_addr_msg, dissect_error}, + {NDMP_NOTIFY_DATA_HALTED, + dissect_notify_data_halted_request, NULL}, + {NDMP_NOTIFY_CONNECTED, + dissect_notify_connected_request, NULL}, + {NDMP_NOTIFY_MOVER_HALTED, + dissect_notify_data_halted_request, NULL}, + {NDMP_NOTIFY_MOVER_PAUSED, + dissect_notify_mover_paused_request, NULL}, + {NDMP_NOTIFY_DATA_READ, + dissect_mover_set_window_request, NULL}, + {NDMP_LOG_FILE, + dissect_log_file_request, NULL}, + {NDMP_LOG_MESSAGE, + dissect_log_message_request, NULL}, + {NDMP_FH_ADD_FILE, + dissect_fh_add_file_request, NULL}, + {NDMP_FH_ADD_DIR, + dissect_fh_add_dir_request, NULL}, + {NDMP_FH_ADD_NODE, + dissect_fh_add_node_request, NULL}, + {NDMP_CONNECT_OPEN, + dissect_connect_open_request, dissect_error}, + {NDMP_CONNECT_CLIENT_AUTH, + dissect_connect_client_auth_request, dissect_error}, + {NDMP_CONNECT_CLOSE, + NULL,NULL}, + {NDMP_CONNECT_SERVER_AUTH, + dissect_auth_attr_msg, dissect_connect_server_auth_reply}, + {NDMP_MOVER_GET_STATE, + NULL, dissect_mover_get_state_reply}, + {NDMP_MOVER_LISTEN, + dissect_mover_listen_request, dissect_mover_listen_reply}, + {NDMP_MOVER_CONTINUE, + NULL, dissect_error}, + {NDMP_MOVER_ABORT, + NULL, dissect_error}, + {NDMP_MOVER_STOP, + NULL, dissect_error}, + {NDMP_MOVER_SET_WINDOW, + dissect_mover_set_window_request, dissect_error}, + {NDMP_MOVER_READ, + dissect_mover_set_window_request, dissect_error}, + {NDMP_MOVER_CLOSE, + NULL, dissect_error}, + {NDMP_MOVER_SET_RECORD_SIZE, + dissect_mover_set_record_size_request, dissect_error}, + {NDMP_MOVER_CONNECT, + dissect_mover_connect_request, dissect_error}, + {0, NULL,NULL} +}; + + +static int +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; + nstime_t ns; + + if (parent_tree) { + 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_uint(tree, hf_ndmp_sequence, tvb, offset, 4, nh->seq); + offset += 4; + + /* timestamp */ + ns.secs=nh->time; + ns.nsecs=0; + proto_tree_add_time(tree, hf_ndmp_timestamp, tvb, offset, 4, &ns); + offset += 4; + + /* Message Type */ + proto_tree_add_uint(tree, hf_ndmp_msgtype, tvb, offset, 4, nh->type); + offset += 4; + + /* Message */ + proto_tree_add_uint(tree, hf_ndmp_msg, tvb, offset, 4, nh->msg); + offset += 4; + + /* Reply sequence number */ + proto_tree_add_uint(tree, hf_ndmp_reply_sequence, tvb, offset, 4, nh->rep_seq); + offset += 4; + + /* error */ + offset=dissect_error(tvb, offset, pinfo, tree, nh->seq); + + if (check_col(pinfo->cinfo, COL_INFO)){ + 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)") + ); + } + + return offset; +} + + +static int +dissect_ndmp_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, struct ndmp_header *nh) +{ + int i; + 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==nh->msg){ + break; + } + } + + + if(ndmp_commands[i].cmd==0){ + /* we do not know this message */ + 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 (tvb_reported_length_remaining(tvb, offset) > 0) { + 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(nh->type==NDMP_MESSAGE_REQUEST){ + if(ndmp_commands[i].request){ + 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, + nh->rep_seq); + } + } + + return offset; +} + +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, gboolean first_pdu) +{ + 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; + + /* size of this NDMP PDU */ + size = tvb_length_remaining(tvb, offset); + if (size < 24) { + /* too short to be NDMP */ + return FALSE; + } + + /* + * 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)) { + if (first_pdu) + col_clear(pinfo->cinfo, COL_INFO); + else + col_append_fstr(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; + gboolean first_pdu = TRUE; + + 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, first_pdu); + first_pdu = FALSE; + 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_header, { + "NDMP Header", "ndmp.header", FT_NONE, 0, + NULL, 0, "NDMP Header", HFILL }}, + + { &hf_ndmp_sequence, { + "Sequence", "ndmp.sequence", FT_UINT32, BASE_DEC, + NULL, 0, "Sequence number for NDMP PDU", HFILL }}, + + { &hf_ndmp_reply_sequence, { + "Reply Sequence", "ndmp.reply_sequence", FT_UINT32, BASE_DEC, + NULL, 0, "Reply Sequence number for NDMP PDU", HFILL }}, + + { &hf_ndmp_timestamp, { + "Time", "ndmp.timestamp", FT_ABSOLUTE_TIME, BASE_NONE, + NULL, 0, "Timestamp for this NDMP PDU", HFILL }}, + + { &hf_ndmp_msgtype, { + "Type", "ndmp.msg_type", FT_UINT32, BASE_DEC, + VALS(msg_type_vals), 0, "Is this a Request or Response?", HFILL }}, + + { &hf_ndmp_msg, { + "Message", "ndmp.msg", FT_UINT32, BASE_HEX, + VALS(msg_vals), 0, "Type of NDMP PDU", HFILL }}, + + { &hf_ndmp_error, { + "Error", "ndmp.error", FT_UINT32, BASE_DEC, + VALS(error_vals), 0, "Error code for this NDMP PDU", HFILL }}, + + { &hf_ndmp_version, { + "Version", "ndmp.version", FT_UINT32, BASE_DEC, + NULL, 0, "Version of NDMP protocol", HFILL }}, + + { &hf_ndmp_hostname, { + "Hostname", "ndmp.hostname", FT_STRING, BASE_NONE, + NULL, 0, "Hostname", HFILL }}, + + { &hf_ndmp_hostid, { + "HostID", "ndmp.hostid", FT_STRING, BASE_NONE, + NULL, 0, "HostID", HFILL }}, + + { &hf_ndmp_os_type, { + "OS Type", "ndmp.os.type", FT_STRING, BASE_NONE, + NULL, 0, "OS Type", HFILL }}, + + { &hf_ndmp_os_vers, { + "OS Version", "ndmp.os.version", FT_STRING, BASE_NONE, + NULL, 0, "OS Version", HFILL }}, + + { &hf_ndmp_addr_types, { + "Addr Types", "ndmp.addr_types", FT_NONE, BASE_NONE, + NULL, 0, "List Of Address Types", HFILL }}, + + { &hf_ndmp_addr_type, { + "Addr Type", "ndmp.addr_type", FT_UINT32, BASE_DEC, + VALS(addr_type_vals), 0, "Address Type", HFILL }}, + + { &hf_ndmp_auth_type, { + "Auth Type", "ndmp.auth_type", FT_UINT32, BASE_DEC, + VALS(auth_type_vals), 0, "Authentication Type", HFILL }}, + + { &hf_ndmp_auth_challenge, { + "Challenge", "ndmp.auth.challenge", FT_BYTES, BASE_HEX, + NULL, 0, "Authentication Challenge", HFILL }}, + + { &hf_ndmp_auth_digest, { + "Digest", "ndmp.auth.digest", FT_BYTES, BASE_HEX, + NULL, 0, "Authentication Digest", HFILL }}, + + { &hf_ndmp_butype_info, { + "Butype Info", "ndmp.butype.info", FT_NONE, BASE_NONE, + NULL, 0, "Butype Info", HFILL }}, + + { &hf_ndmp_butype_name, { + "Butype Name", "ndmp.butype.name", FT_STRING, BASE_NONE, + NULL, 0, "Name of Butype", HFILL }}, + + { &hf_ndmp_butype_default_env, { + "Default Env", "ndmp.butype.default_env", FT_NONE, BASE_NONE, + NULL, 0, "Default Env's for this Butype Info", HFILL }}, + + { &hf_ndmp_butype_attr_backup_file_history, { + "", "ndmp.butype.attr.backup_file_history", FT_BOOLEAN, 32, + TFS(&tfs_butype_attr_backup_file_history), 0x00000001, "backup_file_history", HFILL }}, + + { &hf_ndmp_butype_attr_backup_filelist, { + "", "ndmp.butype.attr.backup_filelist", FT_BOOLEAN, 32, + TFS(&tfs_butype_attr_backup_filelist), 0x00000002, "backup_filelist", HFILL }}, + + { &hf_ndmp_butype_attr_recover_filelist, { + "", "ndmp.butype.attr.recover_filelist", FT_BOOLEAN, 32, + TFS(&tfs_butype_attr_recover_filelist), 0x00000004, "recover_filelist", HFILL }}, + + { &hf_ndmp_butype_attr_backup_direct, { + "", "ndmp.butype.attr.backup_direct", FT_BOOLEAN, 32, + TFS(&tfs_butype_attr_backup_direct), 0x00000008, "backup_direct", HFILL }}, + + { &hf_ndmp_butype_attr_recover_direct, { + "", "ndmp.butype.attr.recover_direct", FT_BOOLEAN, 32, + TFS(&tfs_butype_attr_recover_direct), 0x00000010, "recover_direct", HFILL }}, + + { &hf_ndmp_butype_attr_backup_incremental, { + "", "ndmp.butype.attr.backup_incremental", FT_BOOLEAN, 32, + TFS(&tfs_butype_attr_backup_incremental), 0x00000020, "backup_incremental", HFILL }}, + + { &hf_ndmp_butype_attr_recover_incremental, { + "", "ndmp.butype.attr.recover_incremental", FT_BOOLEAN, 32, + TFS(&tfs_butype_attr_recover_incremental), 0x00000040, "recover_incremental", HFILL }}, + + { &hf_ndmp_butype_attr_backup_utf8, { + "", "ndmp.butype.attr.backup_utf8", FT_BOOLEAN, 32, + TFS(&tfs_butype_attr_backup_utf8), 0x00000080, "backup_utf8", HFILL }}, + + { &hf_ndmp_butype_attr_recover_utf8, { + "", "ndmp.butype.attr.recover_utf8", FT_BOOLEAN, 32, + TFS(&tfs_butype_attr_recover_utf8), 0x00000100, "recover_utf8", HFILL }}, + + { &hf_ndmp_butype_env_name, { + "Name", "ndmp.butype.env.name", FT_STRING, BASE_NONE, + NULL, 0, "Name for this env-variable", HFILL }}, + + { &hf_ndmp_butype_env_value, { + "Value", "ndmp.butype.env.value", FT_STRING, BASE_NONE, + NULL, 0, "Value for this env-variable", HFILL }}, + + { &hf_ndmp_fs_info, { + "FS Info", "ndmp.fs.info", FT_NONE, BASE_NONE, + NULL, 0, "FS Info", HFILL }}, + + { &hf_ndmp_fs_invalid_total_size, { + "", "ndmp.fs.invalid.total_size", FT_BOOLEAN, 32, + TFS(&tfs_fs_invalid_total_size), 0x00000001, "If total size is invalid", HFILL }}, + + { &hf_ndmp_fs_invalid_used_size, { + "", "ndmp.fs.invalid.used_size", FT_BOOLEAN, 32, + TFS(&tfs_fs_invalid_used_size), 0x00000002, "If used size is invalid", HFILL }}, + + { &hf_ndmp_fs_invalid_avail_size, { + "", "ndmp.fs.invalid.avail_size", FT_BOOLEAN, 32, + TFS(&tfs_fs_invalid_avail_size), 0x00000004, "If available size is invalid", HFILL }}, + + { &hf_ndmp_fs_invalid_total_inodes, { + "", "ndmp.fs.invalid.total_inodes", FT_BOOLEAN, 32, + TFS(&tfs_fs_invalid_total_inodes), 0x00000008, "If total number of inodes is invalid", HFILL }}, + + { &hf_ndmp_fs_invalid_used_inodes, { + "", "ndmp.fs.invalid.used_inodes", FT_BOOLEAN, 32, + TFS(&tfs_fs_invalid_used_inodes), 0x00000010, "If used number of inodes is invalid", HFILL }}, + + { &hf_ndmp_fs_fs_type, { + "Type", "ndmp.fs.type", FT_STRING, BASE_NONE, + NULL, 0, "Type of FS", HFILL }}, + + { &hf_ndmp_fs_logical_device, { + "Logical Device", "ndmp.fs.logical_device", FT_STRING, BASE_NONE, + NULL, 0, "Name of logical device", HFILL }}, + + { &hf_ndmp_fs_physical_device, { + "Physical Device", "ndmp.fs.physical_device", FT_STRING, BASE_NONE, + NULL, 0, "Name of physical device", HFILL }}, + + { &hf_ndmp_fs_total_size, { + "Total Size", "ndmp.fs.total_size", FT_UINT64, BASE_DEC, + NULL, 0, "Total size of FS", HFILL }}, + + { &hf_ndmp_fs_used_size, { + "Used Size", "ndmp.fs.used_size", FT_UINT64, BASE_DEC, + NULL, 0, "Total used size of FS", HFILL }}, + + { &hf_ndmp_fs_avail_size, { + "Avail Size", "ndmp.fs.avail_size", FT_UINT64, BASE_DEC, + NULL, 0, "Total available size on FS", HFILL }}, + + { &hf_ndmp_fs_total_inodes, { + "Total Inodes", "ndmp.fs.total_inodes", FT_UINT64, BASE_DEC, + NULL, 0, "Total number of inodes on FS", HFILL }}, + + { &hf_ndmp_fs_used_inodes, { + "Used Inodes", "ndmp.fs.used_inodes", FT_UINT64, BASE_DEC, + NULL, 0, "Number of used inodes on FS", HFILL }}, + + { &hf_ndmp_fs_env, { + "Env variables", "ndmp.fs.env", FT_NONE, BASE_NONE, + NULL, 0, "Environment variables for FS", HFILL }}, + + { &hf_ndmp_fs_env_name, { + "Name", "ndmp.fs.env.name", FT_STRING, BASE_NONE, + NULL, 0, "Name for this env-variable", HFILL }}, + + { &hf_ndmp_fs_env_value, { + "Value", "ndmp.fs.env.value", FT_STRING, BASE_NONE, + NULL, 0, "Value for this env-variable", HFILL }}, + + { &hf_ndmp_fs_status, { + "Status", "ndmp.fs.status", FT_STRING, BASE_NONE, + NULL, 0, "Status for this FS", HFILL }}, + + { &hf_ndmp_tape_info, { + "Tape Info", "ndmp.tape.info", FT_NONE, BASE_NONE, + NULL, 0, "Tape Info", HFILL }}, + + { &hf_ndmp_tape_model, { + "Model", "ndmp.tape.model", FT_STRING, BASE_NONE, + NULL, 0, "Model of the TAPE drive", HFILL }}, + + { &hf_ndmp_tape_dev_cap, { + "Device Capability", "ndmp.tape.dev_cap", FT_NONE, BASE_NONE, + NULL, 0, "Tape Device Capability", HFILL }}, + + { &hf_ndmp_tape_device, { + "Device", "ndmp.tape.device", FT_STRING, BASE_NONE, + NULL, 0, "Name of TAPE Device", HFILL }}, + + { &hf_ndmp_tape_attr_rewind, { + "", "ndmp.tape.attr.rewind", FT_BOOLEAN, 32, + TFS(&tfs_tape_attr_rewind), 0x00000001, "If this device supports rewind", HFILL }}, + + { &hf_ndmp_tape_attr_unload, { + "", "ndmp.tape.attr.unload", FT_BOOLEAN, 32, + TFS(&tfs_tape_attr_unload), 0x00000002, "If this device supports unload", HFILL }}, + + { &hf_ndmp_tape_capability, { + "Tape Capabilities", "ndmp.tape.capability", FT_NONE, BASE_NONE, + NULL, 0, "Tape Capabilities", HFILL }}, + + { &hf_ndmp_tape_capability_name, { + "Name", "ndmp.tape.cap.name", FT_STRING, BASE_NONE, + NULL, 0, "Name for this env-variable", HFILL }}, + + { &hf_ndmp_tape_capability_value, { + "Value", "ndmp.tape.cap.value", FT_STRING, BASE_NONE, + NULL, 0, "Value for this env-variable", HFILL }}, + + { &hf_ndmp_scsi_info, { + "SCSI Info", "ndmp.scsi.info", FT_NONE, BASE_NONE, + NULL, 0, "SCSI Info", HFILL }}, + + { &hf_ndmp_scsi_model, { + "Model", "ndmp.scsi.model", FT_STRING, BASE_NONE, + NULL, 0, "Model of the SCSI device", HFILL }}, + + { &hf_ndmp_server_vendor, { + "Vendor", "ndmp.server.vendor", FT_STRING, BASE_NONE, + NULL, 0, "Name of vendor", HFILL }}, + + { &hf_ndmp_server_product, { + "Product", "ndmp.server.product", FT_STRING, BASE_NONE, + NULL, 0, "Name of product", HFILL }}, + + { &hf_ndmp_server_revision, { + "Revision", "ndmp.server.revision", FT_STRING, BASE_NONE, + NULL, 0, "Revision of this product", HFILL }}, + + { &hf_ndmp_auth_types, { + "Auth types", "ndmp.auth.types", FT_NONE, BASE_NONE, + NULL, 0, "Auth types", HFILL }}, + + { &hf_ndmp_scsi_device, { + "Device", "ndmp.scsi.device", FT_STRING, BASE_NONE, + NULL, 0, "Name of SCSI Device", HFILL }}, + + { &hf_ndmp_scsi_controller, { + "Controller", "ndmp.scsi.controller", FT_UINT32, BASE_DEC, + NULL, 0, "Target Controller", HFILL }}, + + { &hf_ndmp_scsi_id, { + "ID", "ndmp.scsi.id", FT_UINT32, BASE_DEC, + NULL, 0, "Target ID", HFILL }}, + + { &hf_ndmp_scsi_lun, { + "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_tape_invalid_file_num, { + "", "ndmp.tape.invalid.file_num", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_invalid_file_num), 0x00000001, "invalid_file_num", HFILL }}, + + { &hf_ndmp_tape_invalid_soft_errors, { + "", "ndmp.tape.invalid.soft_errors", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_invalid_soft_errors), 0x00000002, "soft_errors", HFILL }}, + + { &hf_ndmp_tape_invalid_block_size, { + "", "ndmp.tape.invalid.block_size", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_invalid_block_size), 0x00000004, "block_size", HFILL }}, + + { &hf_ndmp_tape_invalid_block_no, { + "", "ndmp.tape.invalid.block_no", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_invalid_block_no), 0x00000008, "block_no", HFILL }}, + + { &hf_ndmp_tape_invalid_total_space, { + "", "ndmp.tape.invalid.total_space", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_invalid_total_space), 0x00000010, "total_space", HFILL }}, + + { &hf_ndmp_tape_invalid_space_remain, { + "", "ndmp.tape.invalid.space_remain", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_invalid_space_remain), 0x00000020, "space_remain", HFILL }}, + + { &hf_ndmp_tape_invalid_partition, { + "", "ndmp.tape.invalid.partition", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_invalid_partition), 0x00000040, "partition", HFILL }}, + + { &hf_ndmp_tape_flags_no_rewind, { + "", "ndmp.tape.flags.no_rewind", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_flags_no_rewind), 0x00000008, "no_rewind", HFILL, }}, + + { &hf_ndmp_tape_flags_write_protect, { + "", "ndmp.tape.flags.write_protect", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_flags_write_protect), 0x00000010, "write_protect", HFILL, }}, + + { &hf_ndmp_tape_flags_error, { + "", "ndmp.tape.flags.error", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_flags_error), 0x00000020, "error", HFILL, }}, + + { &hf_ndmp_tape_flags_unload, { + "", "ndmp.tape.flags.unload", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_tape_flags_unload), 0x00000040, "unload", HFILL, }}, + + { &hf_ndmp_tape_file_num, { + "file_num", "ndmp.tape.status.file_num", FT_UINT32, BASE_DEC, + NULL, 0, "file_num", HFILL }}, + + { &hf_ndmp_tape_soft_errors, { + "soft_errors", "ndmp.tape.status.soft_errors", FT_UINT32, BASE_DEC, + NULL, 0, "soft_errors", HFILL }}, + + { &hf_ndmp_tape_block_size, { + "block_size", "ndmp.tape.status.block_size", FT_UINT32, BASE_DEC, + NULL, 0, "block_size", HFILL }}, + + { &hf_ndmp_tape_block_no, { + "block_no", "ndmp.tape.status.block_no", FT_UINT32, BASE_DEC, + NULL, 0, "block_no", HFILL }}, + + { &hf_ndmp_tape_total_space, { + "total_space", "ndmp.tape.status.total_space", FT_UINT64, BASE_DEC, + NULL, 0, "total_space", HFILL }}, + + { &hf_ndmp_tape_space_remain, { + "space_remain", "ndmp.tape.status.space_remain", FT_UINT64, BASE_DEC, + NULL, 0, "space_remain", HFILL }}, + + { &hf_ndmp_tape_partition, { + "partition", "ndmp.tape.status.partition", FT_UINT32, BASE_DEC, + NULL, 0, "partition", HFILL }}, + + { &hf_ndmp_tape_mtio_op, { + "Operation", "ndmp.tape.mtio.op", FT_UINT32, BASE_DEC, + VALS(tape_mtio_vals), 0, "MTIO Operation", HFILL }}, + + { &hf_ndmp_count, { + "Count", "ndmp.count", FT_UINT32, BASE_DEC, + NULL, 0, "Number of bytes/objects/operations", HFILL }}, + + { &hf_ndmp_resid_count, { + "Resid Count", "ndmp.resid_count", FT_UINT32, BASE_DEC, + NULL, 0, "Number of remaining bytes/objects/operations", HFILL }}, + + { &hf_ndmp_mover_state, { + "State", "ndmp.mover.state", FT_UINT32, BASE_DEC, + VALS(mover_state_vals), 0, "State of the selected mover", HFILL }}, + + { &hf_ndmp_mover_pause, { + "Pause", "ndmp.mover.pause", FT_UINT32, BASE_DEC, + VALS(mover_pause_vals), 0, "Reason why the mover paused", HFILL }}, + + { &hf_ndmp_halt, { + "Halt", "ndmp.halt", FT_UINT32, BASE_DEC, + VALS(halt_vals), 0, "Reason why it halted", HFILL }}, + + { &hf_ndmp_record_size, { + "Record Size", "ndmp.record.size", FT_UINT32, BASE_DEC, + NULL, 0, "Record size in bytes", HFILL }}, + + { &hf_ndmp_record_num, { + "Record Num", "ndmp.record.num", FT_UINT32, BASE_DEC, + NULL, 0, "Number of records", HFILL }}, + + { &hf_ndmp_data_written, { + "Data Written", "ndmp.data.written", FT_UINT64, BASE_DEC, + NULL, 0, "Number of data bytes written", HFILL }}, + + { &hf_ndmp_seek_position, { + "Seek Position", "ndmp.seek.position", FT_UINT64, BASE_DEC, + NULL, 0, "Current seek position on device", HFILL }}, + + { &hf_ndmp_bytes_left_to_read, { + "Bytes left to read", "ndmp.bytes_left_to_read", FT_UINT64, BASE_DEC, + NULL, 0, "Number of bytes left to be read from the device", HFILL }}, + + { &hf_ndmp_window_offset, { + "Window Offset", "ndmp.window.offset", FT_UINT64, BASE_DEC, + NULL, 0, "Offset to window in bytes", HFILL }}, + + { &hf_ndmp_window_length, { + "Window Length", "ndmp.window.length", FT_UINT64, BASE_DEC, + NULL, 0, "Size of window in bytes", HFILL }}, + + { &hf_ndmp_addr_ip, { + "IP Address", "ndmp.addr.ip", FT_IPv4, BASE_DEC, + NULL, 0, "IP Address", HFILL }}, + + { &hf_ndmp_addr_tcp, { + "TCP Port", "ndmp.addr.tcp_port", FT_UINT32, BASE_DEC, + NULL, 0, "TCP Port", HFILL }}, + + { &hf_ndmp_addr_fcal_loop_id, { + "Loop ID", "ndmp.addr.loop_id", FT_UINT32, BASE_HEX, + NULL, 0, "FCAL Loop ID", HFILL }}, + + { &hf_ndmp_addr_ipc, { + "IPC", "ndmp.addr.ipc", FT_BYTES, BASE_HEX, + NULL, 0, "IPC identifier", HFILL }}, + + { &hf_ndmp_mover_mode, { + "Mode", "ndmp.mover.mode", FT_UINT32, BASE_HEX, + VALS(mover_mode_vals), 0, "Mover Mode", HFILL }}, + + { &hf_ndmp_file_name, { + "File", "ndmp.file", FT_STRING, BASE_NONE, + NULL, 0, "Name of File", HFILL }}, + + { &hf_ndmp_nt_file_name, { + "NT File", "ndmp.file", FT_STRING, BASE_NONE, + NULL, 0, "NT Name of File", HFILL }}, + + { &hf_ndmp_dos_file_name, { + "DOS File", "ndmp.file", FT_STRING, BASE_NONE, + NULL, 0, "DOS Name of File", HFILL }}, + + { &hf_ndmp_log_type, { + "Type", "ndmp.log.type", FT_UINT32, BASE_HEX, + VALS(log_type_vals), 0, "Type of log entry", HFILL }}, + + { &hf_ndmp_log_message_id, { + "Message ID", "ndmp.log.message.id", FT_UINT32, BASE_DEC, + NULL, 0, "ID of this log entry", HFILL }}, + + { &hf_ndmp_log_message, { + "Message", "ndmp.log.message", FT_STRING, BASE_NONE, + NULL, 0, "Log entry", HFILL }}, + + { &hf_ndmp_halt_reason, { + "Reason", "ndmp.halt.reason", FT_STRING, BASE_NONE, + NULL, 0, "Textual reason for why it halted", HFILL }}, + + { &hf_ndmp_connected, { + "Connected", "ndmp.connected", FT_UINT32, BASE_DEC, + VALS(connected_vals), 0, "Status of connection", HFILL }}, + + { &hf_ndmp_connected_reason, { + "Reason", "ndmp.connected.reason", FT_STRING, BASE_NONE, + NULL, 0, "Textual description of the connection status", HFILL }}, + + { &hf_ndmp_auth_id, { + "ID", "ndmp.auth.id", FT_STRING, BASE_NONE, + NULL, 0, "ID of client authenticating", HFILL }}, + + { &hf_ndmp_auth_password, { + "Password", "ndmp.auth.password", FT_STRING, BASE_NONE, + NULL, 0, "Password of client authenticating", HFILL }}, + + { &hf_ndmp_data, { + "Data", "ndmp.data", FT_BYTES, BASE_HEX, + NULL, 0, "Data written/read", HFILL }}, + + { &hf_ndmp_files, { + "Files", "ndmp.files", FT_NONE, 0, + NULL, 0, "List of files", HFILL }}, + + { &hf_ndmp_file_names, { + "File Names", "ndmp.file.names", FT_NONE, 0, + NULL, 0, "List of file names", HFILL }}, + + { &hf_ndmp_file_fs_type, { + "File FS Type", "ndmp.file.fs_type", FT_UINT32, BASE_DEC, + VALS(file_fs_type_vals), 0, "Type of file permissions (UNIX or NT)", HFILL }}, + + { &hf_ndmp_file_type, { + "File Type", "ndmp.file.type", FT_UINT32, BASE_DEC, + VALS(file_type_vals), 0, "Type of file", HFILL }}, + + { &hf_ndmp_file_stats, { + "File Stats", "ndmp.file.stats", FT_NONE, 0, + NULL, 0, "List of file stats", HFILL }}, + + { &hf_ndmp_file_node, { + "Node", "ndmp.file.node", FT_UINT64, BASE_DEC, + NULL, 0, "Node used for direct access", HFILL }}, + + { &hf_ndmp_file_parent, { + "Parent", "ndmp.file.parent", FT_UINT64, BASE_DEC, + NULL, 0, "Parent node(directory) for this node", HFILL }}, + + { &hf_ndmp_file_fh_info, { + "FH Info", "ndmp.file.fh_info", FT_UINT64, BASE_DEC, + NULL, 0, "FH Info used for direct access", HFILL }}, + + { &hf_ndmp_file_invalid_atime, { + "", "ndmp.file.invalid_atime", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_file_invalid_atime), 0x00000001, "invalid_atime", HFILL, }}, + + { &hf_ndmp_file_invalid_ctime, { + "", "ndmp.file.invalid_ctime", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_file_invalid_ctime), 0x00000002, "invalid_ctime", HFILL, }}, + + { &hf_ndmp_file_invalid_group, { + "", "ndmp.file.invalid_group", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_file_invalid_group), 0x00000004, "invalid_group", HFILL, }}, + + { &hf_ndmp_file_mtime, { + "mtime", "ndmp.file.mtime", FT_ABSOLUTE_TIME, BASE_NONE, + NULL, 0, "Timestamp for mtime for this file", HFILL }}, + + { &hf_ndmp_file_atime, { + "atime", "ndmp.file.atime", FT_ABSOLUTE_TIME, BASE_NONE, + NULL, 0, "Timestamp for atime for this file", HFILL }}, + + { &hf_ndmp_file_ctime, { + "ctime", "ndmp.file.ctime", FT_ABSOLUTE_TIME, BASE_NONE, + NULL, 0, "Timestamp for ctime for this file", HFILL }}, + + { &hf_ndmp_file_owner, { + "Owner", "ndmp.file.owner", FT_UINT32, BASE_DEC, + NULL, 0, "UID for UNIX, owner for NT", HFILL }}, + + { &hf_ndmp_file_group, { + "Group", "ndmp.file.group", FT_UINT32, BASE_DEC, + NULL, 0, "GID for UNIX, NA for NT", HFILL }}, + + { &hf_ndmp_file_fattr, { + "Fattr", "ndmp.file.fattr", FT_UINT32, BASE_HEX, + NULL, 0, "Mode for UNIX, fattr for NT", HFILL }}, + + { &hf_ndmp_file_size, { + "Size", "ndmp.file.size", FT_UINT64, BASE_DEC, + NULL, 0, "File Size", HFILL }}, + + { &hf_ndmp_file_links, { + "Links", "ndmp.file.links", FT_UINT32, BASE_DEC, + NULL, 0, "Number of links to this file", HFILL }}, + + { &hf_ndmp_dirs, { + "Dirs", "ndmp.dirs", FT_NONE, 0, + NULL, 0, "List of directories", HFILL }}, + + { &hf_ndmp_nodes, { + "Nodes", "ndmp.nodes", FT_NONE, 0, + NULL, 0, "List of nodes", HFILL }}, + + { &hf_ndmp_nlist, { + "Nlist", "ndmp.nlist", FT_NONE, 0, + NULL, 0, "List of names", HFILL }}, + + { &hf_ndmp_bu_original_path, { + "Original Path", "ndmp.bu.original_path", FT_STRING, BASE_NONE, + NULL, 0, "Original path where backup was created", HFILL }}, + + { &hf_ndmp_bu_destination_dir, { + "Destination Dir", "ndmp.bu.destination_dir", FT_STRING, BASE_NONE, + NULL, 0, "Destination directory to restore backup to", HFILL }}, + + { &hf_ndmp_bu_new_name, { + "New Name", "ndmp.bu.new_name", FT_STRING, BASE_NONE, + NULL, 0, "New Name", HFILL }}, + + { &hf_ndmp_bu_other_name, { + "Other Name", "ndmp.bu.other_name", FT_STRING, BASE_NONE, + NULL, 0, "Other Name", HFILL }}, + + { &hf_ndmp_state_invalid_ebr, { + "", "ndmp.bu.state.invalid_ebr", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_state_invalid_ebr), 0x00000001, "Whether EstimatedBytesLeft is valid or not", HFILL, }}, + + { &hf_ndmp_state_invalid_etr, { + "", "ndmp.bu.state.invalid_etr", FT_BOOLEAN, 32, + TFS(&tfs_ndmp_state_invalid_etr), 0x00000002, "Whether EstimatedTimeLeft is valid or not", HFILL, }}, + + { &hf_ndmp_bu_operation, { + "Operation", "ndmp.bu.operation", FT_UINT32, BASE_DEC, + VALS(bu_operation_vals), 0, "BU Operation", HFILL, }}, + + { &hf_ndmp_data_state, { + "State", "ndmp.data.state", FT_UINT32, BASE_DEC, + VALS(data_state_vals), 0, "Data state", HFILL, }}, + + { &hf_ndmp_data_halted, { + "Halted Reason", "ndmp.data.halted", FT_UINT32, BASE_DEC, + VALS(data_halted_vals), 0, "Data halted reason", HFILL, }}, + + { &hf_ndmp_data_bytes_processed, { + "Bytes Processed", "ndmp.data.bytes_processed", FT_UINT64, BASE_DEC, + NULL, 0, "Number of bytes processed", HFILL }}, + + { &hf_ndmp_data_est_bytes_remain, { + "Est Bytes Remain", "ndmp.data.est_bytes_remain", FT_UINT64, BASE_DEC, + NULL, 0, "Estimated number of bytes remaining", 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, + &ett_ndmp_header, + &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, + }; + + module_t *ndmp_module; + + proto_ndmp = proto_register_protocol("Network Data Management Protocol", "NDMP", "ndmp"); + proto_register_field_array(proto_ndmp, hf_ndmp, array_length(hf_ndmp)); + + proto_register_subtree_array(ett, array_length(ett)); + + /* desegmentation */ + ndmp_module = prefs_register_protocol(proto_ndmp, NULL); + prefs_register_enum_preference(ndmp_module, + "protocol_version", + "Protocol version", + "Version of the NDMP protocol", + &ndmp_protocol_version, + ndmp_protocol_versions, + FALSE); + 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