aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS4
-rw-r--r--epan/dissectors/Makefile.common2
-rw-r--r--epan/dissectors/packet-dtn.c2309
-rw-r--r--epan/dissectors/packet-dtn.h134
4 files changed, 2449 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
index bf1c492e83..e93fbb09e6 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2874,6 +2874,10 @@ Nathan Hartwell <nhartwell [AT] gmail.com> {
HP NIC Teaming dissector
}
+Don Chirieleison <donc [AT] mitre.org> {
+ DTN Bundle Protocol
+}
+
and by:
Pavel Roskin <proski [AT] gnu.org>
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
index 99e211849c..946fb6f650 100644
--- a/epan/dissectors/Makefile.common
+++ b/epan/dissectors/Makefile.common
@@ -398,6 +398,7 @@ DISSECTOR_SRC = \
packet-drda.c \
packet-dsi.c \
packet-dtls.c \
+ packet-dtn.c \
packet-dtp.c \
packet-dtpt.c \
packet-dua.c \
@@ -1010,6 +1011,7 @@ DISSECTOR_INCLUDES = \
packet-dns.h \
packet-dop.h \
packet-dsp.h \
+ packet-dtn.h \
packet-enip.h \
packet-erf.h \
packet-dvmrp.h \
diff --git a/epan/dissectors/packet-dtn.c b/epan/dissectors/packet-dtn.c
new file mode 100644
index 0000000000..2d7829520d
--- /dev/null
+++ b/epan/dissectors/packet-dtn.c
@@ -0,0 +1,2309 @@
+/*
+ * 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.
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/reassemble.h>
+#include "packet-dtn.h"
+
+void proto_reg_handoff_bundle(void);
+static void dissect_tcp_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static void dissect_udp_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static int dissect_complete_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static int dissect_primary_header(packet_info *pinfo, proto_tree *primary_tree, tvbuff_t *tvb);
+static int dissect_admin_record(proto_tree *primary_tree, tvbuff_t *tvb, int offset);
+static int evaluate_sdnv(tvbuff_t *tvb, int offset, int *bytecount);
+static int dissect_payload_header(proto_tree *tree, tvbuff_t *tvb, int bundle_offset, int *lastheader);
+static int display_metadata_block(proto_tree *tree, tvbuff_t *tvb, int bundle_offset, int *lastheader);
+static int dissect_contact_header(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *conv_tree, proto_item *conv_item);
+static int dissect_tcp_convergence_data_header(tvbuff_t *tvb, proto_tree *tree);
+static int dissect_version_5_primary_header(packet_info *pinfo,
+ proto_tree *primary_tree, tvbuff_t *tvb);
+static int add_sdnv_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id);
+static int add_dtn_time_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id);
+static int add_sdnv_time_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id);
+
+/* For Reassembling TCP Convergence Layer segments */
+static GHashTable *msg_fragment_table = NULL;
+static GHashTable *msg_reassembled_table = NULL;
+
+static int segment_length;
+static int bundle_header_length;
+static int bundle_header_dict_length;
+
+static char magic[] = {'d', 't', 'n', '!'};
+
+static int proto_bundle = -1;
+static int proto_tcp_conv = -1;
+static int hf_bundle_pdu_version = -1;
+
+/* TCP Convergence Header Variables */
+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;
+
+/* 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;
+
+/* 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_reassembled_in = -1;
+
+/* Primary Header Processing Flag Variables */
+static guint8 pri_hdr_procflags; /*This is global to allow processing Payload Header*/
+static int hf_bundle_procflags = -1;
+static int hf_bundle_procflags_fragment = -1;
+static int hf_bundle_procflags_admin = -1;
+static int hf_bundle_procflags_dont_fragment = -1;
+static int hf_bundle_procflags_cust_xfer_req = -1;
+static int hf_bundle_procflags_dest_singleton = -1;
+static int hf_bundle_procflags_application_ack = -1;
+
+/* Additions for Version 5 */
+static int hf_bundle_control_flags = -1;
+static int hf_bundle_procflags_general = -1;
+static int hf_bundle_procflags_cos = -1;
+static int hf_bundle_procflags_status = -1;
+
+/* Primary Header COS Flag Variables */
+static int hf_bundle_cosflags = -1;
+static int hf_bundle_cosflags_priority = -1;
+
+/* Primary Header Status Report Request Flag Variables */
+static int hf_bundle_srrflags = -1;
+static int hf_bundle_srrflags_report_receipt = -1;
+static int hf_bundle_srrflags_report_cust_accept = -1;
+static int hf_bundle_srrflags_report_forward = -1;
+static int hf_bundle_srrflags_report_delivery = -1;
+static int hf_bundle_srrflags_report_deletion = -1;
+static int hf_bundle_srrflags_report_ack = -1;
+
+/* Primary Header Length Fields*/
+static int hf_bundle_primary_header_len = -1;
+static int hf_bundle_dest_scheme_offset = -1;
+static int hf_bundle_dest_ssp_offset = -1;
+static int hf_bundle_source_scheme_offset = -1;
+static int hf_bundle_source_ssp_offset = -1;
+static int hf_bundle_report_scheme_offset = -1;
+static int hf_bundle_report_ssp_offset = -1;
+static int hf_bundle_cust_scheme_offset = -1;
+static int hf_bundle_cust_ssp_offset = -1;
+
+/* Dictionary EIDs */
+static int hf_bundle_dest_scheme = -1;
+static int hf_bundle_dest_ssp = -1;
+static int hf_bundle_source_scheme = -1;
+static int hf_bundle_source_ssp = -1;
+static int hf_bundle_report_scheme = -1;
+static int hf_bundle_report_ssp = -1;
+static int hf_bundle_custodian_scheme = -1;
+static int hf_bundle_custodian_ssp = -1;
+
+/* Remaining Primary Header Fields */
+static int hf_bundle_creation_timestamp = -1;
+static int hf_bundle_lifetime = -1;
+
+/* Secondary Header Processing Flag Variables */
+static int hf_bundle_payload_flags = -1;
+static int hf_bundle_payload_flags_replicate_hdr = -1;
+static int hf_bundle_payload_flags_xmit_report = -1;
+static int hf_bundle_payload_flags_discard_on_fail = -1;
+static int hf_bundle_payload_flags_last_header = -1;
+
+/* Block Processing Control Flag Variables (Version 5) */
+static int hf_block_control_flags = -1;
+static int hf_block_control_replicate = -1;
+static int hf_block_control_transmit_status = -1;
+static int hf_block_control_delete_bundle = -1;
+static int hf_block_control_last_block = -1;
+static int hf_block_control_discard_block = -1;
+static int hf_block_control_not_processed = -1;
+static int hf_block_control_eid_reference = -1;
+
+/* Administrative Record Variables */
+static int hf_bundle_admin_statflags = -1;
+static int hf_bundle_admin_rcvd = -1;
+static int hf_bundle_admin_accepted = -1;
+static int hf_bundle_admin_forwarded = -1;
+static int hf_bundle_admin_delivered = -1;
+static int hf_bundle_admin_deleted = -1;
+static int hf_bundle_admin_acked = -1;
+static int hf_bundle_admin_receipt_time = -1;
+static int hf_bundle_admin_accept_time = -1;
+static int hf_bundle_admin_forward_time = -1;
+static int hf_bundle_admin_delivery_time = -1;
+static int hf_bundle_admin_delete_time = -1;
+static int hf_bundle_admin_ack_time = -1;
+static int hf_bundle_admin_timestamp_copy = -1;
+static int hf_bundle_admin_signal_time = -1;
+
+/* Tree Node Variables */
+static gint ett_bundle = -1;
+static gint ett_tcp_conv = -1;
+static gint ett_tcp_conv_hdr = -1;
+static gint ett_conv_flags = -1;
+static gint ett_shutdown_flags = -1;
+static gint ett_msg_fragment = -1;
+static gint ett_msg_fragments = -1;
+static gint ett_bundle_hdr = -1;
+static gint ett_primary_hdr = -1;
+static gint ett_proc_flags = -1;
+static gint ett_gen_flags = -1;
+static gint ett_cos_flags = -1;
+static gint ett_srr_flags = -1;
+static gint ett_dictionary = -1;
+static gint ett_payload_hdr = -1;
+static gint ett_payload_flags = -1;
+static gint ett_block_flags = -1;
+static gint ett_contact_hdr_flags = -1;
+static gint ett_admin_record = -1;
+static gint ett_admin_rec_status = -1;
+static gint ett_metadata_hdr = -1;
+
+static uint bundle_tcp_port = 4556;
+static uint bundle_udp_port = 4556;
+
+static dissector_handle_t tcp_bundle_handle;
+static dissector_handle_t udp_bundle_handle;
+
+/* Needed to allow entering port option */
+static uint tcp_port = 0;
+static uint udp_port = 0;
+
+static const value_string custody_signal_reason_codes[] = {
+ {0x3, "Redundant Reception"},
+ {0x4, "Depleted Storage"},
+ {0x5, "Destination Endpoint ID Unintelligible"},
+ {0x6, "No Known Route to Destination"},
+ {0x7, "No Timely Contact with Next Node on Route"},
+ {0x8, "Header Unintelligible"},
+ {0, NULL}
+};
+
+static const value_string status_report_reason_codes[] = {
+ {0x1, "Lifetime Expired"},
+ {0x2, "Forwarded over Unidirectional Link"},
+ {0x3, "Transmission Cancelled"},
+ {0x4, "Depleted Storage"},
+ {0x5, "Destination Endpoint ID Unintelligible"},
+ {0x6, "No Known Route to Destination"},
+ {0x7, "No Timely Contact with Next Node on Route"},
+ {0x8, "Header Unintelligible"},
+ {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,
+ /*Reassembled in field*/
+ &hf_msg_reassembled_in,
+ /*Tag*/
+ "Message fragments"
+};
+
+
+static void dissect_tcp_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+
+ proto_item *ti = NULL;
+ proto_tree *bundle_tree = NULL;
+ proto_item *ci = NULL;
+ proto_tree *conv_proto_tree = NULL;
+ int buffer_size; /*Number of bytes in buffer that can be processed*/
+ int bundle_size = 0;
+ tvbuff_t *new_tvb;
+ guint8 conv_hdr;
+ int sdnv_length;
+ int frame_offset; /*To handle the case of > 1 bundle in an Ethernet Frame*/
+ int convergence_hdr_size;
+ int fixed;
+ char *sptr;
+
+ buffer_size = tvb_reported_length(tvb);
+ frame_offset = 0;
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Bundle");
+ col_clear(pinfo->cinfo,COL_INFO); /* Clear out stuff in the info column */
+
+ while(frame_offset < buffer_size) {
+
+ fragment_data *frag_msg = NULL;
+ gboolean more_frags = TRUE;
+
+ conv_hdr = tvb_get_guint8(tvb, frame_offset);
+ if((conv_hdr & TCP_CONVERGENCE_TYPE_MASK) == TCP_CONVERGENCE_DATA_SEGMENT) {
+
+ /* 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) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Invalid TCP CL Data Segment Flags");
+ return;
+ }
+ fixed = 1;
+ segment_length = evaluate_sdnv(tvb, fixed + frame_offset, &sdnv_length);
+ if(segment_length < 0) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Protocol Error (Length)");
+ return;
+ }
+ convergence_hdr_size = sdnv_length + fixed;
+ if((buffer_size - frame_offset - convergence_hdr_size) < segment_length) {
+ /*Segment not complete -- wait for the rest of it*/
+ pinfo->desegment_len =
+ segment_length - (buffer_size - frame_offset
+ - convergence_hdr_size);
+ pinfo->desegment_offset = frame_offset;
+ return;
+ }
+
+ /*
+ * 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;
+ if((conv_hdr & TCP_CONVERGENCE_DATA_END_FLAG) ==
+ TCP_CONVERGENCE_DATA_END_FLAG) {
+ more_frags = FALSE;
+ }
+ else {
+ more_frags = TRUE;
+ }
+ ci = proto_tree_add_item(tree, proto_tcp_conv, tvb,
+ frame_offset, -1, FALSE);
+ conv_proto_tree = proto_item_add_subtree(ci, ett_tcp_conv);
+ dissect_tcp_convergence_data_header(tvb, conv_proto_tree);
+
+ /*
+ * Note: The reassembled bundle will only include the first
+ * Convergence layer header.
+ */
+
+ frag_msg = fragment_add_seq_next(tvb, frame_offset + convergence_hdr_size,
+ pinfo, 0, msg_fragment_table,
+ msg_reassembled_table, segment_length,
+ more_frags);
+ if(frag_msg && !more_frags) {
+ ti = proto_tree_add_item(tree, proto_bundle, tvb,
+ frame_offset, -1, FALSE);
+ bundle_tree = proto_item_add_subtree(ti, ett_bundle);
+ new_tvb = process_reassembled_data(tvb,
+ frame_offset + convergence_hdr_size,
+ pinfo, "Reassembled Message", frag_msg,
+ &msg_frag_items, NULL, bundle_tree);
+ }
+ if(new_tvb){
+ bundle_size = dissect_complete_bundle(new_tvb, pinfo, bundle_tree);
+ if(bundle_size == 0) { /*Couldn't parse bundle*/
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Dissection Failed");
+ return; /*Give up*/
+ }
+ }
+ 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_fstr(pinfo->cinfo, COL_INFO, "[Reassembled Segment of a Bundle]");
+ }
+
+ /*
+ * If we could be sure that the current tvb buffer ended with the CL segment,
+ * we could return here. But the buffer could contain multiple complete setments
+ * or bundles or a bundle plus other CL messages. In order to process whatever
+ * follow the current segment, we have to continue through the buffer until
+ * frame_offset indicates everything in the buffer has been processed.
+ */
+
+ frame_offset += (segment_length + convergence_hdr_size);
+ }
+ else { /*Else this is not a Data Segment*/
+
+ proto_item *conv_item = NULL;
+ proto_tree *conv_tree = NULL;
+
+ if(frame_offset == 0) {
+ ci = proto_tree_add_item(tree, proto_tcp_conv, tvb,
+ frame_offset, -1, FALSE);
+ conv_proto_tree = proto_item_add_subtree(ci, ett_tcp_conv);
+ }
+
+ /*
+ * Other Convergence Layer messages are short; assume they won't need
+ * reassembly. Start with the Convergence Layer Tree.
+ */
+
+ conv_item = proto_tree_add_text(conv_proto_tree, tvb, frame_offset, -1,
+ "TCP Convergence Header");
+ conv_tree = proto_item_add_subtree(conv_item, ett_tcp_conv_hdr);
+
+ if(conv_hdr == magic[0]) {
+ sptr = (char *) tvb_get_ephemeral_string(tvb, frame_offset, 4);
+ if(!memcmp(sptr, magic, 4)){
+ dissect_contact_header(tvb, pinfo, conv_tree, conv_item);
+ return; /*Assumes Contact Header is alone in segment*/
+ }
+ }
+ if(conv_hdr == TCP_CONVERGENCE_ACK_SEGMENT) { /*No valid flags in Ack*/
+ int ack_length;
+ proto_item *ack_length_item = NULL;
+
+ proto_tree_add_text(conv_tree, tvb, frame_offset, 1, "Pkt Type: Ack");
+ fixed = 1;
+ ack_length = evaluate_sdnv(tvb, frame_offset + fixed, &sdnv_length);
+ ack_length_item = proto_tree_add_text(conv_tree, tvb,
+ frame_offset + fixed, sdnv_length, " ");
+ if(ack_length < 0) {
+ proto_item_set_text(ack_length_item, "Ack Length: Error");
+ return;
+ }
+ proto_item_set_text(ack_length_item, "Ack Length: %d", ack_length);
+ /*return (sdnv_length + fixed);*/
+ frame_offset += (sdnv_length + fixed);
+ proto_item_set_len(conv_item, sdnv_length + fixed);
+ }
+ else if(conv_hdr == TCP_CONVERGENCE_KEEP_ALIVE) { /*No valid flags in Keep Alive*/
+ proto_item_set_len(conv_item, 1);
+ proto_tree_add_text(conv_tree, tvb, frame_offset, 1, "Pkt Type: Keep Alive");
+ frame_offset += 1;
+ }
+ else if((conv_hdr & TCP_CONVERGENCE_TYPE_MASK) ==
+ TCP_CONVERGENCE_SHUTDOWN) {
+ proto_item *shutdown_flag_item = NULL;
+ proto_tree *shutdown_flag_tree = NULL;
+ guint8 shutdown_flags;
+ proto_item *shutdown_reason_item = NULL;
+ proto_item *shutdown_delay_item = NULL;
+ int field_length;
+
+ if((conv_hdr &
+ ~(TCP_CONVERGENCE_TYPE_MASK || TCP_CONVERGENCE_SHUTDOWN_FLAGS)) != 0) {
+ proto_tree_add_text(conv_tree, tvb, frame_offset,
+ -1, "Invalid Convergence Layer Shutdown Packet");
+ return;
+ }
+ proto_item_set_len(conv_item, 1);
+ proto_tree_add_text(conv_tree, tvb, 0, 1, "Pkt Type: Shutdown");
+
+ /* Add tree for Shutdown Flags */
+ shutdown_flags = conv_hdr;
+ shutdown_flag_item = proto_tree_add_item(conv_tree,
+ hf_tcp_convergence_shutdown_flags, tvb,
+ frame_offset, 1, FALSE);
+ shutdown_flag_tree = proto_item_add_subtree(shutdown_flag_item,
+ ett_shutdown_flags);
+ proto_tree_add_boolean(shutdown_flag_tree,
+ hf_tcp_convergence_shutdown_flags_reason,
+ tvb, frame_offset, 1, shutdown_flags);
+ proto_tree_add_boolean(shutdown_flag_tree,
+ hf_tcp_convergence_shutdown_flags_delay,
+ tvb, frame_offset, 1, shutdown_flags);
+
+ frame_offset += 1;
+ field_length = 1;
+ if(conv_hdr & TCP_CONVERGENCE_SHUTDOWN_REASON) {
+ shutdown_reason_item = proto_tree_add_item(conv_tree,
+ hf_tcp_convergence_shutdown_reason, tvb,
+ frame_offset, 1, FALSE);
+ frame_offset += 1;
+ field_length += 1;
+ }
+ if(conv_hdr & TCP_CONVERGENCE_SHUTDOWN_DELAY) {
+ shutdown_delay_item = proto_tree_add_item(conv_tree,
+ hf_tcp_convergence_shutdown_delay, tvb,
+ frame_offset, 2, FALSE);
+ frame_offset += 2;
+ field_length += 2;
+ }
+ proto_item_set_len(conv_item, field_length);
+ }
+ else if(conv_hdr == TCP_CONVERGENCE_REFUSE_BUNDLE) { /*No valid flags*/
+ proto_item_set_len(conv_item, 1);
+ proto_tree_add_text(conv_tree, tvb, frame_offset,
+ 1, "Pkt Type: Refuse Bundle");
+ frame_offset += 1;
+ }
+ else {
+ proto_tree_add_text(conv_tree, tvb, frame_offset,
+ -1, "Invalid/Partial Convergence Layer Packet");
+ return;
+ }
+ }
+ } /*end while()*/
+ return;
+}
+
+static void
+dissect_udp_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+
+ int buffer_size; /*Number of bytes in buffer that can be processed*/
+ int hdr_offset;
+ int lasthdrflag;
+ guint8 next_header_type;
+ proto_item *ti = NULL;
+ proto_tree *bundle_tree = NULL;
+ proto_item *primary_item = NULL;
+ proto_tree *primary_tree = NULL;
+
+ buffer_size = tvb_reported_length_remaining(tvb, 0);
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Bundle");
+ /* Clear out stuff in the info column */
+ col_clear(pinfo->cinfo,COL_INFO);
+
+ ti = proto_tree_add_item(tree, proto_bundle, tvb, 0, -1, FALSE);
+ bundle_tree = proto_item_add_subtree(ti, ett_bundle);
+
+ primary_item = proto_tree_add_text(bundle_tree, tvb, 0, -1,
+ "Primary Bundle Header");
+ primary_tree = proto_item_add_subtree(primary_item, ett_primary_hdr);
+ hdr_offset = dissect_primary_header(pinfo, primary_tree, tvb);
+ if(hdr_offset == 0) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Protocol Error");
+ return;
+ }
+ proto_item_set_len(primary_item, hdr_offset);
+
+ /*
+ * Done with primary header; decode the remaining headers
+ */
+
+ lasthdrflag = 0;
+ while((hdr_offset > 0) && (buffer_size > hdr_offset)) {
+ next_header_type = tvb_get_guint8(tvb, hdr_offset);
+ if(next_header_type == PAYLOAD_HEADER_TYPE) {
+ hdr_offset +=
+ dissect_payload_header(bundle_tree, tvb, hdr_offset, &lasthdrflag);
+ }
+ else { /*Assume anything else is a Metadata Block*/
+ hdr_offset += display_metadata_block(bundle_tree, tvb,
+ hdr_offset, &lasthdrflag);
+ }
+ if(hdr_offset == 0) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Protocol Error");
+ return;
+ }
+ if(lasthdrflag) {
+ return;
+ }
+ }
+ return;
+}
+
+static int
+dissect_tcp_convergence_data_header(tvbuff_t *tvb, proto_tree *tree)
+{
+ proto_item *conv_item = NULL;
+ proto_tree *conv_tree = NULL;
+ int buflen = tvb_length(tvb);
+ int sdnv_length;
+ int segment_length;
+ proto_item *conv_flag_item = NULL;
+ proto_tree *conv_flag_tree = NULL;
+ guint8 tcp_convergence_hdr_procflags;
+
+ conv_item = proto_tree_add_text(tree, tvb, 0, -1, "TCP Convergence Header");
+ conv_tree = proto_item_add_subtree(conv_item, ett_tcp_conv_hdr);
+ proto_tree_add_text(conv_tree, tvb, 0, 1, "Pkt Type: Data");
+
+ /* Add tree for Start/End bits */
+ tcp_convergence_hdr_procflags = tvb_get_guint8(tvb, 0);
+ conv_flag_item = proto_tree_add_item(conv_tree, hf_tcp_convergence_data_procflags, tvb,
+ 0, 1, FALSE);
+ conv_flag_tree = proto_item_add_subtree(conv_flag_item, ett_conv_flags);
+ proto_tree_add_boolean(conv_flag_tree, hf_tcp_convergence_data_procflags_start,
+ tvb, 0, 1, tcp_convergence_hdr_procflags);
+ proto_tree_add_boolean(conv_flag_tree, hf_tcp_convergence_data_procflags_end,
+ tvb, 0, 1, tcp_convergence_hdr_procflags);
+
+ segment_length = evaluate_sdnv(tvb, 1, &sdnv_length);
+ proto_tree_add_text(conv_tree, tvb, 1, sdnv_length, "Segment Length: %d", segment_length);
+ proto_item_set_len(conv_item, sdnv_length + 1);
+ return buflen;
+}
+
+/*
+ * Dissect a complete bundle starting at offset 0 in tvb. Return 0 on failure,
+ * otherwise the length of the bundle.
+ */
+
+static int
+dissect_complete_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *primary_item = NULL;
+ proto_tree *primary_tree = NULL;
+ int primary_header_size;
+ int payload_size = 0;
+ int lastheader = 0;
+ int offset;
+ guint8 next_header_type;
+
+ primary_item = proto_tree_add_text(tree, tvb, 0, -1,
+ "Primary Bundle Header");
+ primary_tree = proto_item_add_subtree(primary_item, ett_primary_hdr);
+ primary_header_size = dissect_primary_header(pinfo, primary_tree, tvb);
+ if(primary_header_size == 0) { /*Couldn't parse primary header*/
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Protocol Error");
+ return(0); /*Give up*/
+ }
+ proto_item_set_len(primary_item, primary_header_size);
+ offset = primary_header_size;
+
+ /*
+ * Done with primary header; decode the remaining headers
+ */
+
+ while(lastheader == 0) {
+ next_header_type = tvb_get_guint8(tvb, offset);
+ if(next_header_type == PAYLOAD_HEADER_TYPE) {
+
+ /*
+ * Returns payload size or 0 if can't parse payload
+ */
+
+ payload_size = dissect_payload_header(tree, tvb, offset, &lastheader);
+ }
+ else { /*Assume anything else is a Metadata Block*/
+ payload_size = display_metadata_block(tree, tvb,
+ offset, &lastheader);
+ }
+ if(payload_size == 0) { /*Payload header parse failed*/
+
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Dissection Failed");
+ return (0);
+ }
+ offset += payload_size;
+ }
+ return(offset);
+}
+
+/*
+ * This routine returns 0 if header decoding fails, otherwise the length of the primary
+ * header. The bundle starts right at the beginning of the tvbuff.
+ */
+
+static int
+dissect_primary_header(packet_info *pinfo, proto_tree *primary_tree, tvbuff_t *tvb)
+{
+ guint8 cosflags;
+ guint8 *dict_ptr;
+ guint8 *string_ptr;
+ gint string_length;
+ int offset; /*Total offset into frame (frame_offset + convergence layer size)*/
+ int sdnv_length;
+ int dest_scheme_offset, dest_ssp_offset, source_scheme_offset, source_ssp_offset;
+ int report_scheme_offset, report_ssp_offset, cust_scheme_offset, cust_ssp_offset;
+ int fragment_offset, total_adu_length;
+
+ guint8 srrflags;
+ guint8 version;
+ proto_item *srr_flag_item = NULL;
+ proto_tree *srr_flag_tree = NULL;
+
+ proto_item *proc_flag_item = NULL;
+ proto_tree *proc_flag_tree = NULL;
+ proto_item *cos_flag_item = NULL;
+ proto_tree *cos_flag_tree = NULL;
+ proto_item *hdr_length_item = NULL;
+ proto_item *dict_length_item = NULL;
+ proto_item *dict_item = NULL;
+ proto_tree *dict_tree = NULL;
+ proto_item *dest_item = NULL;
+ proto_item *source_scheme_item = NULL;
+ proto_item *source_item = NULL;
+ proto_item *rpt_scheme_item = NULL;
+ proto_item *rpt_item = NULL;
+ proto_item *cust_scheme_item = NULL;
+ proto_item *cust_item = NULL;
+
+ offset = 0;
+
+ version = tvb_get_guint8(tvb, offset);
+ /* Primary Header Version */
+ if((version != 4) && (version != 5) && (version != 6)) {
+ proto_tree_add_text(primary_tree, tvb, offset, 1, "Invalid Version Number");
+ return 0;
+ }
+ proto_tree_add_item(primary_tree, hf_bundle_pdu_version, tvb, offset, 1, FALSE);
+ if((version == 5) || (version == 6)) {
+ return dissect_version_5_primary_header(pinfo, primary_tree, tvb);
+ }
+
+ /* Primary Header Processing Flags */
+ ++offset;
+ pri_hdr_procflags = tvb_get_guint8(tvb, offset);
+ proc_flag_item = proto_tree_add_item(primary_tree, hf_bundle_procflags, tvb,
+ offset, 1, FALSE);
+ proc_flag_tree = proto_item_add_subtree(proc_flag_item, ett_proc_flags);
+ proto_tree_add_boolean(proc_flag_tree, hf_bundle_procflags_fragment,
+ tvb, offset, 1, pri_hdr_procflags);
+ proto_tree_add_boolean(proc_flag_tree, hf_bundle_procflags_admin,
+ tvb, offset, 1, pri_hdr_procflags);
+ proto_tree_add_boolean(proc_flag_tree, hf_bundle_procflags_dont_fragment,
+ tvb, offset, 1, pri_hdr_procflags);
+ proto_tree_add_boolean(proc_flag_tree, hf_bundle_procflags_cust_xfer_req,
+ tvb, offset, 1, pri_hdr_procflags);
+ proto_tree_add_boolean(proc_flag_tree, hf_bundle_procflags_dest_singleton,
+ tvb, offset, 1, pri_hdr_procflags);
+
+ /* Primary Header COS Flags */
+ ++offset;
+ cosflags = tvb_get_guint8(tvb, offset);
+ cos_flag_item = proto_tree_add_item(primary_tree, hf_bundle_cosflags, tvb,
+ offset, 1, FALSE);
+ cos_flag_tree = proto_item_add_subtree(cos_flag_item, ett_cos_flags);
+ proto_tree_add_uint(cos_flag_tree, hf_bundle_cosflags_priority,
+ tvb, offset, 1, cosflags);
+ /* Status Report Request Flags */
+ ++offset;
+ srrflags = tvb_get_guint8(tvb, offset);
+ srr_flag_item = proto_tree_add_item(primary_tree, hf_bundle_srrflags, tvb,
+ offset, 1, FALSE);
+ srr_flag_tree = proto_item_add_subtree(srr_flag_item, ett_srr_flags);
+
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_receipt,
+ tvb, offset, 1, srrflags);
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_cust_accept,
+ tvb, offset, 1, srrflags);
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_forward,
+ tvb, offset, 1, srrflags);
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_delivery,
+ tvb, offset, 1, srrflags);
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_deletion,
+ tvb, offset, 1, srrflags);
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_ack,
+ tvb, offset, 1, srrflags);
+ ++offset;
+ bundle_header_length = evaluate_sdnv(tvb, offset, &sdnv_length);
+ hdr_length_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if(bundle_header_length < 0) {
+ proto_item_set_text(hdr_length_item, "Bundle Header Length: Error");
+ return 0;
+ }
+ proto_item_set_text(hdr_length_item,
+ "Bundle Header Length: %d", bundle_header_length);
+ tvb_ensure_bytes_exist(tvb, offset + sdnv_length, bundle_header_length);
+ offset += sdnv_length;
+
+ /*
+ * Pick up offsets into dictionary (8 of them)
+ */
+
+ dest_scheme_offset = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(primary_tree, hf_bundle_dest_scheme_offset,
+ tvb, offset, 2, FALSE);
+ offset += 2;
+
+ dest_ssp_offset = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(primary_tree, hf_bundle_dest_ssp_offset,
+ tvb, offset, 2, FALSE);
+ offset += 2;
+
+ source_scheme_offset = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(primary_tree, hf_bundle_source_scheme_offset,
+ tvb, offset, 2, FALSE);
+ offset += 2;
+
+ source_ssp_offset = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(primary_tree, hf_bundle_source_ssp_offset,
+ tvb, offset, 2, FALSE);
+ offset += 2;
+
+ report_scheme_offset = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(primary_tree, hf_bundle_report_scheme_offset,
+ tvb, offset, 2, FALSE);
+ offset += 2;
+
+ report_ssp_offset = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(primary_tree, hf_bundle_report_ssp_offset,
+ tvb, offset, 2, FALSE);
+ offset += 2;
+
+ cust_scheme_offset = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(primary_tree, hf_bundle_cust_scheme_offset,
+ tvb, offset, 2, FALSE);
+ offset += 2;
+
+ cust_ssp_offset = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(primary_tree, hf_bundle_cust_ssp_offset,
+ tvb, offset, 2, FALSE);
+ offset += 2;
+
+ proto_tree_add_item(primary_tree, hf_bundle_creation_timestamp,
+ tvb, offset, 8, FALSE);
+ offset += 8;
+
+ proto_tree_add_item(primary_tree, hf_bundle_lifetime, tvb, offset, 4, FALSE);
+ offset += 4;
+
+ bundle_header_dict_length = evaluate_sdnv(tvb, offset, &sdnv_length);
+ dict_length_item = proto_tree_add_text(primary_tree,
+ tvb, offset, sdnv_length, " ");
+ if(bundle_header_dict_length < 0) {
+ proto_item_set_text(dict_length_item, "Dictionary Length: Error");
+ return 0;
+ }
+ proto_item_set_text(dict_length_item, "Dictionary Length: %d",
+ bundle_header_dict_length);
+ offset += sdnv_length;
+ tvb_ensure_bytes_exist(tvb, offset, bundle_header_dict_length);
+
+ /*
+ * Pull out stuff from the dictionary
+ */
+
+ dict_item = proto_tree_add_text(primary_tree, tvb, offset,
+ bundle_header_dict_length, "Dictionary");
+ dict_tree = proto_item_add_subtree(dict_item, ett_dictionary);
+ dict_ptr = (guint8 *) tvb_get_ptr(tvb, offset, bundle_header_dict_length);
+
+ /*
+ * This pointer can be made to address outside the packet boundaries so we
+ * need to check for improperly formatted strings (no null termination).
+ */
+
+ /*
+ * Destination info
+ */
+
+ string_ptr = tvb_get_ephemeral_stringz(tvb, offset + dest_scheme_offset, &string_length);
+
+ proto_tree_add_text(dict_tree, tvb, offset + dest_scheme_offset,
+ strlen((char *) (dict_ptr + dest_scheme_offset)),
+ "Destination Scheme: %s", string_ptr);
+ string_ptr = tvb_get_ephemeral_stringz(tvb, offset + dest_ssp_offset, &string_length);
+ dest_item = proto_tree_add_text(dict_tree, tvb, offset + dest_ssp_offset,
+ strlen((char *) (dict_ptr + dest_ssp_offset)), " ");
+ proto_item_set_text(dest_item, "Destination: %s", string_ptr);
+
+ /*
+ * Source info
+ */
+
+ string_ptr = tvb_get_ephemeral_stringz(tvb,
+ offset + source_scheme_offset, &string_length);
+ source_scheme_item = proto_tree_add_text(dict_tree, tvb, offset+source_scheme_offset,
+ strlen((char *) (dict_ptr + source_scheme_offset)), " ");
+ proto_item_set_text(source_scheme_item, "Source Scheme: %s", string_ptr);
+ string_ptr = tvb_get_ephemeral_stringz(tvb,
+ offset + source_ssp_offset, &string_length);
+ source_item = proto_tree_add_text(dict_tree, tvb, offset + source_ssp_offset,
+ strlen((char *) (dict_ptr + source_ssp_offset)), " ");
+ proto_item_set_text(source_item, "Source: %s", string_ptr);
+
+ /*
+ * Report to info
+ */
+
+ string_ptr = tvb_get_ephemeral_stringz(tvb,
+ offset + report_scheme_offset, &string_length);
+ rpt_scheme_item = proto_tree_add_text(dict_tree, tvb, offset + report_scheme_offset,
+ strlen((char *) (dict_ptr + report_scheme_offset)), " ");
+ proto_item_set_text(rpt_scheme_item, "Report To Scheme: %s", string_ptr);
+ string_ptr = tvb_get_ephemeral_stringz(tvb,
+ offset + report_ssp_offset, &string_length);
+ rpt_item = proto_tree_add_text(dict_tree, tvb, offset + report_ssp_offset,
+ strlen((char *) (dict_ptr + report_ssp_offset)), " ");
+ proto_item_set_text(rpt_item, "Report To: %s", string_ptr);
+
+ /*
+ * Custodian info
+ */
+
+ string_ptr = tvb_get_ephemeral_stringz(tvb,
+ offset + cust_scheme_offset, &string_length);
+ cust_scheme_item = proto_tree_add_text(dict_tree, tvb, offset + cust_scheme_offset,
+ strlen((char *) (dict_ptr + cust_scheme_offset)), " ");
+ proto_item_set_text(cust_scheme_item, "Custodian Scheme: %s", string_ptr);
+ string_ptr = tvb_get_ephemeral_stringz(tvb,
+ offset + cust_ssp_offset, &string_length);
+ cust_item = proto_tree_add_text(dict_tree, tvb, offset + cust_ssp_offset,
+ strlen((char *) (dict_ptr + cust_ssp_offset)), " ");
+ proto_item_set_text(cust_item, "Custodian: %s", string_ptr);
+
+ /*
+ * Add Source/Destination to INFO Field
+ */
+
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s:%s > %s:%s",
+ dict_ptr + source_scheme_offset, dict_ptr + source_ssp_offset,
+ dict_ptr + dest_scheme_offset, dict_ptr + dest_ssp_offset);
+ offset += bundle_header_dict_length; /*Skip over dictionary*/
+
+ /*
+ * Do this only if Fragment Flag is set
+ */
+
+ if(pri_hdr_procflags & BUNDLE_PROCFLAGS_FRAG_MASK) {
+ fragment_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
+ if(fragment_offset < 0) {
+ return 0;
+ }
+ proto_tree_add_text(primary_tree, tvb, offset, sdnv_length,
+ "Fragment Offset: %d", fragment_offset);
+ offset += sdnv_length;
+
+ total_adu_length = evaluate_sdnv(tvb, offset, &sdnv_length);
+ if(total_adu_length < 0) {
+ return 0;
+ }
+ proto_tree_add_text(primary_tree, tvb, offset, sdnv_length,
+ "Total Application Data Unit Length: %d", fragment_offset);
+ offset += sdnv_length;
+ }
+ return (offset);
+}
+
+
+/*
+ * This routine returns 0 if header decoding fails, otherwise the length of the primary
+ * header. The bundle starts right at the beginning of the tvbuff.
+ */
+
+static int
+dissect_version_5_primary_header(packet_info *pinfo,
+ proto_tree *primary_tree, tvbuff_t *tvb)
+{
+ int bundle_processing_control_flags;
+ guint8 cosflags;
+ guint8 *dict_ptr;
+ int offset; /*Total offset into frame (frame_offset + convergence layer size)*/
+ int sdnv_length;
+ int dest_scheme_offset, dest_ssp_offset, source_scheme_offset, source_ssp_offset;
+ int report_scheme_offset, report_ssp_offset, cust_scheme_offset, cust_ssp_offset;
+ int fragment_offset, total_adu_length;
+ int timestamp;
+ time_t time_since_2000;
+ int timestamp_sequence;
+ int lifetime;
+ char *time_string;
+ guint8 srrflags;
+ proto_item *srr_flag_item = NULL;
+ proto_tree *srr_flag_tree = NULL;
+ proto_item *gen_flag_item = NULL;
+ proto_tree *gen_flag_tree = NULL;
+
+ proto_item *proc_flag_item = NULL;
+ proto_tree *proc_flag_tree = NULL;
+ proto_item *cos_flag_item = NULL;
+ proto_item *cos_flag_value = NULL;
+ proto_tree *cos_flag_tree = NULL;
+ proto_item *hdr_length_item = NULL;
+ proto_item *dict_length_item = NULL;
+ proto_item *dict_item = NULL;
+ proto_tree *dict_tree = NULL;
+
+ proto_item *timestamp_item = NULL;
+ proto_item *timestamp_sequence_item = NULL;
+ proto_item *lifetime_item = NULL;
+ proto_item *dest_scheme_offset_item = NULL;
+ proto_item *dest_ssp_offset_item = NULL;
+ proto_item *source_scheme_offset_item = NULL;
+ proto_item *source_ssp_offset_item = NULL;
+ proto_item *report_scheme_offset_item = NULL;
+ proto_item *report_ssp_offset_item = NULL;
+ proto_item *cust_scheme_offset_item = NULL;
+ proto_item *cust_ssp_offset_item = NULL;
+
+ offset = 1; /*Already displayed Version Number*/
+ bundle_processing_control_flags = evaluate_sdnv(tvb, offset, &sdnv_length);
+
+ /* Primary Header Processing Flags */
+ pri_hdr_procflags = (guint8) (bundle_processing_control_flags & 0x7f);
+
+ proc_flag_item = proto_tree_add_item(primary_tree, hf_bundle_control_flags, tvb,
+ offset, sdnv_length, FALSE);
+ proc_flag_tree = proto_item_add_subtree(proc_flag_item, ett_proc_flags);
+
+ gen_flag_item = proto_tree_add_text(proc_flag_tree, tvb, offset,
+ sdnv_length, "General Flags");
+ gen_flag_tree = proto_item_add_subtree(gen_flag_item, ett_gen_flags);
+
+ proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_fragment,
+ tvb, offset, sdnv_length, pri_hdr_procflags);
+ proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_admin,
+ tvb, offset, sdnv_length, pri_hdr_procflags);
+ proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_dont_fragment,
+ tvb, offset, sdnv_length, pri_hdr_procflags);
+ proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_cust_xfer_req,
+ tvb, offset, sdnv_length, pri_hdr_procflags);
+ proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_dest_singleton,
+ tvb, offset, sdnv_length, pri_hdr_procflags);
+ proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_application_ack,
+ tvb, offset, sdnv_length, pri_hdr_procflags);
+
+ /* Primary Header COS Flags */
+ cosflags = (guint8) ((bundle_processing_control_flags >> 7) & 0x7f);
+ cos_flag_item = proto_tree_add_text(proc_flag_tree, tvb, offset,
+ sdnv_length, "Class of Service Flags");
+ cos_flag_tree = proto_item_add_subtree(cos_flag_item, ett_cos_flags);
+ if((cosflags & BUNDLE_COSFLAGS_PRIORITY_MASK) == BUNDLE_COSFLAGS_PRIORITY_BULK) {
+ cos_flag_value = proto_tree_add_text(cos_flag_tree, tvb, offset,
+ sdnv_length, "00 -- Priority = Bulk");
+ }
+ else if((cosflags & BUNDLE_COSFLAGS_PRIORITY_MASK) ==
+ BUNDLE_COSFLAGS_PRIORITY_NORMAL) {
+ cos_flag_value = proto_tree_add_text(cos_flag_tree, tvb, offset,
+ sdnv_length, "01 -- Priority = Normal");
+ }
+ else if((cosflags & BUNDLE_COSFLAGS_PRIORITY_MASK) ==
+ BUNDLE_COSFLAGS_PRIORITY_EXP) {
+ cos_flag_value = proto_tree_add_text(cos_flag_tree, tvb, offset,
+ sdnv_length, "10 -- Priority = Expedited");
+ }
+ else {
+ cos_flag_value = proto_tree_add_text(cos_flag_tree, tvb, offset,
+ sdnv_length, "11 -- Invalid (Reserved)");
+ return 0;
+ }
+
+ /* Status Report Request Flags */
+ srrflags = (guint8) ((bundle_processing_control_flags >> 14) & 0x7f);
+ srr_flag_item = proto_tree_add_text(proc_flag_tree, tvb, offset,
+ sdnv_length, "Status Report Request Flags");
+ srr_flag_tree = proto_item_add_subtree(srr_flag_item, ett_srr_flags);
+
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_receipt,
+ tvb, offset, sdnv_length, srrflags);
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_cust_accept,
+ tvb, offset, sdnv_length, srrflags);
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_forward,
+ tvb, offset, sdnv_length, srrflags);
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_delivery,
+ tvb, offset, sdnv_length, srrflags);
+ proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_deletion,
+ tvb, offset, sdnv_length, srrflags);
+ offset += sdnv_length;
+
+ bundle_header_length = evaluate_sdnv(tvb, offset, &sdnv_length);
+ hdr_length_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if(bundle_header_length < 0) {
+ proto_item_set_text(hdr_length_item, "Bundle Header Length: Error");
+ return 0;
+ }
+ proto_item_set_text(hdr_length_item,
+ "Bundle Header Length: %d", bundle_header_length);
+ tvb_ensure_bytes_exist(tvb, offset + sdnv_length, bundle_header_length);
+ offset += sdnv_length;
+
+ /*
+ * Pick up offsets into dictionary (8 of them). Do rough sanity check that SDNV
+ * hasn't told us to access way past the Primary Header.
+ */
+
+ dest_scheme_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
+ dest_scheme_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if((dest_scheme_offset < 0) || (dest_scheme_offset > bundle_header_length)) {
+ proto_item_set_text(dest_scheme_offset_item, "Destination Scheme Offset: Error");
+ return 0;
+ }
+ proto_item_set_text(dest_scheme_offset_item,
+ "Destination Scheme Offset: %d", dest_scheme_offset);
+ offset += sdnv_length;
+
+ dest_ssp_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
+ dest_ssp_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if((dest_ssp_offset < 0) || (dest_ssp_offset > bundle_header_length)) {
+ proto_item_set_text(dest_ssp_offset_item, "Destination SSP Offset: Error");
+ return 0;
+ }
+ proto_item_set_text(dest_ssp_offset_item,
+ "Destination SSP Offset: %d", dest_ssp_offset);
+ offset += sdnv_length;
+
+ source_scheme_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
+ source_scheme_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if((source_scheme_offset < 0) || (source_scheme_offset > bundle_header_length)) {
+ proto_item_set_text(source_scheme_offset_item, "Source Scheme Offset: Error");
+ return 0;
+ }
+ proto_item_set_text(source_scheme_offset_item,
+ "Source Scheme Offset: %d", source_scheme_offset);
+ offset += sdnv_length;
+
+ source_ssp_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
+ source_ssp_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if((source_ssp_offset < 0) || (source_ssp_offset > bundle_header_length)) {
+ proto_item_set_text(source_ssp_offset_item, "Source SSP Offset: Error");
+ return 0;
+ }
+ proto_item_set_text(source_ssp_offset_item,
+ "Source SSP Offset: %d", source_ssp_offset);
+ offset += sdnv_length;
+
+ report_scheme_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
+ report_scheme_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if((report_scheme_offset < 0) || (report_scheme_offset > bundle_header_length)) {
+ proto_item_set_text(report_scheme_offset_item, "Report Scheme Offset: Error");
+ return 0;
+ }
+ proto_item_set_text(report_scheme_offset_item,
+ "Report Scheme Offset: %d", report_scheme_offset);
+ offset += sdnv_length;
+
+ report_ssp_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
+ report_ssp_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if((report_ssp_offset < 0) || (report_ssp_offset > bundle_header_length)) {
+ proto_item_set_text(report_ssp_offset_item, "Report SSP Offset: Error");
+ return 0;
+ }
+ proto_item_set_text(report_ssp_offset_item,
+ "Report SSP Offset: %d", report_ssp_offset);
+ offset += sdnv_length;
+
+ cust_scheme_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
+ cust_scheme_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if((cust_scheme_offset < 0) || (cust_scheme_offset > bundle_header_length)) {
+ proto_item_set_text(cust_scheme_offset_item, "Custodian Scheme Offset: Error");
+ return 0;
+ }
+ proto_item_set_text(cust_scheme_offset_item,
+ "Custodian Scheme Offset: %d", cust_scheme_offset);
+ offset += sdnv_length;
+
+ cust_ssp_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
+ cust_ssp_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if((cust_ssp_offset < 0) || (cust_ssp_offset > bundle_header_length)) {
+ proto_item_set_text(cust_ssp_offset_item, "Custodian SSP Offset: Error");
+ return 0;
+ }
+ proto_item_set_text(cust_ssp_offset_item,
+ "Custodian SSP Offset: %d", cust_ssp_offset);
+ offset += sdnv_length;
+
+ timestamp = evaluate_sdnv(tvb, offset, &sdnv_length);
+ timestamp_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if(timestamp < 0) {
+ proto_item_set_text(timestamp_item, "Timestamp: Error");
+ return 0;
+ }
+ time_since_2000 = (time_t) (timestamp + 946684800);
+ time_string = ctime(&time_since_2000);
+ time_string[strlen(time_string) - 1] = 0; /*Remove Newline at enc*/
+ proto_item_set_text(timestamp_item,
+ "Timestamp: 0x%x [%s]", timestamp, time_string);
+ offset += sdnv_length;
+
+ timestamp_sequence = evaluate_sdnv(tvb, offset, &sdnv_length);
+ timestamp_sequence_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if(timestamp_sequence < 0) {
+ proto_item_set_text(timestamp_sequence_item, "Timestamp Sequence Number: Error");
+ return 0;
+ }
+ proto_item_set_text(timestamp_sequence_item,
+ "Timestamp Sequence Number: %d", timestamp_sequence);
+ offset += sdnv_length;
+
+ lifetime = evaluate_sdnv(tvb, offset, &sdnv_length);
+ lifetime_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
+ if(lifetime < 0) {
+ proto_item_set_text(lifetime_item, "Lifetime: Error");
+ return 0;
+ }
+ proto_item_set_text(lifetime_item, "Lifetime: %d", lifetime);
+ offset += sdnv_length;
+
+ bundle_header_dict_length = evaluate_sdnv(tvb, offset, &sdnv_length);
+ dict_length_item = proto_tree_add_text(primary_tree,
+ tvb, offset, sdnv_length, " ");
+ if(bundle_header_dict_length < 0) {
+ proto_item_set_text(dict_length_item, "Dictionary Length: Error");
+ return 0;
+ }
+ proto_item_set_text(dict_length_item, "Dictionary Length: %d",
+ bundle_header_dict_length);
+ offset += sdnv_length;
+ tvb_ensure_bytes_exist(tvb, offset, bundle_header_dict_length);
+
+ /*
+ * Pull out stuff from the dictionary
+ */
+
+ dict_item = proto_tree_add_text(primary_tree, tvb, offset,
+ bundle_header_dict_length, "Dictionary");
+ dict_tree = proto_item_add_subtree(dict_item, ett_dictionary);
+ dict_ptr = (guint8 *) tvb_get_ptr(tvb, offset, bundle_header_dict_length);
+
+ /*
+ * This pointer can be made to address outside the packet boundaries so we
+ * need to check for improperly formatted strings (no null termination).
+ */
+
+ /*
+ * Destination info
+ */
+
+ tvb_ensure_bytes_exist(tvb, offset, dest_scheme_offset);
+ proto_tree_add_item(dict_tree, hf_bundle_dest_scheme, tvb, offset + dest_scheme_offset,
+ strlen((char *) (dict_ptr + dest_scheme_offset)), FALSE);
+ tvb_ensure_bytes_exist(tvb, offset, dest_ssp_offset);
+ proto_tree_add_item(dict_tree, hf_bundle_dest_ssp, tvb, offset + dest_ssp_offset,
+ strlen((char *) (dict_ptr + dest_ssp_offset)), FALSE);
+
+ /*
+ * Destination info
+ */
+
+ tvb_ensure_bytes_exist(tvb, offset, source_scheme_offset);
+ proto_tree_add_item(dict_tree, hf_bundle_source_scheme, tvb, offset + source_scheme_offset,
+ strlen((char *) (dict_ptr + source_scheme_offset)), FALSE);
+ tvb_ensure_bytes_exist(tvb, offset, source_ssp_offset);
+ proto_tree_add_item(dict_tree, hf_bundle_source_ssp, tvb, offset + source_ssp_offset,
+ strlen((char *) (dict_ptr + source_ssp_offset)), FALSE);
+
+ /*
+ * Report to info
+ */
+
+ tvb_ensure_bytes_exist(tvb, offset, report_scheme_offset);
+ proto_tree_add_item(dict_tree, hf_bundle_report_scheme, tvb, offset + report_scheme_offset,
+ strlen((char *) (dict_ptr + report_scheme_offset)), FALSE);
+ tvb_ensure_bytes_exist(tvb, offset, report_ssp_offset);
+ proto_tree_add_item(dict_tree, hf_bundle_report_ssp, tvb, offset + report_ssp_offset,
+ strlen((char *) (dict_ptr + report_ssp_offset)), FALSE);
+
+ /*
+ * Custodian info
+ */
+
+ tvb_ensure_bytes_exist(tvb, offset, cust_scheme_offset);
+ proto_tree_add_item(dict_tree, hf_bundle_custodian_scheme, tvb, offset + cust_scheme_offset,
+ strlen((char *) (dict_ptr + cust_scheme_offset)), FALSE);
+
+ tvb_ensure_bytes_exist(tvb, offset, cust_ssp_offset);
+ proto_tree_add_item(dict_tree, hf_bundle_custodian_ssp, tvb, offset + cust_ssp_offset,
+ strlen((char *) (dict_ptr + cust_ssp_offset)), FALSE);
+
+ /*
+ * Add Source/Destination to INFO Field
+ */
+
+ if(check_col(pinfo->cinfo, COL_INFO)) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s:%s > %s:%s",
+ dict_ptr + source_scheme_offset, dict_ptr + source_ssp_offset,
+ dict_ptr + dest_scheme_offset, dict_ptr + dest_ssp_offset);
+ }
+ offset += bundle_header_dict_length; /*Skip over dictionary*/
+
+ /*
+ * Do this only if Fragment Flag is set
+ */
+
+ if(pri_hdr_procflags & BUNDLE_PROCFLAGS_FRAG_MASK) {
+ fragment_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
+ if(fragment_offset < 0) {
+ return 0;
+ }
+ proto_tree_add_text(primary_tree, tvb, offset, sdnv_length,
+ "Fragment Offset: %d", fragment_offset);
+ offset += sdnv_length;
+
+ total_adu_length = evaluate_sdnv(tvb, offset, &sdnv_length);
+ if(total_adu_length < 0) {
+ return 0;
+ }
+ proto_tree_add_text(primary_tree, tvb, offset, sdnv_length,
+ "Total Application Data Unit Length: %d", fragment_offset);
+ offset += sdnv_length;
+ }
+ return (offset);
+}
+
+/*
+ * bundle_offset is offset into this bundle where header starts.
+ * Return size of payload (including payload header) or 0 on failure.
+ */
+
+static int
+dissect_payload_header(proto_tree *tree, tvbuff_t *tvb, int offset, int *lastheader)
+{
+ proto_item *payload_item = NULL;
+ proto_tree *payload_tree = NULL;
+ proto_item *proc_flag_item = NULL;
+ proto_tree *proc_flag_tree = NULL;
+ proto_item *hdr_length_item = NULL;
+ proto_item *type_item = NULL;
+ guint8 procflags;
+ int sdnv_length;
+ int header_start;
+ int payload_length;
+
+ header_start = offset; /*Used to compute total payload length*/
+ payload_item = proto_tree_add_text(tree, tvb, offset, -1, "Payload Header");
+ payload_tree = proto_item_add_subtree(payload_item, ett_payload_hdr);
+
+ type_item = proto_tree_add_text(payload_tree, tvb, offset, 1, "Header Type: 1");
+ ++offset;
+
+ /* Add tree for processing flags */
+ /* This is really a SDNV but there are only 7 bits defined so leave it this way*/
+
+ if(hf_bundle_pdu_version == 4) {
+ procflags = tvb_get_guint8(tvb, offset);
+ if(procflags & HEADER_PROCFLAGS_LAST_HEADER) {
+ *lastheader = 1;
+ }
+ else {
+ *lastheader = 0;
+ }
+ proc_flag_item = proto_tree_add_item(payload_tree, hf_bundle_payload_flags, tvb,
+ offset, 1, FALSE);
+ proc_flag_tree = proto_item_add_subtree(proc_flag_item, ett_payload_flags);
+ proto_tree_add_boolean(proc_flag_tree, hf_bundle_payload_flags_replicate_hdr,
+ tvb, offset, 1, procflags);
+ proto_tree_add_boolean(proc_flag_tree, hf_bundle_payload_flags_xmit_report,
+ tvb, offset, 1, procflags);
+ proto_tree_add_boolean(proc_flag_tree, hf_bundle_payload_flags_discard_on_fail,
+ tvb, offset, 1, procflags);
+ proto_tree_add_boolean(proc_flag_tree, hf_bundle_payload_flags_last_header,
+ tvb, offset, 1, procflags);
+ ++offset;
+ }
+ else { /*Bundle Protocol Version 5*/
+ int control_flags;
+ proto_item *block_flag_item = NULL;
+ proto_tree *block_flag_tree = NULL;
+
+ control_flags = evaluate_sdnv(tvb, offset, &sdnv_length);
+ if(control_flags & BLOCK_CONTROL_LAST_BLOCK) {
+ *lastheader = 1;
+ }
+ else {
+ *lastheader = 0;
+ }
+ block_flag_item = proto_tree_add_item(payload_tree, hf_block_control_flags, tvb,
+ offset, sdnv_length, FALSE);
+ block_flag_tree = proto_item_add_subtree(block_flag_item, ett_block_flags);
+
+ proto_tree_add_boolean(block_flag_tree, hf_block_control_replicate,
+ tvb, offset, sdnv_length, control_flags);
+ proto_tree_add_boolean(block_flag_tree, hf_block_control_transmit_status,
+ tvb, offset, sdnv_length, control_flags);
+ proto_tree_add_boolean(block_flag_tree, hf_block_control_delete_bundle,
+ tvb, offset, sdnv_length, control_flags);
+ proto_tree_add_boolean(block_flag_tree, hf_block_control_last_block,
+ tvb, offset, sdnv_length, control_flags);
+ proto_tree_add_boolean(block_flag_tree, hf_block_control_discard_block,
+ tvb, offset, sdnv_length, control_flags);
+ proto_tree_add_boolean(block_flag_tree, hf_block_control_not_processed,
+ tvb, offset, sdnv_length, control_flags);
+ proto_tree_add_boolean(block_flag_tree, hf_block_control_eid_reference,
+ tvb, offset, sdnv_length, control_flags);
+ offset += sdnv_length;
+ }
+ payload_length = evaluate_sdnv(tvb, offset, &sdnv_length);
+ proto_item_set_len(payload_item, 2 + sdnv_length);
+ hdr_length_item = proto_tree_add_text(payload_tree, tvb, offset, sdnv_length, " ");
+ if(payload_length < 0) {
+ proto_item_set_text(hdr_length_item, "Payload Length: Error");
+ return 0;
+ }
+ proto_item_set_text(hdr_length_item, "Payload Length: %d", payload_length);
+
+ offset += sdnv_length;
+ if(pri_hdr_procflags & BUNDLE_PROCFLAGS_ADMIN_MASK) {
+ int admin_size;
+
+ /*
+ * XXXX - Have not allowed for admin record spanning multiple segments!
+ */
+
+ admin_size = dissect_admin_record(payload_tree, tvb, offset);
+ if(admin_size == 0) {
+ return 0;
+ }
+ }
+ return (payload_length + (offset - header_start));
+}
+
+/*
+ * Return the length of the Administrative Record or 0 if analysis fails.
+ */
+
+static int
+dissect_admin_record(proto_tree *primary_tree, tvbuff_t *tvb, int offset)
+{
+ proto_item *admin_record_item = NULL;
+ proto_tree *admin_record_tree = NULL;
+ proto_item *status_flag_item = NULL;
+ proto_tree *status_flag_tree = NULL;
+ proto_item *admin_record_type = NULL;
+ guint8 record_type;
+ guint8 status;
+ guint8 reason;
+ int record_size = 0;
+ int sdnv_length;
+ int endpoint_length;
+ guint8 *string_ptr;
+ int string_length;
+
+ admin_record_item = proto_tree_add_text(primary_tree, tvb, offset, -1,
+ "Administrative Record");
+ admin_record_tree = proto_item_add_subtree(admin_record_item, ett_admin_record);
+ record_type = tvb_get_guint8(tvb, offset);
+
+ if(record_type == (0x05 << 4)) {
+ proto_tree_add_text(admin_record_tree, tvb, offset, 1, "Announce Record (Contact)");
+ return 1; /*Special case for poxy TCP Convergence Layer Announce Bundle*/
+ }
+ if(record_type & ADMIN_REC_FLAGS_FRAGMENT) {
+ proto_tree_add_text(admin_record_tree, tvb, offset, 1, "Record is for a Fragment");
+ }
+ else {
+ proto_tree_add_text(admin_record_tree,
+ tvb, offset, 1, "Record is not for a Fragment");
+ }
+
+ switch((record_type >> 4) & 0xf)
+ {
+
+ case ADMIN_REC_TYPE_STATUS_REPORT:
+ admin_record_type = proto_tree_add_text(admin_record_tree, tvb, offset, 1,
+ "Administrative Record Type: Bundle Status Report");
+ ++record_size; ++offset;
+
+ /* Decode Bundle Status Report Flags */
+ status = tvb_get_guint8(tvb, offset);
+ status_flag_item = proto_tree_add_item(admin_record_tree,
+ hf_bundle_admin_statflags, tvb, offset, 1, FALSE);
+ status_flag_tree = proto_item_add_subtree(status_flag_item,
+ ett_admin_rec_status);
+ proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_rcvd,
+ tvb, offset, 1, status);
+ proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_accepted,
+ tvb, offset, 1, status);
+ proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_forwarded,
+ tvb, offset, 1, status);
+ proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_delivered,
+ tvb, offset, 1, status);
+ proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_deleted,
+ tvb, offset, 1, status);
+ proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_acked,
+ tvb, offset, 1, status);
+ ++record_size; ++offset;
+
+ reason = tvb_get_guint8(tvb, offset);
+ if(reason == 0) {
+ proto_tree_add_text(admin_record_tree, tvb, offset, 1,
+ "Reason Code: 0 (No Additional Information)");
+ }
+ else {
+ proto_tree_add_text(admin_record_tree, tvb, offset, 1,
+ "Reason Code: 0x%x (%s)", reason,
+ val_to_str(reason, status_report_reason_codes,
+ "Invalid"));
+ }
+ ++record_size; ++offset;
+ if(record_type & ADMIN_REC_FLAGS_FRAGMENT) {
+ sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
+ "Fragment Offset");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
+ "Fragment Length");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ }
+ if(status & ADMIN_STATUS_FLAGS_RECEIVED) {
+ sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Received Time");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ }
+ if(status & ADMIN_STATUS_FLAGS_ACCEPTED) {
+ sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Accepted Time");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ }
+ if(status & ADMIN_STATUS_FLAGS_FORWARDED) {
+ sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Forwarded Time");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ }
+ if(status & ADMIN_STATUS_FLAGS_DELIVERED) {
+ sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Delivered Time");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ }
+ if(status & ADMIN_STATUS_FLAGS_DELETED) {
+ sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Deleted Time");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ }
+ if(status & ADMIN_STATUS_FLAGS_ACKNOWLEDGED) {
+ sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Acknowledged Time");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ }
+
+ /* Get 2 SDNVs for Creation Timestamp */
+ sdnv_length = add_sdnv_time_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Creation Timestamp");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Creation Timestamp Sequence");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+
+ endpoint_length = evaluate_sdnv(tvb, offset, &sdnv_length);
+ if(endpoint_length < 0) {
+ return 0;
+ }
+ proto_tree_add_text(admin_record_tree, tvb, offset, sdnv_length,
+ "Endpoint Length: %d", endpoint_length);
+ offset += sdnv_length; record_size += sdnv_length;
+
+ /*
+ * Endpoint name may not be null terminated. This routine is supposed
+ * to add the null at the end of the string buffer.
+ */
+
+ string_ptr = tvb_get_ephemeral_string(tvb, offset, endpoint_length);
+ proto_tree_add_text(admin_record_tree, tvb, offset, endpoint_length,
+ "Bundle Endpoint ID: %s", string_ptr);
+ offset += endpoint_length; record_size += endpoint_length;
+
+ return record_size;
+
+ case ADMIN_REC_TYPE_CUSTODY_SIGNAL:
+ admin_record_type = proto_tree_add_text(admin_record_tree, tvb, offset, 1,
+ "Administrative Record Type: Custody Signal");
+ ++record_size; ++offset;
+
+ status = tvb_get_guint8(tvb, offset);
+ proto_tree_add_text(admin_record_tree, tvb, offset, 1,
+ "Custody Transfer Succeeded Flag: %d", (status >> 7) & 0x01);
+ if((status & ADMIN_REC_CUSTODY_REASON_MASK) == 0) {
+ proto_tree_add_text(admin_record_tree, tvb, offset, 1,
+ "Reason Code: 0 (No Additional Information)");
+ }
+ else {
+ proto_tree_add_text(admin_record_tree, tvb, offset, 1,
+ "Reason Code: 0x%x (%s)",
+ status & ADMIN_REC_CUSTODY_REASON_MASK,
+ val_to_str(status & ADMIN_REC_CUSTODY_REASON_MASK,
+ custody_signal_reason_codes, "Invalid"));
+ }
+ ++record_size; ++offset;
+ if(record_type & ADMIN_REC_FLAGS_FRAGMENT) {
+ sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
+ "Fragment Offset");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
+ "Fragment Length");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ }
+
+ /* Signal Time */
+ sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Signal Time");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+
+ /* Timestamp copy */
+ sdnv_length = add_sdnv_time_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Creation Timestamp");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+ sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
+ "Bundle Creation Timestamp Sequence");
+ if(sdnv_length <= 0) {
+ return 0;
+ }
+ offset += sdnv_length; record_size += sdnv_length;
+
+ endpoint_length = evaluate_sdnv(tvb, offset, &sdnv_length);
+ if(endpoint_length < 0) {
+ return 0;
+ }
+ proto_tree_add_text(admin_record_tree, tvb, offset, sdnv_length,
+ "Endpoint Length: %d", endpoint_length);
+ offset += sdnv_length; record_size += sdnv_length;
+ string_ptr = tvb_get_ephemeral_stringz(tvb, offset, &string_length);
+ proto_tree_add_text(admin_record_tree, tvb, offset, endpoint_length,
+ "Bundle Endpoint ID: %s", string_ptr);
+ offset += string_length; record_size += string_length;
+ return record_size;
+
+ } /* End Switch */
+
+ admin_record_type = proto_tree_add_text(admin_record_tree, tvb, offset, 1,
+ "Administrative Record Type: Unknown");
+ return 0;
+}
+
+/*
+ * Return length of contact header or 0 on failure
+ */
+
+static int
+dissect_contact_header(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *conv_tree, proto_item *conv_item)
+{
+ guint8 contact_hdr_flags;
+ proto_item *contact_hdr_flag_item = NULL;
+ proto_tree *contact_hdr_flag_tree = NULL;
+ proto_item *eid_item = NULL;
+ int eid_length;
+ int sdnv_length;
+ char *sptr;
+
+ /*
+ * I'm going to assume that if this is a contact header, the buffer
+ * contains the complete header and that there are no other packets
+ * in the buffer.
+ */
+
+ proto_tree_add_text(conv_tree, tvb, 0, 4, "Pkt Type: Contact Header");
+ proto_tree_add_item(conv_tree, hf_contact_hdr_version, tvb, 4, 1, FALSE);
+
+ /* Subtree to expand the bits in the Contact Header Flags */
+ contact_hdr_flags = tvb_get_guint8(tvb, 5);
+ contact_hdr_flag_item =
+ proto_tree_add_item(conv_tree, hf_contact_hdr_flags, tvb, 5, 1, FALSE);
+ contact_hdr_flag_tree =
+ proto_item_add_subtree(contact_hdr_flag_item, ett_contact_hdr_flags);
+ proto_tree_add_boolean(contact_hdr_flag_tree, hf_contact_hdr_flags_ack_req,
+ tvb, 5, 1, contact_hdr_flags);
+ proto_tree_add_boolean(contact_hdr_flag_tree, hf_contact_hdr_flags_frag_enable,
+ tvb, 5, 1, contact_hdr_flags);
+ proto_tree_add_boolean(contact_hdr_flag_tree, hf_contact_hdr_flags_nak,
+ tvb, 5, 1, contact_hdr_flags);
+ proto_tree_add_item(conv_tree, hf_contact_hdr_keep_alive, tvb, 6, 2, FALSE);
+
+ /*
+ * New format Contact header has length field followed by Bundle Header.
+ */
+
+ eid_length = evaluate_sdnv(tvb, 8, &sdnv_length);
+ if(eid_length < 0) {
+ if(check_col(pinfo->cinfo, COL_INFO)) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Protocol Error (Local EID Length)");
+ }
+ return 0;
+ }
+ proto_tree_add_text(conv_tree, tvb, 8, sdnv_length,
+ "Local EID Length: %d", eid_length);
+ proto_item_set_len(conv_item, sdnv_length + eid_length + 8);
+ eid_item = proto_tree_add_text(conv_tree, tvb, sdnv_length + 8, eid_length, " ");
+ sptr = (char *) tvb_get_ephemeral_string(tvb, sdnv_length + 8, eid_length);
+ proto_item_set_text(eid_item, "Local EID: %s", sptr);
+ return(sdnv_length + eid_length + 8);
+}
+
+static int
+display_metadata_block(proto_tree *tree, tvbuff_t *tvb, int offset, int *lastheader)
+{
+ proto_item *block_item = NULL;
+ proto_tree *block_tree = NULL;
+ proto_item *hdr_length_item = NULL;
+ proto_item *type_item = NULL;
+ int sdnv_length;
+ int header_start;
+ int block_length;
+ guint8 type;
+ int control_flags;
+ proto_item *block_flag_item = NULL;
+
+ type = tvb_get_guint8(tvb, offset);
+ header_start = offset; /*Used to compute total payload length*/
+ offset = 0;
+ block_item = proto_tree_add_text(tree, tvb,
+ header_start + offset, -1, "Metadata Block");
+ block_tree = proto_item_add_subtree(block_item, ett_metadata_hdr);
+
+ type_item = proto_tree_add_text(block_tree, tvb, header_start + offset, 1, " ");
+ proto_item_set_text(type_item, "Block Type: %d", type);
+ ++offset;
+
+ control_flags = evaluate_sdnv(tvb, header_start + offset, &sdnv_length);
+ if(control_flags & BLOCK_CONTROL_LAST_BLOCK) {
+ *lastheader = 1;
+ }
+ else {
+ *lastheader = 0;
+ }
+ block_flag_item = proto_tree_add_text(block_tree, tvb, header_start + offset, 1, " ");
+ proto_item_set_text(block_flag_item, "Block Flags: 0x%x", control_flags);
+ offset += sdnv_length;
+
+ block_length = evaluate_sdnv(tvb, header_start + offset, &sdnv_length);
+ proto_item_set_len(block_item, offset + sdnv_length + block_length);
+ hdr_length_item = proto_tree_add_text(block_tree, tvb,
+ header_start + offset, sdnv_length, " ");
+ if(block_length < 0) {
+ proto_item_set_text(hdr_length_item, "Metadata Block Length: Error");
+ return 0;
+ }
+ proto_item_set_text(hdr_length_item, "Block Length: %d", block_length);
+ offset += (sdnv_length + block_length);
+
+ return offset;
+}
+/*
+ * SDNV has a zero in high-order bit position of last byte. The high-order
+ * bit of all preceding bytes is set to one. This returns the numeric value
+ * in an integer and sets the value of the second argument to the number of
+ * bytes used to code the SDNV. A -1 is returned if the evaluation fails
+ * (value exceeds maximum for signed integer). 0 is an acceptable value.
+ */
+
+#define SDNV_MASK 0x7f
+
+/*3rd arg is number of bytes in field (returned)*/
+static int
+evaluate_sdnv(tvbuff_t *tvb, int offset, int *bytecount)
+{
+ int value = 0;
+ guint8 curbyte;
+
+ *bytecount = 0;
+
+ /*
+ * Get 1st byte and continue to get them while high-order bit is 1
+ */
+
+ while((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK) {
+ if(*bytecount >= (int) sizeof(int)) {
+ *bytecount = 0;
+ return -1;
+ }
+ value = value << 7;
+ value |= (curbyte & SDNV_MASK);
+ ++offset;
+ ++*bytecount;
+ }
+
+ /*
+ * Add in the byte whose high-order bit is 0 (last one)
+ */
+
+ value = value << 7;
+ value |= (curbyte & SDNV_MASK);
+ ++*bytecount;
+ return value;
+}
+
+static int
+add_sdnv_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id)
+{
+ int sdnv_length;
+ int sdnv_value;
+
+ sdnv_value = evaluate_sdnv(tvb, offset, &sdnv_length);
+ if(sdnv_value < 0) {
+ return 0;
+ }
+ proto_tree_add_text(tree, tvb, offset, sdnv_length, "%s: %d", field_id, sdnv_value);
+ return sdnv_length;
+}
+
+/*
+ * Adds the result of 2 SDNVs to tree: First SDNV is seconds, next is nanoseconds.
+ * Returns bytes in both SDNVs or 0 if something goes wrong.
+ */
+static int
+add_dtn_time_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id)
+{
+ int sdnv_length, sdnv2_length;
+ int sdnv_value;
+ time_t time_since_2000;
+ char *time_string;
+
+ sdnv_value = evaluate_sdnv(tvb, offset, &sdnv_length);
+ if(sdnv_value < 0) {
+ return 0;
+ }
+ time_since_2000 = (time_t) (sdnv_value + 946684800);
+ time_string = ctime(&time_since_2000);
+ time_string[strlen(time_string) - 1] = 0; /*Remove Newline at enc*/
+ proto_tree_add_text(tree, tvb, offset, sdnv_length,
+ "%s (sec): %d [%s]", field_id, sdnv_value, time_string);
+ offset += sdnv_length;
+
+ sdnv_value = evaluate_sdnv(tvb, offset, &sdnv2_length);
+ if(sdnv_value < 0) {
+ return 0;
+ }
+ proto_tree_add_text(tree, tvb, offset, sdnv2_length,
+ "%s (ns): %d", field_id, sdnv_value);
+ return (sdnv_length + sdnv2_length);
+}
+
+/*
+ * Adds the result of SDNV which is a time since 2000 to tree.
+ * Returns bytes in SDNV or 0 if something goes wrong.
+ */
+static int
+add_sdnv_time_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id)
+{
+ int sdnv_length;
+ int sdnv_value;
+ time_t time_since_2000;
+ char *time_string;
+
+ sdnv_value = evaluate_sdnv(tvb, offset, &sdnv_length);
+ if(sdnv_value < 0) {
+ return 0;
+ }
+ time_since_2000 = (time_t) (sdnv_value + 946684800);
+ time_string = ctime(&time_since_2000);
+ time_string[strlen(time_string) - 1] = 0; /*Remove Newline at enc*/
+ proto_tree_add_text(tree, tvb, offset, sdnv_length,
+ "%s: %d [%s]", field_id, sdnv_value, time_string);
+ return sdnv_length;
+}
+
+void
+proto_register_bundle(void)
+{
+
+ static hf_register_info hf[] = {
+ {&hf_bundle_pdu_version,
+ {"Bundle Version", "bundle.version",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_contact_hdr_version,
+ {"Version", "bundle.tcp_conv.contact_hdr.version",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_contact_hdr_flags,
+ {"Flags", "bundle.tcp_conv.contact_hdr.flags",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_contact_hdr_flags_ack_req,
+ {"Bundle Acks Requested", "bundle.tcp_conv.contact_hdr.flags.ackreq",
+ FT_BOOLEAN, 8, NULL, TCP_CONV_BUNDLE_ACK_FLAG, NULL, HFILL}
+ },
+ {&hf_contact_hdr_flags_frag_enable,
+ {"Reactive Fragmentation Enabled", "bundle.tcp_conv.contact_hdr.flags.fragen",
+ FT_BOOLEAN, 8, NULL, TCP_CONV_REACTIVE_FRAG_FLAG, NULL, HFILL}
+ },
+ {&hf_contact_hdr_flags_nak,
+ {"Support Negative Acknowledgements", "bundle.tcp_conv.contact_hdr.flags.nak",
+ FT_BOOLEAN, 8, NULL, TCP_CONV_CONNECTOR_RCVR_FLAG, NULL, HFILL}
+ },
+ {&hf_contact_hdr_keep_alive,
+ {"Keep Alive", "bundle.tcp_conv.contact_hdr.keep_alive",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_tcp_convergence_data_procflags,
+ {"TCP Convergence Data Flags", "bundle.tcp_conv.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", "bundle.tcp_conv.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", "bundle.tcp_conv.data.proc.end",
+ FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_DATA_END_FLAG, NULL, HFILL}
+ },
+ {&hf_tcp_convergence_shutdown_flags,
+ {"TCP Convergence Shutdown Flags", "bundle.tcp_conv.shutdown.flags",
+ FT_UINT8, BASE_HEX, NULL, TCP_CONVERGENCE_SHUTDOWN_FLAGS, NULL, HFILL}
+ },
+ {&hf_tcp_convergence_shutdown_flags_reason,
+ {"Shutdown includes Reason Code", "bundle.tcp_conv.shutdown.reason.flag",
+ FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_SHUTDOWN_REASON, NULL, HFILL}
+ },
+ {&hf_tcp_convergence_shutdown_flags_delay,
+ {"Shutdown includes Reconnection Delay", "bundle.tcp_conv.shutdown.delay.flag",
+ FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_SHUTDOWN_DELAY, NULL, HFILL}
+ },
+ {&hf_tcp_convergence_shutdown_reason,
+ {"Shutdown Reason Code", "bundle.tcp_conv.shutdown.reason",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_tcp_convergence_shutdown_delay,
+ {"Shutdown Reconnection Delay", "bundle.tcp_conv.shutdown.delay",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+
+ {&hf_msg_fragments,
+ {"Message Fragments", "bundle.msg.fragments",
+ FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_msg_fragment,
+ {"Message Fragment", "bundle.msg.fragment",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_msg_fragment_overlap,
+ {"Message fragment overlap", "bundle.msg.fragment.overlap",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_msg_fragment_overlap_conflicts,
+ {"Message fragment overlapping with conflicting data",
+ "bundle.msg.fragment.overlap.conflicts",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_msg_fragment_multiple_tails,
+ {"Message has multiple tails", "bundle.msg.fragment.multiple_tails",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_msg_fragment_too_long_fragment,
+ {"Message fragment too long", "bundle.msg.fragment.too_long_fragment",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_msg_fragment_error,
+ {"Message defragmentation error", "bundle.msg.fragment.error",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_msg_reassembled_in,
+ {"Reassembled in", "bundle.msg.reassembled.in",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_procflags,
+ {"Primary Header Processing Flags", "bundle.primary.proc.flag",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_procflags_fragment,
+ {"Bundle is a Fragment", "bundle.primary.proc.frag",
+ FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_FRAG_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_procflags_admin,
+ {"Administrative Record", "bundle.primary.proc.admin",
+ FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_ADMIN_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_procflags_dont_fragment,
+ {"Do Not Fragment Bundle", "bundle.primary.proc.dontfrag",
+ FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_DONTFRAG_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_procflags_cust_xfer_req,
+ {"Request Custody Transfer", "bundle.primary.proc.xferreq",
+ FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_XFERREQ_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_procflags_dest_singleton,
+ {"Destination is Singleton", "bundle.primary.proc.single",
+ FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_SINGLETON_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_procflags_application_ack,
+ {"Request Acknowledgement by Application", "bundle.primary.proc.ack",
+ FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_APP_ACK_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_control_flags,
+ {"Bundle Processing Control Flags", "bundle.primary.proc.flag",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_procflags_general,
+ {"General Flags", "bundle.primary.proc.gen",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_procflags_cos,
+ {"Cloass of Service Flags", "bundle.primary.proc.cos",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_procflags_status,
+ {"Status Report Flags", "bundle.primary.proc.status",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_cosflags,
+ {"Primary Header COS Flags", "bundle.primary.cos.flags",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_cosflags_priority,
+ {"Priority", "bundle.primary.cos.priority",
+ FT_UINT8, BASE_DEC, NULL, BUNDLE_COSFLAGS_PRIORITY_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_srrflags,
+ {"Primary Header Report Request Flags", "bundle.primary.srr.flag",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_srrflags_report_receipt,
+ {"Request Reception Report", "bundle.primary.srr.report",
+ FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_REPORT_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_srrflags_report_cust_accept,
+ {"Request Report of Custody Acceptance", "bundle.primary.srr.custaccept",
+ FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_CUSTODY_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_srrflags_report_forward,
+ {"Request Report of Bundle Forwarding", "bundle.primary.srr.forward",
+ FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_FORWARD_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_srrflags_report_delivery,
+ {"Request Report of Bundle Delivery", "bundle.primary.srr.delivery",
+ FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_DELIVERY_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_srrflags_report_deletion,
+ {"Request Report of Bundle Deletion", "bundle.primary.srr.delete",
+ FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_DELETION_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_srrflags_report_ack,
+ {"Request Report of Application Ack", "bundle.primary.srr.ack",
+ FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_ACK_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_primary_header_len,
+ {"Bundle Header Length", "bundle.primary.len",
+ FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_dest_scheme_offset,
+ {"Destination Scheme Offset", "bundle.primary.destschemeoff",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_dest_ssp_offset,
+ {"Destination SSP Offset", "bundle.primary.destssspoff",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_source_scheme_offset,
+ {"Source Scheme Offset", "bundle.primary.srcschemeoff",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_source_ssp_offset,
+ {"Source SSP Offset", "bundle.primary.srcsspoff",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_report_scheme_offset,
+ {"Report Scheme Offset", "bundle.primary.rptschemeoff",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_report_ssp_offset,
+ {"Report SSP Offset", "bundle.primary.rptsspoff",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_cust_scheme_offset,
+ {"Custodian Scheme Offset", "bundle.primary.custschemeoff",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_cust_ssp_offset,
+ {"Custodian SSP Offset", "bundle.primary.custsspoff",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_dest_scheme,
+ {"Destination Scheme", "bundle.primary.destination_scheme",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_dest_ssp,
+ {"Destination", "bundle.primary.destination",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_source_scheme,
+ {"Source Scheme", "bundle.primary.source_scheme",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_source_ssp,
+ {"Source", "bundle.primary.source",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_report_scheme,
+ {"Report Scheme", "bundle.primary.report_scheme",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_report_ssp,
+ {"Report", "bundle.primary.report",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_custodian_scheme,
+ {"Custodian Scheme", "bundle.primary.custodian_scheme",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_custodian_ssp,
+ {"Custodian", "bundle.primary.custodian",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_creation_timestamp,
+ {"Creation Timestamp", "bundle.primary.timestamp",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_lifetime,
+ {"Lifetime", "bundle.primary.lifetime",
+ FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_payload_flags,
+ {"Payload Header Processing Flags", "bundle.payload.proc.flag",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_payload_flags_replicate_hdr,
+ {"Replicate Header in Every Fragment", "bundle.payload.proc.replicate",
+ FT_BOOLEAN, 8, NULL, PAYLOAD_PROCFLAGS_REPLICATE_MASK, NULL, HFILL}
+ },
+ {&hf_bundle_payload_flags_xmit_report,
+ {"Report if Can't Process Header", "bundle.payload.proc.report",
+ FT_BOOLEAN, 8, NULL, PAYLOAD_PROCFLAGS_XMIT_STATUS, NULL, HFILL}
+ },
+ {&hf_bundle_payload_flags_discard_on_fail,
+ {"Discard if Can't Process Header", "bundle.payload.proc.discard",
+ FT_BOOLEAN, 8, NULL, PAYLOAD_PROCFLAGS_DISCARD_FAILURE, NULL, HFILL}
+ },
+ {&hf_bundle_payload_flags_last_header,
+ {"Last Header", "bundle.payload.proc.lastheader",
+ FT_BOOLEAN, 8, NULL, PAYLOAD_PROCFLAGS_LAST_HEADER, NULL, HFILL}
+ },
+ {&hf_bundle_admin_statflags,
+ {"Administrative Record Status Flags", "bundle.admin.status.flag",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_admin_rcvd,
+ {"Reporting Node Received Bundle", "bundle.admin.status.rcvd",
+ FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_RECEIVED, NULL, HFILL}
+ },
+ {&hf_bundle_admin_accepted,
+ {"Reporting Node Accepted Custody", "bundle.admin.status.accept",
+ FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_ACCEPTED, NULL, HFILL}
+ },
+ {&hf_bundle_admin_forwarded,
+ {"Reporting Node Forwarded Bundle", "bundle.admin.status.forward",
+ FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_FORWARDED, NULL, HFILL}
+ },
+ {&hf_bundle_admin_delivered,
+ {"Reporting Node Delivered Bundle", "bundle.admin.status.delivered",
+ FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_DELIVERED, NULL, HFILL}
+ },
+ {&hf_bundle_admin_deleted,
+ {"Reporting Node Deleted Bundle", "bundle.admin.status.delete",
+ FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_DELETED, NULL, HFILL}
+ },
+ {&hf_bundle_admin_acked,
+ {"Acknowledged by Application", "bundle.admin.status.ack",
+ FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_ACKNOWLEDGED, NULL, HFILL}
+ },
+ {&hf_bundle_admin_receipt_time,
+ {"Time of Receipt", "bundle.admin.status.receipttime",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_admin_accept_time,
+ {"Time of Custody Acceptance", "bundle.admin.status.accepttime",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_admin_forward_time,
+ {"Time of Forwarding", "bundle.admin.status.forwardtime",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_admin_delivery_time,
+ {"Time of Delivery", "bundle.admin.status.deliverytime",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_admin_delete_time,
+ {"Time of Deletion", "bundle.admin.status.deletetime",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_admin_ack_time,
+ {"Time of Acknowledgement", "bundle.admin.status.acktime",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_admin_timestamp_copy,
+ {"Copy of Creation Timestamp", "bundle.admin.status.timecopy",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_bundle_admin_signal_time,
+ {"Time of Signal", "bundle.admin.signal.time",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_block_control_flags,
+ {"Block Processing Control Flags", "bundle.block.control.flags",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
+ },
+ {&hf_block_control_replicate,
+ {"Replicate Block in Every Fragment", "bundle.block.control.replicate",
+ FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_REPLICATE, NULL, HFILL}
+ },
+ {&hf_block_control_transmit_status,
+ {"Transmit Status if Block Can't be Processeed", "bundle.block.control.status",
+ FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_TRANSMIT_STATUS, NULL, HFILL}
+ },
+ {&hf_block_control_delete_bundle,
+ {"Delete Bundle if Block Can't be Processeed", "bundle.block.control.delete",
+ FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_DELETE_BUNDLE, NULL, HFILL}
+ },
+ {&hf_block_control_last_block,
+ {"Last Block", "bundle.block.control.last",
+ FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_LAST_BLOCK, NULL, HFILL}
+ },
+ {&hf_block_control_discard_block,
+ {"Discard Block If Can't Process", "bundle.block.control.discard",
+ FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_DISCARD_BLOCK, NULL, HFILL}
+ },
+ {&hf_block_control_not_processed,
+ {"Block Was Forwarded Without Processing", "bundle.block.control.process",
+ FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_NOT_PROCESSED, NULL, HFILL}
+ },
+ {&hf_block_control_eid_reference,
+ {"Block Contains an EID-reference Field", "bundle.block.control.eid",
+ FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_EID_REFERENCE, NULL, HFILL}
+ }
+ };
+
+ static gint *ett[] = {
+ &ett_bundle,
+ &ett_tcp_conv,
+ &ett_tcp_conv_hdr,
+ &ett_msg_fragment,
+ &ett_msg_fragments,
+ &ett_bundle_hdr,
+ &ett_primary_hdr,
+ &ett_proc_flags,
+ &ett_gen_flags,
+ &ett_cos_flags,
+ &ett_srr_flags,
+ &ett_dictionary,
+ &ett_payload_hdr,
+ &ett_payload_flags,
+ &ett_block_flags,
+ &ett_contact_hdr_flags,
+ &ett_conv_flags,
+ &ett_shutdown_flags,
+ &ett_admin_record,
+ &ett_admin_rec_status,
+ &ett_metadata_hdr
+ };
+
+ module_t *bundle_module;
+
+ proto_bundle = proto_register_protocol (
+ "Bundle Protocol",
+ "Bundle",
+ "bundle"
+ );
+ bundle_module = prefs_register_protocol(proto_bundle, proto_reg_handoff_bundle);
+
+ proto_tcp_conv = proto_register_protocol (
+ "DTN TCP Convergence Layer Protocol",
+ "TCPCL",
+ "tcpcl"
+ );
+
+ prefs_register_uint_preference(bundle_module, "tcp.port",
+ "Bundle Protocol TCP Port",
+ "TCP Port to Accept Bundle Protocol Connections",
+ 10,
+ &bundle_tcp_port);
+
+ prefs_register_uint_preference(bundle_module, "udp.port",
+ "Bundle Protocol UDP Port",
+ "UDP Port to Accept Bundle Protocol Connections",
+ 10,
+ &bundle_udp_port);
+
+ proto_register_field_array(proto_bundle, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_bundle(void)
+{
+ static int Initialized=FALSE;
+
+ if (!Initialized) {
+ tcp_bundle_handle = create_dissector_handle(dissect_tcp_bundle, proto_bundle);
+ udp_bundle_handle = create_dissector_handle(dissect_udp_bundle, proto_bundle);
+ fragment_table_init(&msg_fragment_table);
+ reassembled_table_init(&msg_reassembled_table);
+ Initialized = TRUE;
+ }
+ else {
+ dissector_delete("tcp.port", tcp_port, tcp_bundle_handle);
+ dissector_delete("udp.port", udp_port, udp_bundle_handle);
+
+ }
+ tcp_port = bundle_tcp_port;
+ udp_port = bundle_udp_port;
+ dissector_add("tcp.port", tcp_port, tcp_bundle_handle);
+ dissector_add("udp.port", udp_port, udp_bundle_handle);
+}
diff --git a/epan/dissectors/packet-dtn.h b/epan/dissectors/packet-dtn.h
new file mode 100644
index 0000000000..4c09121479
--- /dev/null
+++ b/epan/dissectors/packet-dtn.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * 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.
+ */
+
+/* TCP Convergence Layer - Message Types */
+#define TCP_CONV_MSG_TYPE_DATA 0x01
+#define TCP_CONV_MSG_TYPE_ACK 0x02
+#define TCP_CONV_MSG_TYPE_KEEP_ALIVE 0x03
+#define TCP_CONV_MSG_TYPE_SHUTDOWN 0x04
+
+/* TCP Convergence Layer (3) - Message Types */
+#define TCP_CONVERGENCE_TYPE_MASK 0xf0
+#define TCP_CONVERGENCE_DATA_SEGMENT 0x10
+#define TCP_CONVERGENCE_ACK_SEGMENT 0x20
+#define TCP_CONVERGENCE_REFUSE_BUNDLE 0x30
+#define TCP_CONVERGENCE_KEEP_ALIVE 0x40
+#define TCP_CONVERGENCE_SHUTDOWN 0x50
+
+/* TCP Convergence Layer - Contact Header Flags */
+#define TCP_CONV_BUNDLE_ACK_FLAG 0x01
+#define TCP_CONV_REACTIVE_FRAG_FLAG 0x02
+#define TCP_CONV_CONNECTOR_RCVR_FLAG 0x04
+
+/* TCP Convergence Layer - Data Segment Flags */
+#define TCP_CONVERGENCE_DATA_FLAGS 0x03
+#define TCP_CONVERGENCE_DATA_END_FLAG 0x01
+#define TCP_CONVERGENCE_DATA_START_FLAG 0x02
+
+/* TCP Convergence Layer - Shutdown Segment Flags */
+#define TCP_CONVERGENCE_SHUTDOWN_FLAGS 0x03
+#define TCP_CONVERGENCE_SHUTDOWN_REASON 0x02
+#define TCP_CONVERGENCE_SHUTDOWN_DELAY 0x01
+
+/*
+ * TCP Convergence Layer - Minimum buffer sizes
+ * For Data Packet require 5 bytes fixed plus
+ * up to 4 additional for length SDV
+ */
+
+#define TCP_CONV_MIN_DATA_BUFFER 9
+
+
+#define BUNDLE_PROCFLAGS_FRAG_MASK 0x01
+#define BUNDLE_PROCFLAGS_ADMIN_MASK 0x02
+#define BUNDLE_PROCFLAGS_DONTFRAG_MASK 0x04
+#define BUNDLE_PROCFLAGS_XFERREQ_MASK 0x08
+#define BUNDLE_PROCFLAGS_SINGLETON_MASK 0x10
+#define BUNDLE_PROCFLAGS_APP_ACK_MASK 0x20
+
+#define BUNDLE_COSFLAGS_PRIORITY_MASK 0x03
+#define BUNDLE_COSFLAGS_PRIORITY_BULK 0x00
+#define BUNDLE_COSFLAGS_PRIORITY_NORMAL 0x01
+#define BUNDLE_COSFLAGS_PRIORITY_EXP 0x10
+
+#define BUNDLE_SRRFLAGS_REPORT_MASK 0x01
+#define BUNDLE_SRRFLAGS_CUSTODY_MASK 0x02
+#define BUNDLE_SRRFLAGS_FORWARD_MASK 0x04
+#define BUNDLE_SRRFLAGS_DELIVERY_MASK 0x08
+#define BUNDLE_SRRFLAGS_DELETION_MASK 0x10
+#define BUNDLE_SRRFLAGS_ACK_MASK 0x20
+
+/* Header Processing Flags (non-primary) */
+#define HEADER_PROCFLAGS_REPLICATE 0x01
+#define HEADER_PROCFLAGS_XMIT_STATUS 0x02
+#define HEADER_PROCFLAGS_DISCARD 0x04
+#define HEADER_PROCFLAGS_LAST_HEADER 0x08
+
+/* Header Types (excluding Primary Header) */
+#define PAYLOAD_HEADER_TYPE 0x01
+
+/* Payload Header Processing Flags */
+#define PAYLOAD_PROCFLAGS_REPLICATE_MASK 0x01
+#define PAYLOAD_PROCFLAGS_XMIT_STATUS 0x02
+#define PAYLOAD_PROCFLAGS_DISCARD_FAILURE 0x04
+#define PAYLOAD_PROCFLAGS_LAST_HEADER 0x08
+
+/* Header Fixed Sizes */
+#define TCP_CONV_HDR_DATA_FIXED_LENGTH 5
+#define TCP_CONV_HDR_ACK_LENGTH 9
+#define TCP_CONV_HDR_KEEP_ALIVE_LENGTH 1
+#define TCP_CONV_HDR_SHUTDOWN_LENGTH 1
+
+/* Administrative Record Definitions */
+#define ADMIN_REC_TYPE_STATUS_REPORT 0x01
+#define ADMIN_REC_TYPE_CUSTODY_SIGNAL 0x02
+
+#define ADMIN_REC_FLAGS_FRAGMENT 0x01
+#define ADMIN_REC_CUSTODY_REASON_MASK 0x7f
+
+/* Bundle Status Report Flags */
+#define ADMIN_STATUS_FLAGS_RECEIVED 0x01
+#define ADMIN_STATUS_FLAGS_ACCEPTED 0x02
+#define ADMIN_STATUS_FLAGS_FORWARDED 0x04
+#define ADMIN_STATUS_FLAGS_DELIVERED 0x08
+#define ADMIN_STATUS_FLAGS_DELETED 0x10
+#define ADMIN_STATUS_FLAGS_ACKNOWLEDGED 0x20
+
+/* Block Processing Control Flags (Version 5) */
+#define BLOCK_CONTROL_REPLICATE 0x01
+#define BLOCK_CONTROL_TRANSMIT_STATUS 0x02
+#define BLOCK_CONTROL_DELETE_BUNDLE 0x04
+#define BLOCK_CONTROL_LAST_BLOCK 0x08
+#define BLOCK_CONTROL_DISCARD_BLOCK 0x10
+#define BLOCK_CONTROL_NOT_PROCESSED 0x20
+#define BLOCK_CONTROL_EID_REFERENCE 0x40
+