wireshark/epan/dissectors/packet-tcpclv3.c

776 lines
28 KiB
C

/* packet-tcpclv3.c
* References:
* RFC 7242: https://tools.ietf.org/html/rfc7242
*
* Copyright 2006-2007 The MITRE Corporation.
* All Rights Reserved.
* Approved for Public Release; Distribution Unlimited.
* Tracking Number 07-0090.
*
* The US Government will not be charged any license fee and/or royalties
* related to this software. Neither name of The MITRE Corporation; nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Specification reference:
* RFC 5050
* https://tools.ietf.org/html/rfc5050
*/
/*
* Modifications were made to this file under designation MFS-33289-1 and
* are Copyright 2015 United States Government as represented by NASA
* Marshall Space Flight Center. All Rights Reserved.
*
* Released under the GNU GPL with NASA legal approval granted 2016-06-10.
*
* The subject software is provided "AS IS" WITHOUT ANY WARRANTY of any kind,
* either expressed, implied or statutory and this agreement does not,
* in any manner, constitute an endorsement by government agency of any
* results, designs or products resulting from use of the subject software.
* See the Agreement for the specific language governing permissions and
* limitations.
*/
#include "config.h"
#include <stdio.h>
#include <epan/packet.h>
#include <epan/reassemble.h>
#include <epan/expert.h>
#include "packet-tcpclv3.h"
#include "packet-bpv6.h"
#include "packet-tcp.h"
/* For Reassembling TCP Convergence Layer segments */
static reassembly_table msg_reassembly_table;
static const char magic[] = {'d', 't', 'n', '!'};
static int proto_tcp_conv = -1;
/* TCP Convergence Header Variables */
static int hf_tcp_convergence_pkt_type = -1;
/* Refuse-Bundle reason code */
static int hf_dtn_refuse_bundle_reason_code = -1;
static int hf_contact_hdr_version = -1;
static int hf_contact_hdr_flags = -1;
static int hf_contact_hdr_keep_alive = -1;
static int hf_contact_hdr_flags_ack_req = -1;
static int hf_contact_hdr_flags_frag_enable = -1;
static int hf_contact_hdr_flags_nak = -1;
static int hf_contact_hdr_magic = -1;
static int hf_contact_hdr_local_eid_length = -1;
static int hf_contact_hdr_local_eid = -1;
/* TCP Convergence Data Header Variables */
static int hf_tcp_convergence_data_procflags = -1;
static int hf_tcp_convergence_data_procflags_start = -1;
static int hf_tcp_convergence_data_procflags_end = -1;
static int hf_tcp_convergence_data_segment_length = -1;
/* TCP Convergence Ack Variables */
static int hf_tcp_convergence_ack_length = -1;
/* TCP Convergence Shutdown Header Variables */
static int hf_tcp_convergence_shutdown_flags = -1;
static int hf_tcp_convergence_shutdown_flags_reason = -1;
static int hf_tcp_convergence_shutdown_flags_delay = -1;
static int hf_tcp_convergence_shutdown_reason = -1;
static int hf_tcp_convergence_shutdown_delay = -1;
/*TCP Convergence Layer Reassembly boilerplate*/
static int hf_msg_fragments = -1;
static int hf_msg_fragment = -1;
static int hf_msg_fragment_overlap = -1;
static int hf_msg_fragment_overlap_conflicts = -1;
static int hf_msg_fragment_multiple_tails = -1;
static int hf_msg_fragment_too_long_fragment = -1;
static int hf_msg_fragment_error = -1;
static int hf_msg_fragment_count = -1;
static int hf_msg_reassembled_in = -1;
static int hf_msg_reassembled_length = -1;
/* Tree Node Variables */
static gint ett_conv_flags = -1;
static gint ett_shutdown_flags = -1;
static gint ett_contact_hdr_flags = -1;
static gint ett_tcp_conv = -1;
static gint ett_tcp_conv_hdr = -1;
static gint ett_msg_fragment = -1;
static gint ett_msg_fragments = -1;
static expert_field ei_tcp_convergence_data_flags = EI_INIT;
static expert_field ei_tcp_convergence_segment_length = EI_INIT;
static expert_field ei_tcp_convergence_ack_length = EI_INIT;
static dissector_handle_t bundle_handle;
typedef struct dictionary_data {
int bundle_header_dict_length;
int dest_scheme_offset;
int dst_scheme_pos;
int dst_scheme_len;
int source_scheme_offset;
int src_scheme_pos;
int src_scheme_len;
int report_scheme_offset;
int rpt_scheme_pos;
int rpt_scheme_len;
int cust_scheme_offset;
int cust_scheme_pos;
int cust_scheme_len;
int dest_ssp_offset;
int dst_ssp_len;
int source_ssp_offset;
int src_ssp_len;
int report_ssp_offset;
int rpt_ssp_len;
int cust_ssp_offset;
int cust_ssp_len;
} dictionary_data_t;
static const value_string packet_type_vals[] = {
{((TCP_CONVERGENCE_DATA_SEGMENT>>4) & 0x0F), "Data"},
{((TCP_CONVERGENCE_ACK_SEGMENT>>4) & 0x0F), "Ack"},
{((TCP_CONVERGENCE_REFUSE_BUNDLE>>4) & 0x0F), "Refuse Bundle"},
{((TCP_CONVERGENCE_KEEP_ALIVE>>4) & 0x0F), "Keep Alive"},
{((TCP_CONVERGENCE_SHUTDOWN>>4) & 0x0F), "Shutdown"},
{((TCP_CONVERGENCE_LENGTH>>4) & 0x0F), "Length"},
{0, NULL}
};
/* Refuse-Bundle Reason-Code Flags as per RFC-7242: Section-5.4 */
static const value_string refuse_bundle_reason_code[] = {
{TCP_REFUSE_BUNDLE_REASON_UNKNOWN, "Reason for refusal is unknown"},
{TCP_REFUSE_BUNDLE_REASON_RX_COMPLETE, "Complete Bundle Received"},
{TCP_REFUSE_BUNDLE_REASON_RX_EXHAUSTED, "Receiver's resources exhausted"},
{TCP_REFUSE_BUNDLE_REASON_RX_RETRANSMIT, "Receiver expects re-transmission of bundle"},
{0, NULL}
};
static const fragment_items msg_frag_items = {
/*Fragment subtrees*/
&ett_msg_fragment,
&ett_msg_fragments,
/*Fragment Fields*/
&hf_msg_fragments,
&hf_msg_fragment,
&hf_msg_fragment_overlap,
&hf_msg_fragment_overlap_conflicts,
&hf_msg_fragment_multiple_tails,
&hf_msg_fragment_too_long_fragment,
&hf_msg_fragment_error,
&hf_msg_fragment_count,
/*Reassembled in field*/
&hf_msg_reassembled_in,
/*Reassembled length field*/
&hf_msg_reassembled_length,
/* Reassembled data field */
NULL,
/*Tag*/
"Message fragments"
};
static guint
get_dtn_contact_header_len(packet_info *pinfo _U_, tvbuff_t *tvb,
int offset, void *data _U_)
{
int len, bytecount;
/* get length from sdnv */
len = evaluate_sdnv(tvb, offset+8, &bytecount);
if (len < 0)
return 0;
return len+bytecount+8;
}
static int
dissect_dtn_contact_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
proto_item *ti;
proto_tree *conv_proto_tree, *conv_tree, *conv_flag_tree;
int eid_length, sdnv_length;
int offset = 0;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "TCPCLv3");
col_clear(pinfo->cinfo,COL_INFO); /* Clear out stuff in the info column */
col_add_str(pinfo->cinfo, COL_INFO, "Contact Header");
ti = proto_tree_add_item(tree, proto_tcp_conv, tvb, offset, -1, ENC_NA);
conv_proto_tree = proto_item_add_subtree(ti, ett_tcp_conv);
conv_tree = proto_tree_add_subtree(conv_proto_tree, tvb, offset, -1, ett_tcp_conv, NULL, "Contact Header");
proto_tree_add_item(conv_tree, hf_contact_hdr_magic, tvb, offset, 4, ENC_NA|ENC_ASCII);
offset += 4;
proto_tree_add_item(conv_tree, hf_contact_hdr_version, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
/* Subtree to expand the bits in the Contact Header Flags */
ti = proto_tree_add_item(conv_tree, hf_contact_hdr_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
conv_flag_tree = proto_item_add_subtree(ti, ett_contact_hdr_flags);
proto_tree_add_item(conv_flag_tree, hf_contact_hdr_flags_ack_req, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(conv_flag_tree, hf_contact_hdr_flags_frag_enable, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(conv_flag_tree, hf_contact_hdr_flags_nak, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(conv_tree, hf_contact_hdr_keep_alive, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
/*
* New format Contact header has length field followed by Bundle Header.
*/
expert_field *ei_bundle_sdnv_length;
eid_length = evaluate_sdnv_ei(tvb, offset, &sdnv_length, &ei_bundle_sdnv_length);
ti = proto_tree_add_int(tree, hf_contact_hdr_local_eid_length, tvb, offset, sdnv_length, eid_length);
if (ei_bundle_sdnv_length) {
expert_add_info(pinfo, ti, ei_bundle_sdnv_length);
return offset;
}
proto_tree_add_item(conv_tree, hf_contact_hdr_local_eid, tvb, sdnv_length + offset, eid_length, ENC_NA|ENC_ASCII);
return tvb_captured_length(tvb);
}
static guint
get_tcpcl_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
{
int len, bytecount;
guint8 conv_hdr = tvb_get_guint8(tvb, offset);
switch (conv_hdr & TCP_CONVERGENCE_TYPE_MASK)
{
case TCP_CONVERGENCE_DATA_SEGMENT:
/* get length from sdnv */
len = evaluate_sdnv(tvb, offset+1, &bytecount);
if (len < 0)
return 0;
return len+bytecount+1;
case TCP_CONVERGENCE_ACK_SEGMENT:
/* get length from sdnv */
len = evaluate_sdnv(tvb, offset+1, &bytecount);
if (len < 0)
return 0;
return bytecount+1;
case TCP_CONVERGENCE_KEEP_ALIVE:
case TCP_CONVERGENCE_REFUSE_BUNDLE:
/* always 1 byte */
return 1;
case TCP_CONVERGENCE_SHUTDOWN:
len = 1;
if (conv_hdr & TCP_CONVERGENCE_SHUTDOWN_REASON) {
len += 1;
}
if (conv_hdr & TCP_CONVERGENCE_SHUTDOWN_DELAY) {
len += 2;
}
return len;
case TCP_CONVERGENCE_LENGTH:
/* get length from sdnv */
len = evaluate_sdnv(tvb, offset+1, &bytecount);
if (len < 0)
return 0;
return bytecount+1;
}
/* This probably isn't a TCPCL/Bundle packet, so just stop dissection */
return -1;
}
static int
dissect_tcpcl_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
guint8 conv_hdr;
guint8 refuse_bundle_hdr;
int offset = 0;
int sdnv_length, segment_length, convergence_hdr_size;
proto_item *ci, *sub_item;
proto_tree *conv_proto_tree, *conv_tree, *sub_tree;
fragment_head *frag_msg;
tvbuff_t *new_tvb;
gboolean more_frags;
int processed_length = 0;
const gchar* col_text;
gboolean bundle_in_col_info;
static guint32 frag_id = 0;
static guint32 last_frame = 0;
static int last_raw_offset = 0;
if (last_frame != pinfo->fd->num || tvb_raw_offset(tvb) < last_raw_offset)
frag_id = 0;
last_frame = pinfo->fd->num;
last_raw_offset = tvb_raw_offset(tvb);
col_set_str(pinfo->cinfo, COL_PROTOCOL, "TCPCL");
col_clear(pinfo->cinfo,COL_INFO); /* Clear out stuff in the info column */
col_text = col_get_text(pinfo->cinfo, COL_INFO);
bundle_in_col_info = (col_text && strstr(col_text, " > "));
ci = proto_tree_add_item(tree, proto_tcp_conv, tvb, offset, -1, ENC_NA);
conv_proto_tree = proto_item_add_subtree(ci, ett_tcp_conv);
conv_tree = proto_tree_add_subtree(conv_proto_tree, tvb, 0, -1, ett_tcp_conv_hdr, NULL, "TCP Convergence Header");
conv_hdr = tvb_get_guint8(tvb, offset);
proto_tree_add_item(conv_tree, hf_tcp_convergence_pkt_type, tvb, offset, 1, ENC_BIG_ENDIAN);
col_add_str(pinfo->cinfo, COL_INFO, val_to_str_const((conv_hdr>>4)&0xF, packet_type_vals, "Unknown"));
switch (conv_hdr & TCP_CONVERGENCE_TYPE_MASK)
{
case TCP_CONVERGENCE_DATA_SEGMENT:
sub_item = proto_tree_add_item(conv_tree, hf_tcp_convergence_data_procflags, tvb,
offset, 1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(sub_item, ett_conv_flags);
proto_tree_add_item(sub_tree, hf_tcp_convergence_data_procflags_start,
tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_tcp_convergence_data_procflags_end,
tvb, offset, 1, ENC_BIG_ENDIAN);
/* Only Start and End flags (bits 0 & 1) are valid in Data Segment */
if ((conv_hdr & ~(TCP_CONVERGENCE_TYPE_MASK | TCP_CONVERGENCE_DATA_FLAGS)) != 0) {
expert_add_info(pinfo, sub_item, &ei_tcp_convergence_data_flags);
}
segment_length = evaluate_sdnv(tvb, 1, &sdnv_length);
sub_item = proto_tree_add_int(conv_tree, hf_tcp_convergence_data_segment_length, tvb, 1, sdnv_length, segment_length);
if (segment_length < 0) {
expert_add_info(pinfo, sub_item, &ei_tcp_convergence_segment_length);
return 1;
}
convergence_hdr_size = sdnv_length + 1;
/*
* 1/11/2006 - If I got here, I should have a complete convergence layer
* "segment" beginning at frame_offset. However that might not be a
* complete bundle. Or there might be a complete bundle plus one or more
* additional convergence layer headers.
*/
new_tvb = NULL;
sub_tree = NULL;
if ((conv_hdr & TCP_CONVERGENCE_DATA_END_FLAG) == TCP_CONVERGENCE_DATA_END_FLAG) {
more_frags = FALSE;
}
else {
more_frags = TRUE;
}
frag_msg = fragment_add_seq_next(&msg_reassembly_table,
tvb, offset + convergence_hdr_size,
pinfo, frag_id, data,
segment_length, more_frags);
if (!more_frags) ++frag_id;
processed_length = convergence_hdr_size + segment_length;
if (frag_msg && !more_frags) {
int save_fd_head_layer = frag_msg->reas_in_layer_num;
frag_msg->reas_in_layer_num = pinfo->curr_layer_num;
new_tvb = process_reassembled_data(tvb, offset + convergence_hdr_size,
pinfo, "Reassembled DTN", frag_msg,
&msg_frag_items, NULL,
proto_tree_get_parent_tree(tree)
);
frag_msg->reas_in_layer_num = save_fd_head_layer;
}
if (new_tvb) {
if (0 == call_dissector_with_data(bundle_handle, new_tvb, pinfo, sub_tree, data)) {
/*Couldn't parse bundle, treat as raw data */
call_data_dissector(new_tvb, pinfo, sub_tree);
return tvb_captured_length(tvb);
}
}
else {
/*
* If there are 2 segments, the second of which is very short, this
* gets displayed instead of the usual Source EID/Destination EID in
* the Bundle Dissection frame. If these statements are left out entirely,
* nothing is displayed, i.e., there seems to be no way to get the
* Source/Destination in the 2-segment case. I'll leave it in because I
* think it is informative in the multi-segment case although confusing in the
* 2-segment case.
*/
col_add_str(pinfo->cinfo, COL_INFO, "[Bundle TCPCL Segment]");
}
break;
case TCP_CONVERGENCE_ACK_SEGMENT:
if (bundle_in_col_info) {
if (!strstr(col_text, ", TCPL ACK")) {
col_add_str(pinfo->cinfo, COL_INFO, ", TCPL ACK Segment(s)");
}
} else {
col_set_str(pinfo->cinfo, COL_INFO, "TCPL ACK Segment(s)");
}
segment_length = evaluate_sdnv(tvb, offset+1, &sdnv_length);
sub_item = proto_tree_add_int(conv_tree, hf_tcp_convergence_ack_length, tvb, offset+1, sdnv_length, segment_length);
if (segment_length < 0) {
expert_add_info(pinfo, sub_item, &ei_tcp_convergence_ack_length);
processed_length = tvb_captured_length(tvb);
} else {
processed_length = sdnv_length + 1;
}
break;
case TCP_CONVERGENCE_KEEP_ALIVE:
if (bundle_in_col_info) {
if (!strstr(col_text, ", TCPL KEEPALIVE")) {
col_add_str(pinfo->cinfo, COL_INFO, ", TCPL KEEPALIVE Segment");
}
} else {
col_set_str(pinfo->cinfo, COL_INFO, "TCPL KEEPALIVE Segment");
}
/*No valid flags in Keep Alive*/
processed_length = 1;
break;
case TCP_CONVERGENCE_SHUTDOWN:
if (bundle_in_col_info) {
if (!strstr(col_text, ", TCPL SHUTDOWN")) {
col_add_str(pinfo->cinfo, COL_INFO, ", TCPL SHUTDOWN Segment");
}
} else {
col_set_str(pinfo->cinfo, COL_INFO, "TCPL SHUTDOWN Segment");
}
/* Add tree for Shutdown Flags */
sub_item = proto_tree_add_item(conv_tree, hf_tcp_convergence_shutdown_flags, tvb,
offset, 1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(sub_item, ett_shutdown_flags);
proto_tree_add_item(sub_tree, hf_tcp_convergence_shutdown_flags_reason,
tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sub_tree, hf_tcp_convergence_shutdown_flags_delay,
tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
if (conv_hdr & TCP_CONVERGENCE_SHUTDOWN_REASON) {
proto_tree_add_item(conv_tree,
hf_tcp_convergence_shutdown_reason, tvb,
offset, 1, ENC_BIG_ENDIAN);
offset += 1;
}
if (conv_hdr & TCP_CONVERGENCE_SHUTDOWN_DELAY) {
proto_tree_add_item(conv_tree,
hf_tcp_convergence_shutdown_delay, tvb,
offset, 2, ENC_BIG_ENDIAN);
}
break;
case TCP_CONVERGENCE_REFUSE_BUNDLE:
if (bundle_in_col_info) {
if (!strstr(col_text, ", TCPL REFUSE")) {
col_add_str(pinfo->cinfo, COL_INFO, ", TCPL REFUSE_BUNDLE Segment");
}
} else {
col_set_str(pinfo->cinfo, COL_INFO, "TCPL REFUSE_BUNDLE Segment");
}
refuse_bundle_hdr = tvb_get_guint8(tvb, offset);
proto_tree_add_item(conv_tree, hf_dtn_refuse_bundle_reason_code, tvb, offset, 1, ENC_BIG_ENDIAN);
col_add_str(pinfo->cinfo, COL_INFO, val_to_str_const((refuse_bundle_hdr>>4)&0xF, refuse_bundle_reason_code, "Unknown"));
/*No valid flags*/
processed_length = tvb_captured_length(tvb);
break;
}
return processed_length;
}
static int
dissect_tcpcl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
guint8 conv_hdr;
int offset, bytecount;
int processed_length;
/* Make sure we have a convergence header byte */
if (!tvb_bytes_exist(tvb, 0, 1))
return 0;
conv_hdr = tvb_get_guint8(tvb, 0);
switch (conv_hdr & TCP_CONVERGENCE_TYPE_MASK)
{
case TCP_CONVERGENCE_DATA_SEGMENT:
case TCP_CONVERGENCE_ACK_SEGMENT:
/* ensure sdnv */
offset = 1;
bytecount = 1;
if (!tvb_bytes_exist(tvb, offset, 1)) {
pinfo->desegment_offset = 0;
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
return 0;
}
while (tvb_get_guint8(tvb, offset) & ~SDNV_MASK) {
if (bytecount > (int)sizeof(int)) {
/* invalid length field */
return 0;
}
bytecount++;
offset++;
if (!tvb_bytes_exist(tvb, offset, 1)) {
pinfo->desegment_offset = 0;
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
return 0;
}
}
break;
case TCP_CONVERGENCE_KEEP_ALIVE:
case TCP_CONVERGENCE_REFUSE_BUNDLE:
/* always 1 byte */
break;
case TCP_CONVERGENCE_SHUTDOWN:
if ((conv_hdr &
~(TCP_CONVERGENCE_TYPE_MASK | TCP_CONVERGENCE_SHUTDOWN_FLAGS)) != 0) {
/* Not for us */
return 0;
}
break;
default:
if (conv_hdr == (guint8)magic[0]) {
if (!tvb_bytes_exist(tvb, 0, 4) || tvb_memeql(tvb, 0, magic, 4)) {
/* Not for us */
return 0;
}
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 8, get_dtn_contact_header_len, dissect_dtn_contact_header, data);
return tvb_captured_length(tvb);
}
/* Not for us */
return 0;
};
processed_length = get_tcpcl_pdu_len(pinfo, tvb, 0, data);
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 1, get_tcpcl_pdu_len, dissect_tcpcl_pdu, data);
return processed_length;
}
void
proto_register_tcpclv3(void)
{
static hf_register_info hf_tcpcl[] = {
{&hf_tcp_convergence_pkt_type,
{"Pkt Type", "tcpcl.pkt_type",
FT_UINT8, BASE_DEC, VALS(packet_type_vals), 0xF0, NULL, HFILL}
},
{&hf_dtn_refuse_bundle_reason_code,
{"Reason-Code", "tcpcl.refuse.reason_code",
FT_UINT8, BASE_DEC, VALS(refuse_bundle_reason_code), 0x0F, NULL, HFILL}
},
{&hf_tcp_convergence_data_procflags,
{"TCP Convergence Data Flags", "tcpcl.data.proc.flag",
FT_UINT8, BASE_HEX, NULL, TCP_CONVERGENCE_DATA_FLAGS, NULL, HFILL}
},
{&hf_tcp_convergence_data_procflags_start,
{"Segment contains start of bundle", "tcpcl.data.proc.start",
FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_DATA_START_FLAG, NULL, HFILL}
},
{&hf_tcp_convergence_data_procflags_end,
{"Segment contains end of Bundle", "tcpcl.data.proc.end",
FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_DATA_END_FLAG, NULL, HFILL}
},
{&hf_tcp_convergence_data_segment_length,
{"Segment Length", "tcpcl.data.length",
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_tcp_convergence_shutdown_flags,
{"TCP Convergence Shutdown Flags", "tcpcl.shutdown.flags",
FT_UINT8, BASE_HEX, NULL, TCP_CONVERGENCE_SHUTDOWN_FLAGS, NULL, HFILL}
},
{&hf_tcp_convergence_shutdown_flags_reason,
{"Shutdown includes Reason Code", "tcpcl.shutdown.reason.flag",
FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_SHUTDOWN_REASON, NULL, HFILL}
},
{&hf_tcp_convergence_shutdown_flags_delay,
{"Shutdown includes Reconnection Delay", "tcpcl.shutdown.delay.flag",
FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_SHUTDOWN_DELAY, NULL, HFILL}
},
{&hf_tcp_convergence_shutdown_reason,
{"Shutdown Reason Code", "tcpcl.shutdown.reason",
FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_tcp_convergence_shutdown_delay,
{"Shutdown Reconnection Delay", "tcpcl.shutdown.delay",
FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_tcp_convergence_ack_length,
{"Ack Length", "tcpcl.ack.length",
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_contact_hdr_version,
{"Version", "tcpcl.contact_hdr.version",
FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_contact_hdr_flags,
{"Flags", "tcpcl.contact_hdr.flags",
FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
},
{&hf_contact_hdr_flags_ack_req,
{"Bundle Acks Requested", "tcpcl.contact_hdr.flags.ackreq",
FT_BOOLEAN, 8, NULL, TCP_CONV_BUNDLE_ACK_FLAG, NULL, HFILL}
},
{&hf_contact_hdr_flags_frag_enable,
{"Reactive Fragmentation Enabled", "tcpcl.contact_hdr.flags.fragen",
FT_BOOLEAN, 8, NULL, TCP_CONV_REACTIVE_FRAG_FLAG, NULL, HFILL}
},
{&hf_contact_hdr_flags_nak,
{"Support Negative Acknowledgements", "tcpcl.contact_hdr.flags.nak",
FT_BOOLEAN, 8, NULL, TCP_CONV_CONNECTOR_RCVR_FLAG, NULL, HFILL}
},
{&hf_contact_hdr_keep_alive,
{"Keep Alive", "tcpcl.contact_hdr.keep_alive",
FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_contact_hdr_magic,
{"Magic", "tcpcl.contact_hdr.magic",
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
},
{&hf_contact_hdr_local_eid,
{"Local EID", "tcpcl.contact_hdr.local_eid",
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
},
{&hf_contact_hdr_local_eid_length,
{"Local EID Length", "tcpcl.contact_hdr.local_eid_length",
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_msg_fragments,
{"Message Fragments", "tcpcl.msg.fragments",
FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
},
{&hf_msg_fragment,
{"Message Fragment", "tcpcl.msg.fragment",
FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
},
{&hf_msg_fragment_overlap,
{"Message fragment overlap", "tcpcl.msg.fragment.overlap",
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
},
{&hf_msg_fragment_overlap_conflicts,
{"Message fragment overlapping with conflicting data",
"tcpcl.msg.fragment.overlap.conflicts",
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
},
{&hf_msg_fragment_multiple_tails,
{"Message has multiple tails", "tcpcl.msg.fragment.multiple_tails",
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
},
{&hf_msg_fragment_too_long_fragment,
{"Message fragment too long", "tcpcl.msg.fragment.too_long_fragment",
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
},
{&hf_msg_fragment_error,
{"Message defragmentation error", "tcpcl.msg.fragment.error",
FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
},
{&hf_msg_fragment_count,
{"Message fragment count", "tcpcl.msg.fragment.count",
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_msg_reassembled_in,
{"Reassembled in", "tcpcl.msg.reassembled.in",
FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
},
{&hf_msg_reassembled_length,
{"Reassembled DTN length", "tcpcl.msg.reassembled.length",
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
};
static gint *ett_tcpcl[] = {
&ett_tcp_conv,
&ett_tcp_conv_hdr,
&ett_conv_flags,
&ett_contact_hdr_flags,
&ett_shutdown_flags,
&ett_msg_fragment,
&ett_msg_fragments,
};
static ei_register_info ei_tcpcl[] = {
{ &ei_tcp_convergence_data_flags,
{ "tcpcl.data.flags.invalid", PI_PROTOCOL, PI_WARN, "Invalid TCP CL Data Segment Flags", EXPFILL }
},
{ &ei_tcp_convergence_segment_length,
{ "tcpcl.data.length.invalid", PI_PROTOCOL, PI_ERROR, "Invalid Data Length", EXPFILL }
},
{ &ei_tcp_convergence_ack_length,
{ "tcpcl.ack.length.error", PI_PROTOCOL, PI_WARN, "Ack Length: Error", EXPFILL }
},
};
expert_module_t *expert_tcpcl;
proto_tcp_conv = proto_register_protocol ("DTN TCP Convergence Layer Protocol", "TCPCL", "tcpcl");
proto_register_field_array(proto_tcp_conv, hf_tcpcl, array_length(hf_tcpcl));
proto_register_subtree_array(ett_tcpcl, array_length(ett_tcpcl));
expert_tcpcl = expert_register_protocol(proto_tcp_conv);
expert_register_field_array(expert_tcpcl, ei_tcpcl, array_length(ei_tcpcl));
reassembly_table_register(&msg_reassembly_table,
&addresses_reassembly_table_functions);
}
void
proto_reg_handoff_tcpclv3(void)
{
dissector_handle_t tcpcl_handle;
bundle_handle = find_dissector("bundle");
tcpcl_handle = create_dissector_handle(dissect_tcpcl, proto_tcp_conv);
dissector_add_uint_with_preference("tcp.port", BUNDLE_PORT, tcpcl_handle);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/