Add data parameter to dissect_function_t in vsff structure. The intention here is...
[metze/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  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  */
28
29 /* see www.ndmp.org for protocol specifications.
30    this file implements version 3 of ndmp
31 */
32
33 #include "config.h"
34
35 #include <string.h>
36 #include <glib.h>
37
38 #include <epan/packet.h>
39 #include <epan/conversation.h>
40 #include <epan/wmem/wmem.h>
41 #include "packet-rpc.h"
42 #include "packet-ndmp.h"
43 #include "packet-tcp.h"
44 #include "packet-scsi.h"
45 #include <epan/prefs.h>
46 #include <epan/reassemble.h>
47
48 #define TCP_PORT_NDMP 10000
49
50 static  dissector_handle_t ndmp_handle;
51
52 static int proto_ndmp = -1;
53 static int hf_ndmp_request_frame = -1;
54 static int hf_ndmp_response_frame = -1;
55 static int hf_ndmp_time = -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 static int hf_ndmp_ex_class_id = -1;
224 static int hf_ndmp_class_list = -1;
225 static int hf_ndmp_ext_version = -1;
226 static int hf_ndmp_ext_version_list = -1;
227 static int hf_ndmp_class_version = -1;
228 static int hf_ndmp_ex_class_version = -1;
229
230 static int hf_ndmp_fragments = -1;
231 static int hf_ndmp_fragment = -1;
232 static int hf_ndmp_fragment_overlap = -1;
233 static int hf_ndmp_fragment_overlap_conflicts = -1;
234 static int hf_ndmp_fragment_multiple_tails = -1;
235 static int hf_ndmp_fragment_too_long_fragment = -1;
236 static int hf_ndmp_fragment_error = -1;
237 static int hf_ndmp_fragment_count = -1;
238 static int hf_ndmp_reassembled_in = -1;
239 static int hf_ndmp_reassembled_length = -1;
240
241 static gint ett_ndmp = -1;
242 static gint ett_ndmp_fraghdr = -1;
243 static gint ett_ndmp_header = -1;
244 static gint ett_ndmp_butype_attrs = -1;
245 static gint ett_ndmp_fs_invalid = -1;
246 static gint ett_ndmp_tape_attr = -1;
247 static gint ett_ndmp_execute_cdb_flags = -1;
248 static gint ett_ndmp_execute_cdb_cdb = -1;
249 static gint ett_ndmp_execute_cdb_sns = -1;
250 static gint ett_ndmp_execute_cdb_payload = -1;
251 static gint ett_ndmp_tape_invalid = -1;
252 static gint ett_ndmp_tape_flags = -1;
253 static gint ett_ndmp_addr = -1;
254 static gint ett_ndmp_file = -1;
255 static gint ett_ndmp_file_name = -1;
256 static gint ett_ndmp_file_stats = -1;
257 static gint ett_ndmp_file_invalids = -1;
258 static gint ett_ndmp_state_invalids = -1;
259 static gint ett_ndmp_fragment = -1;
260 static gint ett_ndmp_fragments = -1;
261
262 static const fragment_items ndmp_frag_items = {
263        /* Fragment subtrees */
264        &ett_ndmp_fragment,
265        &ett_ndmp_fragments,
266        /* Fragment fields */
267        &hf_ndmp_fragments,
268        &hf_ndmp_fragment,
269        &hf_ndmp_fragment_overlap,
270        &hf_ndmp_fragment_overlap_conflicts,
271        &hf_ndmp_fragment_multiple_tails,
272        &hf_ndmp_fragment_too_long_fragment,
273        &hf_ndmp_fragment_error,
274        &hf_ndmp_fragment_count,
275        /* Reassembled in field */
276        &hf_ndmp_reassembled_in,
277        /* Reassembled length field */
278        &hf_ndmp_reassembled_length,
279        /* Reassembled data field */
280        NULL,
281        /* Tag */
282        "NDMP fragments"
283 };
284
285 static reassembly_table ndmp_reassembly_table;
286
287 /* XXX someone should start adding the new stuff from v3, v4 and v5*/
288 #define NDMP_PROTOCOL_UNKNOWN   0
289 #define NDMP_PROTOCOL_V2        2
290 #define NDMP_PROTOCOL_V3        3
291 #define NDMP_PROTOCOL_V4        4
292 #define NDMP_PROTOCOL_V5        5
293 static const enum_val_t ndmp_protocol_versions[] = {
294         { "version2",   "Version 2",    NDMP_PROTOCOL_V2 },
295         { "version3",   "Version 3",    NDMP_PROTOCOL_V3 },
296         { "version4",   "Version 4",    NDMP_PROTOCOL_V4 },
297         { "version5",   "Version 5",    NDMP_PROTOCOL_V5 },
298         { NULL, NULL, 0 }
299 };
300
301 static gint ndmp_default_protocol_version = NDMP_PROTOCOL_V4;
302
303 typedef struct _ndmp_frag_info {
304         guint32 first_seq;
305         guint16 offset;
306 } ndmp_frag_info;
307
308 typedef struct _ndmp_task_data_t {
309         guint32 request_frame;
310         guint32 response_frame;
311         nstime_t ndmp_time;
312         itlq_nexus_t *itlq;
313 } ndmp_task_data_t;
314
315 typedef struct _ndmp_conv_data_t {
316         guint8 version;
317         wmem_tree_t *tasks;     /* indexed by Sequence# */
318         wmem_tree_t *itl;               /* indexed by packet# */
319         wmem_tree_t *fragsA; /* indexed by Sequence# */
320         wmem_tree_t *fragsB;
321         ndmp_task_data_t *task;
322         conversation_t *conversation;
323 } ndmp_conv_data_t;
324 static ndmp_conv_data_t *ndmp_conv_data=NULL;
325 static proto_tree *top_tree;
326
327 static itl_nexus_t *
328 get_itl_nexus(packet_info *pinfo, gboolean create_new)
329 {
330         itl_nexus_t *itl;
331
332         if(create_new || !(itl=(itl_nexus_t *)wmem_tree_lookup32_le(ndmp_conv_data->itl, pinfo->fd->num))){
333                 itl=wmem_new(wmem_file_scope(), itl_nexus_t);
334                 itl->cmdset=0xff;
335                 itl->conversation=ndmp_conv_data->conversation;
336                 wmem_tree_insert32(ndmp_conv_data->itl, pinfo->fd->num, itl);
337         }
338         return itl;
339 }
340
341 static guint8
342 get_ndmp_protocol_version(void)
343 {
344         if(!ndmp_conv_data || (ndmp_conv_data->version==NDMP_PROTOCOL_UNKNOWN)){
345                 return ndmp_default_protocol_version;
346         }
347         return ndmp_conv_data->version;
348 }
349
350 struct ndmp_header {
351         guint32 seq;
352         guint32 time;
353         guint32 type;
354         guint32 msg;
355         guint32 rep_seq;
356         guint32 err;
357 };
358
359 /* desegmentation of NDMP packets */
360 static gboolean ndmp_desegment = TRUE;
361
362 /* defragmentation of fragmented NDMP records */
363 static gboolean ndmp_defragment = TRUE;
364
365 #define NDMP_MESSAGE_REQUEST    0x00
366 #define NDMP_MESSAGE_REPLY      0x01
367 static const value_string msg_type_vals[] = {
368         {NDMP_MESSAGE_REQUEST,          "Request"},
369         {NDMP_MESSAGE_REPLY,            "Reply"},
370         {0, NULL}
371 };
372
373 #define NDMP_NO_ERR                     0x00
374 #define NDMP_NOT_SUPPORTED_ERR          0x01
375 #define NDMP_DEVICE_BUSY_ERR            0x02
376 #define NDMP_DEVICE_OPENED_ERR          0x03
377 #define NDMP_NOT_AUTHORIZED_ERR         0x04
378 #define NDMP_PERMISSION_ERR             0x05
379 #define NDMP_DEV_NOT_OPEN_ERR           0x06
380 #define NDMP_IO_ERR                     0x07
381 #define NDMP_TIMEOUT_ERR                0x08
382 #define NDMP_ILLEGAL_ARGS_ERR           0x09
383 #define NDMP_NO_TAPE_LOADED_ERR         0x0a
384 #define NDMP_WRITE_PROTECT_ERR          0x0b
385 #define NDMP_EOF_ERR                    0x0c
386 #define NDMP_EOM_ERR                    0x0d
387 #define NDMP_FILE_NOT_FOUND_ERR         0x0e
388 #define NDMP_BAD_FILE_ERR               0x0f
389 #define NDMP_NO_DEVICE_ERR              0x10
390 #define NDMP_NO_BUS_ERR                 0x11
391 #define NDMP_XDR_DECODE_ERR             0x12
392 #define NDMP_ILLEGAL_STATE_ERR          0x13
393 #define NDMP_UNDEFINED_ERR              0x14
394 #define NDMP_XDR_ENCODE_ERR             0x15
395 #define NDMP_NO_MEM_ERR                 0x16
396 #define NDMP_CONNECT_ERR                0x17
397 #define NDMP_SEQUENCE_NUM_ERR           0x18
398 #define NDMP_READ_IN_PROGRESS_ERR       0x19
399 #define NDMP_PRECONDITION_ERR           0x1a
400 #define NDMP_CLASS_NOT_SUPPORTED_ERR    0x1b
401 #define NDMP_VERSION_NOT_SUPPORTED_ERR  0x1c
402 #define NDMP_EXT_DUPL_CLASSES_ERR       0x1d
403 #define NDMP_EXT_DANDN_ILLEGAL_ERR      0x1e
404
405 static const value_string error_vals[] = {
406         {NDMP_NO_ERR,                   "NO_ERR"},
407         {NDMP_NOT_SUPPORTED_ERR,        "NOT_SUPPORTED_ERR"},
408         {NDMP_DEVICE_BUSY_ERR,          "DEVICE_BUSY_ERR"},
409         {NDMP_DEVICE_OPENED_ERR,        "DEVICE_OPENED_ERR"},
410         {NDMP_NOT_AUTHORIZED_ERR,       "NOT_AUTHORIZED_ERR"},
411         {NDMP_PERMISSION_ERR,           "PERMISSION_ERR"},
412         {NDMP_DEV_NOT_OPEN_ERR,         "DEV_NOT_OPEN_ERR"},
413         {NDMP_IO_ERR,                   "IO_ERR"},
414         {NDMP_TIMEOUT_ERR,              "TIMEOUT_ERR"},
415         {NDMP_ILLEGAL_ARGS_ERR,         "ILLEGAL_ARGS_ERR"},
416         {NDMP_NO_TAPE_LOADED_ERR,       "NO_TAPE_LOADED_ERR"},
417         {NDMP_WRITE_PROTECT_ERR,        "WRITE_PROTECT_ERR"},
418         {NDMP_EOF_ERR,                  "EOF_ERR"},
419         {NDMP_EOM_ERR,                  "EOM_ERR"},
420         {NDMP_FILE_NOT_FOUND_ERR,       "FILE_NOT_FOUND_ERR"},
421         {NDMP_BAD_FILE_ERR,             "BAD_FILE_ERR"},
422         {NDMP_NO_DEVICE_ERR,            "NO_DEVICE_ERR"},
423         {NDMP_NO_BUS_ERR,               "NO_BUS_ERR"},
424         {NDMP_XDR_DECODE_ERR,           "XDR_DECODE_ERR"},
425         {NDMP_ILLEGAL_STATE_ERR,        "ILLEGAL_STATE_ERR"},
426         {NDMP_UNDEFINED_ERR,            "UNDEFINED_ERR"},
427         {NDMP_XDR_ENCODE_ERR,           "XDR_ENCODE_ERR"},
428         {NDMP_NO_MEM_ERR,               "NO_MEM_ERR"},
429         {NDMP_CONNECT_ERR,              "CONNECT_ERR"},
430         {NDMP_SEQUENCE_NUM_ERR,         "NDMP_SEQUENCE_NUM_ERR"},
431         {NDMP_READ_IN_PROGRESS_ERR,     "NDMP_READ_IN_PROGRESS_ERR"},
432         {NDMP_PRECONDITION_ERR,         "NDMP_PRECONDITION_ERR"},
433         {NDMP_CLASS_NOT_SUPPORTED_ERR,  "NDMP_CLASS_NOT_SUPPORTED_ERR"},
434         {NDMP_VERSION_NOT_SUPPORTED_ERR,"NDMP_VERSION_NOT_SUPPORTED_ERR"},
435         {NDMP_EXT_DUPL_CLASSES_ERR,     "NDMP_EXT_DUPL_CLASSES_ERR"},
436         {NDMP_EXT_DANDN_ILLEGAL_ERR,    "NDMP_EXT_DANDN_ILLEGAL_ERR"},
437         {0, NULL}
438 };
439
440
441
442 #define NDMP_CONFIG_GET_HOST_INFO       0x100
443 #define NDMP_CONFIG_GET_CONNECTION_TYPE 0x102
444 #define NDMP_CONFIG_GET_AUTH_ATTR       0x103
445 #define NDMP_CONFIG_GET_BUTYPE_INFO     0x104
446 #define NDMP_CONFIG_GET_FS_INFO         0x105
447 #define NDMP_CONFIG_GET_TAPE_INFO       0x106
448 #define NDMP_CONFIG_GET_SCSI_INFO       0x107
449 #define NDMP_CONFIG_GET_SERVER_INFO     0x108
450 #define NDMP_CONFIG_SET_EXT_LIST        0x109
451 #define NDMP_CONFIG_GET_EXT_LIST        0x10a
452 #define NDMP_SCSI_OPEN                  0x200
453 #define NDMP_SCSI_CLOSE                 0x201
454 #define NDMP_SCSI_GET_STATE             0x202
455 #define NDMP_SCSI_SET_TARGET            0x203
456 #define NDMP_SCSI_RESET_DEVICE          0x204
457 #define NDMP_SCSI_RESET_BUS             0x205
458 #define NDMP_SCSI_EXECUTE_CDB           0x206
459 #define NDMP_TAPE_OPEN                  0x300
460 #define NDMP_TAPE_CLOSE                 0x301
461 #define NDMP_TAPE_GET_STATE             0x302
462 #define NDMP_TAPE_MTIO                  0x303
463 #define NDMP_TAPE_WRITE                 0x304
464 #define NDMP_TAPE_READ                  0x305
465 #define NDMP_TAPE_EXECUTE_CDB           0x307
466 #define NDMP_DATA_GET_STATE             0x400
467 #define NDMP_DATA_START_BACKUP          0x401
468 #define NDMP_DATA_START_RECOVER         0x402
469 #define NDMP_DATA_ABORT                 0x403
470 #define NDMP_DATA_GET_ENV               0x404
471 #define NDMP_DATA_STOP                  0x407
472 #define NDMP_DATA_LISTEN                0x409
473 #define NDMP_DATA_CONNECT               0x40a
474 #define NDMP_NOTIFY_DATA_HALTED         0x501
475 #define NDMP_NOTIFY_CONNECTED           0x502
476 #define NDMP_NOTIFY_MOVER_HALTED        0x503
477 #define NDMP_NOTIFY_MOVER_PAUSED        0x504
478 #define NDMP_NOTIFY_DATA_READ           0x505
479 #define NDMP_LOG_FILE                   0x602
480 #define NDMP_LOG_MESSAGE                0x603
481 #define NDMP_FH_ADD_FILE                0x703
482 #define NDMP_FH_ADD_DIR                 0x704
483 #define NDMP_FH_ADD_NODE                0x705
484 #define NDMP_CONNECT_OPEN               0x900
485 #define NDMP_CONNECT_CLIENT_AUTH        0x901
486 #define NDMP_CONNECT_CLOSE              0x902
487 #define NDMP_CONNECT_SERVER_AUTH        0x903
488 #define NDMP_MOVER_GET_STATE            0xa00
489 #define NDMP_MOVER_LISTEN               0xa01
490 #define NDMP_MOVER_CONTINUE             0xa02
491 #define NDMP_MOVER_ABORT                0xa03
492 #define NDMP_MOVER_STOP                 0xa04
493 #define NDMP_MOVER_SET_WINDOW           0xa05
494 #define NDMP_MOVER_READ                 0xa06
495 #define NDMP_MOVER_CLOSE                0xa07
496 #define NDMP_MOVER_SET_RECORD_SIZE      0xa08
497 #define NDMP_MOVER_CONNECT              0xa09
498
499
500
501
502 static const value_string msg_vals[] = {
503         {NDMP_CONFIG_GET_HOST_INFO,     "CONFIG_GET_HOST_INFO"},
504         {NDMP_CONFIG_GET_CONNECTION_TYPE, "CONFIG_GET_CONNECTION_TYPE"},
505         {NDMP_CONFIG_GET_AUTH_ATTR,     "CONFIG_GET_AUTH_ATTR"},
506         {NDMP_CONFIG_GET_BUTYPE_INFO,   "CONFIG_GET_BUTYPE_INFO"},
507         {NDMP_CONFIG_GET_FS_INFO,       "CONFIG_GET_FS_INFO"},
508         {NDMP_CONFIG_GET_TAPE_INFO,     "CONFIG_GET_TAPE_INFO"},
509         {NDMP_CONFIG_GET_SCSI_INFO,     "CONFIG_GET_SCSI_INFO"},
510         {NDMP_CONFIG_GET_SERVER_INFO,   "CONFIG_GET_SERVER_INFO"},
511         {NDMP_CONFIG_GET_EXT_LIST,      "CONFIG_GET_EXT_LIST"},
512         {NDMP_CONFIG_SET_EXT_LIST,      "CONFIG_SET_EXT_LIST"},
513         {NDMP_SCSI_OPEN,                "SCSI_OPEN"},
514         {NDMP_SCSI_CLOSE,               "SCSI_CLOSE"},
515         {NDMP_SCSI_GET_STATE,           "SCSI_GET_STATE"},
516         {NDMP_SCSI_SET_TARGET,          "SCSI_SET_TARGET"},
517         {NDMP_SCSI_RESET_DEVICE,        "SCSI_RESET_DEVICE"},
518         {NDMP_SCSI_RESET_BUS,           "SCSI_RESET_BUS"},
519         {NDMP_SCSI_EXECUTE_CDB,         "SCSI_EXECUTE_CDB"},
520         {NDMP_TAPE_OPEN,                "TAPE_OPEN"},
521         {NDMP_TAPE_CLOSE,               "TAPE_CLOSE"},
522         {NDMP_TAPE_GET_STATE,           "TAPE_GET_STATE"},
523         {NDMP_TAPE_MTIO,                "TAPE_MTIO"},
524         {NDMP_TAPE_WRITE,               "TAPE_WRITE"},
525         {NDMP_TAPE_READ,                "TAPE_READ"},
526         {NDMP_TAPE_EXECUTE_CDB,         "TAPE_EXECUTE_CDB"},
527         {NDMP_DATA_GET_STATE,           "DATA_GET_STATE"},
528         {NDMP_DATA_START_BACKUP,        "DATA_START_BACKUP"},
529         {NDMP_DATA_START_RECOVER,       "DATA_START_RECOVER"},
530         {NDMP_DATA_ABORT,               "DATA_ABORT"},
531         {NDMP_DATA_GET_ENV,             "DATA_GET_ENV"},
532         {NDMP_DATA_STOP,                "DATA_STOP"},
533         {NDMP_DATA_LISTEN,              "DATA_LISTEN"},
534         {NDMP_DATA_CONNECT,             "DATA_CONNECT"},
535         {NDMP_NOTIFY_DATA_HALTED,       "NOTIFY_DATA_HALTED"},
536         {NDMP_NOTIFY_CONNECTED,         "NOTIFY_CONNECTED"},
537         {NDMP_NOTIFY_MOVER_HALTED,      "NOTIFY_MOVER_HALTED"},
538         {NDMP_NOTIFY_MOVER_PAUSED,      "NOTIFY_MOVER_PAUSED"},
539         {NDMP_NOTIFY_DATA_READ,         "NOTIFY_DATA_READ"},
540         {NDMP_LOG_FILE,                 "LOG_FILE"},
541         {NDMP_LOG_MESSAGE,              "LOG_MESSAGE"},
542         {NDMP_FH_ADD_FILE,              "FH_ADD_FILE"},
543         {NDMP_FH_ADD_DIR,               "FH_ADD_DIR"},
544         {NDMP_FH_ADD_NODE,              "FH_ADD_NODE"},
545         {NDMP_CONNECT_OPEN,             "CONNECT_OPEN"},
546         {NDMP_CONNECT_CLIENT_AUTH,      "CONNECT_CLIENT_AUTH"},
547         {NDMP_CONNECT_CLOSE,            "CONNECT_CLOSE"},
548         {NDMP_CONNECT_SERVER_AUTH,      "CONNECT_SERVER_AUTH"},
549         {NDMP_MOVER_GET_STATE,          "MOVER_GET_STATE"},
550         {NDMP_MOVER_LISTEN,             "MOVER_LISTEN"},
551         {NDMP_MOVER_CONTINUE,           "MOVER_CONTINUE"},
552         {NDMP_MOVER_ABORT,              "MOVER_ABORT"},
553         {NDMP_MOVER_STOP,               "MOVER_STOP"},
554         {NDMP_MOVER_SET_WINDOW,         "MOVER_SET_WINDOW"},
555         {NDMP_MOVER_READ,               "MOVER_READ"},
556         {NDMP_MOVER_CLOSE,              "MOVER_CLOSE"},
557         {NDMP_MOVER_SET_RECORD_SIZE,    "MOVER_SET_RECORD_SIZE"},
558         {NDMP_MOVER_CONNECT,            "MOVER_CONNECT"},
559         {0, NULL}
560 };
561
562 static gboolean
563 check_ndmp_rm(tvbuff_t *tvb, packet_info *pinfo)
564 {
565         guint len;
566         guint32 tmp;
567
568         /* verify that the tcp port is 10000, ndmp always runs on port 10000*/
569         if ((pinfo->srcport!=TCP_PORT_NDMP)&&(pinfo->destport!=TCP_PORT_NDMP)) {
570                 return FALSE;
571         }
572
573         /* check that the header looks sane */
574         len=tvb_length(tvb);
575         /* check the record marker that it looks sane.
576          * It has to be >=0 bytes or (arbitrary limit) <1Mbyte
577          */
578         if(len>=4){
579                 tmp=(tvb_get_ntohl(tvb, 0)&RPC_RM_FRAGLEN);
580                 if( (tmp<1)||(tmp>1000000) ){
581                         return FALSE;
582                 }
583         }
584
585         return TRUE;
586 }
587
588 static gboolean
589 check_ndmp_hdr(tvbuff_t *tvb )
590 {
591         guint len;
592         guint32 tmp;
593
594         len=tvb_length(tvb);
595
596         /* If the length is less than 24, it isn't a valid
597            header */
598         if (len<24){
599                 return FALSE;
600         }
601
602         /* check the timestamp,  timestamps are valid if they
603          * (arbitrary) lie between 1980-jan-1 and 2030-jan-1
604          */
605         if(len>=8){
606                 tmp=tvb_get_ntohl(tvb, 4);
607                 if( (tmp<0x12ceec50)||(tmp>0x70dc1ed0) ){
608                         return FALSE;
609                 }
610         }
611
612         /* check the type */
613         if(len>=12){
614                 tmp=tvb_get_ntohl(tvb, 8);
615                 if( tmp>1 ){
616                         return FALSE;
617                 }
618         }
619
620         /* check message */
621         if(len>=16){
622                 tmp=tvb_get_ntohl(tvb, 12);
623                 if( (tmp>0xa09) || (tmp==0) ){
624                         return FALSE;
625                 }
626         }
627
628         /* check error */
629         if(len>=24){
630                 tmp=tvb_get_ntohl(tvb, 20);
631                 if( (tmp>0x17) ){
632                         return FALSE;
633                 }
634         }
635
636         return TRUE;
637 }
638
639 static int
640 dissect_connect_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
641     proto_tree *tree, guint32 seq _U_)
642 {
643         guint32 version;
644
645         /* version number */
646         proto_tree_add_item(tree, hf_ndmp_version, tvb, offset, 4, ENC_BIG_ENDIAN);
647         version=tvb_get_ntohl(tvb, offset);
648         ndmp_conv_data->version=version;
649         offset += 4;
650
651         return offset;
652 }
653
654 static int
655 dissect_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
656     proto_tree *tree, guint32 seq _U_)
657 {
658         guint32 err;
659
660         /* error */
661         err=tvb_get_ntohl(tvb, offset);
662         proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, ENC_BIG_ENDIAN);
663         if(err) {
664                 col_append_fstr(pinfo->cinfo, COL_INFO,
665                         " NDMP Error:%s ",
666                         val_to_str(err, error_vals,
667                         "Unknown NDMP error code %#x"));
668         }
669
670         offset += 4;
671
672         return offset;
673 }
674
675 static int
676 dissect_ndmp_get_host_info_reply(tvbuff_t *tvb, int offset,
677     packet_info *pinfo, proto_tree *tree, guint32 seq)
678 {
679         /* error */
680         offset=dissect_error(tvb, offset, pinfo, tree, seq);
681
682         /* hostname */
683         offset = dissect_rpc_string(tvb, tree,
684                         hf_ndmp_hostname, offset, NULL);
685
686         /* os type */
687         offset = dissect_rpc_string(tvb, tree,
688                         hf_ndmp_os_type, offset, NULL);
689
690         /* os version */
691         offset = dissect_rpc_string(tvb, tree,
692                         hf_ndmp_os_vers, offset, NULL);
693
694         /* hostid */
695         offset = dissect_rpc_string(tvb, tree,
696                         hf_ndmp_hostid, offset, NULL);
697
698         return offset;
699 }
700
701 #define NDMP_ADDR_LOCAL         0
702 #define NDMP_ADDR_TCP           1
703 #define NDMP_ADDR_FC            2
704 #define NDMP_ADDR_IPC           3
705 static const value_string addr_type_vals[] = {
706         {NDMP_ADDR_LOCAL,       "Local"},
707         {NDMP_ADDR_TCP,         "TCP"},
708         {NDMP_ADDR_FC,          "FC"},
709         {NDMP_ADDR_IPC,         "IPC"},
710         {0,NULL}
711 };
712
713 static int
714 dissect_ndmp_addr_type(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
715     proto_tree *tree, void* data _U_)
716 {
717         proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, ENC_BIG_ENDIAN);
718         offset += 4;
719
720         return offset;
721 }
722
723 static int
724 dissect_ndmp_addr_msg(tvbuff_t *tvb, int offset, packet_info *pinfo,
725     proto_tree *tree, guint32 seq _U_)
726 {
727         /*address type*/
728         return dissect_ndmp_addr_type(tvb, offset, pinfo, tree, NULL);
729 }
730
731 static int
732 dissect_ndmp_config_get_connection_type_reply(tvbuff_t *tvb, int offset,
733     packet_info *pinfo, proto_tree *tree, guint32 seq)
734 {
735         /* error */
736         offset=dissect_error(tvb, offset, pinfo, tree, seq);
737
738         /* addr types */
739         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
740                         dissect_ndmp_addr_type, hf_ndmp_addr_types);
741
742         return offset;
743 }
744
745 #define NDMP_AUTH_NONE          0
746 #define NDMP_AUTH_TEXT          1
747 #define NDMP_AUTH_MD5           2
748 static const value_string auth_type_vals[] = {
749         {NDMP_AUTH_NONE,        "None"},
750         {NDMP_AUTH_TEXT,        "Text"},
751         {NDMP_AUTH_MD5,         "MD5"},
752         {0,NULL}
753 };
754 static int
755 dissect_auth_type(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
756     proto_tree *tree, void* data _U_)
757 {
758         proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, ENC_BIG_ENDIAN);
759         offset += 4;
760
761         return offset;
762 }
763
764 static int
765 dissect_get_auth_type_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
766     proto_tree *tree, guint32 seq _U_)
767 {
768         /* auth type */
769         return dissect_auth_type(tvb, offset, pinfo, tree, NULL);
770 }
771
772 static int
773 dissect_auth_attr_msg(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
774     proto_tree *tree, guint32 seq _U_)
775 {
776         guint type;
777
778         type=tvb_get_ntohl(tvb,offset);
779
780         /* auth type */
781         proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, ENC_BIG_ENDIAN);
782         offset += 4;
783
784         switch(type){
785         case NDMP_AUTH_NONE:
786                 break;
787         case NDMP_AUTH_TEXT:
788                 break;
789         case NDMP_AUTH_MD5:
790                 proto_tree_add_item(tree, hf_ndmp_auth_challenge,
791                         tvb, offset, 64, ENC_NA);
792                 offset+=64;
793         }
794
795         return offset;
796 }
797
798 static int
799 dissect_ndmp_config_get_auth_attr_reply(tvbuff_t *tvb, int offset,
800     packet_info *pinfo, proto_tree *tree, guint32 seq)
801 {
802     /* error */
803     offset = dissect_error(tvb, offset, pinfo, tree, seq);
804
805     /* auth_attr */
806     offset = dissect_auth_attr_msg(tvb, offset, pinfo, tree, seq);
807
808     return offset;
809 }
810
811 static int
812 dissect_default_env(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
813     proto_tree *tree, void* data _U_)
814 {
815         /* name */
816         offset = dissect_rpc_string(tvb, tree,
817                         hf_ndmp_butype_env_name, offset, NULL);
818
819         /* value */
820         offset = dissect_rpc_string(tvb, tree,
821                         hf_ndmp_butype_env_value, offset, NULL);
822
823         return offset;
824 }
825
826
827 static const true_false_string tfs_butype_attr_backup_file_history = {
828         "Backup FILE HISTORY",
829         "Do NOT backup file history"
830 };
831 static const true_false_string tfs_butype_attr_backup_filelist = {
832         "Backup FILELIST",
833         "Do NOT backup filelist"
834 };
835 static const true_false_string tfs_butype_attr_recover_filelist = {
836         "Recover FILELIST",
837         "Do NOT recover filelist"
838 };
839 static const true_false_string tfs_butype_attr_backup_direct = {
840         "Perform DIRECT backup",
841         "Do NOT perform direct backup"
842 };
843 static const true_false_string tfs_butype_attr_recover_direct = {
844         "Perform DIRECT recovery",
845         "Do NOT perform direct recovery"
846 };
847 static const true_false_string tfs_butype_attr_backup_incremental = {
848         "Perform INCREMENTAL backup",
849         "Perform FULL backup"
850 };
851 static const true_false_string tfs_butype_attr_recover_incremental = {
852         "Perform INCREMENTAL recovery",
853         "Perform FULL recovery"
854 };
855 static const true_false_string tfs_butype_attr_backup_utf8 = {
856         "Backup using UTF8",
857         "Normal backup. Do NOT use utf8"
858 };
859 static const true_false_string tfs_butype_attr_recover_utf8 = {
860         "Recover using UTF8",
861         "Normal recover. Do NOT use utf8"
862 };
863 static int
864 dissect_butype_attrs(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
865     proto_tree *parent_tree)
866 {
867         proto_item* item = NULL;
868         proto_tree* tree = NULL;
869         guint32 flags;
870
871         flags=tvb_get_ntohl(tvb, offset);
872         if (parent_tree) {
873                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
874                                 "Attributes: 0x%08x", flags);
875                 tree = proto_item_add_subtree(item, ett_ndmp_butype_attrs);
876         }
877
878         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_utf8,
879                                 tvb, offset, 4, flags);
880         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_utf8,
881                                 tvb, offset, 4, flags);
882         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_incremental,
883                                 tvb, offset, 4, flags);
884         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_incremental,
885                                 tvb, offset, 4, flags);
886         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_direct,
887                                 tvb, offset, 4, flags);
888         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_direct,
889                                 tvb, offset, 4, flags);
890         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_recover_filelist,
891                                 tvb, offset, 4, flags);
892         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_filelist,
893                                 tvb, offset, 4, flags);
894         proto_tree_add_boolean(tree, hf_ndmp_butype_attr_backup_file_history,
895                                 tvb, offset, 4, flags);
896
897         offset += 4;
898         return offset;
899 }
900
901 static int
902 dissect_butype_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void* data _U_)
903 {
904         /*butype name*/
905         offset = dissect_rpc_string(tvb, tree,
906                         hf_ndmp_butype_name, offset, NULL);
907
908         /* default env */
909         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
910                         dissect_default_env, hf_ndmp_butype_default_env);
911
912         /* attrs */
913         offset = dissect_butype_attrs(tvb, offset, pinfo, tree);
914
915         return offset;
916 }
917
918 static int
919 dissect_get_butype_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
920     proto_tree *tree, guint32 seq)
921 {
922         /* error */
923         offset=dissect_error(tvb, offset, pinfo, tree, seq);
924
925         /* butype */
926         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
927                         dissect_butype_info, hf_ndmp_butype_info);
928
929         return offset;
930 }
931
932 static const true_false_string tfs_fs_invalid_total_size = {
933         "Total size is INVALID",
934         "Total size is VALID"
935 };
936 static const true_false_string tfs_fs_invalid_used_size = {
937         "Used size is INVALID",
938         "Used size is VALID"
939 };
940 static const true_false_string tfs_fs_invalid_avail_size = {
941         "Available size is INVALID",
942         "Available size is VALID"
943 };
944 static const true_false_string tfs_fs_invalid_total_inodes = {
945         "Total inode count is INVALID",
946         "Total inode count is VALID"
947 };
948 static const true_false_string tfs_fs_invalid_used_inodes = {
949         "Used inode count is INVALID",
950         "Used inode count is VALID"
951 };
952 static int
953 dissect_fs_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
954     proto_tree *parent_tree)
955 {
956         proto_item* item = NULL;
957         proto_tree* tree = NULL;
958         guint32 flags;
959
960         flags=tvb_get_ntohl(tvb, offset);
961         if (parent_tree) {
962                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
963                                 "Invalids: 0x%08x", flags);
964                 tree = proto_item_add_subtree(item, ett_ndmp_fs_invalid);
965         }
966
967         proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_used_inodes,
968                                 tvb, offset, 4, flags);
969         proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_total_inodes,
970                                 tvb, offset, 4, flags);
971         proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_avail_size,
972                                 tvb, offset, 4, flags);
973         proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_used_size,
974                                 tvb, offset, 4, flags);
975         proto_tree_add_boolean(tree, hf_ndmp_fs_invalid_total_size,
976                                 tvb, offset, 4, flags);
977
978         offset+=4;
979         return offset;
980 }
981
982 static int
983 dissect_fs_env(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
984     proto_tree *tree, void* data _U_)
985 {
986         /* name */
987         offset = dissect_rpc_string(tvb, tree,
988                         hf_ndmp_fs_env_name, offset, NULL);
989
990         /* value */
991         offset = dissect_rpc_string(tvb, tree,
992                         hf_ndmp_fs_env_value, offset, NULL);
993
994         return offset;
995 }
996
997 static int
998 dissect_fs_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void* data _U_)
999 {
1000         /* invalid bits */
1001         offset=dissect_fs_invalid(tvb, offset, pinfo, tree);
1002
1003         /* fs type */
1004         offset = dissect_rpc_string(tvb, tree,
1005                         hf_ndmp_fs_fs_type, offset, NULL);
1006
1007         /* fs logical device */
1008         offset = dissect_rpc_string(tvb, tree,
1009                         hf_ndmp_fs_logical_device, offset, NULL);
1010
1011         /* fs physical device */
1012         offset = dissect_rpc_string(tvb, tree,
1013                         hf_ndmp_fs_physical_device, offset, NULL);
1014
1015         /*total_size*/
1016         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_total_size,
1017                         offset);
1018
1019         /*used_size*/
1020         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_used_size,
1021                         offset);
1022
1023         /*avail_size*/
1024         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_avail_size,
1025                         offset);
1026
1027         /*total_inodes*/
1028         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_total_inodes,
1029                         offset);
1030
1031         /*used_inodes*/
1032         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_fs_used_inodes,
1033                         offset);
1034
1035         /* env */
1036         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1037                         dissect_fs_env, hf_ndmp_fs_env);
1038
1039         /* status */
1040         offset = dissect_rpc_string(tvb, tree,
1041                         hf_ndmp_fs_status, offset, NULL);
1042
1043         return offset;
1044 }
1045
1046 static int
1047 dissect_get_fs_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1048     proto_tree *tree, guint32 seq)
1049 {
1050         /* error */
1051         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1052
1053         /* fs */
1054         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1055                         dissect_fs_info, hf_ndmp_fs_info);
1056
1057         return offset;
1058 }
1059
1060 static const true_false_string tfs_tape_attr_rewind = {
1061         "Device supports REWIND",
1062         "Device does NOT support rewind"
1063 };
1064 static const true_false_string tfs_tape_attr_unload = {
1065         "Device supports UNLOAD",
1066         "Device does NOT support unload"
1067 };
1068 static int
1069 dissect_tape_attr(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1070     proto_tree *parent_tree)
1071 {
1072         proto_item* item = NULL;
1073         proto_tree* tree = NULL;
1074         guint32 flags;
1075
1076         flags=tvb_get_ntohl(tvb, offset);
1077         if (parent_tree) {
1078                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
1079                                 "Attributes: 0x%08x", flags);
1080                 tree = proto_item_add_subtree(item, ett_ndmp_tape_attr);
1081         }
1082
1083         proto_tree_add_boolean(tree, hf_ndmp_tape_attr_unload,
1084                                 tvb, offset, 4, flags);
1085         proto_tree_add_boolean(tree, hf_ndmp_tape_attr_rewind,
1086                                 tvb, offset, 4, flags);
1087
1088         offset+=4;
1089         return offset;
1090 }
1091
1092 static int
1093 dissect_tape_capability(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1094     proto_tree *tree, void* data _U_)
1095 {
1096         /* name */
1097         offset = dissect_rpc_string(tvb, tree,
1098                         hf_ndmp_tape_capability_name, offset, NULL);
1099
1100         /* value */
1101         offset = dissect_rpc_string(tvb, tree,
1102                         hf_ndmp_tape_capability_value, offset, NULL);
1103
1104         return offset;
1105 }
1106
1107 static int
1108 dissect_tape_dev_cap(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void* data _U_)
1109 {
1110         /* device */
1111         offset = dissect_rpc_string(tvb, tree,
1112                         hf_ndmp_tape_device, offset, NULL);
1113
1114         /* tape attributes */
1115         offset = dissect_tape_attr(tvb, offset, pinfo, tree);
1116
1117         /* capability */
1118         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1119                         dissect_tape_capability, hf_ndmp_tape_capability);
1120
1121         return offset;
1122 }
1123
1124 static int
1125 dissect_tape_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void* data _U_)
1126 {
1127         /* model */
1128         offset = dissect_rpc_string(tvb, tree,
1129                         hf_ndmp_tape_model, offset, NULL);
1130
1131         /* device capabilites */
1132         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1133                         dissect_tape_dev_cap, hf_ndmp_tape_dev_cap);
1134
1135         return offset;
1136 }
1137
1138 static int
1139 dissect_get_tape_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1140     proto_tree *tree, guint32 seq)
1141 {
1142         /* error */
1143         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1144
1145         /* tape */
1146         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1147                         dissect_tape_info, hf_ndmp_tape_info);
1148
1149         return offset;
1150 }
1151
1152 static int
1153 dissect_scsi_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void* data _U_)
1154 {
1155         /* model */
1156         offset = dissect_rpc_string(tvb, tree,
1157                         hf_ndmp_scsi_model, offset, NULL);
1158
1159         /* device capabilites */
1160         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1161                         dissect_tape_dev_cap, hf_ndmp_tape_dev_cap);
1162
1163         return offset;
1164 }
1165
1166 static int
1167 dissect_get_scsi_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1168     proto_tree *tree, guint32 seq)
1169 {
1170         /* error */
1171         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1172
1173         /* scsi */
1174         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1175                         dissect_scsi_info, hf_ndmp_scsi_info);
1176
1177         return offset;
1178 }
1179
1180 static int
1181 dissect_get_server_info_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1182     proto_tree *tree, guint32 seq)
1183 {
1184         /* error */
1185         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1186
1187         /* vendor */
1188         offset = dissect_rpc_string(tvb, tree,
1189                         hf_ndmp_server_vendor, offset, NULL);
1190
1191         /* product */
1192         offset = dissect_rpc_string(tvb, tree,
1193                         hf_ndmp_server_product, offset, NULL);
1194
1195         /* revision */
1196         offset = dissect_rpc_string(tvb, tree,
1197                         hf_ndmp_server_revision, offset, NULL);
1198
1199
1200         /* server */
1201         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1202                         dissect_auth_type, hf_ndmp_auth_types);
1203
1204         return offset;
1205 }
1206
1207 static int
1208 dissect_ext_version(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1209                 proto_tree *tree, void* data _U_) {
1210
1211         /* extension version */
1212         proto_tree_add_item(tree, hf_ndmp_ext_version, tvb, offset, 4, ENC_BIG_ENDIAN);
1213         offset += 4;
1214
1215         return offset;
1216 }
1217
1218
1219 static int
1220 dissect_class_list(tvbuff_t *tvb, int offset, packet_info *pinfo,
1221                 proto_tree *tree, void* data _U_) {
1222
1223         /* class id */
1224         proto_tree_add_item(tree, hf_ndmp_ex_class_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1225         offset += 4;
1226
1227         /* ext version */
1228         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1229                         dissect_ext_version, hf_ndmp_ext_version_list);
1230
1231         return offset;
1232 }
1233
1234 static int
1235 dissect_get_ext_list_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1236                 proto_tree *tree, guint32 seq)
1237 {
1238         /* error */
1239         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1240
1241         /* Class list */
1242         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1243                         dissect_class_list, hf_ndmp_class_list);
1244
1245         return offset;
1246 }
1247
1248
1249 static int
1250 dissect_class_version(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1251                 proto_tree *tree, void* data _U_) {
1252
1253         /* class id */
1254         proto_tree_add_item(tree, hf_ndmp_ex_class_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1255         offset += 4;
1256
1257         /* ext version */
1258         proto_tree_add_item(tree, hf_ndmp_ex_class_version, tvb, offset, 4, ENC_BIG_ENDIAN);
1259         offset += 4;
1260
1261         return offset;
1262 }
1263
1264 static int
1265 dissect_set_ext_list_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
1266                 proto_tree *tree, guint32 seq _U_)
1267 {
1268         /* class version */
1269         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1270                         dissect_class_version, hf_ndmp_class_version);
1271
1272         return offset;
1273 }
1274
1275
1276 static int
1277 dissect_set_ext_list_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1278                 proto_tree *tree, guint32 seq _U_)
1279 {
1280         /* error */
1281         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1282
1283         return offset;
1284 }
1285
1286 static int
1287 dissect_scsi_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
1288     proto_tree *tree, guint32 seq _U_)
1289 {
1290         /* device */
1291         offset = dissect_rpc_string(tvb, tree,
1292                         hf_ndmp_scsi_device, offset, NULL);
1293
1294
1295         if(!pinfo->fd->flags.visited){
1296                 /* new scsi device addressed, create a new itl structure */
1297                 get_itl_nexus(pinfo, TRUE);
1298         }
1299
1300         return offset;
1301 }
1302
1303 static int
1304 dissect_scsi_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1305     proto_tree *tree, guint32 seq)
1306 {
1307         /* error */
1308         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1309
1310         /* controller */
1311         proto_tree_add_item(tree, hf_ndmp_scsi_controller, tvb, offset, 4, ENC_BIG_ENDIAN);
1312         offset += 4;
1313
1314         /* id */
1315         proto_tree_add_item(tree, hf_ndmp_scsi_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1316         offset += 4;
1317
1318         /* lun */
1319         proto_tree_add_item(tree, hf_ndmp_scsi_lun, tvb, offset, 4, ENC_BIG_ENDIAN);
1320         offset += 4;
1321
1322         return offset;
1323 }
1324
1325 static int
1326 dissect_scsi_set_state_request(tvbuff_t *tvb, int offset,
1327     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
1328 {
1329         /* device */
1330         offset = dissect_rpc_string(tvb, tree,
1331                         hf_ndmp_scsi_device, offset, NULL);
1332
1333         /* controller */
1334         proto_tree_add_item(tree, hf_ndmp_scsi_controller, tvb, offset, 4, ENC_BIG_ENDIAN);
1335         offset += 4;
1336
1337         /* id */
1338         proto_tree_add_item(tree, hf_ndmp_scsi_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1339         offset += 4;
1340
1341         /* lun */
1342         proto_tree_add_item(tree, hf_ndmp_scsi_lun, tvb, offset, 4, ENC_BIG_ENDIAN);
1343         offset += 4;
1344
1345         return offset;
1346 }
1347
1348 static int
1349 dissect_execute_cdb_flags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1350     proto_tree *parent_tree)
1351 {
1352         proto_item* item = NULL;
1353         proto_tree* tree = NULL;
1354         guint32 flags;
1355
1356         flags = tvb_get_ntohl(tvb, offset);
1357         if (parent_tree) {
1358                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
1359                                 "Flags: 0x%08x", flags);
1360                 tree = proto_item_add_subtree(item, ett_ndmp_execute_cdb_flags);
1361         }
1362
1363         proto_tree_add_boolean(tree, hf_ndmp_execute_cdb_flags_data_in,
1364                                 tvb, offset, 4, flags);
1365         proto_tree_add_boolean(tree, hf_ndmp_execute_cdb_flags_data_out,
1366                                 tvb, offset, 4, flags);
1367         offset += 4;
1368         return offset;
1369 }
1370
1371 static int
1372 dissect_execute_cdb_cdb(tvbuff_t *tvb, int offset, packet_info *pinfo,
1373     proto_tree *parent_tree, gint devtype)
1374 {
1375         proto_item* item = NULL;
1376         proto_tree* tree = NULL;
1377         guint32 cdb_len;
1378         guint32 cdb_len_full;
1379
1380         cdb_len = tvb_get_ntohl(tvb, offset);
1381         cdb_len_full = rpc_roundup(cdb_len);
1382
1383         if (parent_tree) {
1384                 item = proto_tree_add_text(parent_tree, tvb, offset,
1385                                 4+cdb_len_full, "CDB");
1386                 tree = proto_item_add_subtree(item, ett_ndmp_execute_cdb_cdb);
1387         }
1388
1389         proto_tree_add_uint(tree, hf_ndmp_execute_cdb_cdb_len, tvb, offset, 4,
1390                         cdb_len);
1391         offset += 4;
1392
1393         if (cdb_len != 0) {
1394                 tvbuff_t *cdb_tvb;
1395                 int tvb_len, tvb_rlen;
1396
1397                 tvb_len=tvb_length_remaining(tvb, offset);
1398                 if(tvb_len>16)
1399                         tvb_len=16;
1400                 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1401                 if(tvb_rlen>16)
1402                         tvb_rlen=16;
1403                 cdb_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1404
1405                 if(ndmp_conv_data->task && !ndmp_conv_data->task->itlq){
1406                         ndmp_conv_data->task->itlq=wmem_new(wmem_file_scope(), itlq_nexus_t);
1407                         ndmp_conv_data->task->itlq->lun=0xffff;
1408                         ndmp_conv_data->task->itlq->first_exchange_frame=pinfo->fd->num;
1409                         ndmp_conv_data->task->itlq->last_exchange_frame=0;
1410                         ndmp_conv_data->task->itlq->scsi_opcode=0xffff;
1411                         ndmp_conv_data->task->itlq->task_flags=0;
1412                         ndmp_conv_data->task->itlq->data_length=0;
1413                         ndmp_conv_data->task->itlq->bidir_data_length=0;
1414                         ndmp_conv_data->task->itlq->flags=0;
1415                         ndmp_conv_data->task->itlq->alloc_len=0;
1416                         ndmp_conv_data->task->itlq->fc_time=pinfo->fd->abs_ts;
1417                         ndmp_conv_data->task->itlq->extra_data=NULL;
1418                 }
1419                 if(ndmp_conv_data->task && ndmp_conv_data->task->itlq){
1420                         dissect_scsi_cdb(cdb_tvb, pinfo, top_tree, devtype, ndmp_conv_data->task->itlq, get_itl_nexus(pinfo, FALSE));
1421                 }
1422                 offset += cdb_len_full;
1423         }
1424
1425         return offset;
1426 }
1427
1428
1429 static int
1430 dissect_execute_cdb_payload(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree,
1431     const char *name, int hf_len, gboolean isreq)
1432 {
1433         proto_item* item = NULL;
1434         proto_tree* tree = NULL;
1435         guint32 payload_len;
1436         guint32 payload_len_full;
1437
1438         payload_len = tvb_get_ntohl(tvb, offset);
1439         payload_len_full = rpc_roundup(payload_len);
1440
1441         if (parent_tree) {
1442                 item = proto_tree_add_text(parent_tree, tvb, offset,
1443                                 4+payload_len_full, "%s", name);
1444                 tree = proto_item_add_subtree(item,
1445                     ett_ndmp_execute_cdb_payload);
1446         }
1447
1448         proto_tree_add_uint(tree, hf_len, tvb, offset, 4, payload_len);
1449         offset += 4;
1450
1451         if ((int) payload_len > 0) {
1452                 tvbuff_t *data_tvb;
1453                 int tvb_len, tvb_rlen;
1454
1455                 tvb_len=tvb_length_remaining(tvb, offset);
1456                 if(tvb_len>(int)payload_len)
1457                         tvb_len=payload_len;
1458                 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1459                 if(tvb_rlen>(int)payload_len)
1460                         tvb_rlen=payload_len;
1461                 data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1462
1463                 if(ndmp_conv_data->task && ndmp_conv_data->task->itlq){
1464                         /* ndmp conceptually always send both read and write
1465                          * data and always a full nonfragmented pdu
1466                          */
1467                         ndmp_conv_data->task->itlq->task_flags=SCSI_DATA_READ|SCSI_DATA_WRITE;
1468                         ndmp_conv_data->task->itlq->data_length=payload_len;
1469                         ndmp_conv_data->task->itlq->bidir_data_length=payload_len;
1470                         dissect_scsi_payload(data_tvb, pinfo, top_tree, isreq,
1471                                    ndmp_conv_data->task->itlq,
1472                                    get_itl_nexus(pinfo, FALSE),
1473                                    0);
1474                 }
1475                 offset += payload_len_full;
1476         }
1477
1478         return offset;
1479 }
1480
1481 /*
1482  * XXX - we assume that NDMP_SCSI_EXECUTE_CDB requests only go to SCSI Media
1483  * Changer devices and NDMP_TAPE_EXECUTE_CDB only go to SCSI Sequential
1484  * Access devices.
1485  *
1486  * If that's not the case, we'll have to use the SCSI dissector's mechanisms
1487  * for saving inquiry data for devices, and use inquiry data when available.
1488  * Unfortunately, that means we need to save the name of the device, and
1489  * use it as a device identifier; as the name isn't available in the
1490  * NDMP_SCSI_EXECUTE_CDB or NDMP_TAPE_EXECUTE_CDB messages, that means
1491  * we need to remember the currently-opened "SCSI" and "TAPE" devices
1492  * from NDMP_SCSI_OPEN and NDMP_TAPE_OPEN, and attach to all frames
1493  * that are the ones that trigger the dissection of NDMP_SCSI_EXECUTE_CDB
1494  * or NDMP_TAPE_EXECUTE_CDB requests pointers to those names.
1495  */
1496 static int
1497 dissect_execute_cdb_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
1498     proto_tree *tree, guint32 seq _U_, gint devtype)
1499 {
1500         /* flags */
1501         offset = dissect_execute_cdb_flags(tvb, offset, pinfo, tree);
1502
1503         /* timeout */
1504         proto_tree_add_item(tree, hf_ndmp_execute_cdb_timeout, tvb, offset, 4, ENC_BIG_ENDIAN);
1505         offset += 4;
1506
1507         /* datain_len */
1508         proto_tree_add_item(tree, hf_ndmp_execute_cdb_datain_len, tvb, offset, 4, ENC_BIG_ENDIAN);
1509         offset += 4;
1510
1511         /* CDB */
1512         offset = dissect_execute_cdb_cdb(tvb, offset, pinfo, tree, devtype);
1513
1514         /* dataout */
1515         offset = dissect_execute_cdb_payload(tvb, offset, pinfo, tree,
1516             "Data out", hf_ndmp_execute_cdb_dataout_len, TRUE);
1517
1518         return offset;
1519 }
1520
1521 static int
1522 dissect_execute_cdb_request_mc(tvbuff_t *tvb, int offset, packet_info *pinfo,
1523     proto_tree *tree, guint32 seq)
1524 {
1525         return dissect_execute_cdb_request(tvb, offset, pinfo, tree, seq,
1526             SCSI_DEV_SMC);
1527 }
1528
1529 static int
1530 dissect_execute_cdb_request_tape(tvbuff_t *tvb, int offset, packet_info *pinfo,
1531     proto_tree *tree, guint32 seq)
1532 {
1533         return dissect_execute_cdb_request(tvb, offset, pinfo, tree, seq,
1534             SCSI_DEV_SSC);
1535 }
1536
1537 static int
1538 dissect_execute_cdb_sns(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
1539 {
1540         proto_item* item = NULL;
1541         proto_tree* tree = NULL;
1542         guint32 sns_len;
1543         guint32 sns_len_full;
1544
1545         sns_len = tvb_get_ntohl(tvb, offset);
1546         sns_len_full = rpc_roundup(sns_len);
1547
1548         if (parent_tree) {
1549                 item = proto_tree_add_text(parent_tree, tvb, offset,
1550                                 4+sns_len_full, "Sense data");
1551                 tree = proto_item_add_subtree(item, ett_ndmp_execute_cdb_sns);
1552         }
1553
1554         proto_tree_add_uint(tree, hf_ndmp_execute_cdb_sns_len, tvb, offset, 4,
1555                         sns_len);
1556         offset += 4;
1557
1558         if (sns_len != 0) {
1559                 if(ndmp_conv_data->task && ndmp_conv_data->task->itlq){
1560                         dissect_scsi_snsinfo(tvb, pinfo, top_tree, offset, sns_len, ndmp_conv_data->task->itlq, get_itl_nexus(pinfo, FALSE));
1561                 }
1562                 offset += sns_len_full;
1563         }
1564
1565         return offset;
1566 }
1567
1568 static int
1569 dissect_execute_cdb_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1570     proto_tree *tree, guint32 seq)
1571 {
1572         guint32 status;
1573
1574         /* error */
1575         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1576
1577         /* status */
1578         proto_tree_add_item(tree, hf_ndmp_execute_cdb_status, tvb, offset, 4, ENC_BIG_ENDIAN);
1579         status=tvb_get_ntohl(tvb, offset);
1580         if(ndmp_conv_data->task && ndmp_conv_data->task->itlq){
1581                 dissect_scsi_rsp(tvb, pinfo, top_tree, ndmp_conv_data->task->itlq, get_itl_nexus(pinfo, FALSE), (guint8)status);
1582         }
1583         offset += 4;
1584
1585
1586         /* dataout_len */
1587         proto_tree_add_item(tree, hf_ndmp_execute_cdb_dataout_len, tvb, offset, 4, ENC_BIG_ENDIAN);
1588         offset += 4;
1589
1590         /* datain */
1591         offset = dissect_execute_cdb_payload(tvb, offset, pinfo, tree,
1592             "Data in", hf_ndmp_execute_cdb_datain_len, FALSE);
1593
1594         /* ext_sense */
1595         offset = dissect_execute_cdb_sns(tvb, offset, pinfo, tree);
1596
1597         return offset;
1598 }
1599
1600 #define NDMP_TAPE_OPEN_MODE_READ        0
1601 #define NDMP_TAPE_OPEN_MODE_RDWR        1
1602 static const value_string tape_open_mode_vals[] = {
1603         {NDMP_TAPE_OPEN_MODE_READ,      "Read"},
1604         {NDMP_TAPE_OPEN_MODE_RDWR,      "Read/Write"},
1605         {0, NULL}
1606 };
1607
1608 static int
1609 dissect_tape_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
1610     proto_tree *tree, guint32 seq _U_)
1611 {
1612         /* device */
1613         offset = dissect_rpc_string(tvb, tree,
1614                         hf_ndmp_tape_device, offset, NULL);
1615
1616         /* open mode */
1617         proto_tree_add_item(tree, hf_ndmp_tape_open_mode, tvb, offset, 4, ENC_BIG_ENDIAN);
1618         offset += 4;
1619
1620         if(!pinfo->fd->flags.visited){
1621                 /* new scsi device addressed, create a new itl structure */
1622                 get_itl_nexus(pinfo, TRUE);
1623         }
1624
1625         return offset;
1626 }
1627
1628
1629 static const true_false_string tfs_ndmp_tape_invalid_file_num = {
1630         "File num is INVALID",
1631         "File num is VALID"
1632 };
1633 static const true_false_string tfs_ndmp_tape_invalid_soft_errors = {
1634         "Soft errors is INVALID",
1635         "Soft errors is VALID"
1636 };
1637 static const true_false_string tfs_ndmp_tape_invalid_block_size = {
1638         "Block size is INVALID",
1639         "Block size is VALID"
1640 };
1641 static const true_false_string tfs_ndmp_tape_invalid_block_no = {
1642         "Block no is INVALID",
1643         "Block no is VALID"
1644 };
1645 static const true_false_string tfs_ndmp_tape_invalid_total_space = {
1646         "Total space is INVALID",
1647         "Total space is VALID"
1648 };
1649 static const true_false_string tfs_ndmp_tape_invalid_space_remain = {
1650         "Space remaining is INVALID",
1651         "Space remaining is VALID"
1652 };
1653 static const true_false_string tfs_ndmp_tape_invalid_partition = {
1654         "Partition is INVALID",
1655         "Partition is VALID"
1656 };
1657 static int
1658 dissect_tape_invalid(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1659     proto_tree *parent_tree)
1660 {
1661         proto_item* item = NULL;
1662         proto_tree* tree = NULL;
1663         guint32 flags;
1664
1665         flags=tvb_get_ntohl(tvb, offset);
1666         if (parent_tree) {
1667                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
1668                                 "Invalids: 0x%08x", flags);
1669                 tree = proto_item_add_subtree(item, ett_ndmp_tape_invalid);
1670         }
1671
1672         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_partition,
1673                                 tvb, offset, 4, flags);
1674         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_space_remain,
1675                                 tvb, offset, 4, flags);
1676         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_total_space,
1677                                 tvb, offset, 4, flags);
1678         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_block_no,
1679                                 tvb, offset, 4, flags);
1680         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_block_size,
1681                                 tvb, offset, 4, flags);
1682         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_soft_errors,
1683                                 tvb, offset, 4, flags);
1684         proto_tree_add_boolean(tree, hf_ndmp_tape_invalid_file_num,
1685                                 tvb, offset, 4, flags);
1686
1687         offset+=4;
1688         return offset;
1689 }
1690
1691 static const true_false_string tfs_ndmp_tape_flags_no_rewind = {
1692         "This is a NON-REWINDING device",
1693         "This device supports rewind"
1694 };
1695 static const true_false_string tfs_ndmp_tape_flags_write_protect = {
1696         "This device is WRITE-PROTECTED",
1697         "This device is NOT write-protected"
1698 };
1699 static const true_false_string tfs_ndmp_tape_flags_error = {
1700         "This device shows ERROR",
1701         "This device shows NO errors"
1702 };
1703 static const true_false_string tfs_ndmp_tape_flags_unload = {
1704         "This device supports UNLOAD",
1705         "This device does NOT support unload"
1706 };
1707 static int
1708 dissect_tape_flags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1709     proto_tree *parent_tree)
1710 {
1711         proto_item* item = NULL;
1712         proto_tree* tree = NULL;
1713         guint32 flags;
1714
1715         flags=tvb_get_ntohl(tvb, offset);
1716         if (parent_tree) {
1717                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
1718                                 "Flags: 0x%08x", flags);
1719                 tree = proto_item_add_subtree(item, ett_ndmp_tape_flags);
1720         }
1721
1722
1723         proto_tree_add_boolean(tree, hf_ndmp_tape_flags_unload,
1724                                 tvb, offset, 4, flags);
1725         proto_tree_add_boolean(tree, hf_ndmp_tape_flags_error,
1726                                 tvb, offset, 4, flags);
1727         proto_tree_add_boolean(tree, hf_ndmp_tape_flags_write_protect,
1728                                 tvb, offset, 4, flags);
1729         proto_tree_add_boolean(tree, hf_ndmp_tape_flags_no_rewind,
1730                                 tvb, offset, 4, flags);
1731
1732         offset+=4;
1733         return offset;
1734 }
1735
1736 static int
1737 dissect_tape_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1738     proto_tree *tree, guint32 seq)
1739 {
1740         /* invalid bits */
1741         offset=dissect_tape_invalid(tvb, offset, pinfo, tree);
1742
1743         /* error */
1744         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1745
1746         /* flags */
1747         offset=dissect_tape_flags(tvb, offset, pinfo, tree);
1748
1749         /* file_num */
1750         proto_tree_add_item(tree, hf_ndmp_tape_file_num, tvb, offset, 4, ENC_BIG_ENDIAN);
1751         offset += 4;
1752
1753         /* soft_errors */
1754         proto_tree_add_item(tree, hf_ndmp_tape_soft_errors, tvb, offset, 4, ENC_BIG_ENDIAN);
1755         offset += 4;
1756
1757         /* block_size */
1758         proto_tree_add_item(tree, hf_ndmp_tape_block_size, tvb, offset, 4, ENC_BIG_ENDIAN);
1759         offset += 4;
1760
1761         /* block_no */
1762         proto_tree_add_item(tree, hf_ndmp_tape_block_no, tvb, offset, 4, ENC_BIG_ENDIAN);
1763         offset += 4;
1764
1765         /* total_space */
1766         offset = dissect_rpc_uint64(tvb, tree,hf_ndmp_tape_total_space,
1767                         offset);
1768
1769         /* space_remain */
1770         offset = dissect_rpc_uint64(tvb, tree,hf_ndmp_tape_space_remain,
1771                         offset);
1772
1773         /* NDMP Version 4 does not have a partition field here, so just return now. */
1774         if (get_ndmp_protocol_version() == NDMP_PROTOCOL_V4)
1775                 return offset;
1776
1777         /* partition */
1778         proto_tree_add_item(tree, hf_ndmp_tape_partition, tvb, offset, 4, ENC_BIG_ENDIAN);
1779         offset += 4;
1780
1781         return offset;
1782 }
1783
1784 #define NDMP_TAPE_MTIO_FSF      0
1785 #define NDMP_TAPE_MTIO_BSF      1
1786 #define NDMP_TAPE_MTIO_FSR      2
1787 #define NDMP_TAPE_MTIO_BSR      3
1788 #define NDMP_TAPE_MTIO_REW      4
1789 #define NDMP_TAPE_MTIO_EOF      5
1790 #define NDMP_TAPE_MTIO_OFF      6
1791 static const value_string tape_mtio_vals[] = {
1792         {NDMP_TAPE_MTIO_FSF,    "FSF"},
1793         {NDMP_TAPE_MTIO_BSF,    "BSF"},
1794         {NDMP_TAPE_MTIO_FSR,    "FSR"},
1795         {NDMP_TAPE_MTIO_BSR,    "BSR"},
1796         {NDMP_TAPE_MTIO_REW,    "REW"},
1797         {NDMP_TAPE_MTIO_EOF,    "EOF"},
1798         {NDMP_TAPE_MTIO_OFF,    "OFF"},
1799         {0, NULL}
1800 };
1801
1802 static int
1803 dissect_tape_mtio_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1804     proto_tree *tree, guint32 seq _U_)
1805 {
1806         /* op */
1807         proto_tree_add_item(tree, hf_ndmp_tape_mtio_op, tvb, offset, 4, ENC_BIG_ENDIAN);
1808         offset += 4;
1809
1810         /* count */
1811         proto_tree_add_item(tree, hf_ndmp_count, tvb, offset, 4, ENC_BIG_ENDIAN);
1812         offset += 4;
1813
1814         return offset;
1815 }
1816
1817 static int
1818 dissect_tape_mtio_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1819     proto_tree *tree, guint32 seq)
1820 {
1821         /* error */
1822         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1823
1824         /* resid count */
1825         proto_tree_add_item(tree, hf_ndmp_resid_count, tvb, offset, 4, ENC_BIG_ENDIAN);
1826         offset += 4;
1827
1828         return offset;
1829 }
1830
1831 #define NDMP_MOVER_STATE_IDLE           0
1832 #define NDMP_MOVER_STATE_LISTEN         1
1833 #define NDMP_MOVER_STATE_ACTIVE         2
1834 #define NDMP_MOVER_STATE_PAUSED         3
1835 #define NDMP_MOVER_STATE_HALTED         4
1836 static const value_string mover_state_vals[] = {
1837         {NDMP_MOVER_STATE_IDLE, "MOVER_STATE_IDLE"},
1838         {NDMP_MOVER_STATE_LISTEN,       "MOVER_STATE_LISTEN"},
1839         {NDMP_MOVER_STATE_ACTIVE,       "MOVER_STATE_ACTIVE"},
1840         {NDMP_MOVER_STATE_PAUSED,       "MOVER_STATE_PAUSED"},
1841         {NDMP_MOVER_STATE_HALTED,       "MOVER_STATE_HALTED"},
1842         {0, NULL}
1843 };
1844
1845 #define NDMP_MOVER_PAUSE_NA             0
1846 #define NDMP_MOVER_PAUSE_EOM            1
1847 #define NDMP_MOVER_PAUSE_EOF            2
1848 #define NDMP_MOVER_PAUSE_SEEK           3
1849 #define NDMP_MOVER_PAUSE_MEDIA_ERROR    4
1850 #define NDMP_MOVER_PAUSE_EOW            5
1851 static const value_string mover_pause_vals[] = {
1852         {NDMP_MOVER_PAUSE_NA,           "MOVER_PAUSE_NA"},
1853         {NDMP_MOVER_PAUSE_EOM,          "MOVER_PAUSE_EOM"},
1854         {NDMP_MOVER_PAUSE_EOF,          "MOVER_PAUSE_EOF"},
1855         {NDMP_MOVER_PAUSE_SEEK,         "MOVER_PAUSE_SEEK"},
1856         {NDMP_MOVER_PAUSE_MEDIA_ERROR,  "MOVER_PAUSE_MEDIA_ERROR"},
1857         {NDMP_MOVER_PAUSE_EOW,          "MOVER_PAUSE_EOW"},
1858         {0, NULL}
1859 };
1860
1861 #define NDMP_HALT_NA            0
1862 #define NDMP_HALT_CONNECT_CLOSE 1
1863 #define NDMP_HALT_ABORTED               2
1864 #define NDMP_HALT_INTERNAL_ERROR        3
1865 #define NDMP_HALT_CONNECT_ERROR 4
1866 static const value_string halt_vals[] = {
1867         {NDMP_HALT_NA,                  "HALT_NA"},
1868         {NDMP_HALT_CONNECT_CLOSE,       "HALT_CONNECT_CLOSE"},
1869         {NDMP_HALT_ABORTED,             "HALT_ABORTED"},
1870         {NDMP_HALT_INTERNAL_ERROR,      "HALT_INTERNAL_ERROR"},
1871         {NDMP_HALT_CONNECT_ERROR,       "HALT_CONNECT_ERROR"},
1872         {0, NULL}
1873 };
1874
1875 static int
1876 dissect_tcp_env(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
1877 {
1878         /* name */
1879         offset = dissect_rpc_string(tvb, tree,
1880                         hf_ndmp_tcp_env_name, offset, NULL);
1881
1882         /* value */
1883         offset = dissect_rpc_string(tvb, tree,
1884                         hf_ndmp_tcp_env_value, offset, NULL);
1885
1886         return offset;
1887 }
1888
1889
1890 static int
1891 dissect_ndmp_v4_tcp_addr(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void* data _U_)
1892 {
1893         /* IP addr */
1894         proto_tree_add_item(tree, hf_ndmp_addr_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1895         offset+=4;
1896
1897         /* TCP port */
1898         proto_tree_add_item(tree, hf_ndmp_addr_tcp, tvb, offset, 4, ENC_BIG_ENDIAN);
1899         offset+=4;
1900
1901         /* addr_env */
1902         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1903                         dissect_tcp_env, hf_ndmp_tcp_default_env);
1904
1905         return offset;
1906 }
1907
1908 static int
1909 dissect_ndmp_addr(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1910     proto_tree *parent_tree)
1911 {
1912         proto_item* item = NULL;
1913         proto_tree* tree = NULL;
1914         guint32 type;
1915
1916         type=tvb_get_ntohl(tvb, offset);
1917         if (parent_tree) {
1918                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
1919                                 "Type: %s ", val_to_str(type, addr_type_vals,"Unknown addr type (0x%02x)") );
1920                 tree = proto_item_add_subtree(item, ett_ndmp_addr);
1921         }
1922
1923         /*address type*/
1924         proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, ENC_BIG_ENDIAN);
1925         offset += 4;
1926
1927
1928         switch(type){
1929         case NDMP_ADDR_LOCAL:
1930                 break;
1931         case NDMP_ADDR_TCP:
1932                 /* this became an array in version 4 and beyond */
1933                 if(get_ndmp_protocol_version()<NDMP_PROTOCOL_V4){
1934                         /* IP addr */
1935                         proto_tree_add_item(tree, hf_ndmp_addr_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1936                         offset+=4;
1937
1938                         /* TCP port */
1939                         proto_tree_add_item(tree, hf_ndmp_addr_tcp, tvb, offset, 4, ENC_BIG_ENDIAN);
1940                         offset+=4;
1941                 } else {
1942                         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
1943                                 dissect_ndmp_v4_tcp_addr, hf_ndmp_tcp_addr_list);
1944
1945                 }
1946
1947                 break;
1948         case NDMP_ADDR_FC:
1949                 /* FCAL loop id */
1950                 proto_tree_add_item(tree, hf_ndmp_addr_fcal_loop_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1951                 offset+=4;
1952
1953                 break;
1954         case NDMP_ADDR_IPC:
1955                 /* IPC address */
1956                 offset = dissect_rpc_data(tvb, tree, hf_ndmp_addr_ipc, offset);
1957                 break;
1958         }
1959
1960         return offset;
1961 }
1962
1963 static int
1964 dissect_data_connect_msg(tvbuff_t *tvb, int offset, packet_info *pinfo,
1965     proto_tree *tree, guint32 seq _U_)
1966 {
1967         /* ndmp addr */
1968         offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
1969         return offset;
1970 }
1971
1972
1973 static int
1974 dissect_mover_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
1975     proto_tree *tree, guint32 seq)
1976 {
1977         /* error */
1978         offset=dissect_error(tvb, offset, pinfo, tree, seq);
1979
1980         /* mode is only present in version 4 and beyond */
1981         if(get_ndmp_protocol_version()>=NDMP_PROTOCOL_V4){
1982                 proto_tree_add_item(tree, hf_ndmp_mover_mode, tvb, offset, 4, ENC_BIG_ENDIAN);
1983                 offset += 4;
1984         }
1985
1986         /* mover state */
1987         proto_tree_add_item(tree, hf_ndmp_mover_state, tvb, offset, 4, ENC_BIG_ENDIAN);
1988         offset += 4;
1989
1990         /* mover pause */
1991         proto_tree_add_item(tree, hf_ndmp_mover_pause, tvb, offset, 4, ENC_BIG_ENDIAN);
1992         offset += 4;
1993
1994         /* halt */
1995         proto_tree_add_item(tree, hf_ndmp_halt, tvb, offset, 4, ENC_BIG_ENDIAN);
1996         offset += 4;
1997
1998         /* record size */
1999         proto_tree_add_item(tree, hf_ndmp_record_size, tvb, offset, 4, ENC_BIG_ENDIAN);
2000         offset += 4;
2001
2002         /* record num */
2003         proto_tree_add_item(tree, hf_ndmp_record_num, tvb, offset, 4, ENC_BIG_ENDIAN);
2004         offset += 4;
2005
2006         /* data written */
2007         proto_tree_add_item(tree, hf_ndmp_data_written, tvb, offset, 8, ENC_BIG_ENDIAN);
2008         offset += 8;
2009
2010         /* seek position */
2011         proto_tree_add_item(tree, hf_ndmp_seek_position, tvb, offset, 8, ENC_BIG_ENDIAN);
2012         offset += 8;
2013
2014         /* bytes left to read */
2015         proto_tree_add_item(tree, hf_ndmp_bytes_left_to_read, tvb, offset, 8, ENC_BIG_ENDIAN);
2016         offset += 8;
2017
2018         /* window offset */
2019         proto_tree_add_item(tree, hf_ndmp_window_offset, tvb, offset, 8, ENC_BIG_ENDIAN);
2020         offset += 8;
2021
2022         /* window length */
2023         proto_tree_add_item(tree, hf_ndmp_window_length, tvb, offset, 8, ENC_BIG_ENDIAN);
2024         offset += 8;
2025
2026         /* this is where v2 ends */
2027         if(get_ndmp_protocol_version()==NDMP_PROTOCOL_V2){
2028                 return offset;
2029         }
2030
2031
2032         /* ndmp addr */
2033         offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
2034
2035         return offset;
2036 }
2037
2038 #define NDMP_MOVER_MODE_READ            0
2039 #define NDMP_MOVER_MODE_WRITE           1
2040 #define NDMP_MOVER_MODE_NOACTION        2
2041 static const value_string mover_mode_vals[] = {
2042         {NDMP_MOVER_MODE_READ,          "MOVER_MODE_READ"},
2043         {NDMP_MOVER_MODE_WRITE,         "MOVER_MODE_WRITE"},
2044         {NDMP_MOVER_MODE_NOACTION,      "MOVER_MODE_NOACTION"},
2045         {0, NULL}
2046 };
2047
2048 static int
2049 dissect_mover_listen_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2050     proto_tree *tree, guint32 seq _U_)
2051 {
2052         /* mode */
2053         proto_tree_add_item(tree, hf_ndmp_mover_mode, tvb, offset, 4, ENC_BIG_ENDIAN);
2054         offset += 4;
2055
2056         /*address type*/
2057         proto_tree_add_item(tree, hf_ndmp_addr_type, tvb, offset, 4, ENC_BIG_ENDIAN);
2058         offset += 4;
2059
2060         return offset;
2061 }
2062
2063 static int
2064 dissect_mover_listen_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
2065     proto_tree *tree, guint32 seq)
2066 {
2067         /* error */
2068         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2069
2070         /* ndmp addr */
2071         offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
2072
2073         return offset;
2074 }
2075
2076 static int
2077 dissect_mover_set_window_request(tvbuff_t *tvb, int offset,
2078     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
2079 {
2080         /* window offset */
2081         proto_tree_add_item(tree, hf_ndmp_window_offset, tvb, offset, 8, ENC_BIG_ENDIAN);
2082         offset += 8;
2083
2084         /* window length */
2085         proto_tree_add_item(tree, hf_ndmp_window_length, tvb, offset, 8, ENC_BIG_ENDIAN);
2086         offset += 8;
2087
2088         return offset;
2089 }
2090
2091 static int
2092 dissect_mover_set_record_size_request(tvbuff_t *tvb, int offset,
2093     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
2094 {
2095         /* record size */
2096         proto_tree_add_item(tree, hf_ndmp_record_size, tvb, offset, 4, ENC_BIG_ENDIAN);
2097         offset += 4;
2098
2099         return offset;
2100 }
2101
2102 static int
2103 dissect_mover_connect_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
2104     proto_tree *tree, guint32 seq _U_)
2105 {
2106         /* mode */
2107         proto_tree_add_item(tree, hf_ndmp_mover_mode, tvb, offset, 4, ENC_BIG_ENDIAN);
2108         offset += 4;
2109
2110         /* ndmp addr */
2111         offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
2112
2113         return offset;
2114 }
2115
2116 static int
2117 dissect_log_file_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
2118     proto_tree *tree, guint32 seq)
2119 {
2120         /* file */
2121         offset = dissect_rpc_string(tvb, tree,
2122                         hf_ndmp_file_name, offset, NULL);
2123
2124         /* error */
2125         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2126
2127         return offset;
2128 }
2129
2130 #define NDMP_LOG_TYPE_NORMAL    0
2131 #define NDMP_LOG_TYPE_DEBUG     1
2132 #define NDMP_LOG_TYPE_ERROR     2
2133 #define NDMP_LOG_TYPE_WARNING   3
2134 static const value_string log_type_vals[] = {
2135         {NDMP_LOG_TYPE_NORMAL,  "NORMAL"},
2136         {NDMP_LOG_TYPE_DEBUG,   "DEBUG"},
2137         {NDMP_LOG_TYPE_ERROR,   "ERROR"},
2138         {NDMP_LOG_TYPE_WARNING, "WARNING"},
2139         {0, NULL}
2140 };
2141
2142 static int
2143 dissect_log_message_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2144     proto_tree *tree, guint32 seq _U_)
2145 {
2146         /* type */
2147         proto_tree_add_item(tree, hf_ndmp_log_type, tvb, offset, 4, ENC_BIG_ENDIAN);
2148         offset += 4;
2149
2150         /* message id */
2151         proto_tree_add_item(tree, hf_ndmp_log_message_id, tvb, offset, 4, ENC_BIG_ENDIAN);
2152         offset += 4;
2153
2154         /* message */
2155         offset = dissect_rpc_string(tvb, tree,
2156                         hf_ndmp_log_message, offset, NULL);
2157
2158         return offset;
2159 }
2160
2161 static int
2162 dissect_notify_data_halted_request(tvbuff_t *tvb, int offset,
2163     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
2164 {
2165         /* halt */
2166         proto_tree_add_item(tree, hf_ndmp_halt, tvb, offset, 4, ENC_BIG_ENDIAN);
2167         offset += 4;
2168
2169         switch(get_ndmp_protocol_version()){
2170         case NDMP_PROTOCOL_V2:
2171         case NDMP_PROTOCOL_V3:
2172                 /* reason : only in version 2, 3 */
2173                 offset = dissect_rpc_string(tvb, tree,
2174                                 hf_ndmp_halt_reason, offset, NULL);
2175                 break;
2176         }
2177
2178         return offset;
2179 }
2180
2181 static int
2182 dissect_notify_mover_halted_request(tvbuff_t *tvb, int offset,
2183     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
2184 {
2185         /* halt */
2186         proto_tree_add_item(tree, hf_ndmp_halt, tvb, offset, 4, ENC_BIG_ENDIAN);
2187         offset += 4;
2188
2189         switch(get_ndmp_protocol_version()){
2190         case NDMP_PROTOCOL_V2:
2191         case NDMP_PROTOCOL_V3:
2192                 /* reason : only in version 2, 3 */
2193                 offset = dissect_rpc_string(tvb, tree,
2194                                 hf_ndmp_halt_reason, offset, NULL);
2195                 break;
2196         }
2197
2198         return offset;
2199 }
2200
2201 #define NDMP_CONNECTED_CONNECTED        0
2202 #define NDMP_CONNECTED_SHUTDOWN         1
2203 #define NDMP_CONNECTED_REFUSED          2
2204 static const value_string connected_vals[] = {
2205         {NDMP_CONNECTED_CONNECTED,      "CONNECTED"},
2206         {NDMP_CONNECTED_SHUTDOWN,       "SHUTDOWN"},
2207         {NDMP_CONNECTED_REFUSED,        "REFUSED"},
2208         {0, NULL}
2209 };
2210
2211 static int
2212 dissect_notify_connected_request(tvbuff_t *tvb, int offset,
2213     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
2214 {
2215         /* connected */
2216         proto_tree_add_item(tree, hf_ndmp_connected, tvb, offset, 4, ENC_BIG_ENDIAN);
2217         offset += 4;
2218
2219         /* version number */
2220         proto_tree_add_item(tree, hf_ndmp_version, tvb, offset, 4, ENC_BIG_ENDIAN);
2221         offset += 4;
2222
2223         /* reason */
2224         offset = dissect_rpc_string(tvb, tree,
2225                         hf_ndmp_connected_reason, offset, NULL);
2226
2227         return offset;
2228 }
2229
2230
2231 static int
2232 dissect_notify_mover_paused_request(tvbuff_t *tvb, int offset,
2233     packet_info *pinfo _U_, proto_tree *tree, guint32 seq _U_)
2234 {
2235         /* mover pause */
2236         proto_tree_add_item(tree, hf_ndmp_mover_pause, tvb, offset, 4, ENC_BIG_ENDIAN);
2237         offset += 4;
2238
2239         /* seek position */
2240         proto_tree_add_item(tree, hf_ndmp_seek_position, tvb, offset, 8, ENC_BIG_ENDIAN);
2241         offset += 8;
2242
2243         return offset;
2244 }
2245
2246 static int
2247 dissect_auth_data(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2248     proto_tree *tree)
2249 {
2250         guint type;
2251
2252         type=tvb_get_ntohl(tvb,offset);
2253
2254         /* auth type */
2255         proto_tree_add_item(tree, hf_ndmp_auth_type, tvb, offset, 4, ENC_BIG_ENDIAN);
2256         offset += 4;
2257
2258         switch(type){
2259         case NDMP_AUTH_NONE:
2260                 break;
2261         case NDMP_AUTH_TEXT:
2262                 /* auth id */
2263                 offset = dissect_rpc_string(tvb, tree,
2264                                 hf_ndmp_auth_id, offset, NULL);
2265
2266                 /* auth password */
2267                 offset = dissect_rpc_string(tvb, tree,
2268                                 hf_ndmp_auth_password, offset, NULL);
2269
2270
2271                 break;
2272         case NDMP_AUTH_MD5:
2273                 /* auth id */
2274                 offset = dissect_rpc_string(tvb, tree,
2275                                 hf_ndmp_auth_id, offset, NULL);
2276
2277                 /* digest */
2278                 proto_tree_add_item(tree, hf_ndmp_auth_digest,
2279                         tvb, offset, 16, ENC_NA);
2280                 offset+=16;
2281         }
2282
2283         return offset;
2284 }
2285
2286 static int
2287 dissect_connect_client_auth_request(tvbuff_t *tvb, int offset,
2288     packet_info *pinfo, proto_tree *tree, guint32 seq _U_)
2289 {
2290         return dissect_auth_data(tvb, offset, pinfo, tree);
2291 }
2292
2293 static int
2294 dissect_connect_server_auth_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
2295     proto_tree *tree, guint32 seq)
2296 {
2297         /* error */
2298         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2299
2300         /* auth data */
2301         offset = dissect_auth_data(tvb, offset, pinfo, tree);
2302
2303         return offset;
2304 }
2305
2306 static int
2307 dissect_tape_write_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2308     proto_tree *tree, guint32 seq _U_)
2309 {
2310         /* data */
2311         offset = dissect_rpc_data(tvb, tree, hf_ndmp_data, offset);
2312
2313         return offset;
2314 }
2315
2316 static int
2317 dissect_tape_write_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
2318     proto_tree *tree, guint32 seq)
2319 {
2320         /* error */
2321         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2322
2323         /* count */
2324         proto_tree_add_item(tree, hf_ndmp_count, tvb, offset, 4, ENC_BIG_ENDIAN);
2325         offset += 4;
2326
2327         return offset;
2328 }
2329
2330 static int
2331 dissect_tape_read_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2332     proto_tree *tree, guint32 seq _U_)
2333 {
2334         /* count */
2335         proto_tree_add_item(tree, hf_ndmp_count, tvb, offset, 4, ENC_BIG_ENDIAN);
2336         offset += 4;
2337
2338         return offset;
2339 }
2340
2341 static int
2342 dissect_tape_read_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
2343     proto_tree *tree, guint32 seq)
2344 {
2345         /* error */
2346         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2347
2348         /* data */
2349         offset = dissect_rpc_data(tvb, tree, hf_ndmp_data, offset);
2350
2351         return offset;
2352 }
2353
2354 #define NDMP_FS_UNIX    0
2355 #define NDMP_FS_NT      1
2356 #define NDMP_FS_OTHER   2
2357 static const value_string file_fs_type_vals[] = {
2358         {NDMP_FS_UNIX,  "UNIX"},
2359         {NDMP_FS_NT,    "NT"},
2360         {NDMP_FS_OTHER, "OTHER"},
2361         {0, NULL}
2362 };
2363
2364 static int
2365 dissect_file_name(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
2366 {
2367         proto_item* item = NULL;
2368         proto_tree* tree = NULL;
2369         int old_offset=offset;
2370         guint32 type;
2371         const char *name;
2372
2373         if (parent_tree) {
2374                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
2375                                 "File");
2376                 tree = proto_item_add_subtree(item, ett_ndmp_file_name);
2377         }
2378
2379         /* file type */
2380         type=tvb_get_ntohl(tvb, offset);
2381         proto_tree_add_item(tree, hf_ndmp_file_fs_type, tvb, offset, 4, ENC_BIG_ENDIAN);
2382         offset += 4;
2383
2384         switch(type){
2385         case NDMP_FS_UNIX:
2386                 /* file */
2387                 offset = dissect_rpc_string(tvb, tree,
2388                                 hf_ndmp_file_name, offset, &name);
2389                 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", name);
2390                 break;
2391         case NDMP_FS_NT:
2392                 /* nt file */
2393                 offset = dissect_rpc_string(tvb, tree,
2394                                 hf_ndmp_nt_file_name, offset, &name);
2395                 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", name);
2396
2397                 /* dos file */
2398                 offset = dissect_rpc_string(tvb, tree,
2399                                 hf_ndmp_dos_file_name, offset, NULL);
2400                 break;
2401         default:
2402                 /* file */
2403                 offset = dissect_rpc_string(tvb, tree,
2404                                 hf_ndmp_file_name, offset, &name);
2405                 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", name);
2406         }
2407
2408         col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)",
2409                         val_to_str_const(type, file_fs_type_vals, "Unknown type") );
2410
2411         proto_item_set_len(item, offset-old_offset);
2412         return offset;
2413 }
2414
2415
2416 static const true_false_string tfs_ndmp_file_invalid_atime = {
2417         "Atime is INVALID",
2418         "Atime is valid"
2419 };
2420 static const true_false_string tfs_ndmp_file_invalid_ctime = {
2421         "Ctime is INVALID",
2422         "Ctime is valid"
2423 };
2424 static const true_false_string tfs_ndmp_file_invalid_group = {
2425         "Group is INVALID",
2426         "Group is valid"
2427 };
2428 static int
2429 dissect_file_invalids(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2430     proto_tree *parent_tree)
2431 {
2432         proto_item* item = NULL;
2433         proto_tree* tree = NULL;
2434         guint32 flags;
2435
2436         flags=tvb_get_ntohl(tvb, offset);
2437         if (parent_tree) {
2438                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
2439                                 "Invalids: 0x%08x", flags);
2440                 tree = proto_item_add_subtree(item, ett_ndmp_file_invalids);
2441         }
2442
2443         proto_tree_add_boolean(tree, hf_ndmp_file_invalid_group,
2444                         tvb, offset, 4, flags);
2445         proto_tree_add_boolean(tree, hf_ndmp_file_invalid_ctime,
2446                         tvb, offset, 4, flags);
2447         proto_tree_add_boolean(tree, hf_ndmp_file_invalid_atime,
2448                         tvb, offset, 4, flags);
2449
2450         offset+=4;
2451         return offset;
2452 }
2453
2454 #define NDMP_FILE_TYPE_DIR      0
2455 #define NDMP_FILE_TYPE_FIFO     1
2456 #define NDMP_FILE_TYPE_CSPEC    2
2457 #define NDMP_FILE_TYPE_BSPEC    3
2458 #define NDMP_FILE_TYPE_REG      4
2459 #define NDMP_FILE_TYPE_SLINK    5
2460 #define NDMP_FILE_TYPE_SOCK     6
2461 #define NDMP_FILE_TYPE_REGISTRY 7
2462 #define NDMP_FILE_TYPE_OTHER    8
2463 static const value_string file_type_vals[] = {
2464         {NDMP_FILE_TYPE_DIR,    "DIR"},
2465         {NDMP_FILE_TYPE_FIFO,   "FIFO"},
2466         {NDMP_FILE_TYPE_CSPEC,  "CSPEC"},
2467         {NDMP_FILE_TYPE_BSPEC,  "BSPEC"},
2468         {NDMP_FILE_TYPE_REG,    "REG"},
2469         {NDMP_FILE_TYPE_SLINK,  "SLINK"},
2470         {NDMP_FILE_TYPE_SOCK,   "SOCK"},
2471         {NDMP_FILE_TYPE_REGISTRY,       "REGISTRY"},
2472         {NDMP_FILE_TYPE_OTHER,  "OTHER"},
2473         {0, NULL}
2474 };
2475
2476 static int
2477 dissect_file_stats(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
2478 {
2479         proto_item* item = NULL;
2480         proto_tree* tree = NULL;
2481         int old_offset=offset;
2482         nstime_t ns;
2483
2484         if (parent_tree) {
2485                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
2486                                 "Stats:");
2487                 tree = proto_item_add_subtree(item, ett_ndmp_file_stats);
2488         }
2489
2490         /* invalids */
2491         offset = dissect_file_invalids(tvb, offset, pinfo, tree);
2492
2493         /* file fs type */
2494         proto_tree_add_item(tree, hf_ndmp_file_fs_type, tvb, offset, 4, ENC_BIG_ENDIAN);
2495         offset += 4;
2496
2497         /* file type */
2498         proto_tree_add_item(tree, hf_ndmp_file_type, tvb, offset, 4, ENC_BIG_ENDIAN);
2499         offset += 4;
2500
2501         /* mtime */
2502         ns.secs=tvb_get_ntohl(tvb, offset);
2503         ns.nsecs=0;
2504         proto_tree_add_time(tree, hf_ndmp_file_mtime, tvb, offset, 4, &ns);
2505         offset += 4;
2506
2507         /* atime */
2508         ns.secs=tvb_get_ntohl(tvb, offset);
2509         ns.nsecs=0;
2510         proto_tree_add_time(tree, hf_ndmp_file_atime, tvb, offset, 4, &ns);
2511         offset += 4;
2512
2513         /* ctime */
2514         ns.secs=tvb_get_ntohl(tvb, offset);
2515         ns.nsecs=0;
2516         proto_tree_add_time(tree, hf_ndmp_file_ctime, tvb, offset, 4, &ns);
2517         offset += 4;
2518
2519         /* owner */
2520         proto_tree_add_item(tree, hf_ndmp_file_owner, tvb, offset, 4, ENC_BIG_ENDIAN);
2521         offset += 4;
2522
2523         /* group */
2524         proto_tree_add_item(tree, hf_ndmp_file_group, tvb, offset, 4, ENC_BIG_ENDIAN);
2525         offset += 4;
2526
2527         /*XXX here we should do proper dissection of mode for unix or
2528               fattr for nt, call appropriate functions in nfs/smb*/
2529         /* fattr */
2530         proto_tree_add_item(tree, hf_ndmp_file_fattr, tvb, offset, 4, ENC_BIG_ENDIAN);
2531         offset += 4;
2532
2533         /*file size*/
2534         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_file_size,
2535                         offset);
2536
2537         /* links */
2538         proto_tree_add_item(tree, hf_ndmp_file_links, tvb, offset, 4, ENC_BIG_ENDIAN);
2539         offset += 4;
2540
2541         proto_item_set_len(item, offset-old_offset);
2542         return offset;
2543 }
2544
2545
2546 static int
2547 dissect_file(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
2548 {
2549         proto_item* item = NULL;
2550         proto_tree* tree = NULL;
2551         int old_offset=offset;
2552
2553         if (parent_tree) {
2554                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
2555                                 "File:");
2556                 tree = proto_item_add_subtree(item, ett_ndmp_file);
2557         }
2558
2559         /* file names */
2560         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2561                         dissect_file_name, hf_ndmp_file_names);
2562
2563         /* file stats */
2564         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2565                         dissect_file_stats, hf_ndmp_file_stats);
2566
2567         /* node */
2568         proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, ENC_BIG_ENDIAN);
2569         offset += 8;
2570
2571         /* fh_info */
2572         proto_tree_add_item(tree, hf_ndmp_file_fh_info, tvb, offset, 8, ENC_BIG_ENDIAN);
2573         offset += 8;
2574
2575         proto_item_set_len(item, offset-old_offset);
2576         return offset;
2577 }
2578
2579 static int
2580 dissect_fh_add_file_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
2581     proto_tree *tree, guint32 seq _U_)
2582 {
2583         /* files */
2584         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2585                         dissect_file, hf_ndmp_files);
2586
2587         return offset;
2588 }
2589
2590 static int
2591 dissect_dir(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void* data _U_)
2592 {
2593         /* file names */
2594         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2595                         dissect_file_name, hf_ndmp_file_names);
2596
2597         /* node */
2598         proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, ENC_BIG_ENDIAN);
2599         offset += 8;
2600
2601         /* parent */
2602         proto_tree_add_item(tree, hf_ndmp_file_parent, tvb, offset, 8, ENC_BIG_ENDIAN);
2603         offset += 8;
2604
2605         return offset;
2606 }
2607
2608 static int
2609 dissect_fh_add_dir_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
2610     proto_tree *tree, guint32 seq _U_)
2611 {
2612         /* dirs */
2613         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2614                         dissect_dir, hf_ndmp_dirs);
2615
2616         return offset;
2617 }
2618
2619 static int
2620 dissect_node(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void* data _U_)
2621 {
2622         /* file stats */
2623         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2624                         dissect_file_stats, hf_ndmp_file_stats);
2625
2626         /* node */
2627         proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, ENC_BIG_ENDIAN);
2628         offset += 8;
2629
2630         /* fh_info */
2631         proto_tree_add_item(tree, hf_ndmp_file_fh_info, tvb, offset, 8, ENC_BIG_ENDIAN);
2632         offset += 8;
2633
2634         return offset;
2635 }
2636
2637
2638 static int
2639 dissect_fh_add_node_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
2640     proto_tree *tree, guint32 seq _U_)
2641 {
2642         /* node */
2643         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2644                         dissect_node, hf_ndmp_nodes);
2645
2646         return offset;
2647 }
2648
2649 static int
2650 dissect_data_start_backup_request(tvbuff_t *tvb, int offset, packet_info *pinfo,
2651     proto_tree *tree, guint32 seq _U_)
2652 {
2653         /*butype name*/
2654         offset = dissect_rpc_string(tvb, tree,
2655                         hf_ndmp_butype_name, offset, NULL);
2656
2657         /* default env */
2658         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2659                         dissect_default_env, hf_ndmp_butype_default_env);
2660
2661         return offset;
2662 }
2663
2664 static int
2665 dissect_nlist(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2666     proto_tree *tree, void* data _U_)
2667 {
2668         /*original path*/
2669         offset = dissect_rpc_string(tvb, tree,
2670                         hf_ndmp_bu_original_path, offset, NULL);
2671
2672         /*destination dir*/
2673         offset = dissect_rpc_string(tvb, tree,
2674                         hf_ndmp_bu_destination_dir, offset, NULL);
2675
2676         if(get_ndmp_protocol_version()==NDMP_PROTOCOL_V2){
2677                 /* just 2 reserved bytes (4 with padding) */
2678                 offset += 4;
2679         } else {
2680                 /*new name*/
2681                 offset = dissect_rpc_string(tvb, tree,
2682                         hf_ndmp_bu_new_name, offset, NULL);
2683
2684                 /*other name*/
2685                 offset = dissect_rpc_string(tvb, tree,
2686                         hf_ndmp_bu_other_name, offset, NULL);
2687
2688                 /* node */
2689                 proto_tree_add_item(tree, hf_ndmp_file_node, tvb, offset, 8, ENC_BIG_ENDIAN);
2690                 offset += 8;
2691         }
2692
2693         /* fh_info */
2694         proto_tree_add_item(tree, hf_ndmp_file_fh_info, tvb, offset, 8, ENC_BIG_ENDIAN);
2695         offset += 8;
2696
2697         return offset;
2698 }
2699
2700
2701 static int
2702 dissect_data_start_recover_request(tvbuff_t *tvb, int offset,
2703     packet_info *pinfo, proto_tree *tree, guint32 seq _U_)
2704 {
2705         if(get_ndmp_protocol_version()==NDMP_PROTOCOL_V2){
2706                 /* ndmp addr */
2707                 offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
2708         }
2709
2710         /* default env */
2711         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2712                         dissect_default_env, hf_ndmp_butype_default_env);
2713
2714         /* nlist */
2715         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2716                         dissect_nlist, hf_ndmp_nlist);
2717
2718         /*butype name*/
2719         offset = dissect_rpc_string(tvb, tree,
2720                         hf_ndmp_butype_name, offset, NULL);
2721
2722         return offset;
2723 }
2724
2725 static int
2726 dissect_data_get_env_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
2727     proto_tree *tree, guint32 seq)
2728 {
2729         /* error */
2730         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2731
2732         /* default env */
2733         offset = dissect_rpc_array(tvb, pinfo, tree, offset,
2734                         dissect_default_env, hf_ndmp_butype_default_env);
2735
2736         return offset;
2737 }
2738
2739
2740 static const true_false_string tfs_ndmp_state_invalid_ebr = {
2741         "Estimated Bytes Remaining is INVALID",
2742         "Estimated Bytes Remaining is valid"
2743 };
2744 static const true_false_string tfs_ndmp_state_invalid_etr = {
2745         "Estimated Time Remaining is INVALID",
2746         "Estimated Time Remaining is valid"
2747 };
2748 static int
2749 dissect_state_invalids(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
2750     proto_tree *parent_tree)
2751 {
2752         proto_item* item = NULL;
2753         proto_tree* tree = NULL;
2754         guint32 flags;
2755
2756         flags=tvb_get_ntohl(tvb, offset);
2757         if (parent_tree) {
2758                 item = proto_tree_add_text(parent_tree, tvb, offset, 4,
2759                                 "Invalids: 0x%08x", flags);
2760                 tree = proto_item_add_subtree(item, ett_ndmp_state_invalids);
2761         }
2762
2763         proto_tree_add_boolean(tree, hf_ndmp_state_invalid_etr,
2764                                 tvb, offset, 4, flags);
2765         proto_tree_add_boolean(tree, hf_ndmp_state_invalid_ebr,
2766                                 tvb, offset, 4, flags);
2767
2768         offset+=4;
2769         return offset;
2770 }
2771
2772 #define NDMP_DATA_OP_NOACTION   0
2773 #define NDMP_DATA_OP_BACKUP     1
2774 #define NDMP_DATA_OP_RESTORE    2
2775 static const value_string bu_operation_vals[] = {
2776         {NDMP_DATA_OP_NOACTION, "NOACTION"},
2777         {NDMP_DATA_OP_BACKUP,   "BACKUP"},
2778         {NDMP_DATA_OP_RESTORE,  "RESTORE"},
2779         {0, NULL}
2780 };
2781
2782 #define NDMP_DATA_STATE_IDLE            0
2783 #define NDMP_DATA_STATE_ACTIVE          1
2784 #define NDMP_DATA_STATE_HALTED          2
2785 #define NDMP_DATA_STATE_LISTEN          3
2786 #define NDMP_DATA_STATE_CONNECTED       4
2787 static const value_string data_state_vals[] = {
2788         {NDMP_DATA_STATE_IDLE,          "IDLE"},
2789         {NDMP_DATA_STATE_ACTIVE,        "ACTIVE"},
2790         {NDMP_DATA_STATE_HALTED,        "HALTED"},
2791         {NDMP_DATA_STATE_LISTEN,        "LISTEN"},
2792         {NDMP_DATA_STATE_CONNECTED,     "CONNECTED"},
2793         {0, NULL}
2794 };
2795
2796 #define NDMP_DATA_HALTED_NA             0
2797 #define NDMP_DATA_HALTED_SUCCESSFUL     1
2798 #define NDMP_DATA_HALTED_ABORTED        2
2799 #define NDMP_DATA_HALTED_INTERNAL_ERROR 3
2800 #define NDMP_DATA_HALTED_CONNECT_ERROR  4
2801 static const value_string data_halted_vals[] = {
2802         {NDMP_DATA_HALTED_NA,                   "HALTED_NA"},
2803         {NDMP_DATA_HALTED_SUCCESSFUL,           "HALTED_SUCCESSFUL"},
2804         {NDMP_DATA_HALTED_ABORTED,              "HALTED_ABORTED"},
2805         {NDMP_DATA_HALTED_INTERNAL_ERROR,       "HALTED_INTERNAL_ERROR"},
2806         {NDMP_DATA_HALTED_CONNECT_ERROR,        "HALTED_CONNECT_ERROR"},
2807         {0, NULL}
2808 };
2809
2810 static int
2811 dissect_data_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
2812     proto_tree *tree, guint32 seq)
2813 {
2814         nstime_t ns;
2815
2816         /* invalids */
2817         offset = dissect_state_invalids(tvb, offset, pinfo, tree);
2818
2819         /* error */
2820         offset=dissect_error(tvb, offset, pinfo, tree, seq);
2821
2822         /* operation */
2823         proto_tree_add_item(tree, hf_ndmp_bu_operation, tvb, offset, 4, ENC_BIG_ENDIAN);
2824         offset += 4;
2825
2826         /* state */
2827         proto_tree_add_item(tree, hf_ndmp_data_state, tvb, offset, 4, ENC_BIG_ENDIAN);
2828         offset += 4;
2829
2830         /* halted reason */
2831         proto_tree_add_item(tree, hf_ndmp_data_halted, tvb, offset, 4, ENC_BIG_ENDIAN);
2832         offset += 4;
2833
2834         /*bytes processed*/
2835         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_data_bytes_processed,
2836                         offset);
2837
2838         /*est bytes remain*/
2839         offset = dissect_rpc_uint64(tvb, tree, hf_ndmp_data_est_bytes_remain,
2840                         offset);
2841
2842         /* est time remain */
2843         ns.secs=tvb_get_ntohl(tvb, offset);
2844         ns.nsecs=0;
2845         proto_tree_add_time(tree, hf_ndmp_data_est_time_remain, tvb, offset, 4, &ns);
2846         offset += 4;
2847
2848         /* ndmp addr */
2849         offset=dissect_ndmp_addr(tvb, offset, pinfo, tree);
2850
2851         /* window offset */
2852         proto_tree_add_item(tree, hf_ndmp_window_offset, tvb, offset, 8, ENC_BIG_ENDIAN);
2853         offset += 8;
2854
2855         /* window length */
2856         proto_tree_add_item(tree, hf_ndmp_window_length, tvb, offset, 8, ENC_BIG_ENDIAN);
2857         offset += 8;
2858
2859         return offset;
2860 }
2861
2862 typedef struct _ndmp_command {
2863         guint32 cmd;
2864         int (*request) (tvbuff_t *tvb, int offset, packet_info *pinfo,
2865             proto_tree *tree, guint32 seq);
2866         int (*response)(tvbuff_t *tvb, int offset, packet_info *pinfo,
2867             proto_tree *tree, guint32 seq);
2868 } ndmp_command;
2869
2870 static const ndmp_command ndmp_commands[] = {
2871         {NDMP_CONFIG_GET_HOST_INFO,
2872                 NULL, dissect_ndmp_get_host_info_reply},
2873         {NDMP_CONFIG_GET_CONNECTION_TYPE,
2874                 NULL, dissect_ndmp_config_get_connection_type_reply},
2875         {NDMP_CONFIG_GET_AUTH_ATTR,
2876                 dissect_get_auth_type_request, dissect_ndmp_config_get_auth_attr_reply},
2877         {NDMP_CONFIG_GET_BUTYPE_INFO,
2878                 NULL, dissect_get_butype_info_reply},
2879         {NDMP_CONFIG_GET_FS_INFO,
2880                 NULL, dissect_get_fs_info_reply},
2881         {NDMP_CONFIG_GET_TAPE_INFO,
2882                 NULL, dissect_get_tape_info_reply},
2883         {NDMP_CONFIG_GET_SCSI_INFO,
2884                 NULL, dissect_get_scsi_info_reply},
2885         {NDMP_CONFIG_GET_SERVER_INFO,
2886                 NULL, dissect_get_server_info_reply},
2887         {NDMP_CONFIG_GET_EXT_LIST,
2888                 NULL, dissect_get_ext_list_reply},
2889         {NDMP_CONFIG_SET_EXT_LIST,
2890                 dissect_set_ext_list_request, dissect_set_ext_list_reply},
2891         {NDMP_SCSI_OPEN,
2892                 dissect_scsi_open_request, dissect_error},
2893         {NDMP_SCSI_CLOSE,
2894                 NULL, dissect_error},
2895         {NDMP_SCSI_GET_STATE,
2896                 NULL, dissect_scsi_get_state_reply},
2897         {NDMP_SCSI_SET_TARGET,
2898                 dissect_scsi_set_state_request, dissect_error},
2899         {NDMP_SCSI_RESET_DEVICE,
2900                 NULL, dissect_error},
2901         {NDMP_SCSI_RESET_BUS,
2902                 NULL, dissect_error},
2903         {NDMP_SCSI_EXECUTE_CDB,
2904                 dissect_execute_cdb_request_mc, dissect_execute_cdb_reply},
2905         {NDMP_TAPE_OPEN,
2906                 dissect_tape_open_request, dissect_error},
2907         {NDMP_TAPE_CLOSE,
2908                 NULL, dissect_error},
2909         {NDMP_TAPE_GET_STATE,
2910                 NULL, dissect_tape_get_state_reply},
2911         {NDMP_TAPE_MTIO,
2912                 dissect_tape_mtio_request, dissect_tape_mtio_reply},
2913         {NDMP_TAPE_WRITE,
2914                 dissect_tape_write_request, dissect_tape_write_reply},
2915         {NDMP_TAPE_READ,
2916                 dissect_tape_read_request, dissect_tape_read_reply},
2917         {NDMP_TAPE_EXECUTE_CDB,
2918                 dissect_execute_cdb_request_tape, dissect_execute_cdb_reply},
2919         {NDMP_DATA_GET_STATE,
2920                 NULL, dissect_data_get_state_reply},
2921         {NDMP_DATA_START_BACKUP,
2922                 dissect_data_start_backup_request, dissect_error },
2923         {NDMP_DATA_START_RECOVER,
2924                 dissect_data_start_recover_request, dissect_error },
2925         {NDMP_DATA_ABORT,
2926                 NULL, dissect_error},
2927         {NDMP_DATA_GET_ENV,
2928                 NULL, dissect_data_get_env_reply},
2929         {NDMP_DATA_STOP,
2930                 NULL, dissect_error},
2931         {NDMP_DATA_LISTEN,
2932                 dissect_ndmp_addr_msg, dissect_mover_listen_reply},
2933         {NDMP_DATA_CONNECT,
2934                 dissect_data_connect_msg, dissect_error},
2935         {NDMP_NOTIFY_DATA_HALTED,
2936                 dissect_notify_data_halted_request, NULL},
2937         {NDMP_NOTIFY_CONNECTED,
2938                 dissect_notify_connected_request, NULL},
2939         {NDMP_NOTIFY_MOVER_HALTED,
2940                 dissect_notify_mover_halted_request, NULL},
2941         {NDMP_NOTIFY_MOVER_PAUSED,
2942                 dissect_notify_mover_paused_request, NULL},
2943         {NDMP_NOTIFY_DATA_READ,
2944                 dissect_mover_set_window_request, NULL},
2945         {NDMP_LOG_FILE,
2946                 dissect_log_file_request, NULL},
2947         {NDMP_LOG_MESSAGE,
2948                 dissect_log_message_request, NULL},
2949         {NDMP_FH_ADD_FILE,
2950                 dissect_fh_add_file_request, NULL},
2951         {NDMP_FH_ADD_DIR,
2952                 dissect_fh_add_dir_request, NULL},
2953         {NDMP_FH_ADD_NODE,
2954                 dissect_fh_add_node_request, NULL},
2955         {NDMP_CONNECT_OPEN,
2956                 dissect_connect_open_request, dissect_error},
2957         {NDMP_CONNECT_CLIENT_AUTH,
2958                 dissect_connect_client_auth_request, dissect_error},
2959         {NDMP_CONNECT_CLOSE,
2960                 NULL,NULL},
2961         {NDMP_CONNECT_SERVER_AUTH,
2962                 dissect_auth_attr_msg, dissect_connect_server_auth_reply},
2963         {NDMP_MOVER_GET_STATE,
2964                 NULL, dissect_mover_get_state_reply},
2965         {NDMP_MOVER_LISTEN,
2966                 dissect_mover_listen_request, dissect_mover_listen_reply},
2967         {NDMP_MOVER_CONTINUE,
2968                 NULL, dissect_error},
2969         {NDMP_MOVER_ABORT,
2970                 NULL, dissect_error},
2971         {NDMP_MOVER_STOP,
2972                 NULL, dissect_error},
2973         {NDMP_MOVER_SET_WINDOW,
2974                 dissect_mover_set_window_request, dissect_error},
2975         {NDMP_MOVER_READ,
2976                 dissect_mover_set_window_request, dissect_error},
2977         {NDMP_MOVER_CLOSE,
2978                 NULL, dissect_error},
2979         {NDMP_MOVER_SET_RECORD_SIZE,
2980                 dissect_mover_set_record_size_request, dissect_error},
2981         {NDMP_MOVER_CONNECT,
2982                 dissect_mover_connect_request, dissect_error},
2983         {0, NULL,NULL}
2984 };
2985
2986
2987 static int
2988 dissect_ndmp_header(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, struct ndmp_header *nh)
2989 {
2990         proto_item* item = NULL;
2991         proto_tree* tree = NULL;
2992         nstime_t ns;
2993
2994         if (parent_tree) {
2995                 item = proto_tree_add_item(parent_tree, hf_ndmp_header, tvb,
2996                                 offset, 24, ENC_NA);
2997                 tree = proto_item_add_subtree(item, ett_ndmp_header);
2998         }
2999
3000         /* sequence number */
3001         proto_tree_add_uint(tree, hf_ndmp_sequence, tvb, offset, 4, nh->seq);
3002         offset += 4;
3003
3004         /* timestamp */
3005         ns.secs=nh->time;
3006         ns.nsecs=0;
3007         proto_tree_add_time(tree, hf_ndmp_timestamp, tvb, offset, 4, &ns);
3008         offset += 4;
3009
3010         /* Message Type */
3011         proto_tree_add_uint(tree, hf_ndmp_msgtype, tvb, offset, 4, nh->type);
3012         offset += 4;
3013
3014         /* Message */
3015         proto_tree_add_uint(tree, hf_ndmp_msg, tvb, offset, 4, nh->msg);
3016         offset += 4;
3017
3018         /* Reply sequence number */
3019         proto_tree_add_uint(tree, hf_ndmp_reply_sequence, tvb, offset, 4, nh->rep_seq);
3020         offset += 4;
3021
3022         /* error */
3023         offset=dissect_error(tvb, offset, pinfo, tree, nh->seq);
3024
3025         col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s ",
3026                         val_to_str(nh->msg, msg_vals, "Unknown Message (0x%02x)"),
3027                         val_to_str(nh->type, msg_type_vals, "Unknown Type (0x%02x)")
3028                         );
3029
3030         return offset;
3031 }
3032
3033
3034 static int
3035 dissect_ndmp_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, struct ndmp_header *nh)
3036 {
3037         int i;
3038         proto_item *cmd_item=NULL;
3039         proto_tree *cmd_tree=NULL;
3040
3041         offset=dissect_ndmp_header(tvb, offset, pinfo, tree, nh);
3042
3043         for(i=0;ndmp_commands[i].cmd!=0;i++){
3044                 if(ndmp_commands[i].cmd==nh->msg){
3045                         break;
3046                 }
3047         }
3048
3049
3050         if(ndmp_commands[i].cmd==0){
3051                 /* we do not know this message */
3052                 proto_tree_add_text(tree, tvb, offset, -1, "Unknown type of NDMP message: 0x%02x", nh->msg);
3053                 offset+=tvb_length_remaining(tvb, offset);
3054                 return offset;
3055         }
3056
3057         if (tvb_reported_length_remaining(tvb, offset) > 0) {
3058                 if(tree){
3059                         cmd_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
3060                                 msg_vals[i].strptr);
3061                         cmd_tree = proto_item_add_subtree(cmd_item, ett_ndmp);
3062                 }
3063         }
3064
3065         if(nh->type==NDMP_MESSAGE_REQUEST){
3066                 if(ndmp_commands[i].request){
3067                         offset=ndmp_commands[i].request(tvb, offset, pinfo, cmd_tree,
3068                             nh->seq);
3069                 }
3070         } else {
3071                 if(ndmp_commands[i].response){
3072                         offset=ndmp_commands[i].response(tvb, offset, pinfo, cmd_tree,
3073                             nh->rep_seq);
3074                 }
3075         }
3076
3077         return offset;
3078 }
3079
3080 static int
3081 dissect_ndmp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
3082 {
3083         int offset = 0;
3084         guint32 ndmp_rm;
3085         struct ndmp_header nh;
3086         guint32 size;
3087         guint32 seq, len, nxt, frag_num;
3088         gint nbytes;
3089         int direction;
3090         struct tcpinfo *tcpinfo;
3091         ndmp_frag_info* nfi;
3092         proto_item *ndmp_item = NULL;
3093         proto_tree *ndmp_tree = NULL;
3094         proto_item *hdr_item = NULL;
3095         proto_tree *hdr_tree = NULL;
3096         wmem_tree_t *frags;
3097         conversation_t *conversation;
3098         proto_item *vers_item;
3099         gboolean save_fragmented, save_writable;
3100         gboolean do_frag = TRUE;
3101         tvbuff_t* new_tvb = NULL;
3102         fragment_head *frag_msg = NULL;
3103
3104         top_tree=tree; /* scsi should open its expansions on the top level */
3105
3106         /*
3107          * We need to keep track of conversations so that we can track NDMP
3108          * versions.
3109          */
3110         conversation = find_or_create_conversation(pinfo);
3111
3112         ndmp_conv_data=(ndmp_conv_data_t *)conversation_get_proto_data(conversation, proto_ndmp);
3113         if(!ndmp_conv_data){
3114                 ndmp_conv_data=wmem_new(wmem_file_scope(), ndmp_conv_data_t);
3115                 ndmp_conv_data->version = NDMP_PROTOCOL_UNKNOWN;
3116                 ndmp_conv_data->tasks   = wmem_tree_new(wmem_file_scope());
3117                 ndmp_conv_data->itl     = wmem_tree_new(wmem_file_scope());
3118                 ndmp_conv_data->conversation = conversation;
3119                 ndmp_conv_data->fragsA  = wmem_tree_new(wmem_file_scope());
3120                 ndmp_conv_data->fragsB  = wmem_tree_new(wmem_file_scope());
3121
3122                 conversation_add_proto_data(conversation, proto_ndmp, ndmp_conv_data);
3123
3124                 /* Ensure that any & all frames/fragments belonging to this conversation   */
3125                 /*  are dissected as NDMP even if another dissector (eg: IPSEC-TCP) might  */
3126                 /*  decide to dissect an NDMP fragment. This works because the TCP         */
3127                 /*  dissector dispatches to a conversation associated dissector before     */
3128                 /*  dispatching by port or by heuristic. Associating NDMP with this        */
3129                 /*  conversation is necessary because otherwise the IPSEC-TCP(TCPENCAP)    */
3130                 /*  dissector may think NDMP fragments are really TCPENCAP since that      */
3131                 /*  dissector also registers on TCP Port 10000. (See packet-ipsec-tcp.c).  */
3132                 conversation_set_dissector(conversation, ndmp_handle);
3133         }
3134
3135         /*
3136          * Read the NDMP record marker, if we have it.
3137          */
3138         ndmp_rm=tvb_get_ntohl(tvb, offset);
3139
3140         /* Save the flag indicating whether this packet is a fragment */
3141         save_fragmented = pinfo->fragmented;
3142
3143         /* Reassemble if desegmentation and reassembly are enabled, otherwise
3144          * just pass through and use the data in tvb for dissection */
3145         if (ndmp_defragment && ndmp_desegment)
3146         {
3147
3148                 /*
3149                  * Determine the direction of the flow, so we can use the correct fragment tree
3150                  */
3151                 direction=CMP_ADDRESS(&pinfo->src, &pinfo->dst);
3152                 if(direction==0) {
3153                         direction= (pinfo->srcport > pinfo->destport) ? 1 : -1;
3154                 }
3155                 if(direction>=0){
3156                         frags = ndmp_conv_data->fragsA;
3157                 } else {
3158                         frags = ndmp_conv_data->fragsB;
3159                 }
3160
3161                 /*
3162                  * Figure out the tcp seq and pdu length.  Fragment tree is indexed based on seq;
3163                  */
3164                 tcpinfo = (struct tcpinfo *)data;
3165
3166                 seq = tcpinfo->seq;
3167                 len = (ndmp_rm & RPC_RM_FRAGLEN) + 4;
3168                 nxt = seq + len;
3169
3170                 /*
3171                  * In case there are multiple PDUs in the same frame, advance the tcp seq
3172                  * so that they can be distinguished from one another
3173                  */
3174                 tcpinfo->seq = nxt;
3175
3176                 nfi = (ndmp_frag_info *)wmem_tree_lookup32(frags, seq);
3177
3178                 if (!nfi)
3179                 {
3180                         frag_num = 0;
3181
3182                         /*
3183                          * If nfi doesn't exist, then there are no fragments before this one.
3184                          * If there are fragments after this one, create the entry in the frag
3185                          * tree so the next fragment can find it.
3186                          * If we've already seen this frame, no need to create the entry again.
3187                          */
3188                         if ( !(ndmp_rm & RPC_RM_LASTFRAG))
3189                         {
3190                                 if ( !(pinfo->fd->flags.visited))
3191                                 {
3192                                         nfi=wmem_new(wmem_file_scope(), ndmp_frag_info);
3193                                         nfi->first_seq = seq;
3194                                         nfi->offset = 1;
3195                                         wmem_tree_insert32(frags, nxt, (void *)nfi);
3196                                 }
3197                         }
3198                         /*
3199                          * If this is both the first and the last fragment, then there
3200                          * is no reason to even engage the reassembly routines.  Just
3201                          * create the new_tvb directly from tvb.
3202                          */
3203                         else
3204                         {
3205                                 do_frag = FALSE;
3206                                 new_tvb = tvb_new_subset_remaining(tvb, 4);
3207                         }
3208                 }
3209                 else
3210                 {
3211                         /*
3212                          * An entry was found, so we know the offset of this fragment
3213                          */
3214                         frag_num = nfi->offset;
3215                         seq = nfi->first_seq;
3216
3217                         /*
3218                          * If this isn't the last frag, add another entry so the next fragment can find it.
3219                          * If we've already seen this frame, no need to create the entry again.
3220                          */
3221                         if ( !(ndmp_rm & RPC_RM_LASTFRAG))
3222                         {
3223                                 if ( !(pinfo->fd->flags.visited))
3224                                 {
3225                                         nfi=wmem_new(wmem_file_scope(), ndmp_frag_info);
3226                                         nfi->first_seq = seq;
3227                                         nfi->offset = frag_num+1;
3228                                         wmem_tree_insert32(frags, nxt, (void *)nfi);
3229                                 }
3230                         }
3231                 }
3232
3233                 /* If fragmentation is necessary */
3234                 if (do_frag)
3235                 {
3236                         pinfo->fragmented = TRUE;
3237
3238                         frag_msg = fragment_add_seq_check(&ndmp_reassembly_table,
3239                                 tvb, 4, pinfo, seq, NULL,
3240                                 frag_num,
3241                                 tvb_length_remaining(tvb, offset)-4,
3242                                 !(ndmp_rm & RPC_RM_LASTFRAG));
3243
3244                         new_tvb = process_reassembled_data(tvb, 4, pinfo, "Reassembled NDMP", frag_msg, &ndmp_frag_items, NULL, tree);
3245                 }
3246
3247                 /*
3248                  * Check if this is the last fragment.
3249                  */
3250                 if (!(ndmp_rm & RPC_RM_LASTFRAG)) {
3251                         /*
3252                          *  Update the column info.
3253                          */
3254                         col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDMP");
3255
3256                         col_set_str(pinfo->cinfo, COL_INFO, "[NDMP fragment] ");
3257
3258                         /*
3259                          * Add the record marker information to the tree
3260                          */
3261                         if (tree) {
3262                                 ndmp_item = proto_tree_add_item(tree, proto_ndmp, tvb, 0, -1, ENC_NA);
3263                                 ndmp_tree = proto_item_add_subtree(ndmp_item, ett_ndmp);
3264                         }
3265                         hdr_item = proto_tree_add_text(ndmp_tree, tvb, 0, 4,
3266                                 "Fragment header: %s%u %s",
3267                                 (ndmp_rm & RPC_RM_LASTFRAG) ? "Last fragment, " : "",
3268                                 ndmp_rm & RPC_RM_FRAGLEN, plurality(ndmp_rm & RPC_RM_FRAGLEN, "byte", "bytes"));
3269                         hdr_tree = proto_item_add_subtree(hdr_item, ett_ndmp_fraghdr);
3270                         proto_tree_add_boolean(hdr_tree, hf_ndmp_lastfrag, tvb, 0, 4, ndmp_rm);
3271                         proto_tree_add_uint(hdr_tree, hf_ndmp_fraglen, tvb, 0, 4, ndmp_rm);
3272
3273                         /*
3274                          * Decode the remaining bytes as generic NDMP fragment data
3275                          */
3276                         nbytes = tvb_reported_length_remaining(tvb, 4);
3277                         proto_tree_add_text(ndmp_tree, tvb, 4, nbytes, "NDMP fragment data (%u byte%s)", nbytes, plurality(nbytes, "", "s"));
3278
3279                         pinfo->fragmented = save_fragmented;
3280                         return tvb_length(tvb);
3281                 }
3282         }
3283         else
3284         {
3285                 new_tvb = tvb_new_subset_remaining(tvb, 4);
3286         }
3287
3288
3289         /* size of this NDMP PDU */
3290         size = tvb_length_remaining(new_tvb, offset);
3291         if (size < 24) {
3292                 /* too short to be NDMP */
3293                 pinfo->fragmented = save_fragmented;
3294                 return tvb_length(tvb);
3295         }
3296
3297         /*
3298          * If it doesn't look like a valid NDMP header at this point, there is
3299          * no reason to move forward
3300          */
3301         if (!check_ndmp_hdr(new_tvb))
3302         {
3303                 pinfo->fragmented = save_fragmented;
3304                 return tvb_length(tvb);
3305         }
3306
3307         nh.seq = tvb_get_ntohl(new_tvb, offset);
3308         nh.time = tvb_get_ntohl(new_tvb, offset+4);
3309         nh.type = tvb_get_ntohl(new_tvb, offset+8);
3310         nh.msg = tvb_get_ntohl(new_tvb, offset+12);
3311         nh.rep_seq = tvb_get_ntohl(new_tvb, offset+16);
3312         nh.err = tvb_get_ntohl(new_tvb, offset+20);
3313
3314         /* When the last fragment is small and the final frame contains
3315          * multiple fragments, the column becomes unwritable.
3316          * Temporarily change that so that the correct header can be
3317          * applied */
3318         save_writable = col_get_writable(pinfo->cinfo);
3319         col_set_writable(pinfo->cinfo, TRUE);
3320
3321         col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDMP");
3322         col_clear(pinfo->cinfo, COL_INFO);
3323         if (tree) {
3324                 ndmp_item = proto_tree_add_item(tree, proto_ndmp, tvb, 0, -1, ENC_NA);
3325                 ndmp_tree = proto_item_add_subtree(ndmp_item, ett_ndmp);
3326         }
3327
3328         /* ndmp version (and autodetection) */
3329         if(ndmp_conv_data->version!=NDMP_PROTOCOL_UNKNOWN){
3330                 vers_item=proto_tree_add_uint(ndmp_tree, hf_ndmp_version, new_tvb, offset, 0, ndmp_conv_data->version);
3331         } else {
3332                 vers_item=proto_tree_add_uint_format(ndmp_tree, hf_ndmp_version, new_tvb, offset, 0, ndmp_default_protocol_version, "Unknown NDMP version, using default:%d", ndmp_default_protocol_version);
3333         }
3334         PROTO_ITEM_SET_GENERATED(vers_item);
3335
3336         /* request response matching */
3337         ndmp_conv_data->task=NULL;
3338         switch(nh.type){
3339         case NDMP_MESSAGE_REQUEST:
3340                 if(!pinfo->fd->flags.visited){
3341                         ndmp_conv_data->task=wmem_new(wmem_file_scope(), ndmp_task_data_t);
3342                         ndmp_conv_data->task->request_frame=pinfo->fd->num;
3343                         ndmp_conv_data->task->response_frame=0;
3344                         ndmp_conv_data->task->ndmp_time=pinfo->fd->abs_ts;
3345                         ndmp_conv_data->task->itlq=NULL;
3346                         wmem_tree_insert32(ndmp_conv_data->tasks, nh.seq, ndmp_conv_data->task);
3347                 } else {
3348                         ndmp_conv_data->task=(ndmp_task_data_t *)wmem_tree_lookup32(ndmp_conv_data->tasks, nh.seq);
3349                 }
3350                 if(ndmp_conv_data->task && ndmp_conv_data->task->response_frame){
3351                         proto_item *it;
3352                         it=proto_tree_add_uint(ndmp_tree, hf_ndmp_response_frame, new_tvb, 0, 0, ndmp_conv_data->task->response_frame);
3353
3354                         PROTO_ITEM_SET_GENERATED(it);
3355                 }
3356                 break;
3357         case NDMP_MESSAGE_REPLY:
3358                 ndmp_conv_data->task=(ndmp_task_data_t *)wmem_tree_lookup32(ndmp_conv_data->tasks, nh.rep_seq);
3359
3360                 if(ndmp_conv_data->task && !pinfo->fd->flags.visited){
3361                         ndmp_conv_data->task->response_frame=pinfo->fd->num;
3362                         if(ndmp_conv_data->task->itlq){
3363                                 ndmp_conv_data->task->itlq->last_exchange_frame=pinfo->fd->num;
3364                         }
3365                 }
3366                 if(ndmp_conv_data->task && ndmp_conv_data->task->request_frame){
3367                         proto_item *it;
3368                         nstime_t delta_ts;
3369
3370                         it=proto_tree_add_uint(ndmp_tree, hf_ndmp_request_frame, new_tvb, 0, 0, ndmp_conv_data->task->request_frame);
3371
3372                         PROTO_ITEM_SET_GENERATED(it);
3373
3374                         nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &ndmp_conv_data->task->ndmp_time);
3375                         it=proto_tree_add_time(ndmp_tree, hf_ndmp_time, new_tvb, 0, 0, &delta_ts);
3376                         PROTO_ITEM_SET_GENERATED(it);
3377                 }
3378                 break;
3379         }
3380
3381         /* Add the record marker information to the tree */
3382         hdr_item = proto_tree_add_text(ndmp_tree, tvb, 0, 4,
3383                 "Fragment header: %s%u %s",
3384                 (ndmp_rm & RPC_RM_LASTFRAG) ? "Last fragment, " : "",
3385                 ndmp_rm & RPC_RM_FRAGLEN, plurality(ndmp_rm & RPC_RM_FRAGLEN, "byte", "bytes"));
3386         hdr_tree = proto_item_add_subtree(hdr_item, ett_ndmp_fraghdr);
3387         proto_tree_add_boolean(hdr_tree, hf_ndmp_lastfrag, tvb, 0, 4, ndmp_rm);
3388         proto_tree_add_uint(hdr_tree, hf_ndmp_fraglen, tvb, 0, 4, ndmp_rm);
3389
3390         /*
3391          * We cannot trust what dissect_ndmp_cmd() tells us, as there
3392          * are implementations which pad some additional data after
3393          * the PDU.  We MUST use size.
3394          */
3395         dissect_ndmp_cmd(new_tvb, offset, pinfo, ndmp_tree, &nh);
3396
3397         /* restore saved variables */
3398         pinfo->fragmented = save_fragmented;
3399         col_set_writable(pinfo->cinfo, save_writable);
3400
3401         return tvb_length(tvb);
3402 }
3403
3404 static guint
3405 get_ndmp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
3406 {
3407   guint len;
3408
3409   len=tvb_get_ntohl(tvb, offset)&0x7fffffff;
3410   /* Get the length of the NDMP packet. */
3411
3412   /*XXX check header for sanity */
3413   return len+4;
3414 }
3415
3416 gboolean
3417 check_if_ndmp(tvbuff_t *tvb, packet_info *pinfo)
3418 {
3419         guint len;
3420         guint32 tmp;
3421
3422         /* verify that the tcp port is 10000, ndmp always runs on port 10000*/
3423         if ((pinfo->srcport!=TCP_PORT_NDMP)&&(pinfo->destport!=TCP_PORT_NDMP)) {
3424                 return FALSE;
3425         }
3426
3427         /* check that the header looks sane */
3428         len=tvb_length(tvb);
3429         /* check the record marker that it looks sane.
3430          * It has to be >=24 bytes or (arbitrary limit) <1Mbyte
3431          */
3432         if(len>=4){
3433                 tmp=(tvb_get_ntohl(tvb, 0)&RPC_RM_FRAGLEN);
3434                 if( (tmp<24)||(tmp>1000000) ){
3435                         return FALSE;
3436                 }
3437         }
3438
3439         /* check the timestamp,  timestamps are valid if they
3440          * (arbitrary) lie between 1980-jan-1 and 2030-jan-1
3441          */
3442         if(len>=12){
3443                 tmp=tvb_get_ntohl(tvb, 8);
3444                 if( (tmp<0x12ceec50)||(tmp>0x70dc1ed0) ){
3445                         return FALSE;
3446                 }
3447         }
3448
3449         /* check the type */
3450         if(len>=16){
3451                 tmp=tvb_get_ntohl(tvb, 12);
3452                 if( tmp>1 ){
3453                         return FALSE;
3454                 }
3455         }
3456
3457         /* check message */
3458         if(len>=20){
3459                 tmp=tvb_get_ntohl(tvb, 16);
3460                 if( (tmp>0xa09) || (tmp==0) ){
3461                         return FALSE;
3462                 }
3463         }
3464
3465         /* check error */
3466         if(len>=28){
3467                 tmp=tvb_get_ntohl(tvb, 24);
3468                 if( (tmp>0x17) ){
3469                         return FALSE;
3470                 }
3471         }
3472
3473         return TRUE;
3474 }
3475
3476 /* Called because the frame has been identified as part of a conversation
3477  *  assigned to the NDMP protocol.
3478  *  At this point we may have either an NDMP PDU or an NDMP PDU fragment.
3479  */
3480 static int
3481 dissect_ndmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3482 {
3483         /* If we are doing defragmentation, don't check more than the record mark here,
3484          * because if this is a continuation of a fragmented NDMP PDU there won't be a
3485          * NDMP header after the RM */
3486         if(ndmp_defragment && !check_ndmp_rm(tvb, pinfo)) {
3487                 return 0;
3488         }
3489
3490         /* If we aren't doing both desegmentation and fragment reassembly,
3491          * check for the entire NDMP header before proceeding */
3492         if(!(ndmp_desegment && ndmp_defragment) && !check_if_ndmp(tvb, pinfo)) {
3493                 return 0;
3494         }
3495
3496         tcp_dissect_pdus(tvb, pinfo, tree, ndmp_desegment, 4,
3497                          get_ndmp_pdu_len, dissect_ndmp_message, data);
3498         return tvb_length(tvb);
3499 }
3500
3501 /* Called when doing a heuristic check;
3502  * Accept as NDMP only if the full header seems reasonable.
3503  * Note that once the first PDU (or PDU fragment) has been found
3504  *  dissect_ndmp_message will register a dissect_ndmp NDMP handle
3505  *  as the protocol dissector for this conversation.
3506  */
3507 static int
3508 dissect_ndmp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3509 {
3510         if (tvb_length(tvb) < 28)
3511                 return 0;
3512         if (!check_if_ndmp(tvb, pinfo))
3513                 return 0;
3514
3515         tcp_dissect_pdus(tvb, pinfo, tree, ndmp_desegment, 28,
3516                          get_ndmp_pdu_len, dissect_ndmp_message, data);
3517         return tvb_length(tvb);
3518 }
3519
3520 static void
3521 ndmp_init(void)
3522 {
3523         reassembly_table_init(&ndmp_reassembly_table,
3524             &addresses_reassembly_table_functions);
3525 }
3526
3527
3528 void
3529 proto_register_ndmp(void)
3530 {
3531
3532   static hf_register_info hf_ndmp[] = {
3533         { &hf_ndmp_header, {
3534                 "NDMP Header", "ndmp.header", FT_NONE, BASE_NONE,
3535                 NULL, 0, NULL, HFILL }},
3536
3537         { &hf_ndmp_response_frame, {
3538                 "Response In", "ndmp.response_frame", FT_FRAMENUM, BASE_NONE,
3539                 NULL, 0, "The response to this NDMP command is in this frame", HFILL }},
3540
3541         { &hf_ndmp_time,
3542           { "Time from request", "ndmp.time", FT_RELATIVE_TIME, BASE_NONE, NULL,
3543            0, "Time since the request packet", HFILL }},
3544
3545         { &hf_ndmp_request_frame, {
3546                 "Request In", "ndmp.request_frame", FT_FRAMENUM, BASE_NONE,
3547                 NULL, 0, "The request to this NDMP command is in this frame", HFILL }},
3548
3549         { &hf_ndmp_sequence, {
3550                 "Sequence", "ndmp.sequence", FT_UINT32, BASE_DEC,
3551                 NULL, 0, "Sequence number for NDMP PDU", HFILL }},
3552
3553         { &hf_ndmp_reply_sequence, {
3554                 "Reply Sequence", "ndmp.reply_sequence", FT_UINT32, BASE_DEC,
3555                 NULL, 0, "Reply Sequence number for NDMP PDU", HFILL }},
3556
3557         { &hf_ndmp_timestamp, {
3558                 "Time", "ndmp.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
3559                 NULL, 0, "Timestamp for this NDMP PDU", HFILL }},
3560
3561         { &hf_ndmp_msgtype, {
3562                 "Type", "ndmp.msg_type", FT_UINT32, BASE_DEC,
3563                 VALS(msg_type_vals), 0, "Is this a Request or Response?", HFILL }},
3564
3565         { &hf_ndmp_msg, {
3566                 "Message", "ndmp.msg", FT_UINT32, BASE_HEX,
3567                 VALS(msg_vals), 0, "Type of NDMP PDU", HFILL }},
3568
3569         { &hf_ndmp_error, {
3570                 "Error", "ndmp.error", FT_UINT32, BASE_DEC,
3571                 VALS(error_vals), 0, "Error code for this NDMP PDU", HFILL }},
3572
3573         { &hf_ndmp_version, {
3574                 "Version", "ndmp.version", FT_UINT32, BASE_DEC,
3575                 NULL, 0, "Version of NDMP protocol", HFILL }},
3576
3577         { &hf_ndmp_hostname, {
3578                 "Hostname", "ndmp.hostname", FT_STRING, BASE_NONE,
3579                 NULL, 0, NULL, HFILL }},
3580
3581         { &hf_ndmp_hostid, {
3582                 "HostID", "ndmp.hostid", FT_STRING, BASE_NONE,
3583                 NULL, 0, NULL, HFILL }},
3584
3585         { &hf_ndmp_os_type, {
3586                 "OS Type", "ndmp.os.type", FT_STRING, BASE_NONE,
3587                 NULL, 0, NULL, HFILL }},
3588
3589         { &hf_ndmp_os_vers, {
3590                 "OS Version", "ndmp.os.version", FT_STRING, BASE_NONE,
3591                 NULL, 0, NULL, HFILL }},
3592
3593         { &hf_ndmp_addr_types, {
3594                 "Addr Types", "ndmp.addr_types", FT_NONE, BASE_NONE,
3595                 NULL, 0, "List Of Address Types", HFILL }},
3596
3597         { &hf_ndmp_addr_type, {
3598                 "Addr Type", "ndmp.addr_type", FT_UINT32, BASE_DEC,
3599                 VALS(addr_type_vals), 0, "Address Type", HFILL }},
3600
3601         { &hf_ndmp_auth_type, {
3602                 "Auth Type", "ndmp.auth_type", FT_UINT32, BASE_DEC,
3603                 VALS(auth_type_vals), 0, "Authentication Type", HFILL }},
3604
3605         { &hf_ndmp_auth_challenge, {
3606                 "Challenge", "ndmp.auth.challenge", FT_BYTES, BASE_NONE,
3607                 NULL, 0, "Authentication Challenge", HFILL }},
3608
3609         { &hf_ndmp_auth_digest, {
3610                 "Digest", "ndmp.auth.digest", FT_BYTES, BASE_NONE,
3611                 NULL, 0, "Authentication Digest", HFILL }},
3612
3613         { &hf_ndmp_butype_info, {
3614                 "Butype Info", "ndmp.butype.info", FT_NONE, BASE_NONE,
3615                 NULL, 0, NULL, HFILL }},
3616
3617         { &hf_ndmp_butype_name, {
3618                 "Butype Name", "ndmp.butype.name", FT_STRING, BASE_NONE,
3619                 NULL, 0, "Name of Butype", HFILL }},
3620
3621         { &hf_ndmp_butype_default_env, {
3622                 "Default Env", "ndmp.butype.default_env", FT_NONE, BASE_NONE,
3623                 NULL, 0, "Default Env's for this Butype Info", HFILL }},
3624
3625         { &hf_ndmp_tcp_addr_list, {
3626                 "TCP Ports", "ndmp.tcp.port_list", FT_NONE, BASE_NONE,
3627                 NULL, 0, "List of TCP ports", HFILL }},
3628
3629         { &hf_ndmp_tcp_default_env, {
3630                 "Default Env", "ndmp.tcp.default_env", FT_NONE, BASE_NONE,
3631                 NULL, 0, "Default Env's for this Butype Info", HFILL }},
3632
3633         { &hf_ndmp_butype_attr_backup_file_history, {
3634                 "Backup file history", "ndmp.butype.attr.backup_file_history", FT_BOOLEAN, 32,
3635                 TFS(&tfs_butype_attr_backup_file_history), 0x00000001, "backup_file_history", HFILL }},
3636
3637         { &hf_ndmp_butype_attr_backup_filelist, {
3638                 "Backup file list", "ndmp.butype.attr.backup_filelist", FT_BOOLEAN, 32,
3639                 TFS(&tfs_butype_attr_backup_filelist), 0x00000002, "backup_filelist", HFILL }},
3640
3641         { &hf_ndmp_butype_attr_recover_filelist, {
3642                 "Recover file list", "ndmp.butype.attr.recover_filelist", FT_BOOLEAN, 32,
3643                 TFS(&tfs_butype_attr_recover_filelist), 0x00000004, "recover_filelist", HFILL }},
3644
3645         { &hf_ndmp_butype_attr_backup_direct, {
3646                 "Backup direct", "ndmp.butype.attr.backup_direct", FT_BOOLEAN, 32,
3647                 TFS(&tfs_butype_attr_backup_direct), 0x00000008, "backup_direct", HFILL }},
3648
3649         { &hf_ndmp_butype_attr_recover_direct, {
3650                 "Recover direct", "ndmp.butype.attr.recover_direct", FT_BOOLEAN, 32,
3651                 TFS(&tfs_butype_attr_recover_direct), 0x00000010, "recover_direct", HFILL }},
3652
3653         { &hf_ndmp_butype_attr_backup_incremental, {
3654                 "Backup incremental", "ndmp.butype.attr.backup_incremental", FT_BOOLEAN, 32,
3655                 TFS(&tfs_butype_attr_backup_incremental), 0x00000020, "backup_incremental", HFILL }},
3656
3657         { &hf_ndmp_butype_attr_recover_incremental, {
3658                 "Recover incremental", "ndmp.butype.attr.recover_incremental", FT_BOOLEAN, 32,
3659                 TFS(&tfs_butype_attr_recover_incremental), 0x00000040, "recover_incremental", HFILL }},
3660
3661         { &hf_ndmp_butype_attr_backup_utf8, {
3662                 "Backup UTF8", "ndmp.butype.attr.backup_utf8", FT_BOOLEAN, 32,
3663                 TFS(&tfs_butype_attr_backup_utf8), 0x00000080, "backup_utf8", HFILL }},
3664
3665         { &hf_ndmp_butype_attr_recover_utf8, {
3666                 "Recover UTF8", "ndmp.butype.attr.recover_utf8", FT_BOOLEAN, 32,
3667                 TFS(&tfs_butype_attr_recover_utf8), 0x00000100, "recover_utf8", HFILL }},
3668
3669         { &hf_ndmp_butype_env_name, {
3670                 "Name", "ndmp.butype.env.name", FT_STRING, BASE_NONE,
3671                 NULL, 0, "Name for this env-variable", HFILL }},
3672
3673         { &hf_ndmp_butype_env_value, {
3674                 "Value", "ndmp.butype.env.value", FT_STRING, BASE_NONE,
3675                 NULL, 0, "Value for this env-variable", HFILL }},
3676
3677         { &hf_ndmp_tcp_env_name, {
3678                 "Name", "ndmp.tcp.env.name", FT_STRING, BASE_NONE,
3679                 NULL, 0, "Name for this env-variable", HFILL }},
3680
3681         { &hf_ndmp_tcp_env_value, {
3682                 "Value", "ndmp.tcp.env.value", FT_STRING, BASE_NONE,
3683                 NULL, 0, "Value for this env-variable", HFILL }},
3684
3685         { &hf_ndmp_fs_info, {
3686                 "FS Info", "ndmp.fs.info", FT_NONE, BASE_NONE,
3687                 NULL, 0, NULL, HFILL }},
3688
3689         { &hf_ndmp_fs_invalid_total_size, {
3690                 "Total size invalid", "ndmp.fs.invalid.total_size", FT_BOOLEAN, 32,
3691                 TFS(&tfs_fs_invalid_total_size), 0x00000001, "If total size is invalid", HFILL }},
3692
3693         { &hf_ndmp_fs_invalid_used_size, {
3694                 "Used size invalid", "ndmp.fs.invalid.used_size", FT_BOOLEAN, 32,
3695                 TFS(&tfs_fs_invalid_used_size), 0x00000002, "If used size is invalid", HFILL }},
3696
3697         { &hf_ndmp_fs_invalid_avail_size, {
3698                 "Available size invalid", "ndmp.fs.invalid.avail_size", FT_BOOLEAN, 32,
3699                 TFS(&tfs_fs_invalid_avail_size), 0x00000004, "If available size is invalid", HFILL }},
3700
3701         { &hf_ndmp_fs_invalid_total_inodes, {
3702                 "Total number of inodes invalid", "ndmp.fs.invalid.total_inodes", FT_BOOLEAN, 32,
3703                 TFS(&tfs_fs_invalid_total_inodes), 0x00000008, "If total number of inodes is invalid", HFILL }},
3704
3705         { &hf_ndmp_fs_invalid_used_inodes, {
3706                 "Used number of inodes is invalid", "ndmp.fs.invalid.used_inodes", FT_BOOLEAN, 32,
3707                 TFS(&tfs_fs_invalid_used_inodes), 0x00000010, "If used number of inodes is invalid", HFILL }},
3708
3709         { &hf_ndmp_fs_fs_type, {
3710                 "Type", "ndmp.fs.type", FT_STRING, BASE_NONE,
3711                 NULL, 0, "Type of FS", HFILL }},
3712
3713         { &hf_ndmp_fs_logical_device, {
3714                 "Logical Device", "ndmp.fs.logical_device", FT_STRING, BASE_NONE,
3715                 NULL, 0, "Name of logical device", HFILL }},
3716
3717         { &hf_ndmp_fs_physical_device, {
3718                 "Physical Device", "ndmp.fs.physical_device", FT_STRING, BASE_NONE,
3719                 NULL, 0, "Name of physical device", HFILL }},
3720
3721         { &hf_ndmp_fs_total_size, {
3722                 "Total Size", "ndmp.fs.total_size", FT_UINT64, BASE_DEC,
3723                 NULL, 0, "Total size of FS", HFILL }},
3724
3725         { &hf_ndmp_fs_used_size, {
3726                 "Used Size", "ndmp.fs.used_size", FT_UINT64, BASE_DEC,
3727                 NULL, 0, "Total used size of FS", HFILL }},
3728
3729         { &hf_ndmp_fs_avail_size, {
3730                 "Avail Size", "ndmp.fs.avail_size", FT_UINT64, BASE_DEC,
3731                 NULL, 0, "Total available size on FS", HFILL }},
3732
3733         { &hf_ndmp_fs_total_inodes, {
3734                 "Total Inodes", "ndmp.fs.total_inodes", FT_UINT64, BASE_DEC,
3735                 NULL, 0, "Total number of inodes on FS", HFILL }},
3736
3737         { &hf_ndmp_fs_used_inodes, {
3738                 "Used Inodes", "ndmp.fs.used_inodes", FT_UINT64, BASE_DEC,
3739                 NULL, 0, "Number of used inodes on FS", HFILL }},
3740
3741         { &hf_ndmp_fs_env, {
3742                 "Env variables", "ndmp.fs.env", FT_NONE, BASE_NONE,
3743                 NULL, 0, "Environment variables for FS", HFILL }},
3744
3745         { &hf_ndmp_fs_env_name, {
3746                 "Name", "ndmp.fs.env.name", FT_STRING, BASE_NONE,
3747                 NULL, 0, "Name for this env-variable", HFILL }},
3748
3749         { &hf_ndmp_fs_env_value, {
3750                 "Value", "ndmp.fs.env.value", FT_STRING, BASE_NONE,
3751                 NULL, 0, "Value for this env-variable", HFILL }},
3752
3753         { &hf_ndmp_fs_status, {
3754                 "Status", "ndmp.fs.status", FT_STRING, BASE_NONE,
3755                 NULL, 0, "Status for this FS", HFILL }},
3756
3757         { &hf_ndmp_tape_info, {
3758                 "Tape Info", "ndmp.tape.info", FT_NONE, BASE_NONE,
3759                 NULL, 0, NULL, HFILL }},
3760
3761         { &hf_ndmp_tape_model, {
3762                 "Model", "ndmp.tape.model", FT_STRING, BASE_NONE,
3763                 NULL, 0, "Model of the TAPE drive", HFILL }},
3764
3765         { &hf_ndmp_tape_dev_cap, {
3766                 "Device Capability", "ndmp.tape.dev_cap", FT_NONE, BASE_NONE,
3767                 NULL, 0, "Tape Device Capability", HFILL }},
3768
3769         { &hf_ndmp_tape_device, {
3770                 "Device", "ndmp.tape.device", FT_STRING, BASE_NONE,
3771                 NULL, 0, "Name of TAPE Device", HFILL }},
3772
3773         { &hf_ndmp_tape_attr_rewind, {
3774                 "Device supports rewind", "ndmp.tape.attr.rewind", FT_BOOLEAN, 32,
3775                 TFS(&tfs_tape_attr_rewind), 0x00000001, "If this device supports rewind", HFILL }},
3776
3777         { &hf_ndmp_tape_attr_unload, {
3778                 "Device supports unload", "ndmp.tape.attr.unload", FT_BOOLEAN, 32,
3779                 TFS(&tfs_tape_attr_unload), 0x00000002, "If this device supports unload", HFILL }},
3780
3781         { &hf_ndmp_tape_capability, {
3782                 "Tape Capabilities", "ndmp.tape.capability", FT_NONE, BASE_NONE,
3783                 NULL, 0, NULL, HFILL }},
3784
3785         { &hf_ndmp_tape_capability_name, {
3786                 "Name", "ndmp.tape.cap.name", FT_STRING, BASE_NONE,
3787                 NULL, 0, "Name for this env-variable", HFILL }},
3788
3789         { &hf_ndmp_tape_capability_value, {
3790                 "Value", "ndmp.tape.cap.value", FT_STRING, BASE_NONE,
3791                 NULL, 0, "Value for this env-variable", HFILL }},
3792
3793         { &hf_ndmp_scsi_info, {
3794                 "SCSI Info", "ndmp.scsi.info", FT_NONE, BASE_NONE,
3795                 NULL, 0, NULL, HFILL }},
3796
3797         { &hf_ndmp_scsi_model, {
3798                 "Model", "ndmp.scsi.model", FT_STRING, BASE_NONE,
3799                 NULL, 0, "Model of the SCSI device", HFILL }},
3800
3801         { &hf_ndmp_server_vendor, {
3802                 "Vendor", "ndmp.server.vendor", FT_STRING, BASE_NONE,
3803                 NULL, 0, "Name of vendor", HFILL }},
3804
3805         { &hf_ndmp_server_product, {
3806                 "Product", "ndmp.server.product", FT_STRING, BASE_NONE,
3807                 NULL, 0, "Name of product", HFILL }},
3808
3809         { &hf_ndmp_server_revision, {
3810                 "Revision", "ndmp.server.revision", FT_STRING, BASE_NONE,
3811                 NULL, 0, "Revision of this product", HFILL }},
3812
3813         { &hf_ndmp_auth_types, {
3814                 "Auth types", "ndmp.auth.types", FT_NONE, BASE_NONE,
3815                 NULL, 0, NULL, HFILL }},
3816
3817         { &hf_ndmp_scsi_device, {
3818                 "Device", "ndmp.scsi.device", FT_STRING, BASE_NONE,
3819                 NULL, 0, "Name of SCSI Device", HFILL }},
3820
3821         { &hf_ndmp_scsi_controller, {
3822                 "Controller", "ndmp.scsi.controller", FT_UINT32, BASE_DEC,
3823                 NULL, 0, "Target Controller", HFILL }},
3824
3825         { &hf_ndmp_scsi_id, {
3826                 "ID", "ndmp.scsi.id", FT_UINT32, BASE_DEC,
3827                 NULL, 0, "Target ID", HFILL }},
3828
3829         { &hf_ndmp_scsi_lun, {
3830                 "LUN", "ndmp.scsi.lun", FT_UINT32, BASE_DEC,
3831                 NULL, 0, "Target LUN", HFILL }},
3832
3833         { &hf_ndmp_execute_cdb_flags_data_in, {
3834                 "DATA_IN", "ndmp.execute_cdb.flags.data_in", FT_BOOLEAN, 32,
3835                 NULL, 0x00000001, NULL, HFILL }},
3836
3837         { &hf_ndmp_execute_cdb_flags_data_out, {
3838                 "DATA_OUT", "ndmp.execute_cdb.flags.data_out", FT_BOOLEAN, 32,
3839                 NULL, 0x00000002, NULL, HFILL }},
3840
3841         { &hf_ndmp_execute_cdb_timeout, {
3842                 "Timeout", "ndmp.execute_cdb.timeout", FT_UINT32, BASE_DEC,
3843                 NULL, 0, "Reselect timeout, in milliseconds", HFILL }},
3844
3845         { &hf_ndmp_execute_cdb_datain_len, {
3846                 "Data in length", "ndmp.execute_cdb.datain_len", FT_UINT32, BASE_DEC,
3847                 NULL, 0, "Expected length of data bytes to read", HFILL }},
3848
3849         { &hf_ndmp_execute_cdb_cdb_len, {
3850                 "CDB length", "ndmp.execute_cdb.cdb_len", FT_UINT32, BASE_DEC,
3851                 NULL, 0, "Length of CDB", HFILL }},
3852
3853 #if 0
3854         { &hf_ndmp_execute_cdb_dataout, {
3855                 "Data out", "ndmp.execute_cdb.dataout", FT_BYTES, BASE_NONE,
3856                 NULL, 0, "Data to be transferred to the SCSI device", HFILL }},
3857 #endif
3858
3859         { &hf_ndmp_execute_cdb_status, {
3860                 "Status", "ndmp.execute_cdb.status", FT_UINT8, BASE_DEC,
3861                 VALS(scsi_status_val), 0, "SCSI status", HFILL }},
3862
3863         { &hf_ndmp_execute_cdb_dataout_len, {
3864                 "Data out length", "ndmp.execute_cdb.dataout_len", FT_UINT32, BASE_DEC,
3865                 NULL, 0, "Number of bytes transferred to the device", HFILL }},
3866
3867 #if 0
3868         { &hf_ndmp_execute_cdb_datain, {
3869                 "Data in", "ndmp.execute_cdb.datain", FT_BYTES, BASE_NONE,
3870                 NULL, 0, "Data transferred from the SCSI device", HFILL }},
3871 #endif
3872
3873         { &hf_ndmp_execute_cdb_sns_len, {
3874                 "Sense data length", "ndmp.execute_cdb.sns_len", FT_UINT32, BASE_DEC,
3875                 NULL, 0, "Length of sense data", HFILL }},
3876
3877         { &hf_ndmp_tape_open_mode, {
3878                 "Mode", "ndmp.tape.open_mode", FT_UINT32, BASE_DEC,
3879                 VALS(tape_open_mode_vals), 0, "Mode to open tape in", HFILL }},
3880
3881         { &hf_ndmp_tape_invalid_file_num, {
3882                 "Invalid file num", "ndmp.tape.invalid.file_num", FT_BOOLEAN, 32,
3883                 TFS(&tfs_ndmp_tape_invalid_file_num), 0x00000001, "invalid_file_num", HFILL }},
3884
3885         { &hf_ndmp_tape_invalid_soft_errors, {
3886                 "Soft errors", "ndmp.tape.invalid.soft_errors", FT_BOOLEAN, 32,
3887                 TFS(&tfs_ndmp_tape_invalid_soft_errors), 0x00000002, "soft_errors", HFILL }},
3888
3889         { &hf_ndmp_tape_invalid_block_size, {
3890                 "Block size", "ndmp.tape.invalid.block_size", FT_BOOLEAN, 32,
3891                 TFS(&tfs_ndmp_tape_invalid_block_size), 0x00000004, "block_size", HFILL }},
3892
3893         { &hf_ndmp_tape_invalid_block_no, {
3894                 "Block no", "ndmp.tape.invalid.block_no", FT_BOOLEAN, 32,
3895                 TFS(&tfs_ndmp_tape_invalid_block_no), 0x00000008, "block_no", HFILL }},
3896
3897         { &hf_ndmp_tape_invalid_total_space, {
3898                 "Total space", "ndmp.tape.invalid.total_space", FT_BOOLEAN, 32,
3899                 TFS(&tfs_ndmp_tape_invalid_total_space), 0x00000010, "total_space", HFILL }},
3900
3901         { &hf_ndmp_tape_invalid_space_remain, {
3902                 "Space remain", "ndmp.tape.invalid.space_remain", FT_BOOLEAN, 32,
3903                 TFS(&tfs_ndmp_tape_invalid_space_remain), 0x00000020, "space_remain", HFILL }},
3904
3905         { &hf_ndmp_tape_invalid_partition, {
3906                 "Invalid partition", "ndmp.tape.invalid.partition", FT_BOOLEAN, 32,
3907                 TFS(&tfs_ndmp_tape_invalid_partition), 0x00000040, "partition", HFILL }},
3908
3909         { &hf_ndmp_tape_flags_no_rewind, {
3910                 "No rewind", "ndmp.tape.flags.no_rewind", FT_BOOLEAN, 32,
3911                 TFS(&tfs_ndmp_tape_flags_no_rewind), 0x00000008, "no_rewind", HFILL, }},
3912
3913         { &hf_ndmp_tape_flags_write_protect, {
3914                 "Write protect", "ndmp.tape.flags.write_protect", FT_BOOLEAN, 32,
3915                 TFS(&tfs_ndmp_tape_flags_write_protect), 0x00000010, "write_protect", HFILL, }},
3916
3917         { &hf_ndmp_tape_flags_error, {
3918                 "Error", "ndmp.tape.flags.error", FT_BOOLEAN, 32,
3919                 TFS(&tfs_ndmp_tape_flags_error), 0x00000020, NULL, HFILL, }},
3920
3921         { &hf_ndmp_tape_flags_unload, {
3922                 "Unload", "ndmp.tape.flags.unload", FT_BOOLEAN, 32,
3923                 TFS(&tfs_ndmp_tape_flags_unload), 0x00000040, NULL, HFILL, }},
3924
3925         { &hf_ndmp_tape_file_num, {
3926                 "file_num", "ndmp.tape.status.file_num", FT_UINT32, BASE_DEC,
3927                 NULL, 0, NULL, HFILL }},
3928
3929         { &hf_ndmp_tape_soft_errors, {
3930                 "soft_errors", "ndmp.tape.status.soft_errors", FT_UINT32, BASE_DEC,
3931                 NULL, 0, NULL, HFILL }},
3932
3933         { &hf_ndmp_tape_block_size, {
3934                 "block_size", "ndmp.tape.status.block_size", FT_UINT32, BASE_DEC,
3935                 NULL, 0, NULL, HFILL }},
3936
3937         { &hf_ndmp_tape_block_no, {
3938                 "block_no", "ndmp.tape.status.block_no", FT_UINT32, BASE_DEC,
3939                 NULL, 0, NULL, HFILL }},
3940
3941         { &hf_ndmp_tape_total_space, {
3942                 "total_space", "ndmp.tape.status.total_space", FT_UINT64, BASE_DEC,
3943                 NULL, 0, NULL, HFILL }},
3944
3945         { &hf_ndmp_tape_space_remain, {
3946                 "space_remain", "ndmp.tape.status.space_remain", FT_UINT64, BASE_DEC,
3947                 NULL, 0, NULL, HFILL }},
3948
3949         { &hf_ndmp_tape_partition, {
3950                 "partition", "ndmp.tape.status.partition", FT_UINT32, BASE_DEC,
3951                 NULL, 0, NULL, HFILL }},
3952
3953         { &hf_ndmp_tape_mtio_op, {
3954                 "Operation", "ndmp.tape.mtio.op", FT_UINT32, BASE_DEC,
3955                 VALS(tape_mtio_vals), 0, "MTIO Operation", HFILL }},
3956
3957         { &hf_ndmp_count, {
3958                 "Count", "ndmp.count", FT_UINT32, BASE_DEC,
3959                 NULL, 0, "Number of bytes/objects/operations", HFILL }},
3960
3961         { &hf_ndmp_resid_count, {
3962                 "Resid Count", "ndmp.resid_count", FT_UINT32, BASE_DEC,
3963                 NULL, 0, "Number of remaining bytes/objects/operations", HFILL }},
3964
3965         { &hf_ndmp_mover_state, {
3966                 "State", "ndmp.mover.state", FT_UINT32, BASE_DEC,
3967                 VALS(mover_state_vals), 0, "State of the selected mover", HFILL }},
3968
3969         { &hf_ndmp_mover_pause, {
3970                 "Pause", "ndmp.mover.pause", FT_UINT32, BASE_DEC,
3971                 VALS(mover_pause_vals), 0, "Reason why the mover paused", HFILL }},
3972
3973         { &hf_ndmp_halt, {
3974                 "Halt", "ndmp.halt", FT_UINT32, BASE_DEC,
3975                 VALS(halt_vals), 0, "Reason why it halted", HFILL }},
3976
3977         { &hf_ndmp_record_size, {
3978                 "Record Size", "ndmp.record.size", FT_UINT32, BASE_DEC,
3979                 NULL, 0, "Record size in bytes", HFILL }},
3980
3981         { &hf_ndmp_record_num, {
3982                 "Record Num", "ndmp.record.num", FT_UINT32, BASE_DEC,
3983                 NULL, 0, "Number of records", HFILL }},
3984
3985         { &hf_ndmp_data_written, {
3986                 "Data Written", "ndmp.data.written", FT_UINT64, BASE_DEC,
3987                 NULL, 0, "Number of data bytes written", HFILL }},
3988
3989         { &hf_ndmp_seek_position, {
3990                 "Seek Position", "ndmp.seek.position", FT_UINT64, BASE_DEC,
3991                 NULL, 0, "Current seek position on device", HFILL }},
3992
3993         { &hf_ndmp_bytes_left_to_read, {
3994                 "Bytes left to read", "ndmp.bytes_left_to_read", FT_UINT64, BASE_DEC,
3995                 NULL, 0, "Number of bytes left to be read from the device", HFILL }},
3996
3997         { &hf_ndmp_window_offset, {
3998                 "Window Offset", "ndmp.window.offset", FT_UINT64, BASE_DEC,
3999                 NULL, 0, "Offset to window in bytes", HFILL }},
4000
4001         { &hf_ndmp_window_length, {
4002                 "Window Length", "ndmp.window.length", FT_UINT64, BASE_DEC,
4003                 NULL, 0, "Size of window in bytes", HFILL }},
4004
4005         { &hf_ndmp_addr_ip, {
4006                 "IP Address", "ndmp.addr.ip", FT_IPv4, BASE_NONE,
4007                 NULL, 0, NULL, HFILL }},
4008
4009         { &hf_ndmp_addr_tcp, {
4010                 "TCP Port", "ndmp.addr.tcp_port", FT_UINT32, BASE_DEC,
4011                 NULL, 0, NULL, HFILL }},
4012
4013         { &hf_ndmp_addr_fcal_loop_id, {
4014                 "Loop ID", "ndmp.addr.loop_id", FT_UINT32, BASE_HEX,
4015                 NULL, 0, "FCAL Loop ID", HFILL }},
4016
4017         { &hf_ndmp_addr_ipc, {
4018                 "IPC", "ndmp.addr.ipc", FT_BYTES, BASE_NONE,
4019                 NULL, 0, "IPC identifier", HFILL }},
4020
4021         { &hf_ndmp_mover_mode, {
4022                 "Mode", "ndmp.mover.mode", FT_UINT32, BASE_HEX,
4023                 VALS(mover_mode_vals), 0, "Mover Mode", HFILL }},
4024
4025         { &hf_ndmp_file_name, {
4026                 "File", "ndmp.file", FT_STRING, BASE_NONE,
4027                 NULL, 0, "Name of File", HFILL }},
4028
4029         { &hf_ndmp_nt_file_name, {
4030                 "NT File", "ndmp.file", FT_STRING, BASE_NONE,
4031                 NULL, 0, "NT Name of File", HFILL }},
4032
4033         { &hf_ndmp_dos_file_name, {
4034                 "DOS File", "ndmp.file", FT_STRING, BASE_NONE,
4035                 NULL, 0, "DOS Name of File", HFILL }},
4036
4037         { &hf_ndmp_log_type, {
4038                 "Type", "ndmp.log.type", FT_UINT32, BASE_HEX,
4039                 VALS(log_type_vals), 0, "Type of log entry", HFILL }},
4040
4041         { &hf_ndmp_log_message_id, {
4042                 "Message ID", "ndmp.log.message.id", FT_UINT32, BASE_DEC,
4043                 NULL, 0, "ID of this log entry", HFILL }},
4044
4045         { &hf_ndmp_log_message, {
4046                 "Message", "ndmp.log.message", FT_STRING, BASE_NONE,
4047                 NULL, 0, "Log entry", HFILL }},
4048
4049         { &hf_ndmp_halt_reason, {
4050                 "Reason", "ndmp.halt.reason", FT_STRING, BASE_NONE,
4051                 NULL, 0, "Textual reason for why it halted", HFILL }},
4052
4053         { &hf_ndmp_connected, {
4054                 "Connected", "ndmp.connected", FT_UINT32, BASE_DEC,
4055                 VALS(connected_vals), 0, "Status of connection", HFILL }},
4056
4057         { &hf_ndmp_connected_reason, {
4058                 "Reason", "ndmp.connected.reason", FT_STRING, BASE_NONE,
4059                 NULL, 0, "Textual description of the connection status", HFILL }},
4060
4061         { &hf_ndmp_auth_id, {
4062                 "ID", "ndmp.auth.id", FT_STRING, BASE_NONE,
4063                 NULL, 0, "ID of client authenticating", HFILL }},
4064
4065         { &hf_ndmp_auth_password, {
4066                 "Password", "ndmp.auth.password", FT_STRING, BASE_NONE,
4067                 NULL, 0, "Password of client authenticating", HFILL }},
4068
4069         { &hf_ndmp_data, {
4070                 "Data", "ndmp.data", FT_BYTES, BASE_NONE,
4071                 NULL, 0, "Data written/read", HFILL }},
4072
4073         { &hf_ndmp_files, {
4074                 "Files", "ndmp.files", FT_NONE, BASE_NONE,
4075                 NULL, 0, "List of files", HFILL }},
4076
4077         { &hf_ndmp_file_names, {
4078                 "File Names", "ndmp.file.names", FT_NONE, BASE_NONE,
4079                 NULL, 0, "List of file names", HFILL }},
4080
4081         { &hf_ndmp_file_fs_type, {
4082                 "File FS Type", "ndmp.file.fs_type", FT_UINT32, BASE_DEC,
4083                 VALS(file_fs_type_vals), 0, "Type of file permissions (UNIX or NT)", HFILL }},
4084
4085         { &hf_ndmp_file_type, {
4086                 "File Type", "ndmp.file.type", FT_UINT32, BASE_DEC,
4087                 VALS(file_type_vals), 0, "Type of file", HFILL }},
4088
4089         { &hf_ndmp_file_stats, {
4090                 "File Stats", "ndmp.file.stats", FT_NONE, BASE_NONE,
4091                 NULL, 0, "List of file stats", HFILL }},
4092
4093         { &hf_ndmp_file_node, {
4094                 "Node", "ndmp.file.node", FT_UINT64, BASE_DEC,
4095                 NULL, 0, "Node used for direct access", HFILL }},
4096
4097         { &hf_ndmp_file_parent, {
4098                 "Parent", "ndmp.file.parent", FT_UINT64, BASE_DEC,
4099                 NULL, 0, "Parent node(directory) for this node", HFILL }},
4100
4101         { &hf_ndmp_file_fh_info, {
4102                 "FH Info", "ndmp.file.fh_info", FT_UINT64, BASE_DEC,
4103                 NULL, 0, "FH Info used for direct access", HFILL }},
4104
4105         { &hf_ndmp_file_invalid_atime, {
4106                 "Invalid atime", "ndmp.file.invalid_atime", FT_BOOLEAN, 32,
4107                 TFS(&tfs_ndmp_file_invalid_atime), 0x00000001, "invalid_atime", HFILL, }},
4108
4109         { &hf_ndmp_file_invalid_ctime, {
4110                 "Invalid ctime", "ndmp.file.invalid_ctime", FT_BOOLEAN, 32,
4111                 TFS(&tfs_ndmp_file_invalid_ctime), 0x00000002, "invalid_ctime", HFILL, }},
4112
4113         { &hf_ndmp_file_invalid_group, {
4114                 "Invalid group", "ndmp.file.invalid_group", FT_BOOLEAN, 32,
4115                 TFS(&tfs_ndmp_file_invalid_group), 0x00000004, "invalid_group", HFILL, }},
4116
4117         { &hf_ndmp_file_mtime, {
4118                 "mtime", "ndmp.file.mtime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
4119                 NULL, 0, "Timestamp for mtime for this file", HFILL }},
4120
4121         { &hf_ndmp_file_atime, {
4122                 "atime", "ndmp.file.atime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
4123                 NULL, 0, "Timestamp for atime for this file", HFILL }},
4124
4125         { &hf_ndmp_file_ctime, {
4126                 "ctime", "ndmp.file.ctime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
4127                 NULL, 0, "Timestamp for ctime for this file", HFILL }},
4128
4129         { &hf_ndmp_file_owner, {
4130                 "Owner", "ndmp.file.owner", FT_UINT32, BASE_DEC,
4131                 NULL, 0, "UID for UNIX, owner for NT", HFILL }},
4132
4133         { &hf_ndmp_file_group, {
4134                 "Group", "ndmp.file.group", FT_UINT32, BASE_DEC,
4135                 NULL, 0, "GID for UNIX, NA for NT", HFILL }},
4136
4137         { &hf_ndmp_file_fattr, {
4138                 "Fattr", "ndmp.file.fattr", FT_UINT32, BASE_HEX,
4139                 NULL, 0, "Mode for UNIX, fattr for NT", HFILL }},
4140
4141         { &hf_ndmp_file_size, {
4142                 "Size", "ndmp.file.size", FT_UINT64, BASE_DEC,
4143                 NULL, 0, "File Size", HFILL }},
4144
4145         { &hf_ndmp_file_links, {
4146                 "Links", "ndmp.file.links", FT_UINT32, BASE_DEC,
4147                 NULL, 0, "Number of links to this file", HFILL }},
4148
4149         { &hf_ndmp_dirs, {
4150                 "Dirs", "ndmp.dirs", FT_NONE, BASE_NONE,
4151                 NULL, 0, "List of directories", HFILL }},
4152
4153         { &hf_ndmp_nodes, {
4154                 "Nodes", "ndmp.nodes", FT_NONE, BASE_NONE,
4155                 NULL, 0, "List of nodes", HFILL }},
4156
4157         { &hf_ndmp_nlist, {
4158                 "Nlist", "ndmp.nlist", FT_NONE, BASE_NONE,
4159                 NULL, 0, "List of names", HFILL }},
4160
4161         { &hf_ndmp_bu_original_path, {
4162                 "Original Path", "ndmp.bu.original_path", FT_STRING, BASE_NONE,
4163                 NULL, 0, "Original path where backup was created", HFILL }},
4164
4165         { &hf_ndmp_bu_destination_dir, {
4166                 "Destination Dir", "ndmp.bu.destination_dir", FT_STRING, BASE_NONE,
4167                 NULL, 0, "Destination directory to restore backup to", HFILL }},
4168
4169         { &hf_ndmp_bu_new_name, {
4170                 "New Name", "ndmp.bu.new_name", FT_STRING, BASE_NONE,
4171                 NULL, 0, NULL, HFILL }},
4172
4173         { &hf_ndmp_bu_other_name, {
4174                 "Other Name", "ndmp.bu.other_name", FT_STRING, BASE_NONE,
4175                 NULL, 0, NULL, HFILL }},
4176
4177         { &hf_ndmp_state_invalid_ebr, {
4178                 "EstimatedBytesLeft valid", "ndmp.bu.state.invalid_ebr", FT_BOOLEAN, 32,
4179                 TFS(&tfs_ndmp_state_invalid_ebr), 0x00000001, "Whether EstimatedBytesLeft is valid or not", HFILL, }},
4180
4181         { &hf_ndmp_state_invalid_etr, {
4182                 "EstimatedTimeLeft valid", "ndmp.bu.state.invalid_etr", FT_BOOLEAN, 32,
4183                 TFS(&tfs_ndmp_state_invalid_etr), 0x00000002, "Whether EstimatedTimeLeft is valid or not", HFILL, }},
4184
4185         { &hf_ndmp_bu_operation, {
4186                 "Operation", "ndmp.bu.operation", FT_UINT32, BASE_DEC,
4187                 VALS(bu_operation_vals), 0, "BU Operation", HFILL, }},
4188
4189         { &hf_ndmp_data_state, {
4190                 "State", "ndmp.data.state", FT_UINT32, BASE_DEC,
4191                 VALS(data_state_vals), 0, "Data state", HFILL, }},
4192
4193         { &hf_ndmp_data_halted, {
4194                 "Halted Reason", "ndmp.data.halted", FT_UINT32, BASE_DEC,
4195                 VALS(data_halted_vals), 0, "Data halted reason", HFILL, }},
4196
4197         { &hf_ndmp_data_bytes_processed, {
4198                 "Bytes Processed", "ndmp.data.bytes_processed", FT_UINT64, BASE_DEC,
4199                 NULL, 0, "Number of bytes processed", HFILL }},
4200
4201         { &hf_ndmp_data_est_bytes_remain, {
4202                 "Est Bytes Remain", "ndmp.data.est_bytes_remain", FT_UINT64, BASE_DEC,
4203                 NULL, 0, "Estimated number of bytes remaining", HFILL }},
4204
4205         { &hf_ndmp_data_est_time_remain, {
4206                 "Est Time Remain", "ndmp.data.est_time_remain", FT_RELATIVE_TIME, BASE_NONE,
4207                 NULL, 0, "Estimated time remaining", HFILL }},
4208         { &hf_ndmp_lastfrag, {
4209                 "Last Fragment", "ndmp.lastfrag", FT_BOOLEAN, 32,
4210                 TFS(&tfs_yes_no), RPC_RM_LASTFRAG, NULL, HFILL }},
4211         { &hf_ndmp_fraglen, {
4212                 "Fragment Length", "ndmp.fraglen", FT_UINT32, BASE_DEC,
4213                 NULL, RPC_RM_FRAGLEN, NULL, HFILL }},
4214         { &hf_ndmp_class_list, {
4215                 "Ext Class List", "ndmp.class_list", FT_NONE, BASE_NONE,
4216                 NULL, 0, "List of extension classes", HFILL }},
4217         { &hf_ndmp_ex_class_id, {
4218                 "Class ID", "ndmp.class.id", FT_UINT32, BASE_HEX,
4219                 NULL, 0, NULL, HFILL }},
4220         { &hf_ndmp_ext_version_list, {
4221                 "Ext Version List", "ndmp.ext_version_list", FT_NONE, BASE_NONE,
4222                 NULL, 0, "List of extension versions", HFILL }},
4223         { &hf_ndmp_ext_version, {
4224                 "Ext Version", "ndmp.ext_version_list.version", FT_UINT32, BASE_HEX,
4225                 NULL, 0, "Extension version", HFILL }},
4226         { &hf_ndmp_class_version, {
4227                 "Class and version", "ndmp.ext_version", FT_NONE, BASE_NONE,
4228                 NULL, 0, NULL, HFILL }},
4229         { &hf_ndmp_ex_class_version, {
4230                 "Class Version", "ndmp.class.version", FT_UINT32, BASE_HEX,
4231                 NULL, 0, NULL, HFILL }},
4232         {&hf_ndmp_fragments, {
4233                 "NDMP fragments", "ndmp.fragments", FT_NONE, BASE_NONE,
4234                 NULL, 0x00, NULL, HFILL } },
4235         {&hf_ndmp_fragment,
4236                 {"NDMP fragment", "ndmp.fragment",
4237                 FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
4238         {&hf_ndmp_fragment_overlap,
4239                 {"NDMP fragment overlap", "ndmp.fragment.overlap",
4240                 FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
4241         {&hf_ndmp_fragment_overlap_conflicts,
4242                 {"NDMP fragment overlapping with conflicting data",
4243                 "ndmp.fragment.overlap.conflicts",
4244                 FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
4245         {&hf_ndmp_fragment_multiple_tails,
4246                 {"NDMP has multiple tail fragments",
4247                 "ndmp.fragment.multiple_tails",
4248                 FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
4249         {&hf_ndmp_fragment_too_long_fragment,
4250                 {"NDMP fragment too long", "ndmp.fragment.too_long_fragment",
4251                 FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
4252         {&hf_ndmp_fragment_error,
4253                 {"NDMP defragmentation error", "ndmp.fragment.error",
4254                 FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
4255         {&hf_ndmp_fragment_count,
4256                 {"NDMP fragment count", "ndmp.fragment.count",
4257                 FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
4258         {&hf_ndmp_reassembled_in,
4259                 {"Reassembled in", "ndmp.reassembled.in",
4260                 FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
4261         {&hf_ndmp_reassembled_length,
4262                 {"Reassembled NDMP length", "ndmp.reassembled.length",
4263                 FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
4264   };
4265
4266   static gint *ett[] = {
4267           &ett_ndmp,
4268           &ett_ndmp_fraghdr,
4269           &ett_ndmp_header,
4270           &ett_ndmp_butype_attrs,
4271           &ett_ndmp_fs_invalid,
4272           &ett_ndmp_tape_attr,
4273           &ett_ndmp_execute_cdb_flags,
4274           &ett_ndmp_execute_cdb_cdb,
4275           &ett_ndmp_execute_cdb_sns,
4276           &ett_ndmp_execute_cdb_payload,
4277           &ett_ndmp_tape_invalid,
4278           &ett_ndmp_tape_flags,
4279           &ett_ndmp_addr,
4280           &ett_ndmp_file,
4281           &ett_ndmp_file_name,
4282           &ett_ndmp_file_stats,
4283           &ett_ndmp_file_invalids,
4284           &ett_ndmp_state_invalids,
4285           &ett_ndmp_fragment,
4286           &ett_ndmp_fragments,
4287   };
4288
4289   module_t *ndmp_module;
4290
4291   proto_ndmp = proto_register_protocol("Network Data Management Protocol", "NDMP", "ndmp");
4292   proto_register_field_array(proto_ndmp, hf_ndmp, array_length(hf_ndmp));
4293
4294   proto_register_subtree_array(ett, array_length(ett));
4295
4296   /* desegmentation */
4297   ndmp_module = prefs_register_protocol(proto_ndmp, NULL);
4298   prefs_register_obsolete_preference(ndmp_module, "protocol_version");
4299   prefs_register_enum_preference(ndmp_module,
4300         "default_protocol_version",
4301         "Default protocol version",
4302         "Version of the NDMP protocol to assume if the version can not be automatically detected from the capture",
4303         &ndmp_default_protocol_version,
4304         ndmp_protocol_versions,
4305         FALSE);
4306   prefs_register_bool_preference(ndmp_module, "desegment",
4307     "Reassemble NDMP messages spanning multiple TCP segments",
4308     "Whether the NDMP dissector should reassemble messages spanning multiple TCP segments."
4309     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
4310         &ndmp_desegment);
4311   prefs_register_bool_preference(ndmp_module, "defragment",
4312         "Reassemble fragmented NDMP messages spanning multiple packets",
4313         "Whether the dissector should defragment NDMP messages spanning multiple packets.",
4314         &ndmp_defragment);
4315   register_init_routine(ndmp_init);
4316 }
4317
4318 void
4319 proto_reg_handoff_ndmp(void)
4320 {
4321         ndmp_handle = new_create_dissector_handle(dissect_ndmp, proto_ndmp);
4322         dissector_add_uint("tcp.port",TCP_PORT_NDMP, ndmp_handle);
4323         heur_dissector_add("tcp", dissect_ndmp_heur, proto_ndmp);
4324 }
4325
4326 /*
4327  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
4328  *
4329  * Local variables:
4330  * c-basic-offset: 8
4331  * tab-width: 8
4332  * indent-tabs-mode: t
4333  * End:
4334  *
4335  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
4336  * :indentSize=8:tabSize=8:noTabs=false:
4337  */