Fix up a bunch of arguments to "dissect_ber_identifier()" to match its
[obnox/wireshark/wip.git] / epan / dissectors / packet-ndmp.c
1 /* TODO: fixup LUN tracking so we can pass the proper LUN across to
2    dissect_scsi_xxx()
3 */
4 /* packet-ndmp.c
5  * Routines for NDMP dissection
6  * 2001 Ronnie Sahlberg (see AUTHORS for email)
7  *
8  * $Id$
9  *
10  * Ethereal - Network traffic analyzer
11  * By Gerald Combs <gerald@ethereal.com>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 /* see www.ndmp.org for protocol specifications.
30    this file implements version 3 of ndmp
31 */
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <glib.h>
40
41 #include <epan/packet.h>
42 #include <epan/conversation.h>
43 #include "packet-rpc.h"
44 #include "packet-tcp.h"
45 #include "packet-scsi.h"
46 #include "packet-frame.h"
47 #include <epan/prefs.h>
48 #include <epan/reassemble.h>
49 #include "rpc_defrag.h"
50
51 #define TCP_PORT_NDMP 10000
52 #define NDMP_RM_LASTFRAG 0x80000000
53 #define NDMP_RM_LENGTH   0x7fffffff
54
55 static int proto_ndmp = -1;
56 static int hf_ndmp_lastfrag = -1;
57 static int hf_ndmp_fraglen = -1;
58 static int hf_ndmp_version = -1;
59 static int hf_ndmp_header = -1;
60 static int hf_ndmp_sequence = -1;
61 static int hf_ndmp_reply_sequence = -1;
62 static int hf_ndmp_timestamp = -1;
63 static int hf_ndmp_msgtype = -1;
64 static int hf_ndmp_msg = -1;
65 static int hf_ndmp_error = -1;
66 static int hf_ndmp_hostname = -1;
67 static int hf_ndmp_os_type = -1;
68 static int hf_ndmp_os_vers = -1;
69 static int hf_ndmp_hostid = -1;
70 static int hf_ndmp_addr_types = -1;
71 static int hf_ndmp_addr_type = -1;
72 static int hf_ndmp_auth_type = -1;
73 static int hf_ndmp_auth_types = -1;
74 static int hf_ndmp_auth_challenge = -1;
75 static int hf_ndmp_auth_digest = -1;
76 static int hf_ndmp_auth_id = -1;
77 static int hf_ndmp_auth_password = -1;
78 static int hf_ndmp_butype_info = -1;
79 static int hf_ndmp_butype_name = -1;
80 static int hf_ndmp_butype_default_env = -1;
81 static int hf_ndmp_butype_attr_backup_file_history = -1;
82 static int hf_ndmp_butype_attr_backup_filelist = -1;
83 static int hf_ndmp_butype_attr_recover_filelist = -1;
84 static int hf_ndmp_butype_attr_backup_direct = -1;
85 static int hf_ndmp_butype_attr_recover_direct = -1;
86 static int hf_ndmp_butype_attr_backup_incremental = -1;
87 static int hf_ndmp_butype_attr_recover_incremental = -1;
88 static int hf_ndmp_butype_attr_backup_utf8 = -1;
89 static int hf_ndmp_butype_attr_recover_utf8 = -1;
90 static int hf_ndmp_butype_env_name = -1;
91 static int hf_ndmp_butype_env_value = -1;
92 static int hf_ndmp_tcp_env_name = -1;
93 static int hf_ndmp_tcp_env_value = -1;
94 static int hf_ndmp_tcp_default_env = -1;
95 static int hf_ndmp_tcp_addr_list = -1;
96 static int hf_ndmp_fs_info = -1;
97 static int hf_ndmp_fs_invalid_total_size = -1;
98 static int hf_ndmp_fs_invalid_used_size = -1;
99 static int hf_ndmp_fs_invalid_avail_size = -1;
100 static int hf_ndmp_fs_invalid_total_inodes = -1;
101 static int hf_ndmp_fs_invalid_used_inodes = -1;
102 static int hf_ndmp_fs_fs_type = -1;
103 static int hf_ndmp_fs_logical_device = -1;
104 static int hf_ndmp_fs_physical_device = -1;
105 static int hf_ndmp_fs_total_size = -1;
106 static int hf_ndmp_fs_used_size = -1;
107 static int hf_ndmp_fs_avail_size = -1;
108 static int hf_ndmp_fs_total_inodes = -1;
109 static int hf_ndmp_fs_used_inodes = -1;
110 static int hf_ndmp_fs_env = -1;
111 static int hf_ndmp_fs_env_name = -1;
112 static int hf_ndmp_fs_env_value = -1;
113 static int hf_ndmp_fs_status = -1;
114 static int hf_ndmp_tape_info = -1;
115 static int hf_ndmp_tape_model = -1;
116 static int hf_ndmp_tape_dev_cap = -1;
117 static int hf_ndmp_tape_device = -1;
118 static int hf_ndmp_tape_open_mode = -1;
119 static int hf_ndmp_tape_attr_rewind = -1;
120 static int hf_ndmp_tape_attr_unload = -1;
121 static int hf_ndmp_tape_capability = -1;
122 static int hf_ndmp_tape_capability_name = -1;
123 static int hf_ndmp_tape_capability_value = -1;
124 static int hf_ndmp_scsi_info = -1;
125 static int hf_ndmp_scsi_model = -1;
126 static int hf_ndmp_server_vendor = -1;
127 static int hf_ndmp_server_product = -1;
128 static int hf_ndmp_server_revision = -1;
129 static int hf_ndmp_scsi_device = -1;
130 static int hf_ndmp_scsi_controller = -1;
131 static int hf_ndmp_scsi_id = -1;
132 static int hf_ndmp_scsi_lun = -1;
133 static int hf_ndmp_execute_cdb_flags_data_in = -1;
134 static int hf_ndmp_execute_cdb_flags_data_out = -1;
135 static int hf_ndmp_execute_cdb_timeout = -1;
136 static int hf_ndmp_execute_cdb_datain_len = -1;
137 static int hf_ndmp_execute_cdb_cdb_len = -1;
138 static int hf_ndmp_execute_cdb_dataout = -1;
139 static int hf_ndmp_execute_cdb_status = -1;
140 static int hf_ndmp_execute_cdb_dataout_len = -1;
141 static int hf_ndmp_execute_cdb_datain = -1;
142 static int hf_ndmp_execute_cdb_sns_len = -1;
143 static int hf_ndmp_tape_invalid_file_num = -1;
144 static int hf_ndmp_tape_invalid_soft_errors = -1;
145 static int hf_ndmp_tape_invalid_block_size = -1;
146 static int hf_ndmp_tape_invalid_block_no = -1;
147 static int hf_ndmp_tape_invalid_total_space = -1;
148 static int hf_ndmp_tape_invalid_space_remain = -1;
149 static int hf_ndmp_tape_invalid_partition = -1;
150 static int hf_ndmp_tape_flags_no_rewind = -1;
151 static int hf_ndmp_tape_flags_write_protect = -1;
152 static int hf_ndmp_tape_flags_error = -1;
153 static int hf_ndmp_tape_flags_unload = -1;
154 static int hf_ndmp_tape_file_num = -1;
155 static int hf_ndmp_tape_soft_errors = -1;
156 static int hf_ndmp_tape_block_size = -1;
157 static int hf_ndmp_tape_block_no = -1;
158 static int hf_ndmp_tape_total_space = -1;
159 static int hf_ndmp_tape_space_remain = -1;
160 static int hf_ndmp_tape_partition = -1;
161 static int hf_ndmp_tape_mtio_op = -1;
162 static int hf_ndmp_count = -1;
163 static int hf_ndmp_resid_count = -1;
164 static int hf_ndmp_mover_state = -1;
165 static int hf_ndmp_mover_pause = -1;
166 static int hf_ndmp_halt = -1;
167 static int hf_ndmp_halt_reason = -1;
168 static int hf_ndmp_record_size = -1;
169 static int hf_ndmp_record_num = -1;
170 static int hf_ndmp_data_written = -1;
171 static int hf_ndmp_seek_position = -1;
172 static int hf_ndmp_bytes_left_to_read = -1;
173 static int hf_ndmp_window_offset = -1;
174 static int hf_ndmp_window_length = -1;
175 static int hf_ndmp_addr_ip = -1;
176 static int hf_ndmp_addr_tcp = -1;
177 static int hf_ndmp_addr_fcal_loop_id = -1;
178 static int hf_ndmp_addr_ipc = -1;
179 static int hf_ndmp_mover_mode = -1;
180 static int hf_ndmp_file_name = -1;
181 static int hf_ndmp_nt_file_name = -1;
182 static int hf_ndmp_dos_file_name = -1;
183 static int hf_ndmp_log_type = -1;
184 static int hf_ndmp_log_message_id = -1;
185 static int hf_ndmp_log_message = -1;
186 static int hf_ndmp_connected = -1;
187 static int hf_ndmp_connected_reason = -1;
188 static int hf_ndmp_data = -1;
189 static int hf_ndmp_files = -1;
190 static int hf_ndmp_file_fs_type = -1;
191 static int hf_ndmp_file_names = -1;
192 static int hf_ndmp_file_stats = -1;
193 static int hf_ndmp_file_node = -1;
194 static int hf_ndmp_file_parent = -1;
195 static int hf_ndmp_file_fh_info = -1;
196 static int hf_ndmp_file_invalid_atime = -1;
197 static int hf_ndmp_file_invalid_ctime = -1;
198 static int hf_ndmp_file_invalid_group = -1;
199 static int hf_ndmp_file_type = -1;
200 static int hf_ndmp_file_mtime = -1;
201 static int hf_ndmp_file_atime = -1;
202 static int hf_ndmp_file_ctime = -1;
203 static int hf_ndmp_file_owner = -1;
204 static int hf_ndmp_file_group = -1;
205 static int hf_ndmp_file_fattr = -1;
206 static int hf_ndmp_file_size = -1;
207 static int hf_ndmp_file_links = -1;
208 static int hf_ndmp_dirs = -1;
209 static int hf_ndmp_nodes = -1;
210 static int hf_ndmp_nlist = -1;
211 static int hf_ndmp_bu_original_path = -1;
212 static int hf_ndmp_bu_destination_dir = -1;
213 static int hf_ndmp_bu_new_name = -1;
214 static int hf_ndmp_bu_other_name = -1;
215 static int hf_ndmp_state_invalid_ebr = -1;
216 static int hf_ndmp_state_invalid_etr = -1;
217 static int hf_ndmp_bu_operation = -1;
218 static int hf_ndmp_data_state = -1;
219 static int hf_ndmp_data_halted = -1;
220 static int hf_ndmp_data_bytes_processed = -1;
221 static int hf_ndmp_data_est_bytes_remain = -1;
222 static int hf_ndmp_data_est_time_remain = -1;
223
224 static gint ett_ndmp = -1;
225 static gint ett_ndmp_fraghdr = -1;
226 static gint ett_ndmp_header = -1;
227 static gint ett_ndmp_butype_attrs = -1;
228 static gint ett_ndmp_fs_invalid = -1;
229 static gint ett_ndmp_tape_attr = -1;
230 static gint ett_ndmp_execute_cdb_flags = -1;
231 static gint ett_ndmp_execute_cdb_cdb = -1;
232 static gint ett_ndmp_execute_cdb_sns = -1;
233 static gint ett_ndmp_execute_cdb_payload = -1;
234 static gint ett_ndmp_tape_invalid = -1;
235 static gint ett_ndmp_tape_flags = -1;
236 static gint ett_ndmp_addr = -1;
237 static gint ett_ndmp_file = -1;
238 static gint ett_ndmp_file_name = -1;
239 static gint ett_ndmp_file_stats = -1;
240 static gint ett_ndmp_file_invalids = -1;
241 static gint ett_ndmp_state_invalids = -1;
242
243 static struct true_false_string yesno = { "Yes", "No" };
244
245 /* XXX someone should start adding the new stuff from v3, v4 and v5*/
246 #define NDMP_PROTOCOL_V2        1
247 #define NDMP_PROTOCOL_V3        2
248 #define NDMP_PROTOCOL_V4        3
249 #define NDMP_PROTOCOL_V5        4
250
251 static enum_val_t ndmp_protocol_versions[] = {
252         { "version2",   "Version 2",    NDMP_PROTOCOL_V2 },
253         { "version3",   "Version 3",    NDMP_PROTOCOL_V3 },
254         { "version4",   "Version 4",    NDMP_PROTOCOL_V4 },
255         { "version5",   "Version 5",    NDMP_PROTOCOL_V5 },
256         { NULL, NULL, 0 }
257 };
258
259 static gint ndmp_protocol_version = NDMP_PROTOCOL_V2;
260
261
262 struct ndmp_header {
263         guint32 seq;
264         guint32 time;
265         guint32 type;
266         guint32 msg;
267         guint32 rep_seq;
268         guint32 err;
269 };
270
271 /* desegmentation of NDMP packets */
272 static gboolean ndmp_desegment = TRUE;
273
274 /* defragmentation of fragmented NDMP records */
275 static gboolean ndmp_defragment = FALSE;
276
277 #define NDMP_MESSAGE_REQUEST    0x00
278 #define NDMP_MESSAGE_REPLY      0x01
279 static const value_string msg_type_vals[] = {
280         {NDMP_MESSAGE_REQUEST,          "Request"},
281         {NDMP_MESSAGE_REPLY,            "Reply"},
282         {0, NULL}
283 };
284
285 #define NDMP_NO_ERR                     0x00
286 #define NDMP_NOT_SUPPORTED_ERR          0x01
287 #define NDMP_DEVICE_BUSY_ERR            0x02
288 #define NDMP_DEVICE_OPENED_ERR          0x03
289 #define NDMP_NOT_AUTHORIZED_ERR         0x04
290 #define NDMP_PERMISSION_ERR             0x05
291 #define NDMP_DEV_NOT_OPEN_ERR           0x06
292 #define NDMP_IO_ERR                     0x07
293 #define NDMP_TIMEOUT_ERR                0x08
294 #define NDMP_ILLEGAL_ARGS_ERR           0x09
295 #define NDMP_NO_TAPE_LOADED_ERR         0x0a
296 #define NDMP_WRITE_PROTECT_ERR          0x0b
297 #define NDMP_EOF_ERR                    0x0c
298 #define NDMP_EOM_ERR                    0x0d
299 #define NDMP_FILE_NOT_FOUND_ERR         0x0e
300 #define NDMP_BAD_FILE_ERR               0x0f
301 #define NDMP_NO_DEVICE_ERR              0x10
302 #define NDMP_NO_BUS_ERR                 0x11
303 #define NDMP_XDR_DECODE_ERR             0x12
304 #define NDMP_ILLEGAL_STATE_ERR          0x13
305 #define NDMP_UNDEFINED_ERR              0x14
306 #define NDMP_XDR_ENCODE_ERR             0x15
307 #define NDMP_NO_MEM_ERR                 0x16
308 #define NDMP_CONNECT_ERR                0x17
309
310 static const value_string error_vals[] = {
311         {NDMP_NO_ERR,                   "NO_ERR"},
312         {NDMP_NOT_SUPPORTED_ERR,        "NOT_SUPPORTED_ERR"},
313         {NDMP_DEVICE_BUSY_ERR,          "DEVICE_BUSY_ERR"},
314         {NDMP_DEVICE_OPENED_ERR,        "DEVICE_OPENED_ERR"},
315         {NDMP_NOT_AUTHORIZED_ERR,       "NOT_AUTHORIZED_ERR"},
316         {NDMP_PERMISSION_ERR,           "PERMISSION_ERR"},
317         {NDMP_DEV_NOT_OPEN_ERR,         "DEV_NOT_OPEN_ERR"},
318         {NDMP_IO_ERR,                   "IO_ERR"},
319         {NDMP_TIMEOUT_ERR,              "TIMEOUT_ERR"},
320         {NDMP_ILLEGAL_ARGS_ERR,         "ILLEGAL_ARGS_ERR"},
321         {NDMP_NO_TAPE_LOADED_ERR,       "NO_TAPE_LOADED_ERR"},
322         {NDMP_WRITE_PROTECT_ERR,        "WRITE_PROTECT_ERR"},
323         {NDMP_EOF_ERR,                  "EOF_ERR"},
324         {NDMP_EOM_ERR,                  "EOM_ERR"},
325         {NDMP_FILE_NOT_FOUND_ERR,       "FILE_NOT_FOUND_ERR"},
326         {NDMP_BAD_FILE_ERR,             "BAD_FILE_ERR"},
327         {NDMP_NO_DEVICE_ERR,            "NO_DEVICE_ERR"},
328         {NDMP_NO_BUS_ERR,               "NO_BUS_ERR"},
329         {NDMP_XDR_DECODE_ERR,           "XDR_DECODE_ERR"},
330         {NDMP_ILLEGAL_STATE_ERR,        "ILLEGAL_STATE_ERR"},
331         {NDMP_UNDEFINED_ERR,            "UNDEFINED_ERR"},
332         {NDMP_XDR_ENCODE_ERR,           "XDR_ENCODE_ERR"},
333         {NDMP_NO_MEM_ERR,               "NO_MEM_ERR"},
334         {NDMP_CONNECT_ERR,              "CONNECT_ERR"},
335         {0, NULL}
336 };
337
338
339
340 #define NDMP_CONFIG_GET_HOST_INFO       0x100
341 #define NDMP_CONFIG_GET_CONNECTION_TYPE 0x102
342 #define NDMP_CONFIG_GET_AUTH_ATTR       0x103
343 #define NDMP_CONFIG_GET_BUTYPE_INFO     0x104
344 #define NDMP_CONFIG_GET_FS_INFO         0x105
345 #define NDMP_CONFIG_GET_TAPE_INFO       0x106
346 #define NDMP_CONFIG_GET_SCSI_INFO       0x107
347 #define NDMP_CONFIG_GET_SERVER_INFO     0x108
348 #define NDMP_SCSI_OPEN                  0x200
349 #define NDMP_SCSI_CLOSE                 0x201
350 #define NDMP_SCSI_GET_STATE             0x202
351 #define NDMP_SCSI_SET_TARGET            0x203
352 #define NDMP_SCSI_RESET_DEVICE          0x204
353 #define NDMP_SCSI_RESET_BUS             0x205
354 #define NDMP_SCSI_EXECUTE_CDB           0x206
355 #define NDMP_TAPE_OPEN                  0x300
356 #define NDMP_TAPE_CLOSE                 0x301
357 #define NDMP_TAPE_GET_STATE             0x302
358 #define NDMP_TAPE_MTIO                  0x303
359 #define NDMP_TAPE_WRITE                 0x304
360 #define NDMP_TAPE_READ                  0x305
361 #define NDMP_TAPE_EXECUTE_CDB           0x307
362 #define NDMP_DATA_GET_STATE             0x400
363 #define NDMP_DATA_START_BACKUP          0x401
364 #define NDMP_DATA_START_RECOVER         0x402
365 #define NDMP_DATA_ABORT                 0x403
366 #define NDMP_DATA_GET_ENV               0x404
367 #define NDMP_DATA_STOP                  0x407
368 #define NDMP_DATA_LISTEN                0x409
369 #define NDMP_DATA_CONNECT               0x40a
370 #define NDMP_NOTIFY_DATA_HALTED         0x501
371 #define NDMP_NOTIFY_CONNECTED           0x502
372 #define NDMP_NOTIFY_MOVER_HALTED        0x503
373 #define NDMP_NOTIFY_MOVER_PAUSED        0x504
374 #define NDMP_NOTIFY_DATA_READ           0x505
375 #define NDMP_LOG_FILE                   0x602
376 #define NDMP_LOG_MESSAGE                0x603
377 #define NDMP_FH_ADD_FILE                0x703
378 #define NDMP_FH_ADD_DIR                 0x704
379 #define NDMP_FH_ADD_NODE                0x705
380 #define NDMP_CONNECT_OPEN               0x900
381 #define NDMP_CONNECT_CLIENT_AUTH        0x901
382 #define NDMP_CONNECT_CLOSE              0x902
383 #define NDMP_CONNECT_SERVER_AUTH        0x903
384 #define NDMP_MOVER_GET_STATE            0xa00
385 #define NDMP_MOVER_LISTEN               0xa01
386 #define NDMP_MOVER_CONTINUE             0xa02
387 #define NDMP_MOVER_ABORT                0xa03
388 #define NDMP_MOVER_STOP                 0xa04
389 #define NDMP_MOVER_SET_WINDOW           0xa05
390 #define NDMP_MOVER_READ                 0xa06
391 #define NDMP_MOVER_CLOSE                0xa07
392 #define NDMP_MOVER_SET_RECORD_SIZE      0xa08
393 #define NDMP_MOVER_CONNECT              0xa09
394
395
396
397
398 static const value_string msg_vals[] = {
399         {NDMP_CONFIG_GET_HOST_INFO,     "CONFIG_GET_HOST_INFO"},
400         {NDMP_CONFIG_GET_CONNECTION_TYPE, "CONFIG_GET_CONNECTION_TYPE"},
401         {NDMP_CONFIG_GET_AUTH_ATTR,     "CONFIG_GET_AUTH_ATTR"},
402         {NDMP_CONFIG_GET_BUTYPE_INFO,   "CONFIG_GET_BUTYPE_INFO"},
403         {NDMP_CONFIG_GET_FS_INFO,       "CONFIG_GET_FS_INFO"},
404         {NDMP_CONFIG_GET_TAPE_INFO,     "CONFIG_GET_TAPE_INFO"},
405         {NDMP_CONFIG_GET_SCSI_INFO,     "CONFIG_GET_SCSI_INFO"},
406         {NDMP_CONFIG_GET_SERVER_INFO,   "CONFIG_GET_SERVER_INFO"},
407         {NDMP_SCSI_OPEN,                "SCSI_OPEN"},
408         {NDMP_SCSI_CLOSE,               "SCSI_CLOSE"},
409         {NDMP_SCSI_GET_STATE,           "SCSI_GET_STATE"},
410         {NDMP_SCSI_SET_TARGET,          "SCSI_SET_TARGET"},
411         {NDMP_SCSI_RESET_DEVICE,        "SCSI_RESET_DEVICE"},
412         {NDMP_SCSI_RESET_BUS,           "SCSI_RESET_BUS"},
413         {NDMP_SCSI_EXECUTE_CDB,         "SCSI_EXECUTE_CDB"},
414         {NDMP_TAPE_OPEN,                "TAPE_OPEN"},
415         {NDMP_TAPE_CLOSE,               "TAPE_CLOSE"},
416         {NDMP_TAPE_GET_STATE,           "TAPE_GET_STATE"},
417         {NDMP_TAPE_MTIO,                "TAPE_MTIO"},
418         {NDMP_TAPE_WRITE,               "TAPE_WRITE"},
419         {NDMP_TAPE_READ,                "TAPE_READ"},
420         {NDMP_TAPE_EXECUTE_CDB,         "TAPE_EXECUTE_CDB"},
421         {NDMP_DATA_GET_STATE,           "DATA_GET_STATE"},
422         {NDMP_DATA_START_BACKUP,        "DATA_START_BACKUP"},
423         {NDMP_DATA_START_RECOVER,       "DATA_START_RECOVER"},
424         {NDMP_DATA_ABORT,               "DATA_ABORT"},
425         {NDMP_DATA_GET_ENV,             "DATA_GET_ENV"},
426         {NDMP_DATA_STOP,                "DATA_STOP"},
427         {NDMP_DATA_LISTEN,              "DATA_LISTEN"},
428         {NDMP_DATA_CONNECT,             "DATA_CONNECT"},
429         {NDMP_NOTIFY_DATA_HALTED,       "NOTIFY_DATA_HALTED"},
430         {NDMP_NOTIFY_CONNECTED,         "NOTIFY_CONNECTED"},
431         {NDMP_NOTIFY_MOVER_HALTED,      "NOTIFY_MOVER_HALTED"},
432         {NDMP_NOTIFY_MOVER_PAUSED,      "NOTIFY_MOVER_PAUSED"},
433         {NDMP_NOTIFY_DATA_READ,         "NOTIFY_DATA_READ"},
434         {NDMP_LOG_FILE,                 "LOG_FILE"},
435         {NDMP_LOG_MESSAGE,              "LOG_MESSAGE"},
436         {NDMP_FH_ADD_FILE,              "FH_ADD_FILE"},
437         {NDMP_FH_ADD_DIR,               "FH_ADD_DIR"},
438         {NDMP_FH_ADD_NODE,              "FH_ADD_NODE"},
439         {NDMP_CONNECT_OPEN,             "CONNECT_OPEN"},
440         {NDMP_CONNECT_CLIENT_AUTH,      "CONNECT_CLIENT_AUTH"},
441         {NDMP_CONNECT_CLOSE,            "CONNECT_CLOSE"},
442         {NDMP_CONNECT_SERVER_AUTH,      "CONNECT_SERVER_AUTH"},
443         {NDMP_MOVER_GET_STATE,          "MOVER_GET_STATE"},
444         {NDMP_MOVER_LISTEN,             "MOVER_LISTEN"},
445         {NDMP_MOVER_CONTINUE,           "MOVER_CONTINUE"},
446         {NDMP_MOVER_ABORT,              "MOVER_ABORT"},
447         {NDMP_MOVER_STOP,               "MOVER_STOP"},
448         {NDMP_MOVER_SET_WINDOW,         "MOVER_SET_WINDOW"},
449         {NDMP_MOVER_READ,               "MOVER_READ"},
450         {NDMP_MOVER_CLOSE,              "MOVER_CLOSE"},
451         {NDMP_MOVER_SET_RECORD_SIZE,    "MOVER_SET_RECORD_SIZE"},
452         {NDMP_MOVER_CONNECT,            "MOVER_CONNECT"},
453         {0, NULL}
454 };
455
456 static int
457 dissect_connect_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
458     proto_tree *tree, guint32 seq _U_)
459 {
460         /* version number */
461         proto_tree_add_item(tree, hf_ndmp_version, tvb, offset, 4, FALSE);
462         offset += 4;
463
464         return offset;
465 }
466
467 static int
468 dissect_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
469     proto_tree *tree, guint32 seq _U_)
470 {
471         guint32 err;
472
473         /* error */
474         err=tvb_get_ntohl(tvb, offset);
475         proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
476         if(err && check_col(pinfo->cinfo, COL_INFO)) {
477                 col_append_fstr(pinfo->cinfo, COL_INFO, 
478                         " NDMP Error:%s",
479                         val_to_str(err, error_vals,
480                         "Unknown NDMP error code %#x"));
481         }
482         
483         offset += 4;
484
485         return offset;
486 }
487
488 static int
489 dissect_ndmp_get_host_info_reply(tvbuff_t *tvb, int offset,
490     packet_info *pinfo, proto_tree *tree, guint32 seq)
491 {
492         /* error */
493         offset=dissect_error(tvb, offset, pinfo, tree, seq);
494
495         /* hostname */
496         offset = dissect_rpc_string(tvb, tree,
497                         hf_ndmp_hostname, offset, NULL);
498
499         /* os type */
500         offset = dissect_rpc_string(tvb, tree,
501                         hf_ndmp_os_type, offset, NULL);
502
503         /* os version */
504         offset = dissect_rpc_string(tvb, tree,
505                         hf_ndmp_os_vers, offset, NULL);
506
507         /* hostid */
508         offset = dissect_rpc_string(tvb, tree,
509                         hf_ndmp_hostid, offset, NULL);
510
511         return offset;
512 }
513
514 #define NDMP_ADDR_LOCAL         0
515 #define NDMP_ADDR_TCP           1
516 #define NDMP_ADDR_FC            2
517 #define NDMP_ADDR_IPC           3
518 static const value_string addr_type_vals[] = {
519         {NDMP_ADDR_LOCAL,       "Local"},
520         {NDMP_ADDR_TCP,         "TCP"},
521         {NDMP_ADDR_FC,          "FC"},
522         {NDMP_ADDR_IPC,         "IPC"},
523         {0,NULL}
524 };
525
526 static int
527 dissect_ndmp_addr_type(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
528     proto_tree *tree)
529 {
530         proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, FALSE);
531         offset += 4;
532
533         return offset;
534 }
535
536 static int
537 dissect_ndmp_addr_msg(tvbuff_t *tvb, int offset, packet_info *pinfo,
538     proto_tree *tree, guint32 seq _U_)
539 {
540         /*address type*/
541         return dissect_ndmp_addr_type(tvb, offset, pinfo, tree);
542 }
543
544 static int
545 dissect_ndmp_config_get_connection_type_reply(tvbuff_t *tvb, int offset,
546     packet_info *pinfo, proto_tree *tree, guint32 seq)
547 {
548         /* error */
549         offset=dissect_error(tvb, offset, pinfo, tree, seq);
550
551         /* addr types */
552         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
553                         dissect_ndmp_addr_type, hf_ndmp_addr_types);
554
555         return offset;
556 }
557
558 #define NDMP_AUTH_NONE          0
559 #define NDMP_AUTH_TEXT          1
560 #define NDMP_AUTH_MD5           2
561 static const value_string auth_type_vals[] = {
562         {NDMP_AUTH_NONE,        "None"},
563         {NDMP_AUTH_TEXT,        "Text"},
564         {NDMP_AUTH_MD5,         "MD5"},
565         {0,NULL}
566 };
567 static int
568 dissect_auth_type(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
569     proto_tree *tree)
570 {
571         proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, FALSE);
572         offset += 4;
573
574         return offset;
575 }
576
577 static int
578 dissect_get_auth_type_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
579     proto_tree *tree, guint32 seq _U_)
580 {
581         /* auth type */
582         return dissect_auth_type(tvb, offset, pinfo, tree);
583 }
584
585 static int
586 dissect_auth_attr_msg(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
587     proto_tree *tree, guint32 seq _U_)
588 {
589         guint type;
590
591         type=tvb_get_ntohl(tvb,offset);
592
593         /* auth type */
594         proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, FALSE);
595         offset += 4;
596
597         switch(type){
598         case NDMP_AUTH_NONE:
599                 break;
600         case NDMP_AUTH_TEXT:
601                 break;
602         case NDMP_AUTH_MD5:
603                 proto_tree_add_item(tree, hf_ndmp_auth_challenge,
604                         tvb, offset, 64, FALSE);
605                 offset+=64;
606         }
607
608         return offset;
609 }
610
611 static int
612 dissect_default_env(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
613     proto_tree *tree)
614 {
615         /* name */
616         offset = dissect_rpc_string(tvb, tree,
617                         hf_ndmp_butype_env_name, offset, NULL);
618
619         /* value */
620         offset = dissect_rpc_string(tvb, tree,
621                         hf_ndmp_butype_env_value, offset, NULL);
622
623         return offset;
624 }
625
626
627 static const true_false_string tfs_butype_attr_backup_file_history = {
628         "Backup FILE HISTORY",
629         "Do NOT backup file history"
630 };
631 static const true_false_string tfs_butype_attr_backup_filelist = {
632         "Backup FILELIST",
633         "Do NOT backup filelist"
634 };
635 static const true_false_string tfs_butype_attr_recover_filelist = {
636         "Recover FILELIST",
637         "Do NOT recover filelist"
638 };
639 static const true_false_string tfs_butype_attr_backup_direct = {
640         "Perform DIRECT backup",
641         "Do NOT perform direct backup"
642 };
643 static const true_false_string tfs_butype_attr_recover_direct = {
644         "Perform DIRECT recovery",
645         "Do NOT perform direct recovery"
646 };
647 static const true_false_string tfs_butype_attr_backup_incremental = {
648         "Perform INCREMENTAL backup",
649         "Perform FULL backup"
650 };
651 static const true_false_string tfs_butype_attr_recover_incremental = {
652         "Perform INCREMENTAL revocery",
653         "Perform FULL recovery"
654 };
655 static const true_false_string tfs_butype_attr_backup_utf8 = {
656         "Backup using UTF8",
657         "Normal backup. Do NOT use utf8"
658 };
659 static const true_false_string tfs_butype_attr_recover_utf8 = {
660         "Recover using UTF8",
661         "Normal recover. Do NOT use utf8"
662 };
663 static int
664 dissect_butype_attrs(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
665     proto_tree *parent_tree)
666 {
667         proto_item* item = NULL;
668         proto_tree* tree = NULL;
669         guint32 flags;
670
671         flags=tvb_get_ntohl(tvb, offset);
672         if (parent_tree) {
673                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
674                                 "Attributes: 0x%08x", flags);
675                 tree = proto_item_add_subtree(item, ett_ndmp_butype_attrs);
676         }
677
678         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_utf8,
679                                 tvb, offset, 4, flags);
680         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_utf8,
681                                 tvb, offset, 4, flags);
682         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_incremental,
683                                 tvb, offset, 4, flags);
684         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_incremental,
685                                 tvb, offset, 4, flags);
686         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_direct,
687                                 tvb, offset, 4, flags);
688         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_direct,
689                                 tvb, offset, 4, flags);
690         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_filelist,
691                                 tvb, offset, 4, flags);
692         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_filelist,
693                                 tvb, offset, 4, flags);
694         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_file_history,
695                                 tvb, offset, 4, flags);
696
697         offset += 4;
698         return offset;
699 }
700
701 static int
702 dissect_butype_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
703 {
704         /*butype name*/
705         offset = dissect_rpc_string(tvb, tree,
706                         hf_ndmp_butype_name, offset, NULL);
707
708         /* default env */
709         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
710                         dissect_default_env, hf_ndmp_butype_default_env);
711
712         /* attrs */
713         offset = dissect_butype_attrs(tvb, offset, pinfo, tree);
714
715         return offset;
716 }
717
718 static int
719 dissect_get_butype_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
720     proto_tree *tree, guint32 seq)
721 {
722         /* error */
723         offset=dissect_error(tvb, offset, pinfo, tree, seq);
724
725         /* butype */
726         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
727                         dissect_butype_info, hf_ndmp_butype_info);
728
729         return offset;
730 }
731
732 static const true_false_string tfs_fs_invalid_total_size = {
733         "Total size is INVALID",
734         "Total size is VALID"
735 };
736 static const true_false_string tfs_fs_invalid_used_size = {
737         "Used size is INVALID",
738         "Used size is VALID"
739 };
740 static const true_false_string tfs_fs_invalid_avail_size = {
741         "Available size is INVALID",
742         "Available size is VALID"
743 };
744 static const true_false_string tfs_fs_invalid_total_inodes = {
745         "Total inode count is INVALID",
746         "Total inode count is VALID"
747 };
748 static const true_false_string tfs_fs_invalid_used_inodes = {
749         "Used inode count is INVALID",
750         "Used inode count is VALID"
751 };
752 static int
753 dissect_fs_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
754     proto_tree *parent_tree)
755 {
756         proto_item* item = NULL;
757         proto_tree* tree = NULL;
758         guint32 flags;
759
760         flags=tvb_get_ntohl(tvb, offset);
761         if (parent_tree) {
762                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
763                                 "Invalids: 0x%08x", flags);
764                 tree = proto_item_add_subtree(item, ett_ndmp_fs_invalid);
765         }
766
767         proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_used_inodes,
768                                 tvb, offset, 4, flags);
769         proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_total_inodes,
770                                 tvb, offset, 4, flags);
771         proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_avail_size,
772                                 tvb, offset, 4, flags);
773         proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_used_size,
774                                 tvb, offset, 4, flags);
775         proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_total_size,
776                                 tvb, offset, 4, flags);
777
778         offset+=4;
779         return offset;
780 }
781
782 static int
783 dissect_fs_env(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
784     proto_tree *tree)
785 {
786         /* name */
787         offset = dissect_rpc_string(tvb, tree,
788                         hf_ndmp_fs_env_name, offset, NULL);
789
790         /* value */
791         offset = dissect_rpc_string(tvb, tree,
792                         hf_ndmp_fs_env_value, offset, NULL);
793
794         return offset;
795 }
796
797 static int
798 dissect_fs_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
799 {
800         /* invalid bits */
801         offset=dissect_fs_invalid(tvb, offset, pinfo, tree);
802
803         /* fs type */
804         offset = dissect_rpc_string(tvb, tree,
805                         hf_ndmp_fs_fs_type, offset, NULL);
806
807         /* fs logical device */
808         offset = dissect_rpc_string(tvb, tree,
809                         hf_ndmp_fs_logical_device, offset, NULL);
810
811         /* fs physical device */
812         offset = dissect_rpc_string(tvb, tree,
813                         hf_ndmp_fs_physical_device, offset, NULL);
814
815         /*total_size*/
816         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_total_size,
817                         offset);
818
819         /*used_size*/
820         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_used_size,
821                         offset);
822
823         /*avail_size*/
824         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_avail_size,
825                         offset);
826
827         /*total_inodes*/
828         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_total_inodes,
829                         offset);
830
831         /*used_inodes*/
832         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_used_inodes,
833                         offset);
834
835         /* env */
836         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
837                         dissect_fs_env, hf_ndmp_fs_env);
838
839         /* status */
840         offset = dissect_rpc_string(tvb, tree,
841                         hf_ndmp_fs_status, offset, NULL);
842
843         return offset;
844 }
845
846 static int
847 dissect_get_fs_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
848     proto_tree *tree, guint32 seq)
849 {
850         /* error */
851         offset=dissect_error(tvb, offset, pinfo, tree, seq);
852
853         /* fs */
854         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
855                         dissect_fs_info, hf_ndmp_fs_info);
856
857         return offset;
858 }
859
860 static const true_false_string tfs_tape_attr_rewind = {
861         "Device supports REWIND",
862         "Device does NOT support rewind"
863 };
864 static const true_false_string tfs_tape_attr_unload = {
865         "Device supports UNLOAD",
866         "Device does NOT support unload"
867 };
868 static int
869 dissect_tape_attr(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
870     proto_tree *parent_tree)
871 {
872         proto_item* item = NULL;
873         proto_tree* tree = NULL;
874         guint32 flags;
875
876         flags=tvb_get_ntohl(tvb, offset);
877         if (parent_tree) {
878                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
879                                 "Attributes: 0x%08x", flags);
880                 tree = proto_item_add_subtree(item, ett_ndmp_tape_attr);
881         }
882
883         proto_tree_add_boolean(tree, hf_ndmp_tape_attr_unload,
884                                 tvb, offset, 4, flags);
885         proto_tree_add_boolean(tree, hf_ndmp_tape_attr_rewind,
886                                 tvb, offset, 4, flags);
887
888         offset+=4;
889         return offset;
890 }
891
892 static int
893 dissect_tape_capability(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
894     proto_tree *tree)
895 {
896         /* name */
897         offset = dissect_rpc_string(tvb, tree,
898                         hf_ndmp_tape_capability_name, offset, NULL);
899
900         /* value */
901         offset = dissect_rpc_string(tvb, tree,
902                         hf_ndmp_tape_capability_value, offset, NULL);
903
904         return offset;
905 }
906
907 static int
908 dissect_tape_dev_cap(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
909 {
910         /* device */
911         offset = dissect_rpc_string(tvb, tree,
912                         hf_ndmp_tape_device, offset, NULL);
913
914         /* tape attributes */
915         offset = dissect_tape_attr(tvb, offset, pinfo, tree);
916
917         /* capability */
918         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
919                         dissect_tape_capability, hf_ndmp_tape_capability);
920
921         return offset;
922 }
923
924 static int
925 dissect_tape_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
926 {
927         /* model */
928         offset = dissect_rpc_string(tvb, tree,
929                         hf_ndmp_tape_model, offset, NULL);
930
931         /* device capabilites */
932         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
933                         dissect_tape_dev_cap, hf_ndmp_tape_dev_cap);
934
935         return offset;
936 }
937
938 static int
939 dissect_get_tape_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
940     proto_tree *tree, guint32 seq)
941 {
942         /* error */
943         offset=dissect_error(tvb, offset, pinfo, tree, seq);
944
945         /* tape */
946         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
947                         dissect_tape_info, hf_ndmp_tape_info);
948
949         return offset;
950 }
951
952 static int
953 dissect_scsi_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
954 {
955         /* model */
956         offset = dissect_rpc_string(tvb, tree,
957                         hf_ndmp_scsi_model, offset, NULL);
958
959         /* device capabilites */
960         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
961                         dissect_tape_dev_cap, hf_ndmp_tape_dev_cap);
962
963         return offset;
964 }
965
966 static int
967 dissect_get_scsi_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
968     proto_tree *tree, guint32 seq)
969 {
970         /* error */
971         offset=dissect_error(tvb, offset, pinfo, tree, seq);
972
973         /* scsi */
974         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
975                         dissect_scsi_info, hf_ndmp_scsi_info);
976
977         return offset;
978 }
979
980 static int
981 dissect_get_server_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
982     proto_tree *tree, guint32 seq)
983 {
984         /* error */
985         offset=dissect_error(tvb, offset, pinfo, tree, seq);
986
987         /* vendor */
988         offset = dissect_rpc_string(tvb, tree,
989                         hf_ndmp_server_vendor, offset, NULL);
990
991         /* product */
992         offset = dissect_rpc_string(tvb, tree,
993                         hf_ndmp_server_product, offset, NULL);
994
995         /* revision */
996         offset = dissect_rpc_string(tvb, tree,
997                         hf_ndmp_server_revision, offset, NULL);
998
999
1000         /* server */
1001         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1002                         dissect_auth_type, hf_ndmp_auth_types);
1003
1004         return offset;
1005 }
1006
1007 static int
1008 dissect_scsi_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1009     proto_tree *tree, guint32 seq _U_)
1010 {
1011         /* device */
1012         offset = dissect_rpc_string(tvb, tree,
1013                         hf_ndmp_scsi_device, offset, NULL);
1014
1015         return offset;
1016 }
1017
1018 static int
1019 dissect_scsi_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1020     proto_tree *tree, guint32 seq)
1021 {
1022         /* error */
1023         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1024
1025         /* controller */
1026         proto_tree_add_item(tree, hf_ndmp_scsi_controller, tvb, offset, 4, FALSE);
1027         offset += 4;
1028
1029         /* id */
1030         proto_tree_add_item(tree, hf_ndmp_scsi_id, tvb, offset, 4, FALSE);
1031         offset += 4;
1032
1033         /* lun */
1034         proto_tree_add_item(tree, hf_ndmp_scsi_lun, tvb, offset, 4, FALSE);
1035         offset += 4;
1036
1037         return offset;
1038 }
1039
1040 static int
1041 dissect_scsi_set_state_request(tvbuff_t *tvb, int offset,
1042     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
1043 {
1044         /* device */
1045         offset = dissect_rpc_string(tvb, tree,
1046                         hf_ndmp_scsi_device, offset, NULL);
1047
1048         /* controller */
1049         proto_tree_add_item(tree, hf_ndmp_scsi_controller, tvb, offset, 4, FALSE);
1050         offset += 4;
1051
1052         /* id */
1053         proto_tree_add_item(tree, hf_ndmp_scsi_id, tvb, offset, 4, FALSE);
1054         offset += 4;
1055
1056         /* lun */
1057         proto_tree_add_item(tree, hf_ndmp_scsi_lun, tvb, offset, 4, FALSE);
1058         offset += 4;
1059
1060         return offset;
1061 }
1062
1063 static int
1064 dissect_execute_cdb_flags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1065     proto_tree *parent_tree)
1066 {
1067         proto_item* item = NULL;
1068         proto_tree* tree = NULL;
1069         guint32 flags;
1070
1071         flags = tvb_get_ntohl(tvb, offset);
1072         if (parent_tree) {
1073                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
1074                                 "Flags: 0x%08x", flags);
1075                 tree = proto_item_add_subtree(item, ett_ndmp_execute_cdb_flags);
1076         }
1077
1078         proto_tree_add_boolean(tree, hf_ndmp_execute_cdb_flags_data_in,
1079                                 tvb, offset, 4, flags);
1080         proto_tree_add_boolean(tree, hf_ndmp_execute_cdb_flags_data_out,
1081                                 tvb, offset, 4, flags);
1082         offset += 4;
1083         return offset;
1084 }
1085
1086 static int
1087 dissect_execute_cdb_cdb(tvbuff_t *tvb, int offset, packet_info *pinfo,
1088     proto_tree *parent_tree, gint devtype)
1089 {
1090         proto_item* item = NULL;
1091         proto_tree* tree = NULL;
1092         guint32 cdb_len;
1093         guint32 cdb_len_full;
1094
1095         cdb_len = tvb_get_ntohl(tvb, offset);
1096         cdb_len_full = rpc_roundup(cdb_len);
1097
1098         if (parent_tree) {
1099                 item = proto_tree_add_text(parent_tree, tvb, offset,
1100                                 4+cdb_len_full, "CDB");
1101                 tree = proto_item_add_subtree(item, ett_ndmp_execute_cdb_cdb);
1102         }
1103
1104         proto_tree_add_uint(tree, hf_ndmp_execute_cdb_cdb_len, tvb, offset, 4,
1105                         cdb_len);
1106         offset += 4;
1107
1108         if (cdb_len != 0) {
1109                 tvbuff_t *cdb_tvb;
1110                 int tvb_len, tvb_rlen;
1111
1112                 tvb_len=tvb_length_remaining(tvb, offset);
1113                 if(tvb_len>16)
1114                         tvb_len=16;
1115                 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1116                 if(tvb_rlen>16)
1117                         tvb_rlen=16;
1118                 cdb_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1119                 dissect_scsi_cdb(cdb_tvb, pinfo, tree, devtype, 0xffff);
1120                 offset += cdb_len_full;
1121         }
1122
1123         return offset;
1124 }
1125
1126
1127 static int
1128 dissect_execute_cdb_payload(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree,
1129     char *name, int hf_len, gboolean isreq)
1130 {
1131         proto_item* item = NULL;
1132         proto_tree* tree = NULL;
1133         guint32 payload_len;
1134         guint32 payload_len_full;
1135
1136         payload_len = tvb_get_ntohl(tvb, offset);
1137         payload_len_full = rpc_roundup(payload_len);
1138
1139         if (parent_tree) {
1140                 item = proto_tree_add_text(parent_tree, tvb, offset,
1141                                 4+payload_len_full, "%s", name);
1142                 tree = proto_item_add_subtree(item,
1143                     ett_ndmp_execute_cdb_payload);
1144         }
1145
1146         proto_tree_add_uint(tree, hf_len, tvb, offset, 4, payload_len);
1147         offset += 4;
1148
1149         if (payload_len != 0) {
1150                 tvbuff_t *data_tvb;
1151                 int tvb_len, tvb_rlen;
1152
1153                 tvb_len=tvb_length_remaining(tvb, offset);
1154                 if(tvb_len>(int)payload_len)
1155                         tvb_len=payload_len;
1156                 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1157                 if(tvb_rlen>(int)payload_len)
1158                         tvb_rlen=payload_len;
1159                 data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1160
1161                 dissect_scsi_payload(data_tvb, pinfo, tree, isreq,
1162                     0xffff);
1163                 offset += payload_len_full;
1164         }
1165
1166         return offset;
1167 }
1168
1169 /*
1170  * XXX - we assume that NDMP_SCSI_EXECUTE_CDB requests only go to SCSI Media
1171  * Changer devices and NDMP_TAPE_EXECUTE_CDB only go to SCSI Sequential
1172  * Access devices.
1173  *
1174  * If that's not the case, we'll have to use the SCSI dissector's mechanisms
1175  * for saving inquiry data for devices, and use inquiry data when available.
1176  * Unfortunately, that means we need to save the name of the device, and
1177  * use it as a device identifier; as the name isn't available in the
1178  * NDMP_SCSI_EXECUTE_CDB or NDMP_TAPE_EXECUTE_CDB messages, that means
1179  * we need to remember the currently-opened "SCSI" and "TAPE" devices
1180  * from NDMP_SCSI_OPEN and NDMP_TAPE_OPEN, and attach to all frames
1181  * that are the ones that trigger the dissection of NDMP_SCSI_EXECUTE_CDB
1182  * or NDMP_TAPE_EXECUTE_CDB requests pointers to those names.
1183  */
1184 static int
1185 dissect_execute_cdb_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
1186     proto_tree *tree, guint32 seq, gint devtype)
1187 {
1188         conversation_t *conversation;
1189         scsi_task_id_t task_key;
1190
1191         /*
1192          * We need to provide SCSI task information to the SCSI
1193          * dissection routines.  We use a conversation plus the
1194          * sequence number in requests and the reply sequence
1195          * number in replies to identify SCSI tasks.
1196          */
1197         conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1198             pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
1199         if (conversation == NULL) {
1200                 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1201                     pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
1202         }
1203         task_key.conv_id = conversation->index;
1204         task_key.task_id = seq;
1205         pinfo->private_data = &task_key;
1206
1207         /* flags */
1208         offset = dissect_execute_cdb_flags(tvb, offset, pinfo, tree);
1209
1210         /* timeout */
1211         proto_tree_add_item(tree, hf_ndmp_execute_cdb_timeout, tvb, offset, 4, FALSE);
1212         offset += 4;
1213
1214         /* datain_len */
1215         proto_tree_add_item(tree, hf_ndmp_execute_cdb_datain_len, tvb, offset, 4, FALSE);
1216         offset += 4;
1217
1218         /* CDB */
1219         offset = dissect_execute_cdb_cdb(tvb, offset, pinfo, tree, devtype);
1220
1221         /* dataout */
1222         offset = dissect_execute_cdb_payload(tvb, offset, pinfo, tree,
1223             "Data out", hf_ndmp_execute_cdb_dataout_len, TRUE);
1224
1225         return offset;
1226 }
1227
1228 static int
1229 dissect_execute_cdb_request_mc(tvbuff_t *tvb, int offset, packet_info *pinfo,
1230     proto_tree *tree, guint32 seq)
1231 {
1232         return dissect_execute_cdb_request(tvb, offset, pinfo, tree, seq,
1233             SCSI_DEV_SMC);
1234 }
1235
1236 static int
1237 dissect_execute_cdb_request_tape(tvbuff_t *tvb, int offset, packet_info *pinfo,
1238     proto_tree *tree, guint32 seq)
1239 {
1240         return dissect_execute_cdb_request(tvb, offset, pinfo, tree, seq,
1241             SCSI_DEV_SSC);
1242 }
1243
1244 static int
1245 dissect_execute_cdb_sns(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
1246 {
1247         proto_item* item = NULL;
1248         proto_tree* tree = NULL;
1249         guint32 sns_len;
1250         guint32 sns_len_full;
1251
1252         sns_len = tvb_get_ntohl(tvb, offset);
1253         sns_len_full = rpc_roundup(sns_len);
1254
1255         if (parent_tree) {
1256                 item = proto_tree_add_text(parent_tree, tvb, offset,
1257                                 4+sns_len_full, "Sense data");
1258                 tree = proto_item_add_subtree(item, ett_ndmp_execute_cdb_sns);
1259         }
1260
1261         proto_tree_add_uint(tree, hf_ndmp_execute_cdb_sns_len, tvb, offset, 4,
1262                         sns_len);
1263         offset += 4;
1264
1265         if (sns_len != 0) {
1266                 dissect_scsi_snsinfo(tvb, pinfo, tree, offset, sns_len, 0xffff);
1267                 offset += sns_len_full;
1268         }
1269
1270         return offset;
1271 }
1272
1273 static int
1274 dissect_execute_cdb_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1275     proto_tree *tree, guint32 seq)
1276 {
1277         conversation_t *conversation;
1278         scsi_task_id_t task_key;
1279
1280         /*
1281          * We need to provide SCSI task information to the SCSI
1282          * dissection routines.  We use a conversation plus the
1283          * sequence number in requests and the reply sequence
1284          * number in replies to identify SCSI tasks.
1285          */
1286         conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1287             pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
1288         if (conversation != NULL) {
1289                 task_key.conv_id = conversation->index;
1290                 task_key.task_id = seq;
1291                 pinfo->private_data = &task_key;
1292         } else {
1293                 /* no conversation, meaning we didn't see the request */
1294                 pinfo->private_data = NULL;
1295         }
1296
1297         /* error */
1298         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1299
1300         /* status */
1301         proto_tree_add_item(tree, hf_ndmp_execute_cdb_status, tvb, offset, 4, FALSE);
1302         offset += 4;
1303
1304         /* dataout_len */
1305         proto_tree_add_item(tree, hf_ndmp_execute_cdb_dataout_len, tvb, offset, 4, FALSE);
1306         offset += 4;
1307
1308         /* datain */
1309         offset = dissect_execute_cdb_payload(tvb, offset, pinfo, tree,
1310             "Data in", hf_ndmp_execute_cdb_datain_len, FALSE);
1311
1312         /* ext_sense */
1313         offset = dissect_execute_cdb_sns(tvb, offset, pinfo, tree);
1314
1315         return offset;
1316 }
1317
1318 #define NDMP_TAPE_OPEN_MODE_READ        0
1319 #define NDMP_TAPE_OPEN_MODE_RDWR        1
1320 static const value_string tape_open_mode_vals[] = {
1321         {NDMP_TAPE_OPEN_MODE_READ,      "Read"},
1322         {NDMP_TAPE_OPEN_MODE_RDWR,      "Read/Write"},
1323         {0, NULL}
1324 };
1325
1326 static int
1327 dissect_tape_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1328     proto_tree *tree, guint32 seq _U_)
1329 {
1330         /* device */
1331         offset = dissect_rpc_string(tvb, tree,
1332                         hf_ndmp_tape_device, offset, NULL);
1333
1334         /* open mode */
1335         proto_tree_add_item(tree, hf_ndmp_tape_open_mode, tvb, offset, 4, FALSE);
1336         offset += 4;
1337
1338         return offset;
1339 }
1340
1341
1342 static const true_false_string tfs_ndmp_tape_invalid_file_num = {
1343         "File num is valid",
1344         "File num is INVALID"
1345 };
1346 static const true_false_string tfs_ndmp_tape_invalid_soft_errors = {
1347         "Soft errors is valid",
1348         "Soft errors is INVALID"
1349 };
1350 static const true_false_string tfs_ndmp_tape_invalid_block_size = {
1351         "Block size is valid",
1352         "Block size is INVALID"
1353 };
1354 static const true_false_string tfs_ndmp_tape_invalid_block_no = {
1355         "Block no is valid",
1356         "Block no is INVALID"
1357 };
1358 static const true_false_string tfs_ndmp_tape_invalid_total_space = {
1359         "Total space is valid",
1360         "Total space is INVALID"
1361 };
1362 static const true_false_string tfs_ndmp_tape_invalid_space_remain = {
1363         "Space remaining is INVALID",
1364         "Space remaining is valid"
1365 };
1366 static const true_false_string tfs_ndmp_tape_invalid_partition = {
1367         "Partition is INVALID",
1368         "Partition is valid"
1369 };
1370 static int
1371 dissect_tape_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1372     proto_tree *parent_tree)
1373 {
1374         proto_item* item = NULL;
1375         proto_tree* tree = NULL;
1376         guint32 flags;
1377
1378         flags=tvb_get_ntohl(tvb, offset);
1379         if (parent_tree) {
1380                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
1381                                 "Invalids: 0x%08x", flags);
1382                 tree = proto_item_add_subtree(item, ett_ndmp_tape_invalid);
1383         }
1384
1385         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_partition,
1386                                 tvb, offset, 4, flags);
1387         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_space_remain,
1388                                 tvb, offset, 4, flags);
1389         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_total_space,
1390                                 tvb, offset, 4, flags);
1391         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_block_no,
1392                                 tvb, offset, 4, flags);
1393         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_block_size,
1394                                 tvb, offset, 4, flags);
1395         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_soft_errors,
1396                                 tvb, offset, 4, flags);
1397         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_file_num,
1398                                 tvb, offset, 4, flags);
1399
1400         offset+=4;
1401         return offset;
1402 }
1403
1404 static const true_false_string tfs_ndmp_tape_flags_no_rewind = {
1405         "This is a NON-REWINDING device",
1406         "This device supports rewind"
1407 };
1408 static const true_false_string tfs_ndmp_tape_flags_write_protect = {
1409         "This device is WRITE-PROTECTED",
1410         "This device is NOT write-protected"
1411 };
1412 static const true_false_string tfs_ndmp_tape_flags_error = {
1413         "This device shows ERROR",
1414         "This device shows NO errors"
1415 };
1416 static const true_false_string tfs_ndmp_tape_flags_unload = {
1417         "This device supports UNLOAD",
1418         "This device does NOT support unload"
1419 };
1420 static int
1421 dissect_tape_flags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1422     proto_tree *parent_tree)
1423 {
1424         proto_item* item = NULL;
1425         proto_tree* tree = NULL;
1426         guint32 flags;
1427
1428         flags=tvb_get_ntohl(tvb, offset);
1429         if (parent_tree) {
1430                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
1431                                 "Flags: 0x%08x", flags);
1432                 tree = proto_item_add_subtree(item, ett_ndmp_tape_flags);
1433         }
1434
1435
1436         proto_tree_add_boolean(tree, hf_ndmp_tape_flags_unload,
1437                                 tvb, offset, 4, flags);
1438         proto_tree_add_boolean(tree, hf_ndmp_tape_flags_error,
1439                                 tvb, offset, 4, flags);
1440         proto_tree_add_boolean(tree, hf_ndmp_tape_flags_write_protect,
1441                                 tvb, offset, 4, flags);
1442         proto_tree_add_boolean(tree, hf_ndmp_tape_flags_no_rewind,
1443                                 tvb, offset, 4, flags);
1444
1445         offset+=4;
1446         return offset;
1447 }
1448
1449 static int
1450 dissect_tape_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1451     proto_tree *tree, guint32 seq)
1452 {
1453         /* invalid bits */
1454         offset=dissect_tape_invalid(tvb, offset, pinfo, tree);
1455
1456         /* error */
1457         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1458
1459         /* flags */
1460         offset=dissect_tape_flags(tvb, offset, pinfo, tree);
1461
1462         /* file_num */
1463         proto_tree_add_item(tree, hf_ndmp_tape_file_num, tvb, offset, 4, FALSE);
1464         offset += 4;
1465
1466         /* soft_errors */
1467         proto_tree_add_item(tree, hf_ndmp_tape_soft_errors, tvb, offset, 4, FALSE);
1468         offset += 4;
1469
1470         /* block_size */
1471         proto_tree_add_item(tree, hf_ndmp_tape_block_size, tvb, offset, 4, FALSE);
1472         offset += 4;
1473
1474         /* block_no */
1475         proto_tree_add_item(tree, hf_ndmp_tape_block_no, tvb, offset, 4, FALSE);
1476         offset += 4;
1477
1478         /* total_space */
1479         offset = dissect_rpc_uint64(tvb, tree,hf_ndmp_tape_total_space,
1480                         offset);
1481
1482         /* space_remain */
1483         offset = dissect_rpc_uint64(tvb, tree,hf_ndmp_tape_space_remain,
1484                         offset);
1485
1486         /* partition */
1487         proto_tree_add_item(tree, hf_ndmp_tape_partition, tvb, offset, 4, FALSE);
1488         offset += 4;
1489
1490         return offset;
1491 }
1492
1493 #define NDMP_TAPE_MTIO_FSF      0
1494 #define NDMP_TAPE_MTIO_BSF      1
1495 #define NDMP_TAPE_MTIO_FSR      2
1496 #define NDMP_TAPE_MTIO_BSR      3
1497 #define NDMP_TAPE_MTIO_REW      4
1498 #define NDMP_TAPE_MTIO_EOF      5
1499 #define NDMP_TAPE_MTIO_OFF      6
1500 static const value_string tape_mtio_vals[] = {
1501         {NDMP_TAPE_MTIO_FSF,    "FSF"},
1502         {NDMP_TAPE_MTIO_BSF,    "BSF"},
1503         {NDMP_TAPE_MTIO_FSR,    "FSR"},
1504         {NDMP_TAPE_MTIO_BSR,    "BSR"},
1505         {NDMP_TAPE_MTIO_REW,    "REW"},
1506         {NDMP_TAPE_MTIO_EOF,    "EOF"},
1507         {NDMP_TAPE_MTIO_OFF,    "OFF"},
1508         {0, NULL}
1509 };
1510
1511 static int
1512 dissect_tape_mtio_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1513     proto_tree *tree, guint32 seq _U_)
1514 {
1515         /* op */
1516         proto_tree_add_item(tree, hf_ndmp_tape_mtio_op, tvb, offset, 4, FALSE);
1517         offset += 4;
1518
1519         /* count */
1520         proto_tree_add_item(tree, hf_ndmp_count, tvb, offset, 4, FALSE);
1521         offset += 4;
1522
1523         return offset;
1524 }
1525
1526 static int
1527 dissect_tape_mtio_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1528     proto_tree *tree, guint32 seq)
1529 {
1530         /* error */
1531         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1532
1533         /* resid count */
1534         proto_tree_add_item(tree, hf_ndmp_resid_count, tvb, offset, 4, FALSE);
1535         offset += 4;
1536
1537         return offset;
1538 }
1539
1540 #define NDMP_MOVER_STATE_IDLE           0
1541 #define NDMP_MOVER_STATE_LISTEN         1
1542 #define NDMP_MOVER_STATE_ACTIVE         2
1543 #define NDMP_MOVER_STATE_PAUSED         3
1544 #define NDMP_MOVER_STATE_HALTED         4
1545 static const value_string mover_state_vals[] = {
1546         {NDMP_MOVER_STATE_IDLE, "MOVER_STATE_IDLE"},
1547         {NDMP_MOVER_STATE_LISTEN,       "MOVER_STATE_LISTEN"},
1548         {NDMP_MOVER_STATE_ACTIVE,       "MOVER_STATE_ACTIVE"},
1549         {NDMP_MOVER_STATE_PAUSED,       "MOVER_STATE_PAUSED"},
1550         {NDMP_MOVER_STATE_HALTED,       "MOVER_STATE_HALTED"},
1551         {0, NULL}
1552 };
1553
1554 #define NDMP_MOVER_PAUSE_NA             0
1555 #define NDMP_MOVER_PAUSE_EOM            1
1556 #define NDMP_MOVER_PAUSE_EOF            2
1557 #define NDMP_MOVER_PAUSE_SEEK           3
1558 #define NDMP_MOVER_PAUSE_MEDIA_ERROR    4
1559 #define NDMP_MOVER_PAUSE_EOW            5
1560 static const value_string mover_pause_vals[] = {
1561         {NDMP_MOVER_PAUSE_NA,           "MOVER_PAUSE_NA"},
1562         {NDMP_MOVER_PAUSE_EOM,          "MOVER_PAUSE_EOM"},
1563         {NDMP_MOVER_PAUSE_EOF,          "MOVER_PAUSE_EOF"},
1564         {NDMP_MOVER_PAUSE_SEEK,         "MOVER_PAUSE_SEEK"},
1565         {NDMP_MOVER_PAUSE_MEDIA_ERROR,  "MOVER_PAUSE_MEDIA_ERROR"},
1566         {NDMP_MOVER_PAUSE_EOW,          "MOVER_PAUSE_EOW"},
1567         {0, NULL}
1568 };
1569
1570 #define NDMP_HALT_NA            0
1571 #define NDMP_HALT_CONNECT_CLOSE 1
1572 #define NDMP_HALT_ABORTED               2
1573 #define NDMP_HALT_INTERNAL_ERROR        3
1574 #define NDMP_HALT_CONNECT_ERROR 4
1575 static const value_string halt_vals[] = {
1576         {NDMP_HALT_NA,                  "HALT_NA"},
1577         {NDMP_HALT_CONNECT_CLOSE,       "HALT_CONNECT_CLOSE"},
1578         {NDMP_HALT_ABORTED,             "HALT_ABORTED"},
1579         {NDMP_HALT_INTERNAL_ERROR,      "HALT_INTERNAL_ERROR"},
1580         {NDMP_HALT_CONNECT_ERROR,       "HALT_CONNECT_ERROR"},
1581         {0, NULL}
1582 };
1583
1584 static int
1585 dissect_tcp_env(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1586 {
1587         /* name */
1588         offset = dissect_rpc_string(tvb, tree,
1589                         hf_ndmp_tcp_env_name, offset, NULL);
1590
1591         /* value */
1592         offset = dissect_rpc_string(tvb, tree,
1593                         hf_ndmp_tcp_env_value, offset, NULL);
1594
1595         return offset;
1596 }
1597
1598
1599 static int
1600 dissect_ndmp_v4_tcp_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
1601 {
1602         /* IP addr */
1603         proto_tree_add_item(tree, hf_ndmp_addr_ip, tvb, offset, 4, FALSE);
1604         offset+=4;
1605
1606         /* TCP port */
1607         proto_tree_add_item(tree, hf_ndmp_addr_tcp, tvb, offset, 4, FALSE);
1608         offset+=4;
1609
1610         /* addr_env */
1611         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1612                         dissect_tcp_env, hf_ndmp_tcp_default_env);
1613
1614         return offset;
1615 }
1616
1617 static int
1618 dissect_ndmp_addr(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1619     proto_tree *parent_tree)
1620 {
1621         proto_item* item = NULL;
1622         proto_tree* tree = NULL;
1623         guint32 type;
1624
1625         type=tvb_get_ntohl(tvb, offset);
1626         if (parent_tree) {
1627                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
1628                                 "Type: %s ", val_to_str(type, addr_type_vals,"Unknown addr type (0x%02x)") );
1629                 tree = proto_item_add_subtree(item, ett_ndmp_addr);
1630         }
1631
1632         /*address type*/
1633         proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, FALSE);
1634         offset += 4;
1635
1636
1637         switch(type){
1638         case NDMP_ADDR_LOCAL:
1639                 break;
1640         case NDMP_ADDR_TCP:
1641                 /* this became an array in version 4 and beyond */
1642                 if(ndmp_protocol_version<NDMP_PROTOCOL_V4){
1643                         /* IP addr */
1644                         proto_tree_add_item(tree, hf_ndmp_addr_ip, tvb, offset, 4, FALSE);
1645                         offset+=4;
1646         
1647                         /* TCP port */
1648                         proto_tree_add_item(tree, hf_ndmp_addr_tcp, tvb, offset, 4, FALSE);
1649                         offset+=4;
1650                 } else {
1651                         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1652                                 dissect_ndmp_v4_tcp_addr, hf_ndmp_tcp_addr_list);
1653
1654                 }
1655
1656                 break;
1657         case NDMP_ADDR_FC:
1658                 /* FCAL loop id */
1659                 proto_tree_add_item(tree, hf_ndmp_addr_fcal_loop_id, tvb, offset, 4, FALSE);
1660                 offset+=4;
1661
1662                 break;
1663         case NDMP_ADDR_IPC:
1664                 /* IPC address */
1665                 offset = dissect_rpc_data(tvb, tree, hf_ndmp_addr_ipc, offset);
1666                 break;
1667         }
1668
1669         return offset;
1670 }
1671
1672 static int
1673 dissect_data_connect_msg(tvbuff_t *tvb, int offset, packet_info *pinfo,
1674     proto_tree *tree, guint32 seq _U_)
1675 {
1676         /* ndmp addr */
1677         offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
1678         return offset;
1679 }
1680
1681
1682 static int
1683 dissect_mover_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1684     proto_tree *tree, guint32 seq)
1685 {
1686         /* error */
1687         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1688
1689         /* mode is only present in version 4 and beyond */
1690         if(ndmp_protocol_version>=NDMP_PROTOCOL_V4){
1691                 proto_tree_add_item(tree, hf_ndmp_mover_mode, tvb, offset, 4, FALSE);
1692                 offset += 4;
1693         }
1694
1695         /* mover state */
1696         proto_tree_add_item(tree, hf_ndmp_mover_state, tvb, offset, 4, FALSE);
1697         offset += 4;
1698
1699         /* mover pause */
1700         proto_tree_add_item(tree, hf_ndmp_mover_pause, tvb, offset, 4, FALSE);
1701         offset += 4;
1702
1703         /* halt */
1704         proto_tree_add_item(tree, hf_ndmp_halt, tvb, offset, 4, FALSE);
1705         offset += 4;
1706
1707         /* record size */
1708         proto_tree_add_item(tree, hf_ndmp_record_size, tvb, offset, 4, FALSE);
1709         offset += 4;
1710
1711         /* record num */
1712         proto_tree_add_item(tree, hf_ndmp_record_num, tvb, offset, 4, FALSE);
1713         offset += 4;
1714
1715         /* data written */
1716         proto_tree_add_item(tree, hf_ndmp_data_written, tvb, offset, 8, FALSE);
1717         offset += 8;
1718
1719         /* seek position */
1720         proto_tree_add_item(tree, hf_ndmp_seek_position, tvb, offset, 8, FALSE);
1721         offset += 8;
1722
1723         /* bytes left to read */
1724         proto_tree_add_item(tree, hf_ndmp_bytes_left_to_read, tvb, offset, 8, FALSE);
1725         offset += 8;
1726
1727         /* window offset */
1728         proto_tree_add_item(tree, hf_ndmp_window_offset, tvb, offset, 8, FALSE);
1729         offset += 8;
1730
1731         /* window length */
1732         proto_tree_add_item(tree, hf_ndmp_window_length, tvb, offset, 8, FALSE);
1733         offset += 8;
1734
1735         /* this is where v2 ends */
1736         if(ndmp_protocol_version==NDMP_PROTOCOL_V2){
1737                 return offset;
1738         }
1739
1740
1741         /* ndmp addr */
1742         offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
1743
1744         return offset;
1745 }
1746
1747 #define NDMP_MOVER_MODE_READ            0
1748 #define NDMP_MOVER_MODE_WRITE           1
1749 #define NDMP_MOVER_MODE_NOACTION        2
1750 static const value_string mover_mode_vals[] = {
1751         {NDMP_MOVER_MODE_READ,          "MOVER_MODE_READ"},
1752         {NDMP_MOVER_MODE_WRITE,         "MOVER_MODE_WRITE"},
1753         {NDMP_MOVER_MODE_NOACTION,      "MOVER_MODE_NOACTION"},
1754         {0, NULL}
1755 };
1756
1757 static int
1758 dissect_mover_listen_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1759     proto_tree *tree, guint32 seq _U_)
1760 {
1761         /* mode */
1762         proto_tree_add_item(tree, hf_ndmp_mover_mode, tvb, offset, 4, FALSE);
1763         offset += 4;
1764
1765         /*address type*/
1766         proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, FALSE);
1767         offset += 4;
1768
1769         return offset;
1770 }
1771
1772 static int
1773 dissect_mover_listen_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1774     proto_tree *tree, guint32 seq)
1775 {
1776         /* error */
1777         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1778
1779         /* ndmp addr */
1780         offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
1781
1782         return offset;
1783 }
1784
1785 static int
1786 dissect_mover_set_window_request(tvbuff_t *tvb, int offset,
1787     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
1788 {
1789         /* window offset */
1790         proto_tree_add_item(tree, hf_ndmp_window_offset, tvb, offset, 8, FALSE);
1791         offset += 8;
1792
1793         /* window length */
1794         proto_tree_add_item(tree, hf_ndmp_window_length, tvb, offset, 8, FALSE);
1795         offset += 8;
1796
1797         return offset;
1798 }
1799
1800 static int
1801 dissect_mover_set_record_size_request(tvbuff_t *tvb, int offset,
1802     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
1803 {
1804         /* record size */
1805         proto_tree_add_item(tree, hf_ndmp_record_size, tvb, offset, 4, FALSE);
1806         offset += 4;
1807
1808         return offset;
1809 }
1810
1811 static int
1812 dissect_mover_connect_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
1813     proto_tree *tree, guint32 seq _U_)
1814 {
1815         /* mode */
1816         proto_tree_add_item(tree, hf_ndmp_mover_mode, tvb, offset, 4, FALSE);
1817         offset += 4;
1818
1819         /* ndmp addr */
1820         offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
1821
1822         return offset;
1823 }
1824
1825 static int
1826 dissect_log_file_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
1827     proto_tree *tree, guint32 seq)
1828 {
1829         /* file */
1830         offset = dissect_rpc_string(tvb, tree,
1831                         hf_ndmp_file_name, offset, NULL);
1832
1833         /* error */
1834         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1835
1836         return offset;
1837 }
1838
1839 #define NDMP_LOG_TYPE_NORMAL    0
1840 #define NDMP_LOG_TYPE_DEBUG     1
1841 #define NDMP_LOG_TYPE_ERROR     2
1842 #define NDMP_LOG_TYPE_WARNING   3
1843 static const value_string log_type_vals[] = {
1844         {NDMP_LOG_TYPE_NORMAL,  "NORMAL"},
1845         {NDMP_LOG_TYPE_DEBUG,   "DEBUG"},
1846         {NDMP_LOG_TYPE_ERROR,   "ERROR"},
1847         {NDMP_LOG_TYPE_WARNING, "WARNING"},
1848         {0, NULL}
1849 };
1850
1851 static int
1852 dissect_log_message_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1853     proto_tree *tree, guint32 seq _U_)
1854 {
1855         /* type */
1856         proto_tree_add_item(tree, hf_ndmp_log_type, tvb, offset, 4, FALSE);
1857         offset += 4;
1858
1859         /* message id */
1860         proto_tree_add_item(tree, hf_ndmp_log_message_id, tvb, offset, 4, FALSE);
1861         offset += 4;
1862
1863         /* message */
1864         offset = dissect_rpc_string(tvb, tree,
1865                         hf_ndmp_log_message, offset, NULL);
1866
1867         return offset;
1868 }
1869
1870 static int
1871 dissect_notify_data_halted_request(tvbuff_t *tvb, int offset,
1872     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
1873 {
1874         /* halt */
1875         proto_tree_add_item(tree, hf_ndmp_halt, tvb, offset, 4, FALSE);
1876         offset += 4;
1877
1878         /* reason */
1879         offset = dissect_rpc_string(tvb, tree,
1880                         hf_ndmp_halt_reason, offset, NULL);
1881
1882         return offset;
1883 }
1884
1885 #define NDMP_CONNECTED_CONNECTED        0
1886 #define NDMP_CONNECTED_SHUTDOWN         1
1887 #define NDMP_CONNECTED_REFUSED          2
1888 static const value_string connected_vals[] = {
1889         {NDMP_CONNECTED_CONNECTED,      "CONNECTED"},
1890         {NDMP_CONNECTED_SHUTDOWN,       "SHUTDOWN"},
1891         {NDMP_CONNECTED_REFUSED,        "REFUSED"},
1892         {0, NULL}
1893 };
1894
1895 static int
1896 dissect_notify_connected_request(tvbuff_t *tvb, int offset,
1897     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
1898 {
1899         /* connected */
1900         proto_tree_add_item(tree, hf_ndmp_connected, tvb, offset, 4, FALSE);
1901         offset += 4;
1902
1903         /* version number */
1904         proto_tree_add_item(tree, hf_ndmp_version, tvb, offset, 4, FALSE);
1905         offset += 4;
1906
1907         /* reason */
1908         offset = dissect_rpc_string(tvb, tree,
1909                         hf_ndmp_connected_reason, offset, NULL);
1910
1911         return offset;
1912 }
1913
1914
1915 static int
1916 dissect_notify_mover_paused_request(tvbuff_t *tvb, int offset,
1917     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
1918 {
1919         /* mover pause */
1920         proto_tree_add_item(tree, hf_ndmp_mover_pause, tvb, offset, 4, FALSE);
1921         offset += 4;
1922
1923         /* seek position */
1924         proto_tree_add_item(tree, hf_ndmp_seek_position, tvb, offset, 8, FALSE);
1925         offset += 8;
1926
1927         return offset;
1928 }
1929
1930 static int
1931 dissect_auth_data(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1932     proto_tree *tree)
1933 {
1934         guint type;
1935
1936         type=tvb_get_ntohl(tvb,offset);
1937
1938         /* auth type */
1939         proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, FALSE);
1940         offset += 4;
1941
1942         switch(type){
1943         case NDMP_AUTH_NONE:
1944                 break;
1945         case NDMP_AUTH_TEXT:
1946                 /* auth id */
1947                 offset = dissect_rpc_string(tvb, tree,
1948                                 hf_ndmp_auth_id, offset, NULL);
1949
1950                 /* auth password */
1951                 offset = dissect_rpc_string(tvb, tree,
1952                                 hf_ndmp_auth_password, offset, NULL);
1953
1954
1955                 break;
1956         case NDMP_AUTH_MD5:
1957                 /* auth id */
1958                 offset = dissect_rpc_string(tvb, tree,
1959                                 hf_ndmp_auth_id, offset, NULL);
1960
1961                 /* digest */
1962                 proto_tree_add_item(tree, hf_ndmp_auth_digest,
1963                         tvb, offset, 16, FALSE);
1964                 offset+=16;
1965         }
1966
1967         return offset;
1968 }
1969
1970 static int
1971 dissect_connect_client_auth_request(tvbuff_t *tvb, int offset,
1972     packet_info *pinfo, proto_tree *tree, guint32 seq _U_)
1973 {
1974         return dissect_auth_data(tvb, offset, pinfo, tree);
1975 }
1976
1977 static int
1978 dissect_connect_server_auth_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1979     proto_tree *tree, guint32 seq)
1980 {
1981         /* error */
1982         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1983
1984         /* auth data */
1985         offset = dissect_auth_data(tvb, offset, pinfo, tree);
1986
1987         return offset;
1988 }
1989
1990 static int
1991 dissect_tape_write_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1992     proto_tree *tree, guint32 seq _U_)
1993 {
1994         /* data */
1995         offset = dissect_rpc_data(tvb, tree, hf_ndmp_data, offset);
1996
1997         return offset;
1998 }
1999
2000 static int
2001 dissect_tape_write_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
2002     proto_tree *tree, guint32 seq)
2003 {
2004         /* error */
2005         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2006
2007         /* count */
2008         proto_tree_add_item(tree, hf_ndmp_count, tvb, offset, 4, FALSE);
2009         offset += 4;
2010
2011         return offset;
2012 }
2013
2014 static int
2015 dissect_tape_read_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2016     proto_tree *tree, guint32 seq _U_)
2017 {
2018         /* count */
2019         proto_tree_add_item(tree, hf_ndmp_count, tvb, offset, 4, FALSE);
2020         offset += 4;
2021
2022         return offset;
2023 }
2024
2025 static int
2026 dissect_tape_read_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
2027     proto_tree *tree, guint32 seq)
2028 {
2029         /* error */
2030         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2031
2032         /* data */
2033         offset = dissect_rpc_data(tvb, tree, hf_ndmp_data, offset);
2034
2035         return offset;
2036 }
2037
2038 #define NDMP_FS_UNIX    0
2039 #define NDMP_FS_NT      1
2040 #define NDMP_FS_OTHER   2
2041 static const value_string file_fs_type_vals[] = {
2042         {NDMP_FS_UNIX,  "UNIX"},
2043         {NDMP_FS_NT,    "NT"},
2044         {NDMP_FS_OTHER, "OTHER"},
2045         {0, NULL}
2046 };
2047
2048 static int
2049 dissect_file_name(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
2050 {
2051         proto_item* item = NULL;
2052         proto_tree* tree = NULL;
2053         int old_offset=offset;
2054         guint32 type;
2055         char *name;
2056
2057         if (parent_tree) {
2058                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
2059                                 "File");
2060                 tree = proto_item_add_subtree(item, ett_ndmp_file_name);
2061         }
2062
2063         /* file type */
2064         type=tvb_get_ntohl(tvb, offset);
2065         proto_tree_add_item(tree, hf_ndmp_file_fs_type, tvb, offset, 4, FALSE);
2066         offset += 4;
2067
2068         switch(type){
2069         case NDMP_FS_UNIX:
2070                 /* file */
2071                 offset = dissect_rpc_string(tvb, tree,
2072                                 hf_ndmp_file_name, offset, &name);
2073                 if (check_col(pinfo->cinfo, COL_INFO)){
2074                         col_append_fstr(pinfo->cinfo, COL_INFO, " %s", name);
2075                 }
2076                 break;
2077         case NDMP_FS_NT:
2078                 /* nt file */
2079                 offset = dissect_rpc_string(tvb, tree,
2080                                 hf_ndmp_nt_file_name, offset, &name);
2081                 if (check_col(pinfo->cinfo, COL_INFO)){
2082                         col_append_fstr(pinfo->cinfo, COL_INFO, " %s", name);
2083                 }
2084
2085                 /* dos file */
2086                 offset = dissect_rpc_string(tvb, tree,
2087                                 hf_ndmp_dos_file_name, offset, NULL);
2088                 break;
2089         default:
2090                 /* file */
2091                 offset = dissect_rpc_string(tvb, tree,
2092                                 hf_ndmp_file_name, offset, &name);
2093                 if (check_col(pinfo->cinfo, COL_INFO)){
2094                         col_append_fstr(pinfo->cinfo, COL_INFO, " %s", name);
2095                 }
2096         }
2097
2098         if (check_col(pinfo->cinfo, COL_INFO)){
2099                 col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)",
2100                         val_to_str(type, file_fs_type_vals, "Unknown type") );
2101         }
2102
2103         proto_item_set_len(item, offset-old_offset);
2104         return offset;
2105 }
2106
2107
2108 static const true_false_string tfs_ndmp_file_invalid_atime = {
2109         "Atime is INVALID",
2110         "Atime is valid"
2111 };
2112 static const true_false_string tfs_ndmp_file_invalid_ctime = {
2113         "Ctime is INVALID",
2114         "Ctime is valid"
2115 };
2116 static const true_false_string tfs_ndmp_file_invalid_group = {
2117         "Group is INVALID",
2118         "Group is valid"
2119 };
2120 static int
2121 dissect_file_invalids(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2122     proto_tree *parent_tree)
2123 {
2124         proto_item* item = NULL;
2125         proto_tree* tree = NULL;
2126         guint32 flags;
2127
2128         flags=tvb_get_ntohl(tvb, offset);
2129         if (parent_tree) {
2130                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
2131                                 "Invalids: 0x%08x", flags);
2132                 tree = proto_item_add_subtree(item, ett_ndmp_file_invalids);
2133         }
2134
2135         proto_tree_add_boolean(tree, hf_ndmp_file_invalid_group,
2136                         tvb, offset, 4, flags);
2137         proto_tree_add_boolean(tree, hf_ndmp_file_invalid_ctime,
2138                         tvb, offset, 4, flags);
2139         proto_tree_add_boolean(tree, hf_ndmp_file_invalid_atime,
2140                         tvb, offset, 4, flags);
2141
2142         offset+=4;
2143         return offset;
2144 }
2145
2146 #define NDMP_FILE_TYPE_DIR      0
2147 #define NDMP_FILE_TYPE_FIFO     1
2148 #define NDMP_FILE_TYPE_CSPEC    2
2149 #define NDMP_FILE_TYPE_BSPEC    3
2150 #define NDMP_FILE_TYPE_REG      4
2151 #define NDMP_FILE_TYPE_SLINK    5
2152 #define NDMP_FILE_TYPE_SOCK     6
2153 #define NDMP_FILE_TYPE_REGISTRY 7
2154 #define NDMP_FILE_TYPE_OTHER    8
2155 static const value_string file_type_vals[] = {
2156         {NDMP_FILE_TYPE_DIR,    "DIR"},
2157         {NDMP_FILE_TYPE_FIFO,   "FIFO"},
2158         {NDMP_FILE_TYPE_CSPEC,  "CSPEC"},
2159         {NDMP_FILE_TYPE_BSPEC,  "BSPEC"},
2160         {NDMP_FILE_TYPE_REG,    "REG"},
2161         {NDMP_FILE_TYPE_SLINK,  "SLINK"},
2162         {NDMP_FILE_TYPE_SOCK,   "SOCK"},
2163         {NDMP_FILE_TYPE_REGISTRY,       "REGISTRY"},
2164         {NDMP_FILE_TYPE_OTHER,  "OTHER"},
2165         {0, NULL}
2166 };
2167
2168 static int
2169 dissect_file_stats(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
2170 {
2171         proto_item* item = NULL;
2172         proto_tree* tree = NULL;
2173         int old_offset=offset;
2174         nstime_t ns;
2175
2176         if (parent_tree) {
2177                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
2178                                 "Stats:");
2179                 tree = proto_item_add_subtree(item, ett_ndmp_file_stats);
2180         }
2181
2182         /* invalids */
2183         offset = dissect_file_invalids(tvb, offset, pinfo, tree);
2184
2185         /* file fs type */
2186         proto_tree_add_item(tree, hf_ndmp_file_fs_type, tvb, offset, 4, FALSE);
2187         offset += 4;
2188
2189         /* file type */
2190         proto_tree_add_item(tree, hf_ndmp_file_type, tvb, offset, 4, FALSE);
2191         offset += 4;
2192
2193         /* mtime */
2194         ns.secs=tvb_get_ntohl(tvb, offset);
2195         ns.nsecs=0;
2196         proto_tree_add_time(tree, hf_ndmp_file_mtime, tvb, offset, 4, &ns);
2197         offset += 4;
2198
2199         /* atime */
2200         ns.secs=tvb_get_ntohl(tvb, offset);
2201         ns.nsecs=0;
2202         proto_tree_add_time(tree, hf_ndmp_file_atime, tvb, offset, 4, &ns);
2203         offset += 4;
2204
2205         /* ctime */
2206         ns.secs=tvb_get_ntohl(tvb, offset);
2207         ns.nsecs=0;
2208         proto_tree_add_time(tree, hf_ndmp_file_ctime, tvb, offset, 4, &ns);
2209         offset += 4;
2210
2211         /* owner */
2212         proto_tree_add_item(tree, hf_ndmp_file_owner, tvb, offset, 4, FALSE);
2213         offset += 4;
2214
2215         /* group */
2216         proto_tree_add_item(tree, hf_ndmp_file_group, tvb, offset, 4, FALSE);
2217         offset += 4;
2218
2219         /*XXX here we should do proper dissection of mode for unix or
2220               fattr for nt, call appropriate functions in nfs/smb*/
2221         /* fattr */
2222         proto_tree_add_item(tree, hf_ndmp_file_fattr, tvb, offset, 4, FALSE);
2223         offset += 4;
2224
2225         /*file size*/
2226         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_file_size,
2227                         offset);
2228
2229         /* links */
2230         proto_tree_add_item(tree, hf_ndmp_file_links, tvb, offset, 4, FALSE);
2231         offset += 4;
2232
2233         proto_item_set_len(item, offset-old_offset);
2234         return offset;
2235 }
2236
2237
2238 static int
2239 dissect_file(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
2240 {
2241         proto_item* item = NULL;
2242         proto_tree* tree = NULL;
2243         int old_offset=offset;
2244
2245         if (parent_tree) {
2246                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
2247                                 "File:");
2248                 tree = proto_item_add_subtree(item, ett_ndmp_file);
2249         }
2250
2251         /* file names */
2252         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2253                         dissect_file_name, hf_ndmp_file_names);
2254
2255         /* file stats */
2256         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2257                         dissect_file_stats, hf_ndmp_file_stats);
2258
2259         /* node */
2260         proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, FALSE);
2261         offset += 8;
2262
2263         /* fh_info */
2264         proto_tree_add_item(tree, hf_ndmp_file_fh_info, tvb, offset, 8, FALSE);
2265         offset += 8;
2266
2267         proto_item_set_len(item, offset-old_offset);
2268         return offset;
2269 }
2270
2271 static int
2272 dissect_fh_add_file_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
2273     proto_tree *tree, guint32 seq _U_)
2274 {
2275         /* files */
2276         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2277                         dissect_file, hf_ndmp_files);
2278
2279         return offset;
2280 }
2281
2282 static int
2283 dissect_dir(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
2284 {
2285         /* file names */
2286         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2287                         dissect_file_name, hf_ndmp_file_names);
2288
2289         /* node */
2290         proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, FALSE);
2291         offset += 8;
2292
2293         /* parent */
2294         proto_tree_add_item(tree, hf_ndmp_file_parent, tvb, offset, 8, FALSE);
2295         offset += 8;
2296
2297         return offset;
2298 }
2299
2300 static int
2301 dissect_fh_add_dir_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
2302     proto_tree *tree, guint32 seq _U_)
2303 {
2304         /* dirs */
2305         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2306                         dissect_dir, hf_ndmp_dirs);
2307
2308         return offset;
2309 }
2310
2311 static int
2312 dissect_node(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
2313 {
2314         /* file stats */
2315         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2316                         dissect_file_stats, hf_ndmp_file_stats);
2317
2318         /* node */
2319         proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, FALSE);
2320         offset += 8;
2321
2322         /* fh_info */
2323         proto_tree_add_item(tree, hf_ndmp_file_fh_info, tvb, offset, 8, FALSE);
2324         offset += 8;
2325
2326         return offset;
2327 }
2328
2329
2330 static int
2331 dissect_fh_add_node_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
2332     proto_tree *tree, guint32 seq _U_)
2333 {
2334         /* node */
2335         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2336                         dissect_node, hf_ndmp_nodes);
2337
2338         return offset;
2339 }
2340
2341 static int
2342 dissect_data_start_backup_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
2343     proto_tree *tree, guint32 seq _U_)
2344 {
2345         /*butype name*/
2346         offset = dissect_rpc_string(tvb, tree,
2347                         hf_ndmp_butype_name, offset, NULL);
2348
2349         /* default env */
2350         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2351                         dissect_default_env, hf_ndmp_butype_default_env);
2352
2353         return offset;
2354 }
2355
2356 static int
2357 dissect_nlist(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2358     proto_tree *tree)
2359 {
2360         /*original path*/
2361         offset = dissect_rpc_string(tvb, tree,
2362                         hf_ndmp_bu_original_path, offset, NULL);
2363
2364         /*destination dir*/
2365         offset = dissect_rpc_string(tvb, tree,
2366                         hf_ndmp_bu_destination_dir, offset, NULL);
2367
2368         if(ndmp_protocol_version==NDMP_PROTOCOL_V2){
2369                 /* just 2 reserved bytes (4 with padding) */
2370                 offset += 4;
2371         } else {
2372                 /*new name*/
2373                 offset = dissect_rpc_string(tvb, tree,
2374                         hf_ndmp_bu_new_name, offset, NULL);
2375
2376                 /*other name*/
2377                 offset = dissect_rpc_string(tvb, tree,
2378                         hf_ndmp_bu_other_name, offset, NULL);
2379
2380                 /* node */
2381                 proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, FALSE);
2382                 offset += 8;
2383         }
2384
2385         /* fh_info */
2386         proto_tree_add_item(tree, hf_ndmp_file_fh_info, tvb, offset, 8, FALSE);
2387         offset += 8;
2388
2389         return offset;
2390 }
2391
2392
2393 static int
2394 dissect_data_start_recover_request(tvbuff_t *tvb, int offset,
2395     packet_info *pinfo, proto_tree *tree, guint32 seq _U_)
2396 {
2397         if(ndmp_protocol_version==NDMP_PROTOCOL_V2){
2398                 /* ndmp addr */
2399                 offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
2400         }
2401
2402         /* default env */
2403         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2404                         dissect_default_env, hf_ndmp_butype_default_env);
2405
2406         /* nlist */
2407         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2408                         dissect_nlist, hf_ndmp_nlist);
2409
2410         /*butype name*/
2411         offset = dissect_rpc_string(tvb, tree,
2412                         hf_ndmp_butype_name, offset, NULL);
2413
2414         return offset;
2415 }
2416
2417 static int
2418 dissect_data_get_env_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
2419     proto_tree *tree, guint32 seq)
2420 {
2421         /* error */
2422         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2423
2424         /* default env */
2425         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2426                         dissect_default_env, hf_ndmp_butype_default_env);
2427
2428         return offset;
2429 }
2430
2431
2432 static const true_false_string tfs_ndmp_state_invalid_ebr = {
2433         "Estimated Bytes Remaining is INVALID",
2434         "Estimated Bytes Remaining is valid"
2435 };
2436 static const true_false_string tfs_ndmp_state_invalid_etr = {
2437         "Estimated Time Remaining is INVALID",
2438         "Estimated Time Remaining is valid"
2439 };
2440 static int
2441 dissect_state_invalids(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2442     proto_tree *parent_tree)
2443 {
2444         proto_item* item = NULL;
2445         proto_tree* tree = NULL;
2446         guint32 flags;
2447
2448         flags=tvb_get_ntohl(tvb, offset);
2449         if (parent_tree) {
2450                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
2451                                 "Invalids: 0x%08x", flags);
2452                 tree = proto_item_add_subtree(item, ett_ndmp_state_invalids);
2453         }
2454
2455         proto_tree_add_boolean(tree, hf_ndmp_state_invalid_etr,
2456                                 tvb, offset, 4, flags);
2457         proto_tree_add_boolean(tree, hf_ndmp_state_invalid_ebr,
2458                                 tvb, offset, 4, flags);
2459
2460         offset+=4;
2461         return offset;
2462 }
2463
2464 #define NDMP_DATA_OP_NOACTION   0
2465 #define NDMP_DATA_OP_BACKUP     1
2466 #define NDMP_DATA_OP_RESTORE    2
2467 static const value_string bu_operation_vals[] = {
2468         {NDMP_DATA_OP_NOACTION, "NOACTION"},
2469         {NDMP_DATA_OP_BACKUP,   "BACKUP"},
2470         {NDMP_DATA_OP_RESTORE,  "RESTORE"},
2471         {0, NULL}
2472 };
2473
2474 #define NDMP_DATA_STATE_IDLE            0
2475 #define NDMP_DATA_STATE_ACTIVE          1
2476 #define NDMP_DATA_STATE_HALTED          2
2477 #define NDMP_DATA_STATE_LISTEN          3
2478 #define NDMP_DATA_STATE_CONNECTED       4
2479 static const value_string data_state_vals[] = {
2480         {NDMP_DATA_STATE_IDLE,          "IDLE"},
2481         {NDMP_DATA_STATE_ACTIVE,        "ACTIVE"},
2482         {NDMP_DATA_STATE_HALTED,        "HALTED"},
2483         {NDMP_DATA_STATE_LISTEN,        "LISTEN"},
2484         {NDMP_DATA_STATE_CONNECTED,     "CONNECTED"},
2485         {0, NULL}
2486 };
2487
2488 #define NDMP_DATA_HALTED_NA             0
2489 #define NDMP_DATA_HALTED_SUCCESSFUL     1
2490 #define NDMP_DATA_HALTED_ABORTED        2
2491 #define NDMP_DATA_HALTED_INTERNAL_ERROR 3
2492 #define NDMP_DATA_HALTED_CONNECT_ERROR  4
2493 static const value_string data_halted_vals[] = {
2494         {NDMP_DATA_HALTED_NA,                   "HALTED_NA"},
2495         {NDMP_DATA_HALTED_SUCCESSFUL,           "HALTED_SUCCESSFUL"},
2496         {NDMP_DATA_HALTED_ABORTED,              "HALTED_ABORTED"},
2497         {NDMP_DATA_HALTED_INTERNAL_ERROR,       "HALTED_INTERNAL_ERROR"},
2498         {NDMP_DATA_HALTED_CONNECT_ERROR,        "HALTED_CONNECT_ERROR"},
2499         {0, NULL}
2500 };
2501
2502 static int
2503 dissect_data_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
2504     proto_tree *tree, guint32 seq)
2505 {
2506         nstime_t ns;
2507
2508         /* invalids */
2509         offset = dissect_state_invalids(tvb, offset, pinfo, tree);
2510
2511         /* error */
2512         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2513
2514         /* operation */
2515         proto_tree_add_item(tree, hf_ndmp_bu_operation, tvb, offset, 4, FALSE);
2516         offset += 4;
2517
2518         /* state */
2519         proto_tree_add_item(tree, hf_ndmp_data_state, tvb, offset, 4, FALSE);
2520         offset += 4;
2521
2522         /* halted reason */
2523         proto_tree_add_item(tree, hf_ndmp_data_halted, tvb, offset, 4, FALSE);
2524         offset += 4;
2525
2526         /*bytes processed*/
2527         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_data_bytes_processed,
2528                         offset);
2529
2530         /*est bytes remain*/
2531         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_data_est_bytes_remain,
2532                         offset);
2533
2534         /* est time remain */
2535         ns.secs=tvb_get_ntohl(tvb, offset);
2536         ns.nsecs=0;
2537         proto_tree_add_time(tree, hf_ndmp_data_est_time_remain, tvb, offset, 4, &ns);
2538         offset += 4;
2539
2540         /* ndmp addr */
2541         offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
2542
2543         /* window offset */
2544         proto_tree_add_item(tree, hf_ndmp_window_offset, tvb, offset, 8, FALSE);
2545         offset += 8;
2546
2547         /* window length */
2548         proto_tree_add_item(tree, hf_ndmp_window_length, tvb, offset, 8, FALSE);
2549         offset += 8;
2550
2551         return offset;
2552 }
2553
2554
2555 typedef struct _ndmp_command {
2556         guint32 cmd;
2557         int (*request) (tvbuff_t *tvb, int offset, packet_info *pinfo,
2558             proto_tree *tree, guint32 seq);
2559         int (*response)(tvbuff_t *tvb, int offset, packet_info *pinfo,
2560             proto_tree *tree, guint32 seq);
2561 } ndmp_command;
2562
2563 static const ndmp_command ndmp_commands[] = {
2564         {NDMP_CONFIG_GET_HOST_INFO,
2565                 NULL, dissect_ndmp_get_host_info_reply},
2566         {NDMP_CONFIG_GET_CONNECTION_TYPE,
2567                 NULL, dissect_ndmp_config_get_connection_type_reply},
2568         {NDMP_CONFIG_GET_AUTH_ATTR,
2569                 dissect_get_auth_type_request, dissect_auth_attr_msg},
2570         {NDMP_CONFIG_GET_BUTYPE_INFO,
2571                 NULL, dissect_get_butype_info_reply},
2572         {NDMP_CONFIG_GET_FS_INFO,
2573                 NULL, dissect_get_fs_info_reply},
2574         {NDMP_CONFIG_GET_TAPE_INFO,
2575                 NULL, dissect_get_tape_info_reply},
2576         {NDMP_CONFIG_GET_SCSI_INFO,
2577                 NULL, dissect_get_scsi_info_reply},
2578         {NDMP_CONFIG_GET_SERVER_INFO,
2579                 NULL, dissect_get_server_info_reply},
2580         {NDMP_SCSI_OPEN,
2581                 dissect_scsi_open_request, dissect_error},
2582         {NDMP_SCSI_CLOSE,
2583                 NULL, dissect_error},
2584         {NDMP_SCSI_GET_STATE,
2585                 NULL, dissect_scsi_get_state_reply},
2586         {NDMP_SCSI_SET_TARGET,
2587                 dissect_scsi_set_state_request, dissect_error},
2588         {NDMP_SCSI_RESET_DEVICE,
2589                 NULL, dissect_error},
2590         {NDMP_SCSI_RESET_BUS,
2591                 NULL, dissect_error},
2592         {NDMP_SCSI_EXECUTE_CDB,
2593                 dissect_execute_cdb_request_mc, dissect_execute_cdb_reply},
2594         {NDMP_TAPE_OPEN,
2595                 dissect_tape_open_request, dissect_error},
2596         {NDMP_TAPE_CLOSE,
2597                 NULL, dissect_error},
2598         {NDMP_TAPE_GET_STATE,
2599                 NULL, dissect_tape_get_state_reply},
2600         {NDMP_TAPE_MTIO,
2601                 dissect_tape_mtio_request, dissect_tape_mtio_reply},
2602         {NDMP_TAPE_WRITE,
2603                 dissect_tape_write_request, dissect_tape_write_reply},
2604         {NDMP_TAPE_READ,
2605                 dissect_tape_read_request, dissect_tape_read_reply},
2606         {NDMP_TAPE_EXECUTE_CDB,
2607                 dissect_execute_cdb_request_tape, dissect_execute_cdb_reply},
2608         {NDMP_DATA_GET_STATE,
2609                 NULL, dissect_data_get_state_reply},
2610         {NDMP_DATA_START_BACKUP,
2611                 dissect_data_start_backup_request, dissect_error },
2612         {NDMP_DATA_START_RECOVER,
2613                 dissect_data_start_recover_request, dissect_error },
2614         {NDMP_DATA_ABORT,
2615                 NULL, dissect_error},
2616         {NDMP_DATA_GET_ENV,
2617                 NULL, dissect_data_get_env_reply},
2618         {NDMP_DATA_STOP,
2619                 NULL, dissect_error},
2620         {NDMP_DATA_LISTEN,
2621                 dissect_ndmp_addr_msg, dissect_mover_listen_reply},
2622         {NDMP_DATA_CONNECT,
2623                 dissect_data_connect_msg, dissect_error},
2624         {NDMP_NOTIFY_DATA_HALTED,
2625                 dissect_notify_data_halted_request, NULL},
2626         {NDMP_NOTIFY_CONNECTED,
2627                 dissect_notify_connected_request, NULL},
2628         {NDMP_NOTIFY_MOVER_HALTED,
2629                 dissect_notify_data_halted_request, NULL},
2630         {NDMP_NOTIFY_MOVER_PAUSED,
2631                 dissect_notify_mover_paused_request, NULL},
2632         {NDMP_NOTIFY_DATA_READ,
2633                 dissect_mover_set_window_request, NULL},
2634         {NDMP_LOG_FILE,
2635                 dissect_log_file_request, NULL},
2636         {NDMP_LOG_MESSAGE,
2637                 dissect_log_message_request, NULL},
2638         {NDMP_FH_ADD_FILE,
2639                 dissect_fh_add_file_request, NULL},
2640         {NDMP_FH_ADD_DIR,
2641                 dissect_fh_add_dir_request, NULL},
2642         {NDMP_FH_ADD_NODE,
2643                 dissect_fh_add_node_request, NULL},
2644         {NDMP_CONNECT_OPEN,
2645                 dissect_connect_open_request, dissect_error},
2646         {NDMP_CONNECT_CLIENT_AUTH,
2647                 dissect_connect_client_auth_request, dissect_error},
2648         {NDMP_CONNECT_CLOSE,
2649                 NULL,NULL},
2650         {NDMP_CONNECT_SERVER_AUTH,
2651                 dissect_auth_attr_msg, dissect_connect_server_auth_reply},
2652         {NDMP_MOVER_GET_STATE,
2653                 NULL, dissect_mover_get_state_reply},
2654         {NDMP_MOVER_LISTEN,
2655                 dissect_mover_listen_request, dissect_mover_listen_reply},
2656         {NDMP_MOVER_CONTINUE,
2657                 NULL, dissect_error},
2658         {NDMP_MOVER_ABORT,
2659                 NULL, dissect_error},
2660         {NDMP_MOVER_STOP,
2661                 NULL, dissect_error},
2662         {NDMP_MOVER_SET_WINDOW,
2663                 dissect_mover_set_window_request, dissect_error},
2664         {NDMP_MOVER_READ,
2665                 dissect_mover_set_window_request, dissect_error},
2666         {NDMP_MOVER_CLOSE,
2667                 NULL, dissect_error},
2668         {NDMP_MOVER_SET_RECORD_SIZE,
2669                 dissect_mover_set_record_size_request, dissect_error},
2670         {NDMP_MOVER_CONNECT,
2671                 dissect_mover_connect_request, dissect_error},
2672         {0, NULL,NULL}
2673 };
2674
2675
2676 static int
2677 dissect_ndmp_header(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, struct ndmp_header *nh)
2678 {
2679         proto_item* item = NULL;
2680         proto_tree* tree = NULL;
2681         nstime_t ns;
2682
2683         if (parent_tree) {
2684                 item = proto_tree_add_item(parent_tree, hf_ndmp_header, tvb,
2685                                 offset, 24, FALSE);
2686                 tree = proto_item_add_subtree(item, ett_ndmp_header);
2687         }
2688
2689         /* sequence number */
2690         proto_tree_add_uint(tree, hf_ndmp_sequence, tvb, offset, 4, nh->seq);
2691         offset += 4;
2692
2693         /* timestamp */
2694         ns.secs=nh->time;
2695         ns.nsecs=0;
2696         proto_tree_add_time(tree, hf_ndmp_timestamp, tvb, offset, 4, &ns);
2697         offset += 4;
2698
2699         /* Message Type */
2700         proto_tree_add_uint(tree, hf_ndmp_msgtype, tvb, offset, 4, nh->type);
2701         offset += 4;
2702
2703         /* Message */
2704         proto_tree_add_uint(tree, hf_ndmp_msg, tvb, offset, 4, nh->msg);
2705         offset += 4;
2706
2707         /* Reply sequence number */
2708         proto_tree_add_uint(tree, hf_ndmp_reply_sequence, tvb, offset, 4, nh->rep_seq);
2709         offset += 4;
2710
2711         /* error */
2712         offset=dissect_error(tvb, offset, pinfo, tree, nh->seq);
2713
2714         if (check_col(pinfo->cinfo, COL_INFO)){
2715                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s",
2716                         val_to_str(nh->msg, msg_vals, "Unknown Message (0x%02x)"),
2717                         val_to_str(nh->type, msg_type_vals, "Unknown Type (0x%02x)")
2718                         );
2719         }
2720
2721         return offset;
2722 }
2723
2724
2725 static int
2726 dissect_ndmp_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, struct ndmp_header *nh)
2727 {
2728         int i;
2729         proto_item *cmd_item=NULL;
2730         proto_tree *cmd_tree=NULL;
2731
2732         offset=dissect_ndmp_header(tvb, offset, pinfo, tree, nh);
2733
2734         for(i=0;ndmp_commands[i].cmd!=0;i++){
2735                 if(ndmp_commands[i].cmd==nh->msg){
2736                         break;
2737                 }
2738         }
2739
2740
2741         if(ndmp_commands[i].cmd==0){
2742                 /* we do not know this message */
2743                 proto_tree_add_text(tree, tvb, offset, -1, "Unknown type of NDMP message: 0x%02x", nh->msg);
2744                 offset+=tvb_length_remaining(tvb, offset);
2745                 return offset;
2746         }
2747
2748         if (tvb_reported_length_remaining(tvb, offset) > 0) {
2749                 if(tree){
2750                         cmd_item = proto_tree_add_text(tree, tvb, offset, -1,
2751                                 msg_vals[i].strptr);
2752                         cmd_tree = proto_item_add_subtree(cmd_item, ett_ndmp);
2753                 }
2754         }
2755
2756         if(nh->type==NDMP_MESSAGE_REQUEST){
2757                 if(ndmp_commands[i].request){
2758                         offset=ndmp_commands[i].request(tvb, offset, pinfo, cmd_tree,
2759                             nh->seq);
2760                 }
2761         } else {
2762                 if(ndmp_commands[i].response){
2763                         offset=ndmp_commands[i].response(tvb, offset, pinfo, cmd_tree,
2764                             nh->rep_seq);
2765                 }
2766         }
2767
2768         return offset;
2769 }
2770
2771 static void
2772 dissect_ndmp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2773 {
2774         int offset = 0;
2775         guint32 ndmp_rm;
2776         struct ndmp_header nh;
2777         guint32 size;
2778         proto_item *ndmp_item = NULL;
2779         proto_tree *ndmp_tree = NULL;
2780         proto_item *hdr_item = NULL;
2781         proto_tree *hdr_tree = NULL;
2782
2783         /* size of this NDMP PDU */
2784         size = tvb_length_remaining(tvb, offset);
2785         if (size < 28) {
2786                 /* too short to be NDMP */
2787                 return;
2788         }
2789
2790         /*
2791          * Read the NDMP header, if we have it.
2792          */
2793         ndmp_rm=tvb_get_ntohl(tvb, offset);
2794         nh.seq = tvb_get_ntohl(tvb, offset+4);
2795         nh.time = tvb_get_ntohl(tvb, offset+8);
2796         nh.type = tvb_get_ntohl(tvb, offset+12);
2797         nh.msg = tvb_get_ntohl(tvb, offset+16);
2798         nh.rep_seq = tvb_get_ntohl(tvb, offset+20);
2799         nh.err = tvb_get_ntohl(tvb, offset+24);
2800
2801         /*
2802          * Check if this is the last fragment.
2803          */
2804         if (!(ndmp_rm & NDMP_RM_LASTFRAG)) {
2805                 /*
2806                  * This isn't the last fragment.
2807                  * If we're doing reassembly, just return
2808                  * TRUE to indicate that this looks like
2809                  * the beginning of an NDMP message,
2810                  * and let them do reassembly.
2811                  */
2812                 if (ndmp_defragment)
2813                         return;
2814         }
2815
2816         if (check_col(pinfo->cinfo, COL_PROTOCOL))
2817                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDMP");
2818         if (check_col(pinfo->cinfo, COL_INFO)) {
2819                 col_clear(pinfo->cinfo, COL_INFO);
2820         }
2821
2822         if (tree) {
2823                 ndmp_item = proto_tree_add_item(tree, proto_ndmp,
2824                     tvb, 0, -1, FALSE);
2825                 ndmp_tree = proto_item_add_subtree(ndmp_item, ett_ndmp);
2826         }
2827
2828         hdr_item = proto_tree_add_text(ndmp_tree, tvb, 0, 4, 
2829                 "Fragment header: %s%u %s", 
2830                 (ndmp_rm & NDMP_RM_LASTFRAG) ? "Last fragment, " : "", 
2831                 ndmp_rm & NDMP_RM_LENGTH, plurality(ndmp_rm & NDMP_RM_LENGTH, "byte", "bytes"));
2832         hdr_tree = proto_item_add_subtree(hdr_item, ett_ndmp_fraghdr);
2833         proto_tree_add_boolean(hdr_tree, hf_ndmp_lastfrag, tvb, 0, 4, ndmp_rm);
2834         proto_tree_add_uint(hdr_tree, hf_ndmp_fraglen, tvb, 0, 4, ndmp_rm);
2835
2836         /*
2837          * We cannot trust what dissect_ndmp_cmd() tells us, as there
2838          * are implementations which pad some additional data after
2839          * the PDU.  We MUST use size.
2840          */
2841         dissect_ndmp_cmd(tvb, offset+4, pinfo, ndmp_tree, &nh);
2842         return;
2843 }
2844
2845 static guint
2846 get_ndmp_pdu_len(tvbuff_t *tvb, int offset)
2847 {
2848   guint len;
2849
2850   len=tvb_get_ntohl(tvb, offset)&0x7fffffff;
2851   /* Get the length of the NDMP packet. */
2852
2853   /*XXX check header for sanity */
2854   return len+4;
2855 }
2856
2857 static int
2858 dissect_ndmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2859 {
2860         guint len;
2861         guint32 tmp;
2862
2863
2864         /* check that the hgeader looks sane */
2865         len=tvb_length(tvb);
2866         /* check the record marker that it looks sane.
2867          * It has to be >=24 bytes or (arbitrary limit) <1Mbyte
2868          */
2869         if(len>=4){
2870                 tmp=(tvb_get_ntohl(tvb, 0)&NDMP_RM_LENGTH);
2871                 if( (tmp<24)||(tmp>1000000) ){
2872                         return 0;
2873                 }
2874         }
2875         /* check the timestamp,  timestamps are valid if they
2876          * (arbitrary) lie between 1980-jan-1 and 2030-jan-1
2877          */
2878         if(len>=12){
2879                 tmp=tvb_get_ntohl(tvb, 8);
2880                 if( (tmp<0x12ceec50)||(tmp>0x70dc1ed0) ){
2881                         return 0;
2882                 }
2883         }
2884         /* check the type */
2885         if(len>=16){
2886                 tmp=tvb_get_ntohl(tvb, 12);
2887                 if( tmp>1 ){
2888                         return 0;
2889                 }
2890         }
2891         /* check message */
2892         if(len>=20){
2893                 tmp=tvb_get_ntohl(tvb, 16);
2894                 if( (tmp>0xa09) || (tmp==0) ){
2895                         return 0;
2896                 }
2897         }
2898         /* check error */
2899         if(len>=28){
2900                 tmp=tvb_get_ntohl(tvb, 24);
2901                 if( (tmp>0x17) ){
2902                         return 0;
2903                 }
2904         }
2905
2906
2907         tcp_dissect_pdus(tvb, pinfo, tree, ndmp_desegment, 28,
2908                          get_ndmp_pdu_len, dissect_ndmp_message);
2909         return tvb_length(tvb);
2910 }
2911
2912 void
2913 proto_register_ndmp(void)
2914 {
2915
2916   static hf_register_info hf_ndmp[] = {
2917         { &hf_ndmp_header, {
2918                 "NDMP Header", "ndmp.header", FT_NONE, 0,
2919                 NULL, 0, "NDMP Header", HFILL }},
2920
2921         { &hf_ndmp_sequence, {
2922                 "Sequence", "ndmp.sequence", FT_UINT32, BASE_DEC,
2923                 NULL, 0, "Sequence number for NDMP PDU", HFILL }},
2924
2925         { &hf_ndmp_reply_sequence, {
2926                 "Reply Sequence", "ndmp.reply_sequence", FT_UINT32, BASE_DEC,
2927                 NULL, 0, "Reply Sequence number for NDMP PDU", HFILL }},
2928
2929         { &hf_ndmp_timestamp, {
2930                 "Time", "ndmp.timestamp", FT_ABSOLUTE_TIME, BASE_NONE,
2931                 NULL, 0, "Timestamp for this NDMP PDU", HFILL }},
2932
2933         { &hf_ndmp_msgtype, {
2934                 "Type", "ndmp.msg_type", FT_UINT32, BASE_DEC,
2935                 VALS(msg_type_vals), 0, "Is this a Request or Response?", HFILL }},
2936
2937         { &hf_ndmp_msg, {
2938                 "Message", "ndmp.msg", FT_UINT32, BASE_HEX,
2939                 VALS(msg_vals), 0, "Type of NDMP PDU", HFILL }},
2940
2941         { &hf_ndmp_error, {
2942                 "Error", "ndmp.error", FT_UINT32, BASE_DEC,
2943                 VALS(error_vals), 0, "Error code for this NDMP PDU", HFILL }},
2944
2945         { &hf_ndmp_version, {
2946                 "Version", "ndmp.version", FT_UINT32, BASE_DEC,
2947                 NULL, 0, "Version of NDMP protocol", HFILL }},
2948
2949         { &hf_ndmp_hostname, {
2950                 "Hostname", "ndmp.hostname", FT_STRING, BASE_NONE,
2951                 NULL, 0, "Hostname", HFILL }},
2952
2953         { &hf_ndmp_hostid, {
2954                 "HostID", "ndmp.hostid", FT_STRING, BASE_NONE,
2955                 NULL, 0, "HostID", HFILL }},
2956
2957         { &hf_ndmp_os_type, {
2958                 "OS Type", "ndmp.os.type", FT_STRING, BASE_NONE,
2959                 NULL, 0, "OS Type", HFILL }},
2960
2961         { &hf_ndmp_os_vers, {
2962                 "OS Version", "ndmp.os.version", FT_STRING, BASE_NONE,
2963                 NULL, 0, "OS Version", HFILL }},
2964
2965         { &hf_ndmp_addr_types, {
2966                 "Addr Types", "ndmp.addr_types", FT_NONE, BASE_NONE,
2967                 NULL, 0, "List Of Address Types", HFILL }},
2968
2969         { &hf_ndmp_addr_type, {
2970                 "Addr Type", "ndmp.addr_type", FT_UINT32, BASE_DEC,
2971                 VALS(addr_type_vals), 0, "Address Type", HFILL }},
2972
2973         { &hf_ndmp_auth_type, {
2974                 "Auth Type", "ndmp.auth_type", FT_UINT32, BASE_DEC,
2975                 VALS(auth_type_vals), 0, "Authentication Type", HFILL }},
2976
2977         { &hf_ndmp_auth_challenge, {
2978                 "Challenge", "ndmp.auth.challenge", FT_BYTES, BASE_HEX,
2979                 NULL, 0, "Authentication Challenge", HFILL }},
2980
2981         { &hf_ndmp_auth_digest, {
2982                 "Digest", "ndmp.auth.digest", FT_BYTES, BASE_HEX,
2983                 NULL, 0, "Authentication Digest", HFILL }},
2984
2985         { &hf_ndmp_butype_info, {
2986                 "Butype Info", "ndmp.butype.info", FT_NONE, BASE_NONE,
2987                 NULL, 0, "Butype Info", HFILL }},
2988
2989         { &hf_ndmp_butype_name, {
2990                 "Butype Name", "ndmp.butype.name", FT_STRING, BASE_NONE,
2991                 NULL, 0, "Name of Butype", HFILL }},
2992
2993         { &hf_ndmp_butype_default_env, {
2994                 "Default Env", "ndmp.butype.default_env", FT_NONE, BASE_NONE,
2995                 NULL, 0, "Default Env's for this Butype Info", HFILL }},
2996
2997         { &hf_ndmp_tcp_addr_list, {
2998                 "TCP Ports", "ndmp.tcp.port_list", FT_NONE, BASE_NONE,
2999                 NULL, 0, "List of TCP ports", HFILL }},
3000
3001         { &hf_ndmp_tcp_default_env, {
3002                 "Default Env", "ndmp.tcp.default_env", FT_NONE, BASE_NONE,
3003                 NULL, 0, "Default Env's for this Butype Info", HFILL }},
3004
3005         { &hf_ndmp_butype_attr_backup_file_history, {
3006                 "", "ndmp.butype.attr.backup_file_history", FT_BOOLEAN, 32,
3007                 TFS(&tfs_butype_attr_backup_file_history), 0x00000001, "backup_file_history", HFILL }},
3008
3009         { &hf_ndmp_butype_attr_backup_filelist, {
3010                 "", "ndmp.butype.attr.backup_filelist", FT_BOOLEAN, 32,
3011                 TFS(&tfs_butype_attr_backup_filelist), 0x00000002, "backup_filelist", HFILL }},
3012
3013         { &hf_ndmp_butype_attr_recover_filelist, {
3014                 "", "ndmp.butype.attr.recover_filelist", FT_BOOLEAN, 32,
3015                 TFS(&tfs_butype_attr_recover_filelist), 0x00000004, "recover_filelist", HFILL }},
3016
3017         { &hf_ndmp_butype_attr_backup_direct, {
3018                 "", "ndmp.butype.attr.backup_direct", FT_BOOLEAN, 32,
3019                 TFS(&tfs_butype_attr_backup_direct), 0x00000008, "backup_direct", HFILL }},
3020
3021         { &hf_ndmp_butype_attr_recover_direct, {
3022                 "", "ndmp.butype.attr.recover_direct", FT_BOOLEAN, 32,
3023                 TFS(&tfs_butype_attr_recover_direct), 0x00000010, "recover_direct", HFILL }},
3024
3025         { &hf_ndmp_butype_attr_backup_incremental, {
3026                 "", "ndmp.butype.attr.backup_incremental", FT_BOOLEAN, 32,
3027                 TFS(&tfs_butype_attr_backup_incremental), 0x00000020, "backup_incremental", HFILL }},
3028
3029         { &hf_ndmp_butype_attr_recover_incremental, {
3030                 "", "ndmp.butype.attr.recover_incremental", FT_BOOLEAN, 32,
3031                 TFS(&tfs_butype_attr_recover_incremental), 0x00000040, "recover_incremental", HFILL }},
3032
3033         { &hf_ndmp_butype_attr_backup_utf8, {
3034                 "", "ndmp.butype.attr.backup_utf8", FT_BOOLEAN, 32,
3035                 TFS(&tfs_butype_attr_backup_utf8), 0x00000080, "backup_utf8", HFILL }},
3036
3037         { &hf_ndmp_butype_attr_recover_utf8, {
3038                 "", "ndmp.butype.attr.recover_utf8", FT_BOOLEAN, 32,
3039                 TFS(&tfs_butype_attr_recover_utf8), 0x00000100, "recover_utf8", HFILL }},
3040
3041         { &hf_ndmp_butype_env_name, {
3042                 "Name", "ndmp.butype.env.name", FT_STRING, BASE_NONE,
3043                 NULL, 0, "Name for this env-variable", HFILL }},
3044
3045         { &hf_ndmp_butype_env_value, {
3046                 "Value", "ndmp.butype.env.value", FT_STRING, BASE_NONE,
3047                 NULL, 0, "Value for this env-variable", HFILL }},
3048
3049         { &hf_ndmp_tcp_env_name, {
3050                 "Name", "ndmp.tcp.env.name", FT_STRING, BASE_NONE,
3051                 NULL, 0, "Name for this env-variable", HFILL }},
3052
3053         { &hf_ndmp_tcp_env_value, {
3054                 "Value", "ndmp.tcp.env.value", FT_STRING, BASE_NONE,
3055                 NULL, 0, "Value for this env-variable", HFILL }},
3056
3057         { &hf_ndmp_fs_info, {
3058                 "FS Info", "ndmp.fs.info", FT_NONE, BASE_NONE,
3059                 NULL, 0, "FS Info", HFILL }},
3060
3061         { &hf_ndmp_fs_invalid_total_size, {
3062                 "", "ndmp.fs.invalid.total_size", FT_BOOLEAN, 32,
3063                 TFS(&tfs_fs_invalid_total_size), 0x00000001, "If total size is invalid", HFILL }},
3064
3065         { &hf_ndmp_fs_invalid_used_size, {
3066                 "", "ndmp.fs.invalid.used_size", FT_BOOLEAN, 32,
3067                 TFS(&tfs_fs_invalid_used_size), 0x00000002, "If used size is invalid", HFILL }},
3068
3069         { &hf_ndmp_fs_invalid_avail_size, {
3070                 "", "ndmp.fs.invalid.avail_size", FT_BOOLEAN, 32,
3071                 TFS(&tfs_fs_invalid_avail_size), 0x00000004, "If available size is invalid", HFILL }},
3072
3073         { &hf_ndmp_fs_invalid_total_inodes, {
3074                 "", "ndmp.fs.invalid.total_inodes", FT_BOOLEAN, 32,
3075                 TFS(&tfs_fs_invalid_total_inodes), 0x00000008, "If total number of inodes is invalid", HFILL }},
3076
3077         { &hf_ndmp_fs_invalid_used_inodes, {
3078                 "", "ndmp.fs.invalid.used_inodes", FT_BOOLEAN, 32,
3079                 TFS(&tfs_fs_invalid_used_inodes), 0x00000010, "If used number of inodes is invalid", HFILL }},
3080
3081         { &hf_ndmp_fs_fs_type, {
3082                 "Type", "ndmp.fs.type", FT_STRING, BASE_NONE,
3083                 NULL, 0, "Type of FS", HFILL }},
3084
3085         { &hf_ndmp_fs_logical_device, {
3086                 "Logical Device", "ndmp.fs.logical_device", FT_STRING, BASE_NONE,
3087                 NULL, 0, "Name of logical device", HFILL }},
3088
3089         { &hf_ndmp_fs_physical_device, {
3090                 "Physical Device", "ndmp.fs.physical_device", FT_STRING, BASE_NONE,
3091                 NULL, 0, "Name of physical device", HFILL }},
3092
3093         { &hf_ndmp_fs_total_size, {
3094                 "Total Size", "ndmp.fs.total_size", FT_UINT64, BASE_DEC,
3095                 NULL, 0, "Total size of FS", HFILL }},
3096
3097         { &hf_ndmp_fs_used_size, {
3098                 "Used Size", "ndmp.fs.used_size", FT_UINT64, BASE_DEC,
3099                 NULL, 0, "Total used size of FS", HFILL }},
3100
3101         { &hf_ndmp_fs_avail_size, {
3102                 "Avail Size", "ndmp.fs.avail_size", FT_UINT64, BASE_DEC,
3103                 NULL, 0, "Total available size on FS", HFILL }},
3104
3105         { &hf_ndmp_fs_total_inodes, {
3106                 "Total Inodes", "ndmp.fs.total_inodes", FT_UINT64, BASE_DEC,
3107                 NULL, 0, "Total number of inodes on FS", HFILL }},
3108
3109         { &hf_ndmp_fs_used_inodes, {
3110                 "Used Inodes", "ndmp.fs.used_inodes", FT_UINT64, BASE_DEC,
3111                 NULL, 0, "Number of used inodes on FS", HFILL }},
3112
3113         { &hf_ndmp_fs_env, {
3114                 "Env variables", "ndmp.fs.env", FT_NONE, BASE_NONE,
3115                 NULL, 0, "Environment variables for FS", HFILL }},
3116
3117         { &hf_ndmp_fs_env_name, {
3118                 "Name", "ndmp.fs.env.name", FT_STRING, BASE_NONE,
3119                 NULL, 0, "Name for this env-variable", HFILL }},
3120
3121         { &hf_ndmp_fs_env_value, {
3122                 "Value", "ndmp.fs.env.value", FT_STRING, BASE_NONE,
3123                 NULL, 0, "Value for this env-variable", HFILL }},
3124
3125         { &hf_ndmp_fs_status, {
3126                 "Status", "ndmp.fs.status", FT_STRING, BASE_NONE,
3127                 NULL, 0, "Status for this FS", HFILL }},
3128
3129         { &hf_ndmp_tape_info, {
3130                 "Tape Info", "ndmp.tape.info", FT_NONE, BASE_NONE,
3131                 NULL, 0, "Tape Info", HFILL }},
3132
3133         { &hf_ndmp_tape_model, {
3134                 "Model", "ndmp.tape.model", FT_STRING, BASE_NONE,
3135                 NULL, 0, "Model of the TAPE drive", HFILL }},
3136
3137         { &hf_ndmp_tape_dev_cap, {
3138                 "Device Capability", "ndmp.tape.dev_cap", FT_NONE, BASE_NONE,
3139                 NULL, 0, "Tape Device Capability", HFILL }},
3140
3141         { &hf_ndmp_tape_device, {
3142                 "Device", "ndmp.tape.device", FT_STRING, BASE_NONE,
3143                 NULL, 0, "Name of TAPE Device", HFILL }},
3144
3145         { &hf_ndmp_tape_attr_rewind, {
3146                 "", "ndmp.tape.attr.rewind", FT_BOOLEAN, 32,
3147                 TFS(&tfs_tape_attr_rewind), 0x00000001, "If this device supports rewind", HFILL }},
3148
3149         { &hf_ndmp_tape_attr_unload, {
3150                 "", "ndmp.tape.attr.unload", FT_BOOLEAN, 32,
3151                 TFS(&tfs_tape_attr_unload), 0x00000002, "If this device supports unload", HFILL }},
3152
3153         { &hf_ndmp_tape_capability, {
3154                 "Tape Capabilities", "ndmp.tape.capability", FT_NONE, BASE_NONE,
3155                 NULL, 0, "Tape Capabilities", HFILL }},
3156
3157         { &hf_ndmp_tape_capability_name, {
3158                 "Name", "ndmp.tape.cap.name", FT_STRING, BASE_NONE,
3159                 NULL, 0, "Name for this env-variable", HFILL }},
3160
3161         { &hf_ndmp_tape_capability_value, {
3162                 "Value", "ndmp.tape.cap.value", FT_STRING, BASE_NONE,
3163                 NULL, 0, "Value for this env-variable", HFILL }},
3164
3165         { &hf_ndmp_scsi_info, {
3166                 "SCSI Info", "ndmp.scsi.info", FT_NONE, BASE_NONE,
3167                 NULL, 0, "SCSI Info", HFILL }},
3168
3169         { &hf_ndmp_scsi_model, {
3170                 "Model", "ndmp.scsi.model", FT_STRING, BASE_NONE,
3171                 NULL, 0, "Model of the SCSI device", HFILL }},
3172
3173         { &hf_ndmp_server_vendor, {
3174                 "Vendor", "ndmp.server.vendor", FT_STRING, BASE_NONE,
3175                 NULL, 0, "Name of vendor", HFILL }},
3176
3177         { &hf_ndmp_server_product, {
3178                 "Product", "ndmp.server.product", FT_STRING, BASE_NONE,
3179                 NULL, 0, "Name of product", HFILL }},
3180
3181         { &hf_ndmp_server_revision, {
3182                 "Revision", "ndmp.server.revision", FT_STRING, BASE_NONE,
3183                 NULL, 0, "Revision of this product", HFILL }},
3184
3185         { &hf_ndmp_auth_types, {
3186                 "Auth types", "ndmp.auth.types", FT_NONE, BASE_NONE,
3187                 NULL, 0, "Auth types", HFILL }},
3188
3189         { &hf_ndmp_scsi_device, {
3190                 "Device", "ndmp.scsi.device", FT_STRING, BASE_NONE,
3191                 NULL, 0, "Name of SCSI Device", HFILL }},
3192
3193         { &hf_ndmp_scsi_controller, {
3194                 "Controller", "ndmp.scsi.controller", FT_UINT32, BASE_DEC,
3195                 NULL, 0, "Target Controller", HFILL }},
3196
3197         { &hf_ndmp_scsi_id, {
3198                 "ID", "ndmp.scsi.id", FT_UINT32, BASE_DEC,
3199                 NULL, 0, "Target ID", HFILL }},
3200
3201         { &hf_ndmp_scsi_lun, {
3202                 "LUN", "ndmp.scsi.lun", FT_UINT32, BASE_DEC,
3203                 NULL, 0, "Target LUN", HFILL }},
3204
3205         { &hf_ndmp_execute_cdb_flags_data_in, {
3206                 "DATA_IN", "ndmp.execute_cdb.flags.data_in", FT_BOOLEAN, 32,
3207                 NULL, 0x00000001, "DATA_IN", HFILL }},
3208
3209         { &hf_ndmp_execute_cdb_flags_data_out, {
3210                 "DATA_OUT", "ndmp.execute_cdb.flags.data_out", FT_BOOLEAN, 32,
3211                 NULL, 0x00000002, "DATA_OUT", HFILL }},
3212
3213         { &hf_ndmp_execute_cdb_timeout, {
3214                 "Timeout", "ndmp.execute_cdb.timeout", FT_UINT32, BASE_DEC,
3215                 NULL, 0, "Reselect timeout, in milliseconds", HFILL }},
3216
3217         { &hf_ndmp_execute_cdb_datain_len, {
3218                 "Data in length", "ndmp.execute_cdb.datain_len", FT_UINT32, BASE_DEC,
3219                 NULL, 0, "Expected length of data bytes to read", HFILL }},
3220
3221         { &hf_ndmp_execute_cdb_cdb_len, {
3222                 "CDB length", "ndmp.execute_cdb.cdb_len", FT_UINT32, BASE_DEC,
3223                 NULL, 0, "Length of CDB", HFILL }},
3224
3225         { &hf_ndmp_execute_cdb_dataout, {
3226                 "Data out", "ndmp.execute_cdb.dataout", FT_BYTES, BASE_NONE,
3227                 NULL, 0, "Data to be transferred to the SCSI device", HFILL }},
3228
3229         { &hf_ndmp_execute_cdb_status, {
3230                 "Status", "ndmp.execute_cdb.status", FT_UINT8, BASE_DEC,
3231                 VALS(scsi_status_val), 0, "SCSI status", HFILL }},
3232
3233         { &hf_ndmp_execute_cdb_dataout_len, {
3234                 "Data out length", "ndmp.execute_cdb.dataout_len", FT_UINT32, BASE_DEC,
3235                 NULL, 0, "Number of bytes transferred to the device", HFILL }},
3236
3237         { &hf_ndmp_execute_cdb_datain, {
3238                 "Data in", "ndmp.execute_cdb.datain", FT_BYTES, BASE_NONE,
3239                 NULL, 0, "Data transferred from the SCSI device", HFILL }},
3240
3241         { &hf_ndmp_execute_cdb_sns_len, {
3242                 "Sense data length", "ndmp.execute_cdb.sns_len", FT_UINT32, BASE_DEC,
3243                 NULL, 0, "Length of sense data", HFILL }},
3244
3245         { &hf_ndmp_tape_open_mode, {
3246                 "Mode", "ndmp.tape.open_mode", FT_UINT32, BASE_DEC,
3247                 VALS(tape_open_mode_vals), 0, "Mode to open tape in", HFILL }},
3248
3249         { &hf_ndmp_tape_invalid_file_num, {
3250                 "", "ndmp.tape.invalid.file_num", FT_BOOLEAN, 32,
3251                 TFS(&tfs_ndmp_tape_invalid_file_num), 0x00000001, "invalid_file_num", HFILL }},
3252
3253         { &hf_ndmp_tape_invalid_soft_errors, {
3254                 "", "ndmp.tape.invalid.soft_errors", FT_BOOLEAN, 32,
3255                 TFS(&tfs_ndmp_tape_invalid_soft_errors), 0x00000002, "soft_errors", HFILL }},
3256
3257         { &hf_ndmp_tape_invalid_block_size, {
3258                 "", "ndmp.tape.invalid.block_size", FT_BOOLEAN, 32,
3259                 TFS(&tfs_ndmp_tape_invalid_block_size), 0x00000004, "block_size", HFILL }},
3260
3261         { &hf_ndmp_tape_invalid_block_no, {
3262                 "", "ndmp.tape.invalid.block_no", FT_BOOLEAN, 32,
3263                 TFS(&tfs_ndmp_tape_invalid_block_no), 0x00000008, "block_no", HFILL }},
3264
3265         { &hf_ndmp_tape_invalid_total_space, {
3266                 "", "ndmp.tape.invalid.total_space", FT_BOOLEAN, 32,
3267                 TFS(&tfs_ndmp_tape_invalid_total_space), 0x00000010, "total_space", HFILL }},
3268
3269         { &hf_ndmp_tape_invalid_space_remain, {
3270                 "", "ndmp.tape.invalid.space_remain", FT_BOOLEAN, 32,
3271                 TFS(&tfs_ndmp_tape_invalid_space_remain), 0x00000020, "space_remain", HFILL }},
3272
3273         { &hf_ndmp_tape_invalid_partition, {
3274                 "", "ndmp.tape.invalid.partition", FT_BOOLEAN, 32,
3275                 TFS(&tfs_ndmp_tape_invalid_partition), 0x00000040, "partition", HFILL }},
3276
3277         { &hf_ndmp_tape_flags_no_rewind, {
3278                 "", "ndmp.tape.flags.no_rewind", FT_BOOLEAN, 32,
3279                 TFS(&tfs_ndmp_tape_flags_no_rewind), 0x00000008, "no_rewind", HFILL, }},
3280
3281         { &hf_ndmp_tape_flags_write_protect, {
3282                 "", "ndmp.tape.flags.write_protect", FT_BOOLEAN, 32,
3283                 TFS(&tfs_ndmp_tape_flags_write_protect), 0x00000010, "write_protect", HFILL, }},
3284
3285         { &hf_ndmp_tape_flags_error, {
3286                 "", "ndmp.tape.flags.error", FT_BOOLEAN, 32,
3287                 TFS(&tfs_ndmp_tape_flags_error), 0x00000020, "error", HFILL, }},
3288
3289         { &hf_ndmp_tape_flags_unload, {
3290                 "", "ndmp.tape.flags.unload", FT_BOOLEAN, 32,
3291                 TFS(&tfs_ndmp_tape_flags_unload), 0x00000040, "unload", HFILL, }},
3292
3293         { &hf_ndmp_tape_file_num, {
3294                 "file_num", "ndmp.tape.status.file_num", FT_UINT32, BASE_DEC,
3295                 NULL, 0, "file_num", HFILL }},
3296
3297         { &hf_ndmp_tape_soft_errors, {
3298                 "soft_errors", "ndmp.tape.status.soft_errors", FT_UINT32, BASE_DEC,
3299                 NULL, 0, "soft_errors", HFILL }},
3300
3301         { &hf_ndmp_tape_block_size, {
3302                 "block_size", "ndmp.tape.status.block_size", FT_UINT32, BASE_DEC,
3303                 NULL, 0, "block_size", HFILL }},
3304
3305         { &hf_ndmp_tape_block_no, {
3306                 "block_no", "ndmp.tape.status.block_no", FT_UINT32, BASE_DEC,
3307                 NULL, 0, "block_no", HFILL }},
3308
3309         { &hf_ndmp_tape_total_space, {
3310                 "total_space", "ndmp.tape.status.total_space", FT_UINT64, BASE_DEC,
3311                 NULL, 0, "total_space", HFILL }},
3312
3313         { &hf_ndmp_tape_space_remain, {
3314                 "space_remain", "ndmp.tape.status.space_remain", FT_UINT64, BASE_DEC,
3315                 NULL, 0, "space_remain", HFILL }},
3316
3317         { &hf_ndmp_tape_partition, {
3318                 "partition", "ndmp.tape.status.partition", FT_UINT32, BASE_DEC,
3319                 NULL, 0, "partition", HFILL }},
3320
3321         { &hf_ndmp_tape_mtio_op, {
3322                 "Operation", "ndmp.tape.mtio.op", FT_UINT32, BASE_DEC,
3323                 VALS(tape_mtio_vals), 0, "MTIO Operation", HFILL }},
3324
3325         { &hf_ndmp_count, {
3326                 "Count", "ndmp.count", FT_UINT32, BASE_DEC,
3327                 NULL, 0, "Number of bytes/objects/operations", HFILL }},
3328
3329         { &hf_ndmp_resid_count, {
3330                 "Resid Count", "ndmp.resid_count", FT_UINT32, BASE_DEC,
3331                 NULL, 0, "Number of remaining bytes/objects/operations", HFILL }},
3332
3333         { &hf_ndmp_mover_state, {
3334                 "State", "ndmp.mover.state", FT_UINT32, BASE_DEC,
3335                 VALS(mover_state_vals), 0, "State of the selected mover", HFILL }},
3336
3337         { &hf_ndmp_mover_pause, {
3338                 "Pause", "ndmp.mover.pause", FT_UINT32, BASE_DEC,
3339                 VALS(mover_pause_vals), 0, "Reason why the mover paused", HFILL }},
3340
3341         { &hf_ndmp_halt, {
3342                 "Halt", "ndmp.halt", FT_UINT32, BASE_DEC,
3343                 VALS(halt_vals), 0, "Reason why it halted", HFILL }},
3344
3345         { &hf_ndmp_record_size, {
3346                 "Record Size", "ndmp.record.size", FT_UINT32, BASE_DEC,
3347                 NULL, 0, "Record size in bytes", HFILL }},
3348
3349         { &hf_ndmp_record_num, {
3350                 "Record Num", "ndmp.record.num", FT_UINT32, BASE_DEC,
3351                 NULL, 0, "Number of records", HFILL }},
3352
3353         { &hf_ndmp_data_written, {
3354                 "Data Written", "ndmp.data.written", FT_UINT64, BASE_DEC,
3355                 NULL, 0, "Number of data bytes written", HFILL }},
3356
3357         { &hf_ndmp_seek_position, {
3358                 "Seek Position", "ndmp.seek.position", FT_UINT64, BASE_DEC,
3359                 NULL, 0, "Current seek position on device", HFILL }},
3360
3361         { &hf_ndmp_bytes_left_to_read, {
3362                 "Bytes left to read", "ndmp.bytes_left_to_read", FT_INT64, BASE_DEC,
3363                 NULL, 0, "Number of bytes left to be read from the device", HFILL }},
3364
3365         { &hf_ndmp_window_offset, {
3366                 "Window Offset", "ndmp.window.offset", FT_UINT64, BASE_DEC,
3367                 NULL, 0, "Offset to window in bytes", HFILL }},
3368
3369         { &hf_ndmp_window_length, {
3370                 "Window Length", "ndmp.window.length", FT_UINT64, BASE_DEC,
3371                 NULL, 0, "Size of window in bytes", HFILL }},
3372
3373         { &hf_ndmp_addr_ip, {
3374                 "IP Address", "ndmp.addr.ip", FT_IPv4, BASE_DEC,
3375                 NULL, 0, "IP Address", HFILL }},
3376
3377         { &hf_ndmp_addr_tcp, {
3378                 "TCP Port", "ndmp.addr.tcp_port", FT_UINT32, BASE_DEC,
3379                 NULL, 0, "TCP Port", HFILL }},
3380
3381         { &hf_ndmp_addr_fcal_loop_id, {
3382                 "Loop ID", "ndmp.addr.loop_id", FT_UINT32, BASE_HEX,
3383                 NULL, 0, "FCAL Loop ID", HFILL }},
3384
3385         { &hf_ndmp_addr_ipc, {
3386                 "IPC", "ndmp.addr.ipc", FT_BYTES, BASE_HEX,
3387                 NULL, 0, "IPC identifier", HFILL }},
3388
3389         { &hf_ndmp_mover_mode, {
3390                 "Mode", "ndmp.mover.mode", FT_UINT32, BASE_HEX,
3391                 VALS(mover_mode_vals), 0, "Mover Mode", HFILL }},
3392
3393         { &hf_ndmp_file_name, {
3394                 "File", "ndmp.file", FT_STRING, BASE_NONE,
3395                 NULL, 0, "Name of File", HFILL }},
3396
3397         { &hf_ndmp_nt_file_name, {
3398                 "NT File", "ndmp.file", FT_STRING, BASE_NONE,
3399                 NULL, 0, "NT Name of File", HFILL }},
3400
3401         { &hf_ndmp_dos_file_name, {
3402                 "DOS File", "ndmp.file", FT_STRING, BASE_NONE,
3403                 NULL, 0, "DOS Name of File", HFILL }},
3404
3405         { &hf_ndmp_log_type, {
3406                 "Type", "ndmp.log.type", FT_UINT32, BASE_HEX,
3407                 VALS(log_type_vals), 0, "Type of log entry", HFILL }},
3408
3409         { &hf_ndmp_log_message_id, {
3410                 "Message ID", "ndmp.log.message.id", FT_UINT32, BASE_DEC,
3411                 NULL, 0, "ID of this log entry", HFILL }},
3412
3413         { &hf_ndmp_log_message, {
3414                 "Message", "ndmp.log.message", FT_STRING, BASE_NONE,
3415                 NULL, 0, "Log entry", HFILL }},
3416
3417         { &hf_ndmp_halt_reason, {
3418                 "Reason", "ndmp.halt.reason", FT_STRING, BASE_NONE,
3419                 NULL, 0, "Textual reason for why it halted", HFILL }},
3420
3421         { &hf_ndmp_connected, {
3422                 "Connected", "ndmp.connected", FT_UINT32, BASE_DEC,
3423                 VALS(connected_vals), 0, "Status of connection", HFILL }},
3424
3425         { &hf_ndmp_connected_reason, {
3426                 "Reason", "ndmp.connected.reason", FT_STRING, BASE_NONE,
3427                 NULL, 0, "Textual description of the connection status", HFILL }},
3428
3429         { &hf_ndmp_auth_id, {
3430                 "ID", "ndmp.auth.id", FT_STRING, BASE_NONE,
3431                 NULL, 0, "ID of client authenticating", HFILL }},
3432
3433         { &hf_ndmp_auth_password, {
3434                 "Password", "ndmp.auth.password", FT_STRING, BASE_NONE,
3435                 NULL, 0, "Password of client authenticating", HFILL }},
3436
3437         { &hf_ndmp_data, {
3438                 "Data", "ndmp.data", FT_BYTES, BASE_HEX,
3439                 NULL, 0, "Data written/read", HFILL }},
3440
3441         { &hf_ndmp_files, {
3442                 "Files", "ndmp.files", FT_NONE, 0,
3443                 NULL, 0, "List of files", HFILL }},
3444
3445         { &hf_ndmp_file_names, {
3446                 "File Names", "ndmp.file.names", FT_NONE, 0,
3447                 NULL, 0, "List of file names", HFILL }},
3448
3449         { &hf_ndmp_file_fs_type, {
3450                 "File FS Type", "ndmp.file.fs_type", FT_UINT32, BASE_DEC,
3451                 VALS(file_fs_type_vals), 0, "Type of file permissions (UNIX or NT)", HFILL }},
3452
3453         { &hf_ndmp_file_type, {
3454                 "File Type", "ndmp.file.type", FT_UINT32, BASE_DEC,
3455                 VALS(file_type_vals), 0, "Type of file", HFILL }},
3456
3457         { &hf_ndmp_file_stats, {
3458                 "File Stats", "ndmp.file.stats", FT_NONE, 0,
3459                 NULL, 0, "List of file stats", HFILL }},
3460
3461         { &hf_ndmp_file_node, {
3462                 "Node", "ndmp.file.node", FT_UINT64, BASE_DEC,
3463                 NULL, 0, "Node used for direct access", HFILL }},
3464
3465         { &hf_ndmp_file_parent, {
3466                 "Parent", "ndmp.file.parent", FT_UINT64, BASE_DEC,
3467                 NULL, 0, "Parent node(directory) for this node", HFILL }},
3468
3469         { &hf_ndmp_file_fh_info, {
3470                 "FH Info", "ndmp.file.fh_info", FT_UINT64, BASE_DEC,
3471                 NULL, 0, "FH Info used for direct access", HFILL }},
3472
3473         { &hf_ndmp_file_invalid_atime, {
3474                 "", "ndmp.file.invalid_atime", FT_BOOLEAN, 32,
3475                 TFS(&tfs_ndmp_file_invalid_atime), 0x00000001, "invalid_atime", HFILL, }},
3476
3477         { &hf_ndmp_file_invalid_ctime, {
3478                 "", "ndmp.file.invalid_ctime", FT_BOOLEAN, 32,
3479                 TFS(&tfs_ndmp_file_invalid_ctime), 0x00000002, "invalid_ctime", HFILL, }},
3480
3481         { &hf_ndmp_file_invalid_group, {
3482                 "", "ndmp.file.invalid_group", FT_BOOLEAN, 32,
3483                 TFS(&tfs_ndmp_file_invalid_group), 0x00000004, "invalid_group", HFILL, }},
3484
3485         { &hf_ndmp_file_mtime, {
3486                 "mtime", "ndmp.file.mtime", FT_ABSOLUTE_TIME, BASE_NONE,
3487                 NULL, 0, "Timestamp for mtime for this file", HFILL }},
3488
3489         { &hf_ndmp_file_atime, {
3490                 "atime", "ndmp.file.atime", FT_ABSOLUTE_TIME, BASE_NONE,
3491                 NULL, 0, "Timestamp for atime for this file", HFILL }},
3492
3493         { &hf_ndmp_file_ctime, {
3494                 "ctime", "ndmp.file.ctime", FT_ABSOLUTE_TIME, BASE_NONE,
3495                 NULL, 0, "Timestamp for ctime for this file", HFILL }},
3496
3497         { &hf_ndmp_file_owner, {
3498                 "Owner", "ndmp.file.owner", FT_UINT32, BASE_DEC,
3499                 NULL, 0, "UID for UNIX, owner for NT", HFILL }},
3500
3501         { &hf_ndmp_file_group, {
3502                 "Group", "ndmp.file.group", FT_UINT32, BASE_DEC,
3503                 NULL, 0, "GID for UNIX, NA for NT", HFILL }},
3504
3505         { &hf_ndmp_file_fattr, {
3506                 "Fattr", "ndmp.file.fattr", FT_UINT32, BASE_HEX,
3507                 NULL, 0, "Mode for UNIX, fattr for NT", HFILL }},
3508
3509         { &hf_ndmp_file_size, {
3510                 "Size", "ndmp.file.size", FT_UINT64, BASE_DEC,
3511                 NULL, 0, "File Size", HFILL }},
3512
3513         { &hf_ndmp_file_links, {
3514                 "Links", "ndmp.file.links", FT_UINT32, BASE_DEC,
3515                 NULL, 0, "Number of links to this file", HFILL }},
3516
3517         { &hf_ndmp_dirs, {
3518                 "Dirs", "ndmp.dirs", FT_NONE, 0,
3519                 NULL, 0, "List of directories", HFILL }},
3520
3521         { &hf_ndmp_nodes, {
3522                 "Nodes", "ndmp.nodes", FT_NONE, 0,
3523                 NULL, 0, "List of nodes", HFILL }},
3524
3525         { &hf_ndmp_nlist, {
3526                 "Nlist", "ndmp.nlist", FT_NONE, 0,
3527                 NULL, 0, "List of names", HFILL }},
3528
3529         { &hf_ndmp_bu_original_path, {
3530                 "Original Path", "ndmp.bu.original_path", FT_STRING, BASE_NONE,
3531                 NULL, 0, "Original path where backup was created", HFILL }},
3532
3533         { &hf_ndmp_bu_destination_dir, {
3534                 "Destination Dir", "ndmp.bu.destination_dir", FT_STRING, BASE_NONE,
3535                 NULL, 0, "Destination directory to restore backup to", HFILL }},
3536
3537         { &hf_ndmp_bu_new_name, {
3538                 "New Name", "ndmp.bu.new_name", FT_STRING, BASE_NONE,
3539                 NULL, 0, "New Name", HFILL }},
3540
3541         { &hf_ndmp_bu_other_name, {
3542                 "Other Name", "ndmp.bu.other_name", FT_STRING, BASE_NONE,
3543                 NULL, 0, "Other Name", HFILL }},
3544
3545         { &hf_ndmp_state_invalid_ebr, {
3546                 "", "ndmp.bu.state.invalid_ebr", FT_BOOLEAN, 32,
3547                 TFS(&tfs_ndmp_state_invalid_ebr), 0x00000001, "Whether EstimatedBytesLeft is valid or not", HFILL, }},
3548
3549         { &hf_ndmp_state_invalid_etr, {
3550                 "", "ndmp.bu.state.invalid_etr", FT_BOOLEAN, 32,
3551                 TFS(&tfs_ndmp_state_invalid_etr), 0x00000002, "Whether EstimatedTimeLeft is valid or not", HFILL, }},
3552
3553         { &hf_ndmp_bu_operation, {
3554                 "Operation", "ndmp.bu.operation", FT_UINT32, BASE_DEC,
3555                 VALS(bu_operation_vals), 0, "BU Operation", HFILL, }},
3556
3557         { &hf_ndmp_data_state, {
3558                 "State", "ndmp.data.state", FT_UINT32, BASE_DEC,
3559                 VALS(data_state_vals), 0, "Data state", HFILL, }},
3560
3561         { &hf_ndmp_data_halted, {
3562                 "Halted Reason", "ndmp.data.halted", FT_UINT32, BASE_DEC,
3563                 VALS(data_halted_vals), 0, "Data halted reason", HFILL, }},
3564
3565         { &hf_ndmp_data_bytes_processed, {
3566                 "Bytes Processed", "ndmp.data.bytes_processed", FT_UINT64, BASE_DEC,
3567                 NULL, 0, "Number of bytes processed", HFILL }},
3568
3569         { &hf_ndmp_data_est_bytes_remain, {
3570                 "Est Bytes Remain", "ndmp.data.est_bytes_remain", FT_UINT64, BASE_DEC,
3571                 NULL, 0, "Estimated number of bytes remaining", HFILL }},
3572
3573         { &hf_ndmp_data_est_time_remain, {
3574                 "Est Time Remain", "ndmp.data.est_time_remain", FT_RELATIVE_TIME, BASE_DEC,
3575                 NULL, 0, "Estimated time remaining", HFILL }},
3576         { &hf_ndmp_lastfrag, {
3577                 "Last Fragment", "ndmp.lastfrag", FT_BOOLEAN, 32,
3578                 &yesno, NDMP_RM_LASTFRAG, "Last Fragment", HFILL }},
3579         { &hf_ndmp_fraglen, {
3580                 "Fragment Length", "ndmp.fraglen", FT_UINT32, BASE_DEC,
3581                 NULL, NDMP_RM_LENGTH, "Fragment Length", HFILL }},
3582   };
3583
3584   static gint *ett[] = {
3585     &ett_ndmp,
3586     &ett_ndmp_fraghdr,
3587     &ett_ndmp_header,
3588     &ett_ndmp_butype_attrs,
3589     &ett_ndmp_fs_invalid,
3590     &ett_ndmp_tape_attr,
3591     &ett_ndmp_execute_cdb_flags,
3592     &ett_ndmp_execute_cdb_cdb,
3593     &ett_ndmp_execute_cdb_sns,
3594     &ett_ndmp_execute_cdb_payload,
3595     &ett_ndmp_tape_invalid,
3596     &ett_ndmp_tape_flags,
3597     &ett_ndmp_addr,
3598     &ett_ndmp_file,
3599     &ett_ndmp_file_name,
3600     &ett_ndmp_file_stats,
3601     &ett_ndmp_file_invalids,
3602     &ett_ndmp_state_invalids,
3603   };
3604
3605   module_t *ndmp_module;
3606
3607   proto_ndmp = proto_register_protocol("Network Data Management Protocol", "NDMP", "ndmp");
3608   proto_register_field_array(proto_ndmp, hf_ndmp, array_length(hf_ndmp));
3609
3610   proto_register_subtree_array(ett, array_length(ett));
3611
3612   /* desegmentation */
3613   ndmp_module = prefs_register_protocol(proto_ndmp, NULL);
3614   prefs_register_enum_preference(ndmp_module,
3615         "protocol_version",
3616         "Protocol version",
3617         "Version of the NDMP protocol",
3618         &ndmp_protocol_version,
3619         ndmp_protocol_versions,
3620         FALSE);
3621   prefs_register_bool_preference(ndmp_module, "desegment",
3622     "Reassemble NDMP messages spanning multiple TCP segments",
3623     "Whether the NDMP dissector should reassemble messages spanning multiple TCP segments."
3624     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
3625         &ndmp_desegment);
3626   prefs_register_bool_preference(ndmp_module, "defragment",
3627         "Reassemble fragmented NDMP messages spanning multiple packets",
3628         "Whether the dissector should defragment NDMP messages spanning multiple packets.",
3629         &ndmp_defragment);
3630 }
3631
3632 void
3633 proto_reg_handoff_ndmp(void)
3634 {
3635   dissector_handle_t ndmp_handle;
3636
3637   ndmp_handle = new_create_dissector_handle(dissect_ndmp, proto_ndmp);
3638   dissector_add("tcp.port",TCP_PORT_NDMP, ndmp_handle);
3639 }