aboutsummaryrefslogtreecommitdiffstats
path: root/packet-ndmp.c
blob: ecee3927d5825ebd3880c956e9051178ecc789fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
/* packet-ndmp.c
 * Routines for NDMP
 * Ronnie Sahlberg (see AUTHORS for email)
 *
 * $Id: packet-ndmp.c,v 1.1 2001/12/23 21:36:57 guy Exp $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@ethereal.com>
 * Copyright 1998 Gerald Combs
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

/* see www.ndmp.org for protocol specifications.
   this file implements version 3 of ndmp 
*/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <stdio.h>
#include <string.h>
#include <glib.h>

#include "packet.h"
#include "prefs.h"

#define TCP_PORT_NDMP 10000

static int proto_ndmp = -1;
static int hf_ndmp_version = -1;
static int hf_ndmp_size = -1;
static int hf_ndmp_header = -1;
static int hf_ndmp_sequence = -1;
static int hf_ndmp_reply_sequence = -1;
static int hf_ndmp_timestamp = -1;
static int hf_ndmp_msgtype = -1;
static int hf_ndmp_msg = -1;
static int hf_ndmp_error = -1;

static gint ett_ndmp = -1;
static gint ett_ndmp_header = -1;

/* desegmentation of NDMP packets */
static gboolean ndmp_desegment = FALSE;


#define NDMP_MESSAGE_REQUEST	0x00
#define NDMP_MESSAGE_REPLY	0x01
static const value_string msg_type_vals[] = {
	{NDMP_MESSAGE_REQUEST,		"Request"},
	{NDMP_MESSAGE_REPLY,		"Reply"},
	{0, NULL}
};

#define NDMP_NO_ERR			0x00
#define NDMP_NOT_SUPPORTED_ERR		0x01
#define NDMP_DEVICE_BUSY_ERR		0x02
#define NDMP_DEVICE_OPENED_ERR		0x03
#define NDMP_NOT_AUTHORIZED_ERR		0x04
#define NDMP_PERMISSION_ERR		0x05
#define NDMP_DEV_NOT_OPEN_ERR		0x06
#define NDMP_IO_ERR			0x07
#define NDMP_TIMEOUT_ERR		0x08
#define NDMP_ILLEGAL_ARGS_ERR		0x09
#define NDMP_NO_TAPE_LOADED_ERR		0x0a
#define NDMP_WRITE_PROTECT_ERR		0x0b
#define NDMP_EOF_ERR			0x0c
#define NDMP_EOM_ERR			0x0d
#define NDMP_FILE_NOT_FOUND_ERR		0x0e
#define NDMP_BAD_FILE_ERR		0x0f
#define NDMP_NO_DEVICE_ERR		0x10
#define NDMP_NO_BUS_ERR			0x11
#define NDMP_XDR_DECODE_ERR		0x12
#define NDMP_ILLEGAL_STATE_ERR		0x13
#define NDMP_UNDEFINED_ERR		0x14
#define NDMP_XDR_ENCODE_ERR		0x15
#define NDMP_NO_MEM_ERR			0x16
#define NDMP_CONNECT_ERR		0x17

static const value_string error_vals[] = {
	{NDMP_NO_ERR,			"NO_ERR"},
	{NDMP_NOT_SUPPORTED_ERR,	"NOT_SUPPORTED_ERR"},
	{NDMP_DEVICE_BUSY_ERR,		"DEVICE_BUSY_ERR"},
	{NDMP_DEVICE_OPENED_ERR,	"DEVICE_OPENED_ERR"},
	{NDMP_NOT_AUTHORIZED_ERR,	"NOT_AUTHORIZED_ERR"},
	{NDMP_PERMISSION_ERR,		"PERMISSION_ERR"},
	{NDMP_DEV_NOT_OPEN_ERR,		"DEV_NOT_OPEN_ERR"},
	{NDMP_IO_ERR,			"IO_ERR"},
	{NDMP_TIMEOUT_ERR,		"TIMEOUT_ERR"},
	{NDMP_ILLEGAL_ARGS_ERR,		"ILLEGAL_ARGS_ERR"},
	{NDMP_NO_TAPE_LOADED_ERR,	"NO_TAPE_LOADED_ERR"},
	{NDMP_WRITE_PROTECT_ERR,	"WRITE_PROTECT_ERR"},
	{NDMP_EOF_ERR,			"EOF_ERR"},
	{NDMP_EOM_ERR,			"EOM_ERR"},
	{NDMP_FILE_NOT_FOUND_ERR,	"FILE_NOT_FOUND_ERR"},
	{NDMP_BAD_FILE_ERR,		"BAD_FILE_ERR"},
	{NDMP_NO_DEVICE_ERR,		"NO_DEVICE_ERR"},
	{NDMP_NO_BUS_ERR,		"NO_BUS_ERR"},
	{NDMP_XDR_DECODE_ERR,		"XDR_DECODE_ERR"},
	{NDMP_ILLEGAL_STATE_ERR,	"ILLEGAL_STATE_ERR"},
	{NDMP_UNDEFINED_ERR,		"UNDEFINED_ERR"},
	{NDMP_XDR_ENCODE_ERR,		"XDR_ENCODE_ERR"},
	{NDMP_NO_MEM_ERR,		"NO_MEM_ERR"},
	{NDMP_CONNECT_ERR,		"CONNECT_ERR"},
	{0, NULL}
};



#define NDMP_CONFIG_GET_HOST_INFO 	0x100
#define NDMP_CONFIG_GET_CONNECTION_TYPE 0x102
#define NDMP_CONFIG_GET_AUTH_ATTR 	0x103
#define NDMP_CONFIG_GET_BUTYPE_INFO 	0x104
#define NDMP_CONFIG_GET_FS_INFO 	0x105
#define NDMP_CONFIG_GET_TAPE_INFO 	0x106
#define NDMP_CONFIG_GET_SCSI_INFO 	0x107
#define NDMP_CONFIG_GET_SERVER_INFO 	0x108
#define NDMP_SCSI_OPEN 			0x200
#define NDMP_SCSI_CLOSE 		0x201
#define NDMP_SCSI_GET_STATE 		0x202
#define NDMP_SCSI_SET_TARGET 		0x203
#define NDMP_SCSI_RESET_DEVICE 		0x204
#define NDMP_SCSI_RESET_BUS 		0x205
#define NDMP_SCSI_EXECUTE_CDB 		0x206
#define NDMP_TAPE_OPEN 			0x300
#define NDMP_TAPE_CLOSE 		0x301
#define NDMP_TAPE_GET_STATE 		0x302
#define NDMP_TAPE_MTIO 			0x303
#define NDMP_TAPE_WRITE 		0x304
#define NDMP_TAPE_READ 			0x305
#define NDMP_TAPE_EXECUTE_CDB 		0x307
#define NDMP_DATA_GET_STATE 		0x400
#define NDMP_DATA_START_BACKUP 		0x401
#define NDMP_DATA_START_RECOVER 	0x402
#define NDMP_DATA_ABORT 		0x403
#define NDMP_DATA_GET_ENV 		0x404
#define NDMP_DATA_STOP 			0x407
#define NDMP_DATA_LISTEN 		0x409
#define NDMP_DATA_CONNECT 		0x40a
#define NDMP_NOTIFY_DATA_HALTED 	0x501
#define NDMP_NOTIFY_CONNECTED 		0x502
#define NDMP_NOTIFY_MOVER_HALTED 	0x503
#define NDMP_NOTIFY_MOVER_PAUSED 	0x504
#define NDMP_NOTIFY_DATA_READ 		0x505
#define NDMP_LOG_FILE 			0x602
#define NDMP_LOG_MESSAGE 		0x603
#define NDMP_FH_ADD_FILE 		0x703
#define NDMP_FH_ADD_DIR 		0x704
#define NDMP_FH_ADD_NODE 		0x705
#define NDMP_CONNECT_OPEN 		0x900
#define NDMP_CONNECT_CLIENT_AUTH	0x901
#define NDMP_CONNECT_CLOSE 		0x902
#define NDMP_CONNECT_SERVER_AUTH 	0x903
#define NDMP_MOVER_GET_STATE 		0xa00
#define NDMP_MOVER_LISTEN 		0xa01
#define NDMP_MOVER_CONTINUE 		0xa02
#define NDMP_MOVER_ABORT 		0xa03
#define NDMP_MOVER_STOP 		0xa04
#define NDMP_MOVER_SET_WINDOW 		0xa05
#define NDMP_MOVER_READ 		0xa06
#define NDMP_MOVER_CLOSE 		0xa07
#define NDMP_MOVER_SET_RECORD_SIZE 	0xa08
#define NDMP_MOVER_CONNECT 		0xa09




static const value_string msg_vals[] = {
	{NDMP_CONFIG_GET_HOST_INFO, 	"CONFIG_GET_HOST_INFO"},
	{NDMP_CONFIG_GET_CONNECTION_TYPE, "CONFIG_GET_CONNECTION_TYPE"},
	{NDMP_CONFIG_GET_AUTH_ATTR, 	"CONFIG_GET_AUTH_ATTR"},
	{NDMP_CONFIG_GET_BUTYPE_INFO, 	"CONFIG_GET_BUTYPE_INFO"},
	{NDMP_CONFIG_GET_FS_INFO, 	"CONFIG_GET_FS_INFO"},
	{NDMP_CONFIG_GET_TAPE_INFO, 	"CONFIG_GET_TAPE_INFO"},
	{NDMP_CONFIG_GET_SCSI_INFO, 	"CONFIG_GET_SCSI_INFO"},
	{NDMP_CONFIG_GET_SERVER_INFO, 	"CONFIG_GET_SERVER_INFO"},
	{NDMP_SCSI_OPEN, 		"SCSI_OPEN"},
	{NDMP_SCSI_CLOSE, 		"SCSI_CLOSE"},
	{NDMP_SCSI_GET_STATE, 		"SCSI_GET_STATE"},
	{NDMP_SCSI_SET_TARGET, 		"SCSI_SET_TARGET"},
	{NDMP_SCSI_RESET_DEVICE, 	"SCSI_RESET_DEVICE"},
	{NDMP_SCSI_RESET_BUS, 		"SCSI_RESET_BUS"},
	{NDMP_SCSI_EXECUTE_CDB, 	"SCSI_EXECUTE_CDB"},
	{NDMP_TAPE_OPEN, 		"TAPE_OPEN"},
	{NDMP_TAPE_CLOSE, 		"TAPE_CLOSE"},
	{NDMP_TAPE_GET_STATE, 		"TAPE_GET_STATE"},
	{NDMP_TAPE_MTIO, 		"TAPE_MTIO"},
	{NDMP_TAPE_WRITE, 		"TAPE_WRITE"},
	{NDMP_TAPE_READ, 		"TAPE_READ"},
	{NDMP_TAPE_EXECUTE_CDB, 	"TAPE_EXECUTE_CDB"},
	{NDMP_DATA_GET_STATE, 		"DATA_GET_STATE"},
	{NDMP_DATA_START_BACKUP, 	"DATA_START_BACKUP"},
	{NDMP_DATA_START_RECOVER, 	"DATA_START_RECOVER"},
	{NDMP_DATA_ABORT, 		"DATA_ABORT"},
	{NDMP_DATA_GET_ENV, 		"DATA_GET_ENV"},
	{NDMP_DATA_STOP, 		"DATA_STOP"},
	{NDMP_DATA_LISTEN, 		"DATA_LISTEN"},
	{NDMP_DATA_CONNECT, 		"DATA_CONNECT"},
	{NDMP_NOTIFY_DATA_HALTED, 	"NOTIFY_DATA_HALTED"},
	{NDMP_NOTIFY_CONNECTED, 	"NOTIFY_CONNECTED"},
	{NDMP_NOTIFY_MOVER_HALTED, 	"NOTIFY_MOVER_HALTED"},
	{NDMP_NOTIFY_MOVER_PAUSED, 	"NOTIFY_MOVER_PAUSED"},
	{NDMP_NOTIFY_DATA_READ, 	"NOTIFY_DATA_READ"},
	{NDMP_LOG_FILE, 		"LOG_FILE"},
	{NDMP_LOG_MESSAGE, 		"LOG_MESSAGE"},
	{NDMP_FH_ADD_FILE, 		"FH_ADD_FILE"},
	{NDMP_FH_ADD_DIR, 		"FH_ADD_DIR"},
	{NDMP_FH_ADD_NODE, 		"FH_ADD_NODE"},
	{NDMP_CONNECT_OPEN, 		"CONNECT_OPEN"},
	{NDMP_CONNECT_CLIENT_AUTH, 	"CONNECT_CLIENT_AUTH"},
	{NDMP_CONNECT_CLOSE, 		"CONNECT_CLOSE"},
	{NDMP_CONNECT_SERVER_AUTH, 	"CONNECT_SERVER_AUTH"},
	{NDMP_MOVER_GET_STATE, 		"MOVER_GET_STATE"},
	{NDMP_MOVER_LISTEN, 		"MOVER_LISTEN"},
	{NDMP_MOVER_CONTINUE, 		"MOVER_CONTINUE"},
	{NDMP_MOVER_ABORT, 		"MOVER_ABORT"},
	{NDMP_MOVER_STOP, 		"MOVER_STOP"},
	{NDMP_MOVER_SET_WINDOW, 	"MOVER_SET_WINDOW"},
	{NDMP_MOVER_READ, 		"MOVER_READ"},
	{NDMP_MOVER_CLOSE, 		"MOVER_CLOSE"},
	{NDMP_MOVER_SET_RECORD_SIZE, 	"MOVER_SET_RECORD_SIZE"},
	{NDMP_MOVER_CONNECT, 		"MOVER_CONNECT"},
	{0, NULL}
};


static int
dissect_connect_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
{
	/* version number */
	proto_tree_add_item(tree, hf_ndmp_version, tvb, offset, 4, FALSE);
	offset += 4;

	return offset;
}

static int
dissect_error(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
{
	/* error */
	proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
	offset += 4;

	return offset;
}


typedef struct _ndmp_command {
	guint32 cmd;
	int (*request) (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
	int (*response)(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
} ndmp_command;

static const ndmp_command ndmp_commands[] = {
	{NDMP_CONFIG_GET_HOST_INFO, 	NULL,NULL},
	{NDMP_CONFIG_GET_CONNECTION_TYPE, NULL,NULL},
	{NDMP_CONFIG_GET_AUTH_ATTR, 	NULL,NULL},
	{NDMP_CONFIG_GET_BUTYPE_INFO, 	NULL,NULL},
	{NDMP_CONFIG_GET_FS_INFO, 	NULL,NULL},
	{NDMP_CONFIG_GET_TAPE_INFO, 	NULL,NULL},
	{NDMP_CONFIG_GET_SCSI_INFO, 	NULL,NULL},
	{NDMP_CONFIG_GET_SERVER_INFO, 	NULL,NULL},
	{NDMP_SCSI_OPEN, 		NULL,NULL},
	{NDMP_SCSI_CLOSE, 		NULL,NULL},
	{NDMP_SCSI_GET_STATE, 		NULL,NULL},
	{NDMP_SCSI_SET_TARGET, 		NULL,NULL},
	{NDMP_SCSI_RESET_DEVICE, 	NULL,NULL},
	{NDMP_SCSI_RESET_BUS, 		NULL,NULL},
	{NDMP_SCSI_EXECUTE_CDB, 	NULL,NULL},
	{NDMP_TAPE_OPEN, 		NULL,NULL},
	{NDMP_TAPE_CLOSE, 		NULL,NULL},
	{NDMP_TAPE_GET_STATE, 		NULL,NULL},
	{NDMP_TAPE_MTIO, 		NULL,NULL},
	{NDMP_TAPE_WRITE, 		NULL,NULL},
	{NDMP_TAPE_READ, 		NULL,NULL},
	{NDMP_TAPE_EXECUTE_CDB, 	NULL,NULL},
	{NDMP_DATA_GET_STATE, 		NULL,NULL},
	{NDMP_DATA_START_BACKUP, 	NULL,NULL},
	{NDMP_DATA_START_RECOVER, 	NULL,NULL},
	{NDMP_DATA_ABORT, 		NULL,NULL},
	{NDMP_DATA_GET_ENV, 		NULL,NULL},
	{NDMP_DATA_STOP, 		NULL,NULL},
	{NDMP_DATA_LISTEN, 		NULL,NULL},
	{NDMP_DATA_CONNECT, 		NULL,NULL},
	{NDMP_NOTIFY_DATA_HALTED, 	NULL,NULL},
	{NDMP_NOTIFY_CONNECTED, 	NULL,NULL},
	{NDMP_NOTIFY_MOVER_HALTED, 	NULL,NULL},
	{NDMP_NOTIFY_MOVER_PAUSED, 	NULL,NULL},
	{NDMP_NOTIFY_DATA_READ, 	NULL,NULL},
	{NDMP_LOG_FILE, 		NULL,NULL},
	{NDMP_LOG_MESSAGE, 		NULL,NULL},
	{NDMP_FH_ADD_FILE, 		NULL,NULL},
	{NDMP_FH_ADD_DIR, 		NULL,NULL},
	{NDMP_FH_ADD_NODE, 		NULL,NULL},
	{NDMP_CONNECT_OPEN, 		dissect_connect_open_request, dissect_error},
	{NDMP_CONNECT_CLIENT_AUTH, 	NULL,NULL},
	{NDMP_CONNECT_CLOSE, 		NULL,NULL},
	{NDMP_CONNECT_SERVER_AUTH, 	NULL,NULL},
	{NDMP_MOVER_GET_STATE, 		NULL,NULL},
	{NDMP_MOVER_LISTEN, 		NULL,NULL},
	{NDMP_MOVER_CONTINUE, 		NULL,NULL},
	{NDMP_MOVER_ABORT, 		NULL,NULL},
	{NDMP_MOVER_STOP, 		NULL,NULL},
	{NDMP_MOVER_SET_WINDOW, 	NULL,NULL},
	{NDMP_MOVER_READ, 		NULL,NULL},
	{NDMP_MOVER_CLOSE, 		NULL,NULL},
	{NDMP_MOVER_SET_RECORD_SIZE, 	NULL,NULL},
	{NDMP_MOVER_CONNECT, 		NULL,NULL},
	{0, NULL,NULL}
};


static int
dissect_ndmp_header(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree)
{
	proto_item* item = NULL;
	proto_tree* tree = NULL;
	guint32 msgtype, msg;

	if (parent_tree) {
		item = proto_tree_add_item(tree, hf_ndmp_header, tvb,
				offset, 24, FALSE);
		tree = proto_item_add_subtree(item, ett_ndmp_header);
	}

	/* sequence number */
	proto_tree_add_item(tree, hf_ndmp_sequence, tvb, offset, 4, FALSE);
	offset += 4;

	/* timestamp */
	proto_tree_add_item(tree, hf_ndmp_timestamp, tvb, offset, 4, FALSE);
	offset += 4;

	/* Message Type */
	msgtype = tvb_get_ntohl(tvb, offset);
	proto_tree_add_item(tree, hf_ndmp_msgtype, tvb, offset, 4, FALSE);
	offset += 4;

	/* Message */
	msg = tvb_get_ntohl(tvb, offset);
	proto_tree_add_item(tree, hf_ndmp_msg, tvb, offset, 4, FALSE);
	offset += 4;

	/* Reply sequence number */
	proto_tree_add_item(tree, hf_ndmp_reply_sequence, tvb, offset, 4, FALSE);
	offset += 4;

	/* error */
	proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
	offset += 4;

	if (check_col(pinfo->cinfo, COL_INFO)){
		col_clear(pinfo->cinfo, COL_INFO);
		col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s",
			val_to_str(msg, msg_vals, "Unknown Message (0x%02x)"),
			val_to_str(msgtype, msg_type_vals, "Unknown Type (0x%02x)")
			);
	}

	return offset;
}


static int
dissect_ndmp_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
{
	int i;
	guint32 msg, msgtype;

	msg=tvb_get_ntohl(tvb, offset+12);
	msgtype=tvb_get_ntohl(tvb, offset+8);

	offset=dissect_ndmp_header(tvb, offset, pinfo, tree);


	for(i=0;ndmp_commands[i].cmd!=0;i++){
		if(ndmp_commands[i].cmd==msg){
			break;
		}
	}


	if(ndmp_commands[i].cmd==0){
		/* we do not know this message */
		proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset), "Unknown type of NDMP message: 0x%02x", msg);
		offset+=tvb_length_remaining(tvb, offset);
		return offset;
	}


	if(msgtype==NDMP_MESSAGE_REQUEST){
		offset=ndmp_commands[i].request(tvb, offset, pinfo, tree);
	} else {
		offset=ndmp_commands[i].response(tvb, offset, pinfo, tree);
	}

	return offset;
}

static void
dissect_ndmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	int offset = 0;
	guint32 size, available_bytes;

	/* loop through the packet, dissecting multiple NDMP pdus*/
	do {
		available_bytes = tvb_length_remaining(tvb, offset);

		/* size of this NDMP PDU */
		size = tvb_get_ntohl(tvb, offset);	

		/* desegmentation */
		if(ndmp_desegment){
			if(pinfo->can_desegment
			&& size>available_bytes) {
				pinfo->desegment_offset = offset;
				pinfo->desegment_len = size-available_bytes;
				return;
			}
		}

		/* the size of the current PDU */
		proto_tree_add_item(tree, hf_ndmp_size, tvb, offset, 4, size);
		offset += 4;

		offset = dissect_ndmp_cmd(tvb, offset, pinfo, tree);
	} while(offset<(int)tvb_reported_length(tvb));

}




void
proto_register_ndmp(void)
{

  static hf_register_info hf_ndmp[] = {
	{ &hf_ndmp_size, {
		"Size", "ndmp.size", FT_UINT32, BASE_DEC,
		NULL, 0, "Size of this NDMP PDU", HFILL }},

	{ &hf_ndmp_header, {
		"NDMP Header", "ndmp.header", FT_NONE, 0,
		NULL, 0, "NDMP Header", HFILL }},

	{ &hf_ndmp_sequence, {
		"Sequence", "ndmp.sequence", FT_UINT32, BASE_DEC,
		NULL, 0, "Sequence number for NDMP PDU", HFILL }},

	{ &hf_ndmp_reply_sequence, {
		"Reply Sequence", "ndmp.reply_sequence", FT_UINT32, BASE_DEC,
		NULL, 0, "Reply Sequence number for NDMP PDU", HFILL }},

	{ &hf_ndmp_timestamp, {
		"Time", "ndmp.timestamp", FT_ABSOLUTE_TIME, BASE_NONE,
		NULL, 0, "Timestamp for this NDMP PDU", HFILL }},

	{ &hf_ndmp_msgtype, {
		"Type", "ndmp.msg_type", FT_UINT32, BASE_DEC,
		VALS(msg_type_vals), 0, "Is this a Request or Response?", HFILL }},

	{ &hf_ndmp_msg, {
		"Message", "ndmp.msg", FT_UINT32, BASE_DEC,
		VALS(msg_vals), 0, "Type of NDMP PDU", HFILL }},

	{ &hf_ndmp_error, {
		"Error", "ndmp.error", FT_UINT32, BASE_DEC,
		VALS(error_vals), 0, "Error code for this NDMP PDU", HFILL }},

	{ &hf_ndmp_version, {
		"Version", "ndmp.version", FT_UINT32, BASE_DEC,
		NULL, 0, "Version of NDMP protocol", HFILL }},


  };

  static gint *ett[] = {
    &ett_ndmp,
    &ett_ndmp_header,
  };

  module_t *ndmp_module;

  proto_ndmp = proto_register_protocol("Network Data Management Protocol", "NDMP", "ndmp");
  proto_register_field_array(proto_ndmp, hf_ndmp, array_length(hf_ndmp));
  
  proto_register_subtree_array(ett, array_length(ett));

  /* desegmentation */
  ndmp_module = prefs_register_protocol(proto_ndmp, NULL);
  prefs_register_bool_preference(ndmp_module, "ndmp.desegment", "Desegment all NDMP messages spanning multiple TCP segments", "Whether the dissector should desegment NDMP over TCP PDUs or not", &ndmp_desegment);

}

void
proto_reg_handoff_ndmp(void)
{
  dissector_handle_t ndmp_handle;

  ndmp_handle = create_dissector_handle(dissect_ndmp, proto_ndmp);
  dissector_add("tcp.port",TCP_PORT_NDMP, ndmp_handle);
}