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