/* packet-clnp.c
* Routines for ISO/OSI network and transport protocol packet disassembly
*
- * $Id: packet-clnp.c,v 1.20 2001/01/03 06:55:27 guy Exp $
+ * $Id: packet-clnp.c,v 1.53 2002/04/07 21:54:48 guy Exp $
* Laurent Deniel <deniel@worldnet.fr>
* Ralf Schneider <Ralf.Schneider@t-online.de>
*
* Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * 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
* 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.
- *
*/
#ifdef HAVE_CONFIG_H
#include <ctype.h>
#include <glib.h>
#include "prefs.h"
-#include "packet.h"
+#include <epan/packet.h>
+#include "reassemble.h"
#include "packet-osi.h"
#include "packet-osi-options.h"
#include "packet-isis.h"
static int proto_clnp = -1;
static gint ett_clnp = -1;
static gint ett_clnp_type = -1;
+static gint ett_clnp_segments = -1;
+static gint ett_clnp_segment = -1;
static gint ett_clnp_disc_pdu = -1;
static int proto_cotp = -1;
static gint ett_cotp = -1;
static int hf_clnp_dest = -1;
static int hf_clnp_src_length = -1;
static int hf_clnp_src = -1;
+static int hf_clnp_segments = -1;
+static int hf_clnp_segment = -1;
+static int hf_clnp_segment_overlap = -1;
+static int hf_clnp_segment_overlap_conflict = -1;
+static int hf_clnp_segment_multiple_tails = -1;
+static int hf_clnp_segment_too_long_segment = -1;
+static int hf_clnp_segment_error = -1;
+
+static dissector_handle_t data_handle;
/*
* ISO 8473 OSI CLNP definition (see RFC994)
Subset of CLNP. */
static heur_dissector_list_t cotp_is_heur_subdissector_list;
+/*
+ * Reassembly of CLNP.
+ */
+static GHashTable *clnp_segment_table = NULL;
+
/* options */
static guint tp_nsap_selector = NSEL_TP;
static gboolean always_decode_transport = FALSE;
+static gboolean clnp_reassemble = FALSE;
/* function definitions */
case VP_TPDU_SIZE:
c1 = tvb_get_guint8(tvb, offset) & 0x0F;
proto_tree_add_text(tree, tvb, offset, length,
- "TPDU size: %u", 2 << c1);
+ "TPDU size: %u", 1 << c1);
offset += length;
vp_length -= length;
break;
break;
}
- if (check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO,
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO,
"DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
src_ref, dst_ref);
offset += li + 1;
/* User data */
- dissect_data(tvb, offset, pinfo, tree);
+ call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
offset += tvb_length_remaining(tvb, offset);
/* we dissected all of the containing PDU */
break;
}
- if (check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s",
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s",
tpdu_nr,
dst_ref,
(fragment)? "(fragment)" : "");
*subdissector_found = TRUE;
} else {
/* Fill in other Dissectors using inactive subset here */
- dissect_data(next_tvb, 0, pinfo, tree);
+ call_dissector(data_handle,next_tvb, pinfo, tree);
}
} else
- dissect_data(next_tvb, 0, pinfo, tree);
+ call_dissector(data_handle,next_tvb, pinfo, tree);
offset += tvb_length_remaining(tvb, offset);
/* we dissected all of the containing PDU */
break;
} /* li */
- if (check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
tpdu_nr, dst_ref);
if (tree) {
offset += li;
next_tvb = tvb_new_subset(tvb, offset, -1, -1);
- dissect_data(next_tvb, 0, pinfo, tree);
+ call_dissector(data_handle,next_tvb, pinfo, tree);
offset += tvb_length_remaining(tvb, offset);
/* we dissected all of the containing PDU */
break;
}
- if (check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
tpdu_nr, dst_ref);
if (tree) {
if (class_option > 4)
return -1;
- if (check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO,
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO,
"%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
(tpdu == CR_TPDU) ? "CR" : "CC",
src_ref,
offset += li;
/* User data */
- dissect_data(tvb, offset, pinfo, tree);
+ call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
offset += tvb_length_remaining(tvb, offset);
/* we dissected all of the containing PDU */
src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
- if (check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO,
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO,
"DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
src_ref,
dst_ref);
tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
- if (check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
tpdu_nr, dst_ref);
if (tree) {
tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
- if (check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
tpdu_nr, dst_ref);
if (tree) {
break;
} /* li */
- if (check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO,
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO,
"EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
if (tree) {
break;
}
- if (check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
if (tree) {
ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
} /* osi_decode_ER */
static int osi_decode_UD(tvbuff_t *tvb, int offset,
- packet_info *pinfo, proto_tree *tree,
- gboolean *subdissector_found)
+ packet_info *pinfo, proto_tree *tree)
{
proto_item *ti;
proto_tree *cltp_tree = NULL;
tvbuff_t *next_tvb;
- if (check_col(pinfo->fd, COL_INFO))
- col_append_str(pinfo->fd, COL_INFO, "UD TPDU");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
if (tree) {
ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
offset += li;
next_tvb = tvb_new_subset(tvb, offset, -1, -1);
- dissect_data(next_tvb, 0, pinfo, tree);
+ call_dissector(data_handle,next_tvb, pinfo, tree);
offset += tvb_length_remaining(tvb, offset);
/* we dissected all of the containing PDU */
/* Initialize the COL_INFO field; each of the TPDUs will have its
information appended. */
- if (check_col(pinfo->fd, COL_INFO))
- col_add_str(pinfo->fd, COL_INFO, "");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_str(pinfo->cinfo, COL_INFO, "");
while (tvb_offset_exists(tvb, offset)) {
if (!first_tpdu) {
- if (check_col(pinfo->fd, COL_INFO))
- col_append_str(pinfo->fd, COL_INFO, ", ");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, ", ");
}
if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
- if (check_col(pinfo->fd, COL_INFO))
- col_append_str(pinfo->fd, COL_INFO, "Length indicator is zero");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
if (!first_tpdu)
- dissect_data(tvb, offset, pinfo, tree);
+ call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
return found_ositp;
}
new_offset = osi_decode_ER(tvb, offset, pinfo, tree);
break;
case UD_TPDU :
- new_offset = osi_decode_UD(tvb, offset, pinfo, tree,
- &subdissector_found);
+ new_offset = osi_decode_UD(tvb, offset, pinfo, tree);
is_cltp = TRUE;
break;
default :
- if (first_tpdu && check_col(pinfo->fd, COL_INFO))
- col_append_fstr(pinfo->fd, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
+ if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
new_offset = -1; /* bad PDU type */
break;
}
if (new_offset == -1) { /* incorrect TPDU */
if (!first_tpdu)
- dissect_data(tvb, offset, pinfo, tree);
+ call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
break;
}
if (first_tpdu) {
/* Well, we found at least one valid COTP or CLTP PDU, so I guess this
is either COTP or CLTP. */
- if (!subdissector_found && check_col(pinfo->fd, COL_PROTOCOL))
- col_set_str(pinfo->fd, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
+ if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
found_ositp = TRUE;
}
static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
- dissect_data(tvb, 0, pinfo, tree);
+ call_dissector(data_handle,tvb, pinfo, tree);
}
char *pdu_type_string;
proto_tree *type_tree;
guint16 segment_length;
+ guint16 du_id = 0;
guint16 segment_offset = 0;
guint16 cnf_cksum;
+ cksum_status_t cksum_status;
int offset;
u_char src_len, dst_len, nsel, opt_len = 0;
- guint8 *dst_addr, *src_addr;
- guint len;
+ const guint8 *dst_addr, *src_addr;
+ gint len;
guint next_length;
proto_tree *discpdu_tree;
- tvbuff_t *next_tvb;
-
- CHECK_DISPLAY_AS_DATA(proto_clnp, tvb, pinfo, tree);
-
- pinfo->current_proto = "CLNP";
-
- if (check_col(pinfo->fd, COL_PROTOCOL))
- col_set_str(pinfo->fd, COL_PROTOCOL, "CLNP");
+ volatile address save_dl_src;
+ volatile address save_dl_dst;
+ volatile address save_net_src;
+ volatile address save_net_dst;
+ volatile address save_src;
+ volatile address save_dst;
+ gboolean save_in_error_pkt;
+ fragment_data *fd_head;
+ tvbuff_t *volatile next_tvb;
+ gboolean update_col_info = TRUE;
+ gboolean save_fragmented;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_clear(pinfo->cinfo, COL_INFO);
cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
if (cnf_proto_id == NLPID_NULL) {
- if (check_col(pinfo->fd, COL_INFO))
- col_set_str(pinfo->fd, COL_INFO, "Inactive subset");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
if (tree) {
ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
clnp_tree = proto_item_add_subtree(ti, ett_clnp);
/* return if version not known */
cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
if (cnf_vers != ISO8473_V1) {
- dissect_data(tvb, 0, pinfo, tree);
+ call_dissector(data_handle,tvb, pinfo, tree);
return;
}
we set it otherwise. */
if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
- if (check_col(pinfo->fd, COL_INFO))
- col_add_fstr(pinfo->fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
}
segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
+ cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
+ cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
if (tree) {
proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
segment_length);
- cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
- proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2,
+ switch (cksum_status) {
+
+ default:
+ /*
+ * No checksum present, or not enough of the header present to
+ * checksum it.
+ */
+ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
+ P_CLNP_CKSUM, 2,
cnf_cksum,
"Checksum : 0x%04x",
cnf_cksum);
+ break;
+
+ case CKSUM_OK:
+ /*
+ * Checksum is correct.
+ */
+ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
+ P_CLNP_CKSUM, 2,
+ cnf_cksum,
+ "Checksum : 0x%04x (correct)",
+ cnf_cksum);
+ break;
+
+ case CKSUM_NOT_OK:
+ /*
+ * Checksum is not correct.
+ */
+ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
+ P_CLNP_CKSUM, 2,
+ cnf_cksum,
+ "Checksum : 0x%04x (incorrect)",
+ cnf_cksum);
+ break;
+ }
opt_len -= 9; /* Fixed part of Hesder */
} /* tree */
opt_len -= dst_len + src_len +2;
}
- if (check_col(pinfo->fd, COL_RES_NET_SRC))
- col_add_fstr(pinfo->fd, COL_RES_NET_SRC, "%s", print_nsap_net(src_addr, src_len));
- if (check_col(pinfo->fd, COL_RES_NET_DST))
- col_add_fstr(pinfo->fd, COL_RES_NET_DST, "%s", print_nsap_net(dst_addr, dst_len));
+ SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
+ SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
+ SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
+ SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
/* Segmentation Part */
tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */
segment_offset = tvb_get_ntohs(tvb, offset + 2);
+ du_id = tvb_get_ntohs(tvb, offset);
if (tree) {
proto_tree_add_text(clnp_tree, tvb, offset, 2,
"Data unit identifier: %06u",
- tvb_get_ntohs(tvb, offset));
+ du_id);
proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
"Segment offset : %6u",
segment_offset);
dissect_osi_options( 0xff,
opt_len,
- tvb, offset, pinfo, clnp_tree );
+ tvb, offset, clnp_tree );
}
/* Length of CLNP datagram plus headers above it. */
len = segment_length;
- /* Set the payload and captured-payload lengths to the minima of (the
- datagram length plus the length of the headers above it) and the
- frame lengths. */
- if (pinfo->len > len)
- pinfo->len = len;
- if (pinfo->captured_len > len)
- pinfo->captured_len = len;
-
offset = cnf_hdr_len;
- /* For now, dissect the payload of segments other than the initial
- segment as data, rather than handing them off to the transport
- protocol, just as we do with fragments other than the first
- fragment in a fragmented IP datagram; in the future, we will
- probably reassemble fragments for IP, and may reassemble segments
- for CLNP. */
- if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
- if (check_col(pinfo->fd, COL_INFO))
- col_add_fstr(pinfo->fd, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
+ /* If clnp_reassemble is on, and this is a segment, we have all the
+ * data in the segment, and the checksum is valid, then just add the
+ * segment to the hashtable.
+ */
+ save_fragmented = pinfo->fragmented;
+ if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
+ ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
+ (tvb_reported_length(tvb) <= tvb_length(tvb)) &&
+ cksum_status != CKSUM_NOT_OK) {
+ fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table,
+ segment_offset, segment_length - cnf_hdr_len,
+ cnf_type & CNF_MORE_SEGS);
+
+ if (fd_head != NULL) {
+ fragment_data *fd;
+ proto_tree *ft=NULL;
+ proto_item *fi=NULL;
+
+ /* OK, we have the complete reassembled payload.
+ Allocate a new tvbuff, referring to the reassembled payload. */
+ next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen,
+ fd_head->datalen);
+
+ /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
+ were handed refers, so it'll get cleaned up when that tvbuff
+ is cleaned up. */
+ tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+
+ /* Add the defragmented data to the data source list. */
+ add_new_data_source(pinfo->fd, next_tvb, "Reassembled CLNP");
+
+ /* It's not fragmented. */
+ pinfo->fragmented = FALSE;
+
+ /* show all segments */
+ fi = proto_tree_add_item(clnp_tree, hf_clnp_segments,
+ next_tvb, 0, -1, FALSE);
+ ft = proto_item_add_subtree(fi, ett_clnp_segments);
+ for (fd = fd_head->next; fd != NULL; fd = fd->next){
+ if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ /* this segment has some flags set, create a subtree
+ * for it and display the flags.
+ */
+ proto_tree *fet = NULL;
+ proto_item *fei = NULL;
+ int hf;
+
+ if (fd->flags & (FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ hf = hf_clnp_segment_error;
+ } else {
+ hf = hf_clnp_segment;
+ }
+ fei = proto_tree_add_none_format(ft, hf,
+ next_tvb, fd->offset, fd->len,
+ "Frame:%u payload:%u-%u",
+ fd->frame,
+ fd->offset,
+ fd->offset+fd->len-1
+ );
+ fet = proto_item_add_subtree(fei, ett_clnp_segment);
+ if (fd->flags&FD_OVERLAP) {
+ proto_tree_add_boolean(fet,
+ hf_clnp_segment_overlap, next_tvb, 0, 0,
+ TRUE);
+ }
+ if (fd->flags&FD_OVERLAPCONFLICT) {
+ proto_tree_add_boolean(fet,
+ hf_clnp_segment_overlap_conflict, next_tvb, 0, 0,
+ TRUE);
+ }
+ if (fd->flags&FD_MULTIPLETAILS) {
+ proto_tree_add_boolean(fet,
+ hf_clnp_segment_multiple_tails, next_tvb, 0, 0,
+ TRUE);
+ }
+ if (fd->flags&FD_TOOLONGFRAGMENT) {
+ proto_tree_add_boolean(fet,
+ hf_clnp_segment_too_long_segment, next_tvb, 0, 0,
+ TRUE);
+ }
+ } else {
+ /* nothing of interest for this segment */
+ proto_tree_add_none_format(ft, hf_clnp_segment,
+ next_tvb, fd->offset, fd->len,
+ "Frame:%u payload:%u-%u",
+ fd->frame,
+ fd->offset,
+ fd->offset+fd->len-1
+ );
+ }
+ }
+ if (fd_head->flags & (FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_set_str(pinfo->cinfo, COL_INFO, "[Illegal segments]");
+ update_col_info = FALSE;
+ }
+ }
+ } else {
+ /* We don't have the complete reassembled payload. */
+ next_tvb = NULL;
+ }
+ } else {
+ /* If this is the first segment, dissect its contents, otherwise
+ just show it as a segment.
+
+ XXX - if we eventually don't save the reassembled contents of all
+ segmented datagrams, we may want to always reassemble. */
+ if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
+ /* Not the first segment - don't dissect it. */
+ next_tvb = NULL;
+ } else {
+ /* First segment, or not segmented. Dissect what we have here. */
+
+ /* Get a tvbuff for the payload. */
+ next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+
+ /*
+ * If this is the first segment, but not the only segment,
+ * tell the next protocol that.
+ */
+ if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
+ pinfo->fragmented = TRUE;
+ else
+ pinfo->fragmented = FALSE;
+ }
+ }
+
+ if (next_tvb == NULL) {
+ /* Just show this as a segment. */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
pdu_type_string, flag_string, segment_offset);
- dissect_data(tvb, offset, pinfo, tree);
+
+ /* As we haven't reassembled anything, we haven't changed "pi", so
+ we don't have to restore it. */
+ call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
+ pinfo->fragmented = save_fragmented;
return;
}
PDU, skip that? */
if (nsel == (char)tp_nsap_selector || always_decode_transport) {
- next_tvb = tvb_new_subset(tvb, offset, -1, -1);
- if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE))
+ if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
+ pinfo->fragmented = save_fragmented;
return; /* yes, it appears to be COTP or CLTP */
+ }
}
break;
/* The payload is the header and "none, some, or all of the data
part of the discarded PDU", i.e. it's like an ICMP error;
dissect it as a CLNP PDU. */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
if (tree) {
next_length = tvb_length_remaining(tvb, offset);
if (next_length != 0) {
Make the columns non-writable, so the packet isn't shown
in the summary based on what the discarded PDU's contents
are. */
- col_set_writable(pinfo->fd, FALSE);
+ col_set_writable(pinfo->cinfo, FALSE);
+
+ /* Also, save the current values of the addresses, and restore
+ them when we're finished dissecting the contained packet, so
+ that the address columns in the summary don't reflect the
+ contained packet, but reflect this packet instead. */
+ save_dl_src = pinfo->dl_src;
+ save_dl_dst = pinfo->dl_dst;
+ save_net_src = pinfo->net_src;
+ save_net_dst = pinfo->net_dst;
+ save_src = pinfo->src;
+ save_dst = pinfo->dst;
+
+ /* Save the current value of the "we're inside an error packet"
+ flag, and set that flag; subdissectors may treat packets
+ that are the payload of error packets differently from
+ "real" packets. */
+ save_in_error_pkt = pinfo->in_error_pkt;
+ pinfo->in_error_pkt = TRUE;
+
+ /* Dissect the contained packet.
+ Catch ReportedBoundsError, and do nothing if we see it,
+ because it's not an error if the contained packet is short;
+ there's no guarantee that all of it was included.
+
+ XXX - should catch BoundsError, and re-throw it after cleaning
+ up. */
ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
"Discarded PDU");
discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
- next_tvb = tvb_new_subset(tvb, offset, -1, -1);
- dissect_clnp(next_tvb, pinfo, discpdu_tree);
- offset += next_length;
+ TRY {
+ dissect_clnp(next_tvb, pinfo, discpdu_tree);
+ }
+ CATCH(ReportedBoundsError) {
+ ; /* do nothing */
+ }
+ ENDTRY;
+
+ /* Restore the "we're inside an error packet" flag. */
+ pinfo->in_error_pkt = save_in_error_pkt;
+
+ /* Restore the addresses. */
+ pinfo->dl_src = save_dl_src;
+ pinfo->dl_dst = save_dl_dst;
+ pinfo->net_src = save_net_src;
+ pinfo->net_dst = save_net_dst;
+ pinfo->src = save_src;
+ pinfo->dst = save_dst;
}
}
- break;
+ pinfo->fragmented = save_fragmented;
+ return; /* we're done with this PDU */
case ERQ_NPDU:
case ERP_NPDU:
break;
}
}
- if (check_col(pinfo->fd, COL_INFO))
- col_add_fstr(pinfo->fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
- next_tvb = tvb_new_subset(tvb, offset, -1, -1);
- dissect_data(next_tvb, 0, pinfo, tree);
-
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
+ call_dissector(data_handle,next_tvb, pinfo, tree);
+ pinfo->fragmented = save_fragmented;
} /* dissect_clnp */
+static void
+clnp_reassemble_init(void)
+{
+ fragment_table_init(&clnp_segment_table);
+}
void proto_register_clnp(void)
{
static hf_register_info hf[] = {
{ &hf_clnp_id,
{ "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
- VALS(nlpid_vals), 0x0, "" }},
+ VALS(nlpid_vals), 0x0, "", HFILL }},
{ &hf_clnp_length,
- { "HDR Length ", "clnp.len", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
+ { "HDR Length ", "clnp.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_clnp_version,
- { "Version ", "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
+ { "Version ", "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_clnp_ttl,
- { "Holding Time ", "clnp.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
+ { "Holding Time ", "clnp.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_clnp_type,
- { "PDU Type ", "clnp.type", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
+ { "PDU Type ", "clnp.type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_clnp_pdu_length,
- { "PDU length ", "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0, "" }},
+ { "PDU length ", "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_clnp_checksum,
- { "Checksum ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "" }},
+ { "Checksum ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_clnp_dest_length,
- { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
+ { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_clnp_dest,
- { " DA ", "clnp.dsap", FT_BYTES, BASE_NONE, NULL, 0x0, "" }},
+ { " DA ", "clnp.dsap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_clnp_src_length,
- { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
+ { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_clnp_src,
- { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "" }},
+ { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
+
+ { &hf_clnp_segment_overlap,
+ { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Segment overlaps with other segments", HFILL }},
+
+ { &hf_clnp_segment_overlap_conflict,
+ { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Overlapping segments contained conflicting data", HFILL }},
+
+ { &hf_clnp_segment_multiple_tails,
+ { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Several tails were found when reassembling the packet", HFILL }},
+
+ { &hf_clnp_segment_too_long_segment,
+ { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Segment contained data past end of packet", HFILL }},
+
+ { &hf_clnp_segment_error,
+ { "Reassembly error", "clnp.segment.error", FT_NONE, BASE_DEC, NULL, 0x0,
+ "Reassembly error due to illegal segments", HFILL }},
+
+ { &hf_clnp_segment,
+ { "CLNP Segment", "clnp.segment", FT_NONE, BASE_DEC, NULL, 0x0,
+ "CLNP Segment", HFILL }},
+
+ { &hf_clnp_segments,
+ { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
+ "CLNP Segments", HFILL }},
};
static gint *ett[] = {
&ett_clnp,
&ett_clnp_type,
+ &ett_clnp_segments,
+ &ett_clnp_segment,
&ett_clnp_disc_pdu,
};
proto_register_field_array(proto_clnp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
- clnp_module = prefs_register_module("clnp", "CLNP", NULL);
+ clnp_module = prefs_register_protocol(proto_clnp, NULL);
prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
"NSAP selector for Transport Protocol (last byte in hexa)",
"NSAP selector for Transport Protocol (last byte in hexa)",
"Always try to decode NSDU as transport PDUs",
"Always try to decode NSDU as transport PDUs",
&always_decode_transport);
-
+ prefs_register_bool_preference(clnp_module, "reassemble",
+ "Reassemble segmented CLNP datagrams",
+ "Whether segmented CLNP datagrams should be reassembled",
+ &clnp_reassemble);
}
void proto_register_cotp(void)
/* subdissector code */
register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
- register_dissector("ositp", dissect_ositp);
+ /* XXX - what about CLTP? */
+ register_dissector("ositp", dissect_ositp, proto_cotp);
}
void proto_register_cltp(void)
proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
/* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
proto_register_subtree_array(ett, array_length(ett));
+ register_init_routine(clnp_reassemble_init);
}
void
proto_reg_handoff_clnp(void)
{
- dissector_add("osinl", NLPID_ISO8473_CLNP, dissect_clnp);
- dissector_add("osinl", NLPID_NULL, dissect_clnp); /* Inactive subset */
+ dissector_handle_t clnp_handle;
+
+ data_handle = find_dissector("data");
+
+ clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
+ dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
+ dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
+ dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);
}