summaryrefslogtreecommitdiff
path: root/epan/dissectors/packet-ndmp.c
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2009-07-03 11:45:42 +0000
committerAnders Broman <anders.broman@ericsson.com>2009-07-03 11:45:42 +0000
commit24b17483b718522b382ce9165328aa2ec48a1d84 (patch)
treeaf0024171b7887069a014f15ad31b9da3626323d /epan/dissectors/packet-ndmp.c
parent9518d53ab4e7c3bb8a41077660bbe4e800ffd2b1 (diff)
downloadwireshark-24b17483b718522b382ce9165328aa2ec48a1d84.tar.gz
From Chris Costa:
NDMP fragmentation fix. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=3395 svn path=/trunk/; revision=28935
Diffstat (limited to 'epan/dissectors/packet-ndmp.c')
-rw-r--r--epan/dissectors/packet-ndmp.c406
1 files changed, 366 insertions, 40 deletions
diff --git a/epan/dissectors/packet-ndmp.c b/epan/dissectors/packet-ndmp.c
index 0a49ca57b7..a441e3fe7e 100644
--- a/epan/dissectors/packet-ndmp.c
+++ b/epan/dissectors/packet-ndmp.c
@@ -224,6 +224,15 @@ static int hf_ndmp_data_bytes_processed = -1;
static int hf_ndmp_data_est_bytes_remain = -1;
static int hf_ndmp_data_est_time_remain = -1;
+static int hf_ndmp_fragments = -1;
+static int hf_ndmp_fragment = -1;
+static int hf_ndmp_fragment_overlap = -1;
+static int hf_ndmp_fragment_overlap_conflicts = -1;
+static int hf_ndmp_fragment_multiple_tails = -1;
+static int hf_ndmp_fragment_too_long_fragment = -1;
+static int hf_ndmp_fragment_error = -1;
+static int hf_ndmp_reassembled_in = -1;
+
static gint ett_ndmp = -1;
static gint ett_ndmp_fraghdr = -1;
static gint ett_ndmp_header = -1;
@@ -242,6 +251,29 @@ static gint ett_ndmp_file_name = -1;
static gint ett_ndmp_file_stats = -1;
static gint ett_ndmp_file_invalids = -1;
static gint ett_ndmp_state_invalids = -1;
+static gint ett_ndmp_fragment = -1;
+static gint ett_ndmp_fragments = -1;
+
+static const fragment_items ndmp_frag_items = {
+ /* Fragment subtrees */
+ &ett_ndmp_fragment,
+ &ett_ndmp_fragments,
+ /* Fragment fields */
+ &hf_ndmp_fragments,
+ &hf_ndmp_fragment,
+ &hf_ndmp_fragment_overlap,
+ &hf_ndmp_fragment_overlap_conflicts,
+ &hf_ndmp_fragment_multiple_tails,
+ &hf_ndmp_fragment_too_long_fragment,
+ &hf_ndmp_fragment_error,
+ /* Reassembled in field */
+ &hf_ndmp_reassembled_in,
+ /* Tag */
+ "NDMP fragments"
+};
+
+static GHashTable *ndmp_fragment_table = NULL;
+static GHashTable *ndmp_reassembled_table = NULL;
/* XXX someone should start adding the new stuff from v3, v4 and v5*/
#define NDMP_PROTOCOL_UNKNOWN 0
@@ -259,6 +291,11 @@ static enum_val_t ndmp_protocol_versions[] = {
static gint ndmp_default_protocol_version = NDMP_PROTOCOL_V4;
+typedef struct _ndmp_frag_info {
+ guint32 first_seq;
+ guint16 offset;
+} ndmp_frag_info;
+
typedef struct _ndmp_task_data_t {
guint32 request_frame;
guint32 response_frame;
@@ -270,6 +307,8 @@ typedef struct _ndmp_conv_data_t {
guint8 version;
emem_tree_t *tasks; /* indexed by Sequence# */
emem_tree_t *itl; /* indexed by packet# */
+ emem_tree_t *fragsA; /* indexed by Sequence# */
+ emem_tree_t *fragsB;
ndmp_task_data_t *task;
conversation_t *conversation;
} ndmp_conv_data_t;
@@ -493,6 +532,82 @@ static const value_string msg_vals[] = {
{0, NULL}
};
+gboolean
+check_ndmp_rm(tvbuff_t *tvb, packet_info *pinfo)
+{
+ guint len;
+ guint32 tmp;
+
+ /* verify that the tcp port is 10000, ndmp always runs on port 10000*/
+ if ((pinfo->srcport!=TCP_PORT_NDMP)&&(pinfo->destport!=TCP_PORT_NDMP)) {
+ return FALSE;
+ }
+
+ /* check that the header looks sane */
+ len=tvb_length(tvb);
+ /* check the record marker that it looks sane.
+ * It has to be >=24 bytes or (arbitrary limit) <1Mbyte
+ */
+ if(len>=4){
+ tmp=(tvb_get_ntohl(tvb, 0)&RPC_RM_FRAGLEN);
+ if( (tmp<24)||(tmp>1000000) ){
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean
+check_ndmp_hdr(tvbuff_t *tvb, packet_info *pinfo)
+{
+ guint len;
+ guint32 tmp;
+
+ len=tvb_length(tvb);
+
+ /* If the length is less than 24, it isn't a valid
+ header */
+ if (len<24){
+ return FALSE;
+ }
+
+ /* check the timestamp, timestamps are valid if they
+ * (arbitrary) lie between 1980-jan-1 and 2030-jan-1
+ */
+ if(len>=8){
+ tmp=tvb_get_ntohl(tvb, 4);
+ if( (tmp<0x12ceec50)||(tmp>0x70dc1ed0) ){
+ return FALSE;
+ }
+ }
+
+ /* check the type */
+ if(len>=12){
+ tmp=tvb_get_ntohl(tvb, 8);
+ if( tmp>1 ){
+ return FALSE;
+ }
+ }
+
+ /* check message */
+ if(len>=16){
+ tmp=tvb_get_ntohl(tvb, 12);
+ if( (tmp>0xa09) || (tmp==0) ){
+ return FALSE;
+ }
+ }
+
+ /* check error */
+ if(len>=24){
+ tmp=tvb_get_ntohl(tvb, 20);
+ if( (tmp>0x17) ){
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
static int
dissect_connect_open_request(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
@@ -520,7 +635,7 @@ dissect_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree_add_item(tree, hf_ndmp_error, tvb, offset, 4, FALSE);
if(err && check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO,
- " NDMP Error:%s",
+ " NDMP Error:%s ",
val_to_str(err, error_vals,
"Unknown NDMP error code %#x"));
}
@@ -2646,7 +2761,6 @@ dissect_data_get_state_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
return offset;
}
-
typedef struct _ndmp_command {
guint32 cmd;
int (*request) (tvbuff_t *tvb, int offset, packet_info *pinfo,
@@ -2807,7 +2921,7 @@ dissect_ndmp_header(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *p
offset=dissect_error(tvb, offset, pinfo, tree, nh->seq);
if (check_col(pinfo->cinfo, COL_INFO)){
- col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s",
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s ",
val_to_str(nh->msg, msg_vals, "Unknown Message (0x%02x)"),
val_to_str(nh->type, msg_type_vals, "Unknown Type (0x%02x)")
);
@@ -2870,12 +2984,22 @@ dissect_ndmp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
guint32 ndmp_rm;
struct ndmp_header nh;
guint32 size;
+ guint32 seq, len, nxt, frag_num;
+ gint nbytes;
+ int direction;
+ struct tcpinfo *tcpinfo;
+ ndmp_frag_info* nfi;
proto_item *ndmp_item = NULL;
proto_tree *ndmp_tree = NULL;
proto_item *hdr_item = NULL;
proto_tree *hdr_tree = NULL;
+ emem_tree_t *frags;
conversation_t *conversation;
proto_item *vers_item;
+ gboolean save_fragmented, save_writable;
+ gboolean do_frag = TRUE;
+ tvbuff_t* new_tvb = NULL;
+ fragment_data *frag_msg = NULL;
top_tree=tree; /* scsi should open its expansions on the top level */
@@ -2889,6 +3013,7 @@ dissect_ndmp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
}
+
ndmp_conv_data=conversation_get_proto_data(conversation, proto_ndmp);
if(!ndmp_conv_data){
ndmp_conv_data=se_alloc(sizeof(ndmp_conv_data_t));
@@ -2896,66 +3021,223 @@ dissect_ndmp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
ndmp_conv_data->tasks=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "NDMP tasks");
ndmp_conv_data->itl=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "NDMP itl");
ndmp_conv_data->conversation=conversation;
+ ndmp_conv_data->fragsA=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "NDMP fragsA");
+ ndmp_conv_data->fragsB=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "NDMP fragsB");
conversation_add_proto_data(conversation, proto_ndmp, ndmp_conv_data);
}
- /* size of this NDMP PDU */
- size = tvb_length_remaining(tvb, offset);
- if (size < 28) {
- /* too short to be NDMP */
- return;
- }
-
/*
- * Read the NDMP header, if we have it.
+ * Read the NDMP record marker, if we have it.
*/
ndmp_rm=tvb_get_ntohl(tvb, offset);
- nh.seq = tvb_get_ntohl(tvb, offset+4);
- nh.time = tvb_get_ntohl(tvb, offset+8);
- nh.type = tvb_get_ntohl(tvb, offset+12);
- nh.msg = tvb_get_ntohl(tvb, offset+16);
- nh.rep_seq = tvb_get_ntohl(tvb, offset+20);
- nh.err = tvb_get_ntohl(tvb, offset+24);
+ /* Reassemble if desegmentation and reassembly are enabled, otherwise
+ * just pass through and use the data in tvb for dissection */
+ if (ndmp_defragment && ndmp_desegment)
+ {
+
+ /* Initialize the tables, if neccesary */
+ if (ndmp_fragment_table == NULL)
+ {
+ fragment_table_init(&ndmp_fragment_table);
+ reassembled_table_init(&ndmp_reassembled_table);
+ }
+
+ /*
+ * Determine the direction of the flow, so we can use the correct fragment tree
+ */
+ direction=CMP_ADDRESS(&pinfo->src, &pinfo->dst);
+ if(direction==0) {
+ direction= (pinfo->srcport > pinfo->destport) ? 1 : -1;
+ }
+ if(direction>=0){
+ frags = ndmp_conv_data->fragsA;
+ } else {
+ frags = ndmp_conv_data->fragsB;
+ }
- /*
- * Check if this is the last fragment.
- */
- if (!(ndmp_rm & RPC_RM_LASTFRAG)) {
/*
- * This isn't the last fragment.
- * If we're doing reassembly, just return
- * TRUE to indicate that this looks like
- * the beginning of an NDMP message,
- * and let them do reassembly.
+ * Figure out the tcp seq and pdu length. Fragment tree is indexed based on seq;
*/
- if (ndmp_defragment)
+ if (pinfo == NULL || pinfo->private_data == NULL) {
+ return;
+ }
+ tcpinfo = pinfo->private_data;
+
+ if (tcpinfo == NULL) {
return;
+ }
+ seq = tcpinfo->seq;
+ len = (ndmp_rm & RPC_RM_FRAGLEN) + 4;
+ nxt = seq + len;
+
+ /*
+ * In case there are multiple PDUs in the same frame, advance the tcp seq
+ * so that they can be distinguished from one another
+ */
+ tcpinfo->seq = nxt;
+
+ nfi = se_tree_lookup32(frags, seq);
+
+ if (!nfi)
+ {
+ frag_num = 0;
+
+ /*
+ * If nfi doesn't exist, then there are no fragments before this one.
+ * If there are fragments after this one, create the entry in the frag
+ * tree so the next fragment can find it.
+ */
+ if (!(ndmp_rm & RPC_RM_LASTFRAG))
+ {
+ nfi=se_alloc(sizeof(ndmp_frag_info));
+ nfi->first_seq = seq;
+ nfi->offset = 1;
+ se_tree_insert32(frags, nxt, (void *)nfi);
+ }
+ /*
+ * If this is both the first and the last fragment, then there
+ * is no reason to even engage the reassembly routines. Just
+ * create the new_tvb directly from tvb.
+ */
+ else
+ {
+ do_frag = FALSE;
+ new_tvb = tvb_new_subset(tvb, 4, -1, -1);
+ }
+ }
+ else
+ {
+ /*
+ * An entry was found, so we know the offset of this fragment
+ */
+ frag_num = nfi->offset;
+ seq = nfi->first_seq;
+
+ /*
+ * If this isn't the last frag, add another entry so the next fragment can find it.
+ */
+ if (!(ndmp_rm & RPC_RM_LASTFRAG))
+ {
+ nfi=se_alloc(sizeof(ndmp_frag_info));
+ nfi->first_seq = seq;
+ nfi->offset = frag_num+1;
+ se_tree_insert32(frags, nxt, (void *)nfi);
+ }
+ }
+
+ save_fragmented = pinfo->fragmented;
+
+ /* If fragmentation is neccessary */
+ if (do_frag)
+ {
+ pinfo->fragmented = TRUE;
+
+ frag_msg = fragment_add_seq_check(tvb, 4, pinfo,
+ seq,
+ ndmp_fragment_table,
+ ndmp_reassembled_table,
+ frag_num,
+ tvb_length_remaining(tvb, offset)-4,
+ !(ndmp_rm & RPC_RM_LASTFRAG));
+
+ new_tvb = process_reassembled_data(tvb, 4, pinfo, "Reassembled NDMP", frag_msg, &ndmp_frag_items, NULL, tree);
+ }
+
+ /*
+ * Check if this is the last fragment.
+ */
+ if (!(ndmp_rm & RPC_RM_LASTFRAG)) {
+ /*
+ * Update the column info.
+ */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDMP");
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_clear(pinfo->cinfo, COL_INFO);
+ col_append_fstr(pinfo->cinfo, COL_INFO, "[NDMP fragment] ");
+ }
+
+ /*
+ * Add the record marker information to the tree
+ */
+ if (tree) {
+ ndmp_item = proto_tree_add_item(tree, proto_ndmp, tvb, 0, -1, FALSE);
+ ndmp_tree = proto_item_add_subtree(ndmp_item, ett_ndmp);
+ }
+ hdr_item = proto_tree_add_text(ndmp_tree, tvb, 0, 4,
+ "Fragment header: %s%u %s",
+ (ndmp_rm & RPC_RM_LASTFRAG) ? "Last fragment, " : "",
+ ndmp_rm & RPC_RM_FRAGLEN, plurality(ndmp_rm & RPC_RM_FRAGLEN, "byte", "bytes"));
+ hdr_tree = proto_item_add_subtree(hdr_item, ett_ndmp_fraghdr);
+ proto_tree_add_boolean(hdr_tree, hf_ndmp_lastfrag, tvb, 0, 4, ndmp_rm);
+ proto_tree_add_uint(hdr_tree, hf_ndmp_fraglen, tvb, 0, 4, ndmp_rm);
+
+ /*
+ * Decode the remaining bytes as generic NDMP fragment data
+ */
+ nbytes = tvb_reported_length_remaining(tvb, 4);
+ proto_tree_add_text(ndmp_tree, tvb, 4, nbytes, "NDMP fragment data (%u byte%s)", nbytes, plurality(nbytes, "", "s"));
+
+ return;
+ }
+ }
+ else
+ {
+ new_tvb = tvb_new_subset(tvb, 4, -1, -1);
+ }
+
+
+ /* size of this NDMP PDU */
+ size = tvb_length_remaining(new_tvb, offset);
+ if (size < 24) {
+ /* too short to be NDMP */
+ return;
}
+ /*
+ * If it doesn't look like a valid NDMP header at this point, there is
+ * no reason to move forward
+ */
+ if (!check_ndmp_hdr(new_tvb, pinfo))
+ {
+ return;
+ }
+
+ nh.seq = tvb_get_ntohl(new_tvb, offset);
+ nh.time = tvb_get_ntohl(new_tvb, offset+4);
+ nh.type = tvb_get_ntohl(new_tvb, offset+8);
+ nh.msg = tvb_get_ntohl(new_tvb, offset+12);
+ nh.rep_seq = tvb_get_ntohl(new_tvb, offset+16);
+ nh.err = tvb_get_ntohl(new_tvb, offset+20);
+
+ /* When the last fragment is small and the final frame contains
+ * multiple fragments, the column becomes unwritable.
+ * Temporarily change that so that the correct header can be
+ * applied */
+ save_writable = col_get_writable(pinfo->cinfo);
+ col_set_writable(pinfo->cinfo, TRUE);
+
if (check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDMP");
if (check_col(pinfo->cinfo, COL_INFO)) {
col_clear(pinfo->cinfo, COL_INFO);
}
-
if (tree) {
- ndmp_item = proto_tree_add_item(tree, proto_ndmp,
- tvb, 0, -1, FALSE);
+ ndmp_item = proto_tree_add_item(tree, proto_ndmp, tvb, 0, -1, FALSE);
ndmp_tree = proto_item_add_subtree(ndmp_item, ett_ndmp);
}
-
/* ndmp version (and autodetection) */
if(ndmp_conv_data->version!=NDMP_PROTOCOL_UNKNOWN){
- vers_item=proto_tree_add_uint(ndmp_tree, hf_ndmp_version, tvb, offset, 0, ndmp_conv_data->version);
+ vers_item=proto_tree_add_uint(ndmp_tree, hf_ndmp_version, new_tvb, offset, 0, ndmp_conv_data->version);
} else {
- vers_item=proto_tree_add_uint_format(ndmp_tree, hf_ndmp_version, tvb, offset, 0, ndmp_default_protocol_version, "Unknown NDMP version, using default:%d", ndmp_default_protocol_version);
+ 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);
}
PROTO_ITEM_SET_GENERATED(vers_item);
-
/* request response matching */
ndmp_conv_data->task=NULL;
switch(nh.type){
@@ -2972,7 +3254,8 @@ dissect_ndmp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
if(ndmp_conv_data->task && ndmp_conv_data->task->response_frame){
proto_item *it;
- it=proto_tree_add_uint(ndmp_tree, hf_ndmp_response_frame, tvb, 0, 0, ndmp_conv_data->task->response_frame);
+ it=proto_tree_add_uint(ndmp_tree, hf_ndmp_response_frame, new_tvb, 0, 0, ndmp_conv_data->task->response_frame);
+
PROTO_ITEM_SET_GENERATED(it);
}
break;
@@ -2989,17 +3272,18 @@ dissect_ndmp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item *it;
nstime_t delta_ts;
- it=proto_tree_add_uint(ndmp_tree, hf_ndmp_request_frame, tvb, 0, 0, ndmp_conv_data->task->request_frame);
+ it=proto_tree_add_uint(ndmp_tree, hf_ndmp_request_frame, new_tvb, 0, 0, ndmp_conv_data->task->request_frame);
+
PROTO_ITEM_SET_GENERATED(it);
nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &ndmp_conv_data->task->ndmp_time);
- it=proto_tree_add_time(ndmp_tree, hf_ndmp_time, tvb, 0, 0, &delta_ts);
+ it=proto_tree_add_time(ndmp_tree, hf_ndmp_time, new_tvb, 0, 0, &delta_ts);
PROTO_ITEM_SET_GENERATED(it);
}
break;
}
-
+ /* Add the record marker information to the tree */
hdr_item = proto_tree_add_text(ndmp_tree, tvb, 0, 4,
"Fragment header: %s%u %s",
(ndmp_rm & RPC_RM_LASTFRAG) ? "Last fragment, " : "",
@@ -3013,7 +3297,12 @@ dissect_ndmp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
* are implementations which pad some additional data after
* the PDU. We MUST use size.
*/
- dissect_ndmp_cmd(tvb, offset+4, pinfo, ndmp_tree, &nh);
+ dissect_ndmp_cmd(new_tvb, offset, pinfo, ndmp_tree, &nh);
+
+ /* restore saved variabled */
+ pinfo->fragmented = save_fragmented;
+ col_set_writable(pinfo->cinfo, save_writable);
+
return;
}
@@ -3092,7 +3381,16 @@ check_if_ndmp(tvbuff_t *tvb, packet_info *pinfo)
static int
dissect_ndmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- if(!check_if_ndmp(tvb, pinfo)) {
+ /* If we are doing defragmentation, don't check more than the record mark here,
+ * because if this is a continuation of a fragmented NDMP PDU there won't be a
+ * NDMP header after the RM */
+ if(ndmp_defragment && !check_ndmp_rm(tvb, pinfo)) {
+ return 0;
+ }
+
+ /* If we aren't doing both defragmentation and reassembly, check for the entire
+ * NDMP header before proceeding */
+ if(!(ndmp_defragment && ndmp_desegment) && !check_if_ndmp(tvb, pinfo)) {
return 0;
}
@@ -3783,6 +4081,32 @@ proto_register_ndmp(void)
{ &hf_ndmp_fraglen, {
"Fragment Length", "ndmp.fraglen", FT_UINT32, BASE_DEC,
NULL, RPC_RM_FRAGLEN, NULL, HFILL }},
+ {&hf_ndmp_fragments, {
+ "NDMP fragments", "ndmp.fragments", FT_NONE, BASE_NONE,
+ NULL, 0x00, NULL, HFILL } },
+ {&hf_ndmp_fragment,
+ {"NDMP fragment", "ndmp.fragment",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+ {&hf_ndmp_fragment_overlap,
+ {"NDMP fragment overlap", "ndmp.fragment.overlap",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+ {&hf_ndmp_fragment_overlap_conflicts,
+ {"NDMP fragment overlapping with conflicting data",
+ "msg.fragment.overlap.conflicts",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+ {&hf_ndmp_fragment_multiple_tails,
+ {"NDMP has multiple tail fragments",
+ "msg.fragment.multiple_tails",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+ {&hf_ndmp_fragment_too_long_fragment,
+ {"NDMP fragment too long", "ndmp.fragment.too_long_fragment",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+ {&hf_ndmp_fragment_error,
+ {"NDMP defragmentation error", "ndmp.fragment.error",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+ {&hf_ndmp_reassembled_in,
+ {"Reassembled in", "ndmp.reassembled.in",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
};
static gint *ett[] = {
@@ -3804,6 +4128,8 @@ proto_register_ndmp(void)
&ett_ndmp_file_stats,
&ett_ndmp_file_invalids,
&ett_ndmp_state_invalids,
+ &ett_ndmp_fragment,
+ &ett_ndmp_fragments,
};
module_t *ndmp_module;