Remove check_col() guard
[obnox/wireshark/wip.git] / epan / dissectors / packet-dtn.c
1 /*
2  * Copyright 2006-2007 The MITRE Corporation.
3  * All Rights Reserved.
4  * Approved for Public Release; Distribution Unlimited.
5  * Tracking Number 07-0090.
6  *
7  * The US Government will not be charged any license fee and/or royalties
8  * related to this software. Neither name of The MITRE Corporation; nor the
9  * names of its contributors may be used to endorse or promote products
10  * derived from this software without specific prior written permission.
11  *
12  * $Id$
13  *
14  * Wireshark - Network traffic analyzer
15  * By Gerald Combs <gerald@wireshark.org>
16  * Copyright 1998 Gerald Combs
17  *
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <glib.h>
40
41 #include <epan/packet.h>
42 #include <epan/prefs.h>
43 #include <epan/reassemble.h>
44 #include "packet-dtn.h"
45
46 void proto_reg_handoff_bundle(void);
47 static void dissect_tcp_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
48 static void dissect_udp_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
49 static int dissect_complete_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
50 static int dissect_primary_header(packet_info *pinfo, proto_tree *primary_tree, tvbuff_t *tvb);
51 static int dissect_admin_record(proto_tree *primary_tree, tvbuff_t *tvb, int offset);
52 static int evaluate_sdnv(tvbuff_t *tvb, int offset, int *bytecount);
53 static gint64 evaluate_sdnv_64(tvbuff_t *tvb, int offset, int *bytecount);
54 static int dissect_payload_header(proto_tree *tree, tvbuff_t *tvb, int bundle_offset, int *lastheader);
55 static int display_metadata_block(proto_tree *tree, tvbuff_t *tvb, int bundle_offset, int *lastheader);
56 static int dissect_contact_header(tvbuff_t *tvb, packet_info *pinfo,
57                                 proto_tree *conv_tree, proto_item *conv_item);
58 static int dissect_tcp_convergence_data_header(tvbuff_t *tvb, proto_tree *tree);
59 static int dissect_version_5_primary_header(packet_info *pinfo,
60                                         proto_tree *primary_tree, tvbuff_t *tvb);
61 static int add_sdnv_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id);
62 static int add_dtn_time_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id);
63 static int add_sdnv_time_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id);
64
65 /* For Reassembling TCP Convergence Layer segments */
66 static GHashTable *msg_fragment_table = NULL;
67 static GHashTable *msg_reassembled_table = NULL;
68
69 static int segment_length;
70 static int bundle_header_length;
71 static int bundle_header_dict_length;
72
73 static char magic[] = {'d', 't', 'n', '!'};
74
75 static int proto_bundle = -1;
76 static int proto_tcp_conv = -1;
77 static int hf_bundle_pdu_version = -1;
78
79 /* TCP Convergence Header Variables */
80 static int hf_contact_hdr_version = -1;
81 static int hf_contact_hdr_flags = -1;
82 static int hf_contact_hdr_keep_alive = -1;
83 static int hf_contact_hdr_flags_ack_req = -1;
84 static int hf_contact_hdr_flags_frag_enable = -1;
85 static int hf_contact_hdr_flags_nak = -1;
86
87 /* TCP Convergence Data Header Variables */
88 static int hf_tcp_convergence_data_procflags = -1;
89 static int hf_tcp_convergence_data_procflags_start = -1;
90 static int hf_tcp_convergence_data_procflags_end = -1;
91
92 /* TCP Convergence Shutdown Header Variables */
93 static int hf_tcp_convergence_shutdown_flags = -1;
94 static int hf_tcp_convergence_shutdown_flags_reason = -1;
95 static int hf_tcp_convergence_shutdown_flags_delay = -1;
96 static int hf_tcp_convergence_shutdown_reason = -1;
97 static int hf_tcp_convergence_shutdown_delay = -1;
98
99 /*TCP Convergence Layer Reassembly boilerplate*/
100 static int hf_msg_fragments = -1;
101 static int hf_msg_fragment = -1;
102 static int hf_msg_fragment_overlap = -1;
103 static int hf_msg_fragment_overlap_conflicts = -1;
104 static int hf_msg_fragment_multiple_tails = -1;
105 static int hf_msg_fragment_too_long_fragment = -1;
106 static int hf_msg_fragment_error = -1;
107 static int hf_msg_reassembled_in = -1;
108
109 /* Primary Header Processing Flag Variables */
110 static guint8 pri_hdr_procflags; /*This is global to allow processing Payload Header*/
111 static int hf_bundle_procflags = -1;
112 static int hf_bundle_procflags_fragment = -1;
113 static int hf_bundle_procflags_admin = -1;
114 static int hf_bundle_procflags_dont_fragment = -1;
115 static int hf_bundle_procflags_cust_xfer_req = -1;
116 static int hf_bundle_procflags_dest_singleton = -1;
117 static int hf_bundle_procflags_application_ack = -1;
118
119 /* Additions for Version 5 */
120 static int hf_bundle_control_flags = -1;
121 static int hf_bundle_procflags_general = -1;
122 static int hf_bundle_procflags_cos = -1;
123 static int hf_bundle_procflags_status = -1;
124
125 /* Primary Header COS Flag Variables */
126 static int hf_bundle_cosflags = -1;
127 static int hf_bundle_cosflags_priority = -1;
128
129 /* Primary Header Status Report Request Flag Variables */
130 static int hf_bundle_srrflags = -1;
131 static int hf_bundle_srrflags_report_receipt = -1;
132 static int hf_bundle_srrflags_report_cust_accept = -1;
133 static int hf_bundle_srrflags_report_forward = -1;
134 static int hf_bundle_srrflags_report_delivery = -1;
135 static int hf_bundle_srrflags_report_deletion = -1;
136 static int hf_bundle_srrflags_report_ack = -1;
137
138 /* Primary Header Length Fields*/
139 static int hf_bundle_primary_header_len = -1;
140 static int hf_bundle_dest_scheme_offset = -1;
141 static int hf_bundle_dest_ssp_offset = -1;
142 static int hf_bundle_source_scheme_offset = -1;
143 static int hf_bundle_source_ssp_offset = -1;
144 static int hf_bundle_report_scheme_offset = -1;
145 static int hf_bundle_report_ssp_offset = -1;
146 static int hf_bundle_cust_scheme_offset = -1;
147 static int hf_bundle_cust_ssp_offset = -1;
148
149 /* Dictionary EIDs */
150 static int hf_bundle_dest_scheme = -1;
151 static int hf_bundle_dest_ssp = -1;
152 static int hf_bundle_source_scheme = -1;
153 static int hf_bundle_source_ssp = -1;
154 static int hf_bundle_report_scheme = -1;
155 static int hf_bundle_report_ssp = -1;
156 static int hf_bundle_custodian_scheme = -1;
157 static int hf_bundle_custodian_ssp = -1;
158
159 /* Remaining Primary Header Fields */
160 static int hf_bundle_creation_timestamp = -1;
161 static int hf_bundle_lifetime = -1;
162
163 /* Secondary Header Processing Flag Variables */
164 static int hf_bundle_payload_flags = -1;
165 static int hf_bundle_payload_flags_replicate_hdr = -1;
166 static int hf_bundle_payload_flags_xmit_report = -1;
167 static int hf_bundle_payload_flags_discard_on_fail = -1;
168 static int hf_bundle_payload_flags_last_header = -1;
169
170 /* Block Processing Control Flag Variables (Version 5) */
171 static int hf_block_control_flags = -1;
172 static int hf_block_control_replicate = -1;
173 static int hf_block_control_transmit_status = -1;
174 static int hf_block_control_delete_bundle = -1;
175 static int hf_block_control_last_block = -1;
176 static int hf_block_control_discard_block = -1;
177 static int hf_block_control_not_processed = -1;
178 static int hf_block_control_eid_reference = -1;
179
180 /* Administrative Record Variables */
181 static int hf_bundle_admin_statflags = -1;
182 static int hf_bundle_admin_rcvd = -1;
183 static int hf_bundle_admin_accepted = -1;
184 static int hf_bundle_admin_forwarded = -1;
185 static int hf_bundle_admin_delivered = -1;
186 static int hf_bundle_admin_deleted = -1;
187 static int hf_bundle_admin_acked = -1;
188 static int hf_bundle_admin_receipt_time = -1;
189 static int hf_bundle_admin_accept_time = -1;
190 static int hf_bundle_admin_forward_time = -1;
191 static int hf_bundle_admin_delivery_time = -1;
192 static int hf_bundle_admin_delete_time = -1;
193 static int hf_bundle_admin_ack_time = -1;
194 static int hf_bundle_admin_timestamp_copy = -1;
195 static int hf_bundle_admin_signal_time = -1;
196
197 /* Tree Node Variables */
198 static gint ett_bundle = -1;
199 static gint ett_tcp_conv = -1;
200 static gint ett_tcp_conv_hdr = -1;
201 static gint ett_conv_flags = -1;
202 static gint ett_shutdown_flags = -1;
203 static gint ett_msg_fragment = -1;
204 static gint ett_msg_fragments = -1;
205 static gint ett_bundle_hdr = -1;
206 static gint ett_primary_hdr = -1;
207 static gint ett_proc_flags = -1;
208 static gint ett_gen_flags = -1;
209 static gint ett_cos_flags = -1;
210 static gint ett_srr_flags = -1;
211 static gint ett_dictionary = -1;
212 static gint ett_payload_hdr = -1;
213 static gint ett_payload_flags = -1;
214 static gint ett_block_flags = -1;
215 static gint ett_contact_hdr_flags = -1;
216 static gint ett_admin_record = -1;
217 static gint ett_admin_rec_status = -1;
218 static gint ett_metadata_hdr = -1;
219
220 static guint bundle_tcp_port = 4556;
221 static guint bundle_udp_port = 4556;
222
223 /* Needed to allow entering port option */
224 static guint tcp_port = 0;
225 static guint udp_port = 0;
226
227 static const value_string custody_signal_reason_codes[] = {
228     {0x3, "Redundant Reception"},
229     {0x4, "Depleted Storage"},
230     {0x5, "Destination Endpoint ID Unintelligible"},
231     {0x6, "No Known Route to Destination"},
232     {0x7, "No Timely Contact with Next Node on Route"},
233     {0x8, "Header Unintelligible"},
234     {0, NULL}
235 };
236
237 static const value_string status_report_reason_codes[] = {
238     {0x1, "Lifetime Expired"},
239     {0x2, "Forwarded over Unidirectional Link"},
240     {0x3, "Transmission Cancelled"},
241     {0x4, "Depleted Storage"},
242     {0x5, "Destination Endpoint ID Unintelligible"},
243     {0x6, "No Known Route to Destination"},
244     {0x7, "No Timely Contact with Next Node on Route"},
245     {0x8, "Header Unintelligible"},
246     {0, NULL}
247 };
248
249 static const fragment_items msg_frag_items = {
250     /*Fragment subtrees*/
251     &ett_msg_fragment,
252     &ett_msg_fragments,
253     /*Fragment Fields*/
254     &hf_msg_fragments,
255     &hf_msg_fragment,
256     &hf_msg_fragment_overlap,
257     &hf_msg_fragment_overlap_conflicts,
258     &hf_msg_fragment_multiple_tails,
259     &hf_msg_fragment_too_long_fragment,
260     &hf_msg_fragment_error,
261     /*Reassembled in field*/
262     &hf_msg_reassembled_in,
263     /*Tag*/
264     "Message fragments"
265 };
266
267
268 static void dissect_tcp_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
269 {
270
271     proto_item *ti = NULL;
272     proto_tree *bundle_tree = NULL;
273     proto_item *ci = NULL;
274     proto_tree *conv_proto_tree = NULL;
275     int buffer_size;    /*Number of bytes in buffer that can be processed*/
276     int bundle_size = 0;
277     tvbuff_t *new_tvb;
278     guint8 conv_hdr;
279     int sdnv_length;
280     int frame_offset;   /*To handle the case of > 1 bundle in an Ethernet Frame*/
281     int convergence_hdr_size;
282     int fixed;
283     char *sptr;
284
285     buffer_size = tvb_reported_length(tvb);
286     frame_offset = 0;
287     col_set_str(pinfo->cinfo, COL_PROTOCOL, "Bundle");
288     col_clear(pinfo->cinfo,COL_INFO); /* Clear out stuff in the info column */
289
290     while(frame_offset < buffer_size) {
291
292         fragment_data *frag_msg = NULL;
293         gboolean more_frags = TRUE;
294
295         conv_hdr = tvb_get_guint8(tvb, frame_offset);
296         if((conv_hdr & TCP_CONVERGENCE_TYPE_MASK) == TCP_CONVERGENCE_DATA_SEGMENT) {
297
298             /* Only Start and End flags (bits 0 & 1) are valid in Data Segment */
299             if((conv_hdr & ~(TCP_CONVERGENCE_TYPE_MASK | TCP_CONVERGENCE_DATA_FLAGS)) != 0) {
300                 col_set_str(pinfo->cinfo, COL_INFO, "Invalid TCP CL Data Segment Flags");
301                 return;
302             }
303             fixed = 1;
304             segment_length = evaluate_sdnv(tvb, fixed + frame_offset, &sdnv_length);
305             if(segment_length < 0) {
306                 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error (Length)");
307                 return;
308             }
309             convergence_hdr_size = sdnv_length + fixed;
310             if((buffer_size - frame_offset - convergence_hdr_size) < segment_length) {
311                 /*Segment not complete -- wait for the rest of it*/
312                 pinfo->desegment_len =
313                             segment_length - (buffer_size - frame_offset
314                                                         - convergence_hdr_size);
315                 pinfo->desegment_offset = frame_offset;
316                 return;
317             }
318
319             /*
320              * 1/11/2006 - If I got here, I should have a complete convergence layer
321              * "segment" beginning at frame_offset. However that might not be a
322              * complete bundle. Or there might be a complete bundle plus one or more
323              * additional convergence layer headers.
324              */
325
326             new_tvb = NULL;
327             if((conv_hdr & TCP_CONVERGENCE_DATA_END_FLAG) ==
328                                                 TCP_CONVERGENCE_DATA_END_FLAG) {
329                 more_frags = FALSE;
330             }
331             else {
332                 more_frags = TRUE;
333             }
334             ci = proto_tree_add_item(tree, proto_tcp_conv, tvb,
335                                                         frame_offset, -1, FALSE);
336             conv_proto_tree = proto_item_add_subtree(ci, ett_tcp_conv);
337             dissect_tcp_convergence_data_header(tvb, conv_proto_tree);
338
339             /*
340              * Note: The reassembled bundle will only include the first
341              * Convergence layer header.
342              */
343
344             frag_msg = fragment_add_seq_next(tvb, frame_offset + convergence_hdr_size,
345                                            pinfo, 0, msg_fragment_table,
346                                            msg_reassembled_table, segment_length,
347                                            more_frags);
348             if(frag_msg && !more_frags) {
349                 ti = proto_tree_add_item(tree, proto_bundle, tvb,
350                                                         frame_offset, -1, FALSE);
351                 bundle_tree = proto_item_add_subtree(ti, ett_bundle);
352                 new_tvb = process_reassembled_data(tvb,
353                                                    frame_offset + convergence_hdr_size,
354                                                    pinfo, "Reassembled Message", frag_msg,
355                                                    &msg_frag_items, NULL, bundle_tree);
356             }
357             if(new_tvb){
358                 bundle_size = dissect_complete_bundle(new_tvb, pinfo, bundle_tree);
359                 if(bundle_size == 0) {  /*Couldn't parse bundle*/
360                     col_set_str(pinfo->cinfo, COL_INFO, "Dissection Failed");
361                     return;                     /*Give up*/
362                 }
363             }
364             else {
365
366                 /*
367                  * If there are 2 segments, the second of which is very short, this
368                  * gets displayed instead of the usual Source EID/Destination EID in
369                  * the Bundle Dissection frame. If these statements are left out entirely,
370                  * nothing is displayed, i.e., there seems to be no way to get the
371                  * Source/Destination in the 2-segment case. I'll leave it in because I
372                  * think it is informative in the multi-segment case although confusing in the
373                  * 2-segment case.
374                  */
375
376                 col_set_str(pinfo->cinfo, COL_INFO, "[Reassembled Segment of a Bundle]");
377             }
378
379             /*
380              * If we could be sure that the current tvb buffer ended with the CL segment,
381              * we could return here. But the buffer could contain multiple complete segments
382              * or bundles or a bundle plus other CL messages. In order to process whatever
383              * follow the current segment, we have to continue through the buffer until
384              * frame_offset indicates everything in the buffer has been processed.
385              */
386
387             frame_offset += (segment_length + convergence_hdr_size);
388         }
389         else {  /*Else this is not a Data Segment*/
390
391             proto_item *conv_item = NULL;
392             proto_tree *conv_tree = NULL;
393
394             if(frame_offset == 0) {
395                 ci = proto_tree_add_item(tree, proto_tcp_conv, tvb,
396                                                         frame_offset, -1, FALSE);
397                 conv_proto_tree = proto_item_add_subtree(ci, ett_tcp_conv);
398             }
399
400             /*
401              * Other Convergence Layer messages are short; assume they won't need
402              * reassembly. Start with the Convergence Layer Tree.
403              */
404
405             conv_item = proto_tree_add_text(conv_proto_tree, tvb, frame_offset, -1,
406                                                                 "TCP Convergence Header");
407             conv_tree = proto_item_add_subtree(conv_item, ett_tcp_conv_hdr);
408
409             if(conv_hdr == magic[0]) {
410                 sptr = (char *) tvb_get_ephemeral_string(tvb, frame_offset, 4);
411                 if(!memcmp(sptr, magic, 4)){
412                     dissect_contact_header(tvb, pinfo, conv_tree, conv_item);
413                     return;     /*Assumes Contact Header is alone in segment*/
414                 }
415             }
416             if(conv_hdr == TCP_CONVERGENCE_ACK_SEGMENT) {       /*No valid flags in Ack*/
417                 int ack_length;
418                 proto_item *ack_length_item = NULL;
419
420                 proto_tree_add_text(conv_tree, tvb, frame_offset, 1, "Pkt Type: Ack");
421                 fixed = 1;
422                 ack_length = evaluate_sdnv(tvb, frame_offset + fixed, &sdnv_length);
423                 ack_length_item = proto_tree_add_text(conv_tree, tvb,
424                                                 frame_offset + fixed, sdnv_length, " ");
425                 if(ack_length < 0) {
426                     proto_item_set_text(ack_length_item, "Ack Length: Error");
427                     return;
428                 }
429                 proto_item_set_text(ack_length_item, "Ack Length: %d", ack_length);
430                 /*return (sdnv_length + fixed);*/
431                 frame_offset += (sdnv_length + fixed);
432                 proto_item_set_len(conv_item, sdnv_length + fixed);
433             }
434             else if(conv_hdr == TCP_CONVERGENCE_KEEP_ALIVE) { /*No valid flags in Keep Alive*/
435                 proto_item_set_len(conv_item, 1);
436                 proto_tree_add_text(conv_tree, tvb, frame_offset, 1, "Pkt Type: Keep Alive");
437                 frame_offset += 1;
438             }
439             else if((conv_hdr & TCP_CONVERGENCE_TYPE_MASK) ==
440                                                         TCP_CONVERGENCE_SHUTDOWN) {
441                 proto_item *shutdown_flag_item = NULL;
442                 proto_tree *shutdown_flag_tree = NULL;
443                 guint8 shutdown_flags;
444                 proto_item *shutdown_reason_item = NULL;
445                 proto_item *shutdown_delay_item = NULL;
446                 int field_length;
447
448                 if((conv_hdr &
449                         ~(TCP_CONVERGENCE_TYPE_MASK || TCP_CONVERGENCE_SHUTDOWN_FLAGS)) != 0) {
450                     proto_tree_add_text(conv_tree, tvb, frame_offset,
451                                                 -1, "Invalid Convergence Layer Shutdown Packet");
452                     return;
453                 }
454                 proto_item_set_len(conv_item, 1);
455                 proto_tree_add_text(conv_tree, tvb, 0, 1, "Pkt Type: Shutdown");
456
457                 /* Add tree for Shutdown Flags */
458                 shutdown_flags = conv_hdr;
459                 shutdown_flag_item = proto_tree_add_item(conv_tree,
460                                                 hf_tcp_convergence_shutdown_flags, tvb,
461                                                 frame_offset, 1, FALSE);
462                 shutdown_flag_tree = proto_item_add_subtree(shutdown_flag_item,
463                                                                         ett_shutdown_flags);
464                 proto_tree_add_boolean(shutdown_flag_tree,
465                                                 hf_tcp_convergence_shutdown_flags_reason,
466                                                 tvb, frame_offset, 1, shutdown_flags);
467                 proto_tree_add_boolean(shutdown_flag_tree,
468                                                 hf_tcp_convergence_shutdown_flags_delay,
469                                                 tvb, frame_offset, 1, shutdown_flags);
470
471                 frame_offset += 1;
472                 field_length = 1;
473                 if(conv_hdr & TCP_CONVERGENCE_SHUTDOWN_REASON) {
474                     shutdown_reason_item = proto_tree_add_item(conv_tree,
475                                                 hf_tcp_convergence_shutdown_reason, tvb,
476                                                 frame_offset, 1, FALSE);
477                     frame_offset += 1;
478                     field_length += 1;
479                 }
480                 if(conv_hdr & TCP_CONVERGENCE_SHUTDOWN_DELAY) {
481                     shutdown_delay_item = proto_tree_add_item(conv_tree,
482                                                 hf_tcp_convergence_shutdown_delay, tvb,
483                                                 frame_offset, 2, FALSE);
484                     frame_offset += 2;
485                     field_length += 2;
486                 }
487                 proto_item_set_len(conv_item, field_length);
488             }
489             else if(conv_hdr == TCP_CONVERGENCE_REFUSE_BUNDLE) { /*No valid flags*/
490                 proto_item_set_len(conv_item, 1);
491                 proto_tree_add_text(conv_tree, tvb, frame_offset,
492                                                         1, "Pkt Type: Refuse Bundle");
493                 frame_offset += 1;
494             }
495             else {
496                 proto_tree_add_text(conv_tree, tvb, frame_offset,
497                                                 -1, "Invalid/Partial Convergence Layer Packet");
498                 return;
499             }
500         }
501     }           /*end while()*/
502     return;
503 }
504
505 static void
506 dissect_udp_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
507 {
508
509     int buffer_size;    /*Number of bytes in buffer that can be processed*/
510     int hdr_offset;
511     int lasthdrflag;
512     guint8 next_header_type;
513     proto_item *ti = NULL;
514     proto_tree *bundle_tree = NULL;
515     proto_item *primary_item = NULL;
516     proto_tree *primary_tree = NULL;
517
518     buffer_size = tvb_reported_length_remaining(tvb, 0);
519     col_set_str(pinfo->cinfo, COL_PROTOCOL, "Bundle");
520     /* Clear out stuff in the info column */
521     col_clear(pinfo->cinfo,COL_INFO);
522
523     ti = proto_tree_add_item(tree, proto_bundle, tvb, 0, -1, FALSE);
524     bundle_tree = proto_item_add_subtree(ti, ett_bundle);
525
526     primary_item = proto_tree_add_text(bundle_tree, tvb, 0, -1,
527                                                 "Primary Bundle Header");
528     primary_tree = proto_item_add_subtree(primary_item, ett_primary_hdr);
529     hdr_offset = dissect_primary_header(pinfo, primary_tree, tvb);
530     if(hdr_offset == 0) {
531         col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
532         return;
533     }
534     proto_item_set_len(primary_item, hdr_offset);
535
536     /*
537      * Done with primary header; decode the remaining headers
538      */
539
540     lasthdrflag = 0;
541     while((hdr_offset > 0) && (buffer_size > hdr_offset)) {
542         next_header_type = tvb_get_guint8(tvb, hdr_offset);
543         if(next_header_type == PAYLOAD_HEADER_TYPE) {
544             hdr_offset +=
545                 dissect_payload_header(bundle_tree, tvb, hdr_offset, &lasthdrflag);
546         }
547         else {  /*Assume anything else is a Metadata Block*/
548             hdr_offset += display_metadata_block(bundle_tree, tvb,
549                                                         hdr_offset, &lasthdrflag);
550         }
551         if(hdr_offset == 0) {
552             col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
553             return;
554         }
555         if(lasthdrflag) {
556             return;
557         }
558     }
559     return;
560 }
561
562 static int
563 dissect_tcp_convergence_data_header(tvbuff_t *tvb, proto_tree *tree)
564 {
565     proto_item *conv_item = NULL;
566     proto_tree *conv_tree = NULL;
567     int buflen = tvb_length(tvb);
568     int sdnv_length;
569     int segment_length;
570     proto_item *conv_flag_item = NULL;
571     proto_tree *conv_flag_tree = NULL;
572     guint8 tcp_convergence_hdr_procflags;
573
574     conv_item = proto_tree_add_text(tree, tvb, 0, -1, "TCP Convergence Header");
575     conv_tree = proto_item_add_subtree(conv_item, ett_tcp_conv_hdr);
576     proto_tree_add_text(conv_tree, tvb, 0, 1, "Pkt Type: Data");
577
578     /* Add tree for Start/End bits */
579     tcp_convergence_hdr_procflags = tvb_get_guint8(tvb, 0);
580     conv_flag_item = proto_tree_add_item(conv_tree, hf_tcp_convergence_data_procflags, tvb,
581                                                 0, 1, FALSE);
582     conv_flag_tree = proto_item_add_subtree(conv_flag_item, ett_conv_flags);
583     proto_tree_add_boolean(conv_flag_tree, hf_tcp_convergence_data_procflags_start,
584                                                 tvb, 0, 1, tcp_convergence_hdr_procflags);
585     proto_tree_add_boolean(conv_flag_tree, hf_tcp_convergence_data_procflags_end,
586                                                 tvb, 0, 1, tcp_convergence_hdr_procflags);
587
588     segment_length = evaluate_sdnv(tvb, 1, &sdnv_length);
589     proto_tree_add_text(conv_tree, tvb, 1, sdnv_length, "Segment Length: %d", segment_length);
590     proto_item_set_len(conv_item, sdnv_length + 1);
591     return buflen;
592 }
593
594 /*
595  * Dissect a complete bundle starting at offset 0 in tvb. Return 0 on failure,
596  * otherwise the length of the bundle.
597  */
598
599 static int
600 dissect_complete_bundle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
601 {
602     proto_item *primary_item = NULL;
603     proto_tree *primary_tree = NULL;
604     int primary_header_size;
605     int payload_size = 0;
606     int lastheader = 0;
607     int offset;
608     guint8 next_header_type;
609
610     primary_item = proto_tree_add_text(tree, tvb, 0, -1,
611                                                 "Primary Bundle Header");
612     primary_tree = proto_item_add_subtree(primary_item, ett_primary_hdr);
613     primary_header_size = dissect_primary_header(pinfo, primary_tree, tvb);
614     if(primary_header_size == 0) {      /*Couldn't parse primary header*/
615         col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
616         return(0);      /*Give up*/
617     }
618     proto_item_set_len(primary_item, primary_header_size);
619     offset = primary_header_size;
620
621     /*
622      * Done with primary header; decode the remaining headers
623      */
624
625     while(lastheader == 0) {
626         next_header_type = tvb_get_guint8(tvb, offset);
627         if(next_header_type == PAYLOAD_HEADER_TYPE) {
628
629             /*
630              * Returns payload size or 0 if can't parse payload
631              */
632
633             payload_size = dissect_payload_header(tree, tvb, offset, &lastheader);
634         }
635         else {  /*Assume anything else is a Metadata Block*/
636             payload_size = display_metadata_block(tree, tvb,
637                                                         offset, &lastheader);
638         }
639         if(payload_size == 0) { /*Payload header parse failed*/
640
641             col_set_str(pinfo->cinfo, COL_INFO, "Dissection Failed");
642             return (0);
643         }
644         offset += payload_size;
645     }
646     return(offset);
647 }
648
649 /*
650  * This routine returns 0 if header decoding fails, otherwise the length of the primary
651  * header. The bundle starts right at the beginning of the tvbuff.
652  */
653
654 static int
655 dissect_primary_header(packet_info *pinfo, proto_tree *primary_tree, tvbuff_t *tvb)
656 {
657     guint8 cosflags;
658     guint8 *dict_ptr;
659     guint8 *string_ptr;
660     gint string_length;
661     int offset;     /*Total offset into frame (frame_offset + convergence layer size)*/
662     int sdnv_length;
663     int dest_scheme_offset, dest_ssp_offset, source_scheme_offset, source_ssp_offset;
664     int report_scheme_offset, report_ssp_offset, cust_scheme_offset, cust_ssp_offset;
665     int fragment_offset, total_adu_length;
666
667     guint8 srrflags;
668     guint8 version;
669     proto_item *srr_flag_item = NULL;
670     proto_tree *srr_flag_tree = NULL;
671
672     proto_item *proc_flag_item = NULL;
673     proto_tree *proc_flag_tree = NULL;
674     proto_item *cos_flag_item = NULL;
675     proto_tree *cos_flag_tree = NULL;
676     proto_item *hdr_length_item = NULL;
677     proto_item *dict_length_item = NULL;
678     proto_item *dict_item = NULL;
679     proto_tree *dict_tree = NULL;
680     proto_item *dest_item = NULL;
681     proto_item *source_scheme_item = NULL;
682     proto_item *source_item = NULL;
683     proto_item *rpt_scheme_item = NULL;
684     proto_item *rpt_item = NULL;
685     proto_item *cust_scheme_item = NULL;
686     proto_item *cust_item = NULL;
687
688     offset = 0;
689
690     version = tvb_get_guint8(tvb, offset);
691     /* Primary Header Version */
692     if((version != 4) && (version != 5) && (version != 6)) {
693         proto_tree_add_text(primary_tree, tvb, offset, 1, "Invalid Version Number");
694         return 0;
695     }
696     proto_tree_add_item(primary_tree, hf_bundle_pdu_version, tvb, offset, 1, FALSE);
697     if((version == 5) || (version == 6)) {
698         return dissect_version_5_primary_header(pinfo, primary_tree, tvb);
699     }
700
701     /* Primary Header Processing Flags */
702     ++offset;
703     pri_hdr_procflags = tvb_get_guint8(tvb, offset);
704     proc_flag_item = proto_tree_add_item(primary_tree, hf_bundle_procflags, tvb,
705                                                 offset, 1, FALSE);
706     proc_flag_tree = proto_item_add_subtree(proc_flag_item, ett_proc_flags);
707     proto_tree_add_boolean(proc_flag_tree, hf_bundle_procflags_fragment,
708                                                 tvb, offset, 1, pri_hdr_procflags);
709     proto_tree_add_boolean(proc_flag_tree, hf_bundle_procflags_admin,
710                                                 tvb, offset, 1, pri_hdr_procflags);
711     proto_tree_add_boolean(proc_flag_tree, hf_bundle_procflags_dont_fragment,
712                                                 tvb, offset, 1, pri_hdr_procflags);
713     proto_tree_add_boolean(proc_flag_tree, hf_bundle_procflags_cust_xfer_req,
714                                                 tvb, offset, 1, pri_hdr_procflags);
715     proto_tree_add_boolean(proc_flag_tree, hf_bundle_procflags_dest_singleton,
716                                                 tvb, offset, 1, pri_hdr_procflags);
717
718     /* Primary Header COS Flags */
719     ++offset;
720     cosflags = tvb_get_guint8(tvb, offset);
721     cos_flag_item = proto_tree_add_item(primary_tree, hf_bundle_cosflags, tvb,
722                                                 offset, 1, FALSE);
723     cos_flag_tree = proto_item_add_subtree(cos_flag_item, ett_cos_flags);
724     proto_tree_add_uint(cos_flag_tree, hf_bundle_cosflags_priority,
725                                                 tvb, offset, 1, cosflags);
726     /* Status Report Request Flags */
727     ++offset;
728     srrflags = tvb_get_guint8(tvb, offset);
729     srr_flag_item = proto_tree_add_item(primary_tree, hf_bundle_srrflags, tvb,
730                                                 offset, 1, FALSE);
731     srr_flag_tree = proto_item_add_subtree(srr_flag_item, ett_srr_flags);
732
733     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_receipt,
734                                                 tvb, offset, 1, srrflags);
735     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_cust_accept,
736                                                 tvb, offset, 1, srrflags);
737     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_forward,
738                                                 tvb, offset, 1, srrflags);
739     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_delivery,
740                                                 tvb, offset, 1, srrflags);
741     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_deletion,
742                                                 tvb, offset, 1, srrflags);
743     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_ack,
744                                                 tvb, offset, 1, srrflags);
745     ++offset;
746     bundle_header_length = evaluate_sdnv(tvb, offset, &sdnv_length);
747     hdr_length_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
748     if(bundle_header_length < 0) {
749         proto_item_set_text(hdr_length_item, "Bundle Header Length: Error");
750         return 0;
751     }
752     proto_item_set_text(hdr_length_item,
753                         "Bundle Header Length: %d", bundle_header_length);
754     tvb_ensure_bytes_exist(tvb, offset + sdnv_length, bundle_header_length);
755     offset += sdnv_length;
756
757     /*
758      * Pick up offsets into dictionary (8 of them)
759      */
760
761     dest_scheme_offset = tvb_get_ntohs(tvb, offset);
762     proto_tree_add_item(primary_tree, hf_bundle_dest_scheme_offset,
763                                                         tvb, offset, 2, FALSE);
764     offset += 2;
765
766     dest_ssp_offset = tvb_get_ntohs(tvb, offset);
767     proto_tree_add_item(primary_tree, hf_bundle_dest_ssp_offset,
768                                                         tvb, offset, 2, FALSE);
769     offset += 2;
770
771     source_scheme_offset = tvb_get_ntohs(tvb, offset);
772     proto_tree_add_item(primary_tree, hf_bundle_source_scheme_offset,
773                                                         tvb, offset, 2, FALSE);
774     offset += 2;
775
776     source_ssp_offset = tvb_get_ntohs(tvb, offset);
777     proto_tree_add_item(primary_tree, hf_bundle_source_ssp_offset,
778                                                         tvb, offset, 2, FALSE);
779     offset += 2;
780
781     report_scheme_offset = tvb_get_ntohs(tvb, offset);
782     proto_tree_add_item(primary_tree, hf_bundle_report_scheme_offset,
783                                                         tvb, offset, 2, FALSE);
784     offset += 2;
785
786     report_ssp_offset = tvb_get_ntohs(tvb, offset);
787     proto_tree_add_item(primary_tree, hf_bundle_report_ssp_offset,
788                                                         tvb, offset, 2, FALSE);
789     offset += 2;
790
791     cust_scheme_offset = tvb_get_ntohs(tvb, offset);
792     proto_tree_add_item(primary_tree, hf_bundle_cust_scheme_offset,
793                                                         tvb, offset, 2, FALSE);
794     offset += 2;
795
796     cust_ssp_offset = tvb_get_ntohs(tvb, offset);
797     proto_tree_add_item(primary_tree, hf_bundle_cust_ssp_offset,
798                                                         tvb, offset, 2, FALSE);
799     offset += 2;
800
801     proto_tree_add_item(primary_tree, hf_bundle_creation_timestamp,
802                                                         tvb, offset, 8, FALSE);
803     offset += 8;
804
805     proto_tree_add_item(primary_tree, hf_bundle_lifetime, tvb, offset, 4, FALSE);
806     offset += 4;
807
808     bundle_header_dict_length = evaluate_sdnv(tvb, offset, &sdnv_length);
809     dict_length_item = proto_tree_add_text(primary_tree,
810                                                 tvb, offset, sdnv_length, " ");
811     if(bundle_header_dict_length < 0) {
812         proto_item_set_text(dict_length_item, "Dictionary Length: Error");
813         return 0;
814     }
815     proto_item_set_text(dict_length_item, "Dictionary Length: %d",
816                                                         bundle_header_dict_length);
817     offset += sdnv_length;
818     tvb_ensure_bytes_exist(tvb, offset, bundle_header_dict_length);
819
820     /*
821      * Pull out stuff from the dictionary
822      */
823
824     dict_item = proto_tree_add_text(primary_tree, tvb, offset,
825                                         bundle_header_dict_length, "Dictionary");
826     dict_tree = proto_item_add_subtree(dict_item, ett_dictionary);
827     dict_ptr = (guint8 *) tvb_get_ptr(tvb, offset, bundle_header_dict_length);
828
829     /*
830      * This pointer can be made to address outside the packet boundaries so we
831      * need to check for improperly formatted strings (no null termination).
832      */
833
834     /*
835      * Destination info
836      */
837
838     string_ptr = tvb_get_ephemeral_stringz(tvb, offset + dest_scheme_offset, &string_length);
839
840     proto_tree_add_text(dict_tree, tvb, offset + dest_scheme_offset,
841                                 (gint)strlen((char *) (dict_ptr + dest_scheme_offset)),
842                                                 "Destination Scheme: %s", string_ptr);
843     string_ptr = tvb_get_ephemeral_stringz(tvb, offset + dest_ssp_offset, &string_length);
844     dest_item = proto_tree_add_text(dict_tree, tvb, offset + dest_ssp_offset,
845                                 (gint)strlen((char *) (dict_ptr + dest_ssp_offset)), " ");
846     proto_item_set_text(dest_item, "Destination: %s", string_ptr);
847
848     /*
849      * Source info
850      */
851
852     string_ptr = tvb_get_ephemeral_stringz(tvb,
853                                 offset + source_scheme_offset, &string_length);
854     source_scheme_item = proto_tree_add_text(dict_tree, tvb, offset+source_scheme_offset,
855                                 (gint)strlen((char *) (dict_ptr + source_scheme_offset)), " ");
856     proto_item_set_text(source_scheme_item, "Source Scheme: %s", string_ptr);
857     string_ptr = tvb_get_ephemeral_stringz(tvb,
858                                 offset + source_ssp_offset, &string_length);
859     source_item = proto_tree_add_text(dict_tree, tvb, offset + source_ssp_offset,
860                                 (gint)strlen((char *) (dict_ptr + source_ssp_offset)), " ");
861     proto_item_set_text(source_item, "Source: %s", string_ptr);
862
863     /*
864      * Report to info
865      */
866
867     string_ptr = tvb_get_ephemeral_stringz(tvb,
868                                 offset + report_scheme_offset, &string_length);
869     rpt_scheme_item = proto_tree_add_text(dict_tree, tvb, offset + report_scheme_offset,
870                                 (gint)strlen((char *) (dict_ptr + report_scheme_offset)), " ");
871     proto_item_set_text(rpt_scheme_item, "Report To Scheme: %s", string_ptr);
872     string_ptr = tvb_get_ephemeral_stringz(tvb,
873                                 offset + report_ssp_offset, &string_length);
874     rpt_item = proto_tree_add_text(dict_tree, tvb, offset + report_ssp_offset,
875                                 (gint)strlen((char *) (dict_ptr + report_ssp_offset)), " ");
876     proto_item_set_text(rpt_item, "Report To: %s", string_ptr);
877
878     /*
879      * Custodian info
880      */
881
882     string_ptr = tvb_get_ephemeral_stringz(tvb,
883                                 offset + cust_scheme_offset, &string_length);
884     cust_scheme_item = proto_tree_add_text(dict_tree, tvb, offset + cust_scheme_offset,
885                                 (gint)strlen((char *) (dict_ptr + cust_scheme_offset)), " ");
886     proto_item_set_text(cust_scheme_item, "Custodian Scheme: %s", string_ptr);
887     string_ptr = tvb_get_ephemeral_stringz(tvb,
888                                 offset + cust_ssp_offset, &string_length);
889     cust_item = proto_tree_add_text(dict_tree, tvb, offset + cust_ssp_offset,
890                                 (gint)strlen((char *) (dict_ptr + cust_ssp_offset)), " ");
891     proto_item_set_text(cust_item, "Custodian: %s", string_ptr);
892
893     /*
894      * Add Source/Destination to INFO Field
895      */
896
897     col_add_fstr(pinfo->cinfo, COL_INFO, "%s:%s > %s:%s",
898                                 dict_ptr + source_scheme_offset, dict_ptr + source_ssp_offset,
899                                 dict_ptr + dest_scheme_offset, dict_ptr + dest_ssp_offset);
900     offset += bundle_header_dict_length;        /*Skip over dictionary*/
901
902     /*
903      * Do this only if Fragment Flag is set
904      */
905
906     if(pri_hdr_procflags & BUNDLE_PROCFLAGS_FRAG_MASK) {
907         fragment_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
908         if(fragment_offset < 0) {
909             return 0;
910         }
911         proto_tree_add_text(primary_tree, tvb, offset, sdnv_length,
912                                         "Fragment Offset: %d", fragment_offset);
913         offset += sdnv_length;
914
915         total_adu_length = evaluate_sdnv(tvb, offset, &sdnv_length);
916         if(total_adu_length < 0) {
917             return 0;
918         }
919         proto_tree_add_text(primary_tree, tvb, offset, sdnv_length,
920                         "Total Application Data Unit Length: %d", fragment_offset);
921         offset += sdnv_length;
922     }
923     return (offset);
924 }
925
926
927 /*
928  * This routine returns 0 if header decoding fails, otherwise the length of the primary
929  * header. The bundle starts right at the beginning of the tvbuff.
930  */
931
932 static int
933 dissect_version_5_primary_header(packet_info *pinfo,
934                                         proto_tree *primary_tree, tvbuff_t *tvb)
935 {
936     int bundle_processing_control_flags;
937     guint8 cosflags;
938     guint8 *dict_ptr;
939     int offset;         /*Total offset into frame (frame_offset + convergence layer size)*/
940     int sdnv_length;
941     int dest_scheme_offset, dest_ssp_offset, source_scheme_offset, source_ssp_offset;
942     int report_scheme_offset, report_ssp_offset, cust_scheme_offset, cust_ssp_offset;
943     int fragment_offset, total_adu_length;
944     int timestamp;
945     time_t time_since_2000;
946     int timestamp_sequence;
947     int lifetime;
948     char *time_string;
949     guint8 srrflags;
950     proto_item *srr_flag_item = NULL;
951     proto_tree *srr_flag_tree = NULL;
952     proto_item *gen_flag_item = NULL;
953     proto_tree *gen_flag_tree = NULL;
954
955     proto_item *proc_flag_item = NULL;
956     proto_tree *proc_flag_tree = NULL;
957     proto_item *cos_flag_item = NULL;
958     proto_item *cos_flag_value = NULL;
959     proto_tree *cos_flag_tree = NULL;
960     proto_item *hdr_length_item = NULL;
961     proto_item *dict_length_item = NULL;
962     proto_item *dict_item = NULL;
963     proto_tree *dict_tree = NULL;
964
965     proto_item *timestamp_item = NULL;
966     proto_item *timestamp_sequence_item = NULL;
967     proto_item *lifetime_item = NULL;
968     proto_item *dest_scheme_offset_item = NULL;
969     proto_item *dest_ssp_offset_item = NULL;
970     proto_item *source_scheme_offset_item = NULL;
971     proto_item *source_ssp_offset_item = NULL;
972     proto_item *report_scheme_offset_item = NULL;
973     proto_item *report_ssp_offset_item = NULL;
974     proto_item *cust_scheme_offset_item = NULL;
975     proto_item *cust_ssp_offset_item = NULL;
976
977     offset = 1;         /*Already displayed Version Number*/
978     bundle_processing_control_flags = evaluate_sdnv(tvb, offset, &sdnv_length);
979
980     /* Primary Header Processing Flags */
981     pri_hdr_procflags = (guint8) (bundle_processing_control_flags & 0x7f);
982
983     proc_flag_item = proto_tree_add_item(primary_tree, hf_bundle_control_flags, tvb,
984                                                 offset, sdnv_length, FALSE);
985     proc_flag_tree = proto_item_add_subtree(proc_flag_item, ett_proc_flags);
986
987     gen_flag_item = proto_tree_add_text(proc_flag_tree, tvb, offset,
988                                         sdnv_length, "General Flags");
989     gen_flag_tree = proto_item_add_subtree(gen_flag_item, ett_gen_flags);
990
991     proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_fragment,
992                                         tvb, offset, sdnv_length, pri_hdr_procflags);
993     proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_admin,
994                                         tvb, offset, sdnv_length, pri_hdr_procflags);
995     proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_dont_fragment,
996                                         tvb, offset, sdnv_length, pri_hdr_procflags);
997     proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_cust_xfer_req,
998                                         tvb, offset, sdnv_length, pri_hdr_procflags);
999     proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_dest_singleton,
1000                                         tvb, offset, sdnv_length, pri_hdr_procflags);
1001     proto_tree_add_boolean(gen_flag_tree, hf_bundle_procflags_application_ack,
1002                                         tvb, offset, sdnv_length, pri_hdr_procflags);
1003
1004     /* Primary Header COS Flags */
1005     cosflags = (guint8) ((bundle_processing_control_flags >> 7) & 0x7f);
1006     cos_flag_item = proto_tree_add_text(proc_flag_tree, tvb, offset,
1007                                         sdnv_length, "Class of Service Flags");
1008     cos_flag_tree = proto_item_add_subtree(cos_flag_item, ett_cos_flags);
1009     if((cosflags & BUNDLE_COSFLAGS_PRIORITY_MASK) == BUNDLE_COSFLAGS_PRIORITY_BULK) {
1010         cos_flag_value = proto_tree_add_text(cos_flag_tree, tvb, offset,
1011                                         sdnv_length, "00 -- Priority = Bulk");
1012     }
1013     else if((cosflags & BUNDLE_COSFLAGS_PRIORITY_MASK) ==
1014                                         BUNDLE_COSFLAGS_PRIORITY_NORMAL) {
1015         cos_flag_value = proto_tree_add_text(cos_flag_tree, tvb, offset,
1016                                         sdnv_length, "01 -- Priority = Normal");
1017     }
1018     else if((cosflags & BUNDLE_COSFLAGS_PRIORITY_MASK) ==
1019                                         BUNDLE_COSFLAGS_PRIORITY_EXP) {
1020         cos_flag_value = proto_tree_add_text(cos_flag_tree, tvb, offset,
1021                                         sdnv_length, "10 -- Priority = Expedited");
1022     }
1023     else {
1024         cos_flag_value = proto_tree_add_text(cos_flag_tree, tvb, offset,
1025                                         sdnv_length, "11 -- Invalid (Reserved)");
1026         return 0;
1027     }
1028
1029     /* Status Report Request Flags */
1030     srrflags = (guint8) ((bundle_processing_control_flags >> 14) & 0x7f);
1031     srr_flag_item = proto_tree_add_text(proc_flag_tree, tvb, offset,
1032                                         sdnv_length, "Status Report Request Flags");
1033     srr_flag_tree = proto_item_add_subtree(srr_flag_item, ett_srr_flags);
1034
1035     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_receipt,
1036                                                 tvb, offset, sdnv_length, srrflags);
1037     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_cust_accept,
1038                                                 tvb, offset, sdnv_length, srrflags);
1039     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_forward,
1040                                                 tvb, offset, sdnv_length, srrflags);
1041     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_delivery,
1042                                                 tvb, offset, sdnv_length, srrflags);
1043     proto_tree_add_boolean(srr_flag_tree, hf_bundle_srrflags_report_deletion,
1044                                                 tvb, offset, sdnv_length, srrflags);
1045     offset += sdnv_length;
1046
1047     bundle_header_length = evaluate_sdnv(tvb, offset, &sdnv_length);
1048     hdr_length_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1049     if(bundle_header_length < 0) {
1050         proto_item_set_text(hdr_length_item, "Bundle Header Length: Error");
1051         return 0;
1052     }
1053     proto_item_set_text(hdr_length_item,
1054                         "Bundle Header Length: %d", bundle_header_length);
1055     tvb_ensure_bytes_exist(tvb, offset + sdnv_length, bundle_header_length);
1056     offset += sdnv_length;
1057
1058     /*
1059      * Pick up offsets into dictionary (8 of them). Do rough sanity check that SDNV
1060      * hasn't told us to access way past the Primary Header.
1061      */
1062
1063     dest_scheme_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
1064     dest_scheme_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1065     if((dest_scheme_offset < 0) || (dest_scheme_offset > bundle_header_length)) {
1066         proto_item_set_text(dest_scheme_offset_item, "Destination Scheme Offset: Error");
1067         return 0;
1068     }
1069     proto_item_set_text(dest_scheme_offset_item,
1070                         "Destination Scheme Offset: %d", dest_scheme_offset);
1071     offset += sdnv_length;
1072
1073     dest_ssp_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
1074     dest_ssp_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1075     if((dest_ssp_offset < 0) || (dest_ssp_offset > bundle_header_length)) {
1076         proto_item_set_text(dest_ssp_offset_item, "Destination SSP Offset: Error");
1077         return 0;
1078     }
1079     proto_item_set_text(dest_ssp_offset_item,
1080                         "Destination SSP Offset: %d", dest_ssp_offset);
1081     offset += sdnv_length;
1082
1083     source_scheme_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
1084     source_scheme_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1085     if((source_scheme_offset < 0) || (source_scheme_offset > bundle_header_length)) {
1086         proto_item_set_text(source_scheme_offset_item, "Source Scheme Offset: Error");
1087         return 0;
1088     }
1089     proto_item_set_text(source_scheme_offset_item,
1090                         "Source Scheme Offset: %d", source_scheme_offset);
1091     offset += sdnv_length;
1092
1093     source_ssp_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
1094     source_ssp_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1095     if((source_ssp_offset < 0) || (source_ssp_offset > bundle_header_length)) {
1096         proto_item_set_text(source_ssp_offset_item, "Source SSP Offset: Error");
1097         return 0;
1098     }
1099     proto_item_set_text(source_ssp_offset_item,
1100                         "Source SSP Offset: %d", source_ssp_offset);
1101     offset += sdnv_length;
1102
1103     report_scheme_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
1104     report_scheme_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1105     if((report_scheme_offset < 0) || (report_scheme_offset > bundle_header_length)) {
1106         proto_item_set_text(report_scheme_offset_item, "Report Scheme Offset: Error");
1107         return 0;
1108     }
1109     proto_item_set_text(report_scheme_offset_item,
1110                         "Report Scheme Offset: %d", report_scheme_offset);
1111     offset += sdnv_length;
1112
1113     report_ssp_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
1114     report_ssp_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1115     if((report_ssp_offset < 0) || (report_ssp_offset > bundle_header_length)) {
1116         proto_item_set_text(report_ssp_offset_item, "Report SSP Offset: Error");
1117         return 0;
1118     }
1119     proto_item_set_text(report_ssp_offset_item,
1120                         "Report SSP Offset: %d", report_ssp_offset);
1121     offset += sdnv_length;
1122
1123     cust_scheme_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
1124     cust_scheme_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1125     if((cust_scheme_offset < 0) || (cust_scheme_offset > bundle_header_length)) {
1126         proto_item_set_text(cust_scheme_offset_item, "Custodian Scheme Offset: Error");
1127         return 0;
1128     }
1129     proto_item_set_text(cust_scheme_offset_item,
1130                         "Custodian Scheme Offset: %d", cust_scheme_offset);
1131     offset += sdnv_length;
1132
1133     cust_ssp_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
1134     cust_ssp_offset_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1135     if((cust_ssp_offset < 0) || (cust_ssp_offset > bundle_header_length)) {
1136         proto_item_set_text(cust_ssp_offset_item, "Custodian SSP Offset: Error");
1137         return 0;
1138     }
1139     proto_item_set_text(cust_ssp_offset_item,
1140                         "Custodian SSP Offset: %d", cust_ssp_offset);
1141     offset += sdnv_length;
1142
1143     timestamp = evaluate_sdnv(tvb, offset, &sdnv_length);
1144     timestamp_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1145     if(timestamp < 0) {
1146         proto_item_set_text(timestamp_item, "Timestamp: Error");
1147         return 0;
1148     }
1149     time_since_2000 = (time_t) (timestamp + 946684800);
1150     time_string = ctime(&time_since_2000);
1151     time_string[strlen(time_string) - 1] = 0; /*Remove Newline at enc*/
1152     proto_item_set_text(timestamp_item,
1153                         "Timestamp: 0x%x [%s]", timestamp, time_string);
1154     offset += sdnv_length;
1155
1156     timestamp_sequence = evaluate_sdnv(tvb, offset, &sdnv_length);
1157     timestamp_sequence_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1158
1159     if(timestamp_sequence < 0) {
1160         gint64 ts_seq;
1161
1162         if((ts_seq = evaluate_sdnv_64(tvb, offset, &sdnv_length)) < 0) {
1163             proto_item_set_text(timestamp_sequence_item, "Timestamp Sequence Number: Error");
1164             return 0;
1165         }
1166         proto_item_set_text(timestamp_sequence_item,
1167                 "Timestamp Sequence Number: 0x%" G_GINT64_MODIFIER "x", ts_seq);
1168     }
1169     else {
1170         proto_item_set_text(timestamp_sequence_item,
1171                                 "Timestamp Sequence Number: %d", timestamp_sequence);
1172     }
1173     offset += sdnv_length;
1174
1175     lifetime = evaluate_sdnv(tvb, offset, &sdnv_length);
1176     lifetime_item = proto_tree_add_text(primary_tree, tvb, offset, sdnv_length, " ");
1177     if(lifetime < 0) {
1178         proto_item_set_text(lifetime_item, "Lifetime: Error");
1179         return 0;
1180     }
1181     proto_item_set_text(lifetime_item, "Lifetime: %d", lifetime);
1182     offset += sdnv_length;
1183
1184     bundle_header_dict_length = evaluate_sdnv(tvb, offset, &sdnv_length);
1185     dict_length_item = proto_tree_add_text(primary_tree,
1186                                                 tvb, offset, sdnv_length, " ");
1187     if(bundle_header_dict_length < 0) {
1188         proto_item_set_text(dict_length_item, "Dictionary Length: Error");
1189         return 0;
1190     }
1191     proto_item_set_text(dict_length_item, "Dictionary Length: %d",
1192                                                         bundle_header_dict_length);
1193     offset += sdnv_length;
1194     tvb_ensure_bytes_exist(tvb, offset, bundle_header_dict_length);
1195
1196     /*
1197      * Pull out stuff from the dictionary
1198      */
1199
1200     dict_item = proto_tree_add_text(primary_tree, tvb, offset,
1201                                         bundle_header_dict_length, "Dictionary");
1202     dict_tree = proto_item_add_subtree(dict_item, ett_dictionary);
1203     dict_ptr = (guint8 *) tvb_get_ptr(tvb, offset, bundle_header_dict_length);
1204
1205     /*
1206      * This pointer can be made to address outside the packet boundaries so we
1207      * need to check for improperly formatted strings (no null termination).
1208      */
1209
1210     /*
1211      * Destination info
1212      */
1213
1214     tvb_ensure_bytes_exist(tvb, offset, dest_scheme_offset);
1215     proto_tree_add_item(dict_tree, hf_bundle_dest_scheme, tvb, offset + dest_scheme_offset,
1216                                 (gint)strlen((char *) (dict_ptr + dest_scheme_offset)), FALSE);
1217     tvb_ensure_bytes_exist(tvb, offset, dest_ssp_offset);
1218     proto_tree_add_item(dict_tree, hf_bundle_dest_ssp, tvb, offset + dest_ssp_offset,
1219                                 (gint)strlen((char *) (dict_ptr + dest_ssp_offset)), FALSE);
1220
1221     /*
1222      * Destination info
1223      */
1224
1225     tvb_ensure_bytes_exist(tvb, offset, source_scheme_offset);
1226     proto_tree_add_item(dict_tree, hf_bundle_source_scheme, tvb, offset + source_scheme_offset,
1227                                 (gint)strlen((char *) (dict_ptr + source_scheme_offset)), FALSE);
1228     tvb_ensure_bytes_exist(tvb, offset, source_ssp_offset);
1229     proto_tree_add_item(dict_tree, hf_bundle_source_ssp, tvb, offset + source_ssp_offset,
1230                                 (gint)strlen((char *) (dict_ptr + source_ssp_offset)), FALSE);
1231
1232     /*
1233      * Report to info
1234      */
1235
1236     tvb_ensure_bytes_exist(tvb, offset, report_scheme_offset);
1237     proto_tree_add_item(dict_tree, hf_bundle_report_scheme, tvb, offset + report_scheme_offset,
1238                                 (gint)strlen((char *) (dict_ptr + report_scheme_offset)), FALSE);
1239     tvb_ensure_bytes_exist(tvb, offset, report_ssp_offset);
1240     proto_tree_add_item(dict_tree, hf_bundle_report_ssp, tvb, offset + report_ssp_offset,
1241                                 (gint)strlen((char *) (dict_ptr + report_ssp_offset)), FALSE);
1242
1243     /*
1244      * Custodian info
1245      */
1246
1247     tvb_ensure_bytes_exist(tvb, offset, cust_scheme_offset);
1248     proto_tree_add_item(dict_tree, hf_bundle_custodian_scheme, tvb, offset + cust_scheme_offset,
1249                                 (gint)strlen((char *) (dict_ptr + cust_scheme_offset)), FALSE);
1250
1251     tvb_ensure_bytes_exist(tvb, offset, cust_ssp_offset);
1252     proto_tree_add_item(dict_tree, hf_bundle_custodian_ssp, tvb, offset + cust_ssp_offset,
1253                                 (gint)strlen((char *) (dict_ptr + cust_ssp_offset)), FALSE);
1254
1255     /*
1256      * Add Source/Destination to INFO Field
1257      */
1258
1259     if(check_col(pinfo->cinfo, COL_INFO)) {
1260         col_add_fstr(pinfo->cinfo, COL_INFO, "%s:%s > %s:%s",
1261                         dict_ptr + source_scheme_offset, dict_ptr + source_ssp_offset,
1262                         dict_ptr + dest_scheme_offset, dict_ptr + dest_ssp_offset);
1263     }
1264     offset += bundle_header_dict_length;        /*Skip over dictionary*/
1265
1266     /*
1267      * Do this only if Fragment Flag is set
1268      */
1269
1270     if(pri_hdr_procflags & BUNDLE_PROCFLAGS_FRAG_MASK) {
1271         fragment_offset = evaluate_sdnv(tvb, offset, &sdnv_length);
1272         if(fragment_offset < 0) {
1273             return 0;
1274         }
1275         proto_tree_add_text(primary_tree, tvb, offset, sdnv_length,
1276                                         "Fragment Offset: %d", fragment_offset);
1277         offset += sdnv_length;
1278
1279         total_adu_length = evaluate_sdnv(tvb, offset, &sdnv_length);
1280         if(total_adu_length < 0) {
1281             return 0;
1282         }
1283         proto_tree_add_text(primary_tree, tvb, offset, sdnv_length,
1284                         "Total Application Data Unit Length: %d", fragment_offset);
1285         offset += sdnv_length;
1286     }
1287     return (offset);
1288 }
1289
1290 /*
1291  * bundle_offset is offset into this bundle where header starts.
1292  * Return size of payload (including payload header) or 0 on failure.
1293  */
1294
1295 static int
1296 dissect_payload_header(proto_tree *tree, tvbuff_t *tvb, int offset, int *lastheader)
1297 {
1298     proto_item *payload_item = NULL;
1299     proto_tree *payload_tree = NULL;
1300     proto_item *proc_flag_item = NULL;
1301     proto_tree *proc_flag_tree = NULL;
1302     proto_item *hdr_length_item = NULL;
1303     proto_item *type_item = NULL;
1304     guint8 procflags;
1305     int sdnv_length;
1306     int header_start;
1307     int payload_length;
1308
1309     header_start = offset;      /*Used to compute total payload length*/
1310     payload_item = proto_tree_add_text(tree, tvb, offset, -1, "Payload Header");
1311     payload_tree = proto_item_add_subtree(payload_item, ett_payload_hdr);
1312
1313     type_item = proto_tree_add_text(payload_tree, tvb, offset, 1, "Header Type: 1");
1314     ++offset;
1315
1316     /* Add tree for processing flags */
1317     /* This is really a SDNV but there are only 7 bits defined so leave it this way*/
1318
1319     if(hf_bundle_pdu_version == 4) {
1320         procflags = tvb_get_guint8(tvb, offset);
1321         if(procflags & HEADER_PROCFLAGS_LAST_HEADER) {
1322             *lastheader = 1;
1323         }
1324         else {
1325             *lastheader = 0;
1326         }
1327         proc_flag_item = proto_tree_add_item(payload_tree, hf_bundle_payload_flags, tvb,
1328                                                 offset, 1, FALSE);
1329         proc_flag_tree = proto_item_add_subtree(proc_flag_item, ett_payload_flags);
1330         proto_tree_add_boolean(proc_flag_tree, hf_bundle_payload_flags_replicate_hdr,
1331                                                 tvb, offset, 1, procflags);
1332         proto_tree_add_boolean(proc_flag_tree, hf_bundle_payload_flags_xmit_report,
1333                                                 tvb, offset, 1, procflags);
1334         proto_tree_add_boolean(proc_flag_tree, hf_bundle_payload_flags_discard_on_fail,
1335                                                 tvb, offset, 1, procflags);
1336         proto_tree_add_boolean(proc_flag_tree, hf_bundle_payload_flags_last_header,
1337                                                 tvb, offset, 1, procflags);
1338         ++offset;
1339     }
1340     else {      /*Bundle Protocol Version 5*/
1341         int control_flags;
1342         proto_item *block_flag_item = NULL;
1343         proto_tree *block_flag_tree = NULL;
1344
1345         control_flags = evaluate_sdnv(tvb, offset, &sdnv_length);
1346         if(control_flags & BLOCK_CONTROL_LAST_BLOCK) {
1347             *lastheader = 1;
1348         }
1349         else {
1350             *lastheader = 0;
1351         }
1352         block_flag_item = proto_tree_add_item(payload_tree, hf_block_control_flags, tvb,
1353                                                 offset, sdnv_length, FALSE);
1354         block_flag_tree = proto_item_add_subtree(block_flag_item, ett_block_flags);
1355
1356         proto_tree_add_boolean(block_flag_tree, hf_block_control_replicate,
1357                                         tvb, offset, sdnv_length, control_flags);
1358         proto_tree_add_boolean(block_flag_tree, hf_block_control_transmit_status,
1359                                         tvb, offset, sdnv_length, control_flags);
1360         proto_tree_add_boolean(block_flag_tree, hf_block_control_delete_bundle,
1361                                         tvb, offset, sdnv_length, control_flags);
1362         proto_tree_add_boolean(block_flag_tree, hf_block_control_last_block,
1363                                         tvb, offset, sdnv_length, control_flags);
1364         proto_tree_add_boolean(block_flag_tree, hf_block_control_discard_block,
1365                                         tvb, offset, sdnv_length, control_flags);
1366         proto_tree_add_boolean(block_flag_tree, hf_block_control_not_processed,
1367                                         tvb, offset, sdnv_length, control_flags);
1368         proto_tree_add_boolean(block_flag_tree, hf_block_control_eid_reference,
1369                                         tvb, offset, sdnv_length, control_flags);
1370         offset += sdnv_length;
1371     }
1372     payload_length = evaluate_sdnv(tvb, offset, &sdnv_length);
1373     proto_item_set_len(payload_item, 2 + sdnv_length);
1374     hdr_length_item = proto_tree_add_text(payload_tree, tvb, offset, sdnv_length, " ");
1375     if(payload_length < 0) {
1376         proto_item_set_text(hdr_length_item, "Payload Length: Error");
1377         return 0;
1378     }
1379     proto_item_set_text(hdr_length_item, "Payload Length: %d", payload_length);
1380
1381     offset += sdnv_length;
1382     if(pri_hdr_procflags & BUNDLE_PROCFLAGS_ADMIN_MASK) {
1383         int admin_size;
1384
1385         /*
1386          * XXXX - Have not allowed for admin record spanning multiple segments!
1387          */
1388
1389         admin_size = dissect_admin_record(payload_tree, tvb, offset);
1390         if(admin_size == 0) {
1391             return 0;
1392         }
1393     }
1394     return (payload_length + (offset - header_start));
1395 }
1396
1397 /*
1398  * Return the length of the Administrative Record or 0 if analysis fails.
1399  */
1400
1401 static int
1402 dissect_admin_record(proto_tree *primary_tree, tvbuff_t *tvb, int offset)
1403 {
1404     proto_item *admin_record_item = NULL;
1405     proto_tree *admin_record_tree = NULL;
1406     proto_item *status_flag_item = NULL;
1407     proto_tree *status_flag_tree = NULL;
1408     proto_item *admin_record_type = NULL;
1409     guint8 record_type;
1410     guint8 status;
1411     guint8 reason;
1412     int record_size = 0;
1413     int sdnv_length;
1414     int endpoint_length;
1415     guint8 *string_ptr;
1416     int string_length;
1417
1418     admin_record_item = proto_tree_add_text(primary_tree, tvb, offset, -1,
1419                                                         "Administrative Record");
1420     admin_record_tree = proto_item_add_subtree(admin_record_item, ett_admin_record);
1421     record_type = tvb_get_guint8(tvb, offset);
1422
1423     if(record_type == (0x05 << 4)) {
1424         proto_tree_add_text(admin_record_tree, tvb, offset, 1, "Announce Record (Contact)");
1425         return 1;       /*Special case for poxy TCP Convergence Layer Announce Bundle*/
1426     }
1427     if(record_type & ADMIN_REC_FLAGS_FRAGMENT) {
1428         proto_tree_add_text(admin_record_tree, tvb, offset, 1, "Record is for a Fragment");
1429     }
1430     else {
1431         proto_tree_add_text(admin_record_tree,
1432                                 tvb, offset, 1, "Record is not for a Fragment");
1433     }
1434
1435     switch((record_type >> 4) & 0xf)
1436     {
1437
1438     case ADMIN_REC_TYPE_STATUS_REPORT:
1439         admin_record_type = proto_tree_add_text(admin_record_tree, tvb, offset, 1,
1440                                 "Administrative Record Type: Bundle Status Report");
1441         ++record_size; ++offset;
1442
1443         /* Decode Bundle Status Report Flags */
1444         status = tvb_get_guint8(tvb, offset);
1445         status_flag_item = proto_tree_add_item(admin_record_tree,
1446                                 hf_bundle_admin_statflags, tvb, offset, 1, FALSE);
1447         status_flag_tree = proto_item_add_subtree(status_flag_item,
1448                                                         ett_admin_rec_status);
1449         proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_rcvd,
1450                                                 tvb, offset, 1, status);
1451         proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_accepted,
1452                                                 tvb, offset, 1, status);
1453         proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_forwarded,
1454                                                 tvb, offset, 1, status);
1455         proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_delivered,
1456                                                 tvb, offset, 1, status);
1457         proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_deleted,
1458                                                 tvb, offset, 1, status);
1459         proto_tree_add_boolean(status_flag_tree, hf_bundle_admin_acked,
1460                                                 tvb, offset, 1, status);
1461         ++record_size; ++offset;
1462
1463         reason = tvb_get_guint8(tvb, offset);
1464         if(reason == 0) {
1465             proto_tree_add_text(admin_record_tree, tvb, offset, 1,
1466                                 "Reason Code: 0 (No Additional Information)");
1467         }
1468         else {
1469             proto_tree_add_text(admin_record_tree, tvb, offset, 1,
1470                                         "Reason Code: 0x%x (%s)", reason,
1471                                         val_to_str(reason, status_report_reason_codes,
1472                                                         "Invalid"));
1473         }
1474         ++record_size; ++offset;
1475         if(record_type & ADMIN_REC_FLAGS_FRAGMENT) {
1476             sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
1477                                                         "Fragment Offset");
1478             if(sdnv_length <= 0) {
1479                 return 0;
1480             }
1481             offset += sdnv_length; record_size += sdnv_length;
1482             sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
1483                                                         "Fragment Length");
1484             if(sdnv_length <= 0) {
1485                 return 0;
1486             }
1487             offset += sdnv_length; record_size += sdnv_length;
1488         }
1489         if(status & ADMIN_STATUS_FLAGS_RECEIVED) {
1490             sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
1491                                                         "Bundle Received Time");
1492             if(sdnv_length <= 0) {
1493                 return 0;
1494             }
1495             offset += sdnv_length; record_size += sdnv_length;
1496         }
1497         if(status & ADMIN_STATUS_FLAGS_ACCEPTED) {
1498             sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
1499                                                         "Bundle Accepted Time");
1500             if(sdnv_length <= 0) {
1501                 return 0;
1502             }
1503             offset += sdnv_length; record_size += sdnv_length;
1504         }
1505         if(status & ADMIN_STATUS_FLAGS_FORWARDED) {
1506             sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
1507                                                         "Bundle Forwarded Time");
1508             if(sdnv_length <= 0) {
1509                 return 0;
1510             }
1511             offset += sdnv_length; record_size += sdnv_length;
1512         }
1513         if(status & ADMIN_STATUS_FLAGS_DELIVERED) {
1514             sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
1515                                                         "Bundle Delivered Time");
1516             if(sdnv_length <= 0) {
1517                 return 0;
1518             }
1519             offset += sdnv_length; record_size += sdnv_length;
1520         }
1521         if(status & ADMIN_STATUS_FLAGS_DELETED) {
1522             sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
1523                                                         "Bundle Deleted Time");
1524             if(sdnv_length <= 0) {
1525                 return 0;
1526             }
1527             offset += sdnv_length; record_size += sdnv_length;
1528         }
1529         if(status & ADMIN_STATUS_FLAGS_ACKNOWLEDGED) {
1530             sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
1531                                                         "Bundle Acknowledged Time");
1532             if(sdnv_length <= 0) {
1533                 return 0;
1534             }
1535             offset += sdnv_length; record_size += sdnv_length;
1536         }
1537
1538         /* Get 2 SDNVs for Creation Timestamp */
1539         sdnv_length = add_sdnv_time_to_tree(admin_record_tree, tvb, offset,
1540                                         "Bundle Creation Timestamp");
1541         if(sdnv_length <= 0) {
1542             return 0;
1543         }
1544         offset += sdnv_length; record_size += sdnv_length;
1545         sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
1546                                         "Bundle Creation Timestamp Sequence");
1547         if(sdnv_length <= 0) {
1548             return 0;
1549         }
1550         offset += sdnv_length; record_size += sdnv_length;
1551
1552         endpoint_length = evaluate_sdnv(tvb, offset, &sdnv_length);
1553         if(endpoint_length < 0) {
1554             return 0;
1555         }
1556         proto_tree_add_text(admin_record_tree, tvb, offset, sdnv_length,
1557                                         "Endpoint Length: %d", endpoint_length);
1558         offset += sdnv_length; record_size += sdnv_length;
1559
1560         /*
1561          * Endpoint name may not be null terminated. This routine is supposed
1562          * to add the null at the end of the string buffer.
1563          */
1564
1565         string_ptr = tvb_get_ephemeral_string(tvb, offset, endpoint_length);
1566         proto_tree_add_text(admin_record_tree, tvb, offset, endpoint_length,
1567                                                 "Bundle Endpoint ID: %s", string_ptr);
1568         offset += endpoint_length; record_size += endpoint_length;
1569
1570         return record_size;
1571
1572     case ADMIN_REC_TYPE_CUSTODY_SIGNAL:
1573         admin_record_type = proto_tree_add_text(admin_record_tree, tvb, offset, 1,
1574                                 "Administrative Record Type: Custody Signal");
1575         ++record_size; ++offset;
1576
1577         status = tvb_get_guint8(tvb, offset);
1578         proto_tree_add_text(admin_record_tree, tvb, offset, 1,
1579                         "Custody Transfer Succeeded Flag: %d", (status >> 7) & 0x01);
1580         if((status & ADMIN_REC_CUSTODY_REASON_MASK) == 0) {
1581             proto_tree_add_text(admin_record_tree, tvb, offset, 1,
1582                                         "Reason Code: 0 (No Additional Information)");
1583         }
1584         else {
1585             proto_tree_add_text(admin_record_tree, tvb, offset, 1,
1586                                 "Reason Code: 0x%x (%s)",
1587                                 status & ADMIN_REC_CUSTODY_REASON_MASK,
1588                                 val_to_str(status & ADMIN_REC_CUSTODY_REASON_MASK,
1589                                                 custody_signal_reason_codes, "Invalid"));
1590         }
1591         ++record_size; ++offset;
1592         if(record_type & ADMIN_REC_FLAGS_FRAGMENT) {
1593             sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
1594                                                         "Fragment Offset");
1595             if(sdnv_length <= 0) {
1596                 return 0;
1597             }
1598             offset += sdnv_length; record_size += sdnv_length;
1599             sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
1600                                                         "Fragment Length");
1601             if(sdnv_length <= 0) {
1602                 return 0;
1603             }
1604             offset += sdnv_length; record_size += sdnv_length;
1605         }
1606
1607         /* Signal Time */
1608         sdnv_length = add_dtn_time_to_tree(admin_record_tree, tvb, offset,
1609                                                         "Bundle Signal Time");
1610         if(sdnv_length <= 0) {
1611             return 0;
1612         }
1613         offset += sdnv_length; record_size += sdnv_length;
1614
1615         /* Timestamp copy */
1616         sdnv_length = add_sdnv_time_to_tree(admin_record_tree, tvb, offset,
1617                                                         "Bundle Creation Timestamp");
1618         if(sdnv_length <= 0) {
1619             return 0;
1620         }
1621         offset += sdnv_length; record_size += sdnv_length;
1622         sdnv_length = add_sdnv_to_tree(admin_record_tree, tvb, offset,
1623                                                         "Bundle Creation Timestamp Sequence");
1624         if(sdnv_length <= 0) {
1625             return 0;
1626         }
1627         offset += sdnv_length; record_size += sdnv_length;
1628
1629         endpoint_length = evaluate_sdnv(tvb, offset, &sdnv_length);
1630         if(endpoint_length < 0) {
1631             return 0;
1632         }
1633         proto_tree_add_text(admin_record_tree, tvb, offset, sdnv_length,
1634                                         "Endpoint Length: %d", endpoint_length);
1635         offset += sdnv_length; record_size += sdnv_length;
1636         string_ptr = tvb_get_ephemeral_stringz(tvb, offset, &string_length);
1637         proto_tree_add_text(admin_record_tree, tvb, offset, endpoint_length,
1638                                                 "Bundle Endpoint ID: %s", string_ptr);
1639         offset += string_length; record_size += string_length;
1640         return record_size;
1641
1642     }   /* End Switch */
1643
1644     admin_record_type = proto_tree_add_text(admin_record_tree, tvb, offset, 1,
1645                                 "Administrative Record Type: Unknown");
1646     return 0;
1647 }
1648
1649 /*
1650  * Return length of contact header or 0 on failure
1651  */
1652
1653 static int
1654 dissect_contact_header(tvbuff_t *tvb, packet_info *pinfo,
1655                                 proto_tree *conv_tree, proto_item *conv_item)
1656 {
1657     guint8 contact_hdr_flags;
1658     proto_item *contact_hdr_flag_item = NULL;
1659     proto_tree *contact_hdr_flag_tree = NULL;
1660     proto_item *eid_item = NULL;
1661     int eid_length;
1662     int sdnv_length;
1663     char *sptr;
1664
1665     /*
1666      * I'm going to assume that if this is a contact header, the buffer
1667      * contains the complete header and that there are no other packets
1668      * in the buffer.
1669      */
1670
1671     proto_tree_add_text(conv_tree, tvb, 0, 4, "Pkt Type: Contact Header");
1672     proto_tree_add_item(conv_tree, hf_contact_hdr_version, tvb, 4, 1, FALSE);
1673
1674     /* Subtree to expand the bits in the Contact Header Flags */
1675     contact_hdr_flags = tvb_get_guint8(tvb, 5);
1676     contact_hdr_flag_item =
1677                 proto_tree_add_item(conv_tree, hf_contact_hdr_flags, tvb, 5, 1, FALSE);
1678     contact_hdr_flag_tree =
1679                 proto_item_add_subtree(contact_hdr_flag_item, ett_contact_hdr_flags);
1680     proto_tree_add_boolean(contact_hdr_flag_tree, hf_contact_hdr_flags_ack_req,
1681                                                 tvb, 5, 1, contact_hdr_flags);
1682     proto_tree_add_boolean(contact_hdr_flag_tree, hf_contact_hdr_flags_frag_enable,
1683                                 tvb, 5, 1, contact_hdr_flags);
1684     proto_tree_add_boolean(contact_hdr_flag_tree, hf_contact_hdr_flags_nak,
1685                                 tvb, 5, 1, contact_hdr_flags);
1686     proto_tree_add_item(conv_tree, hf_contact_hdr_keep_alive, tvb, 6, 2, FALSE);
1687
1688     /*
1689      * New format Contact header has length field followed by Bundle Header.
1690      */
1691
1692     eid_length = evaluate_sdnv(tvb, 8, &sdnv_length);
1693     if(eid_length < 0) {
1694         col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error (Local EID Length)");
1695         return 0;
1696     }
1697     proto_tree_add_text(conv_tree, tvb, 8, sdnv_length,
1698                                 "Local EID Length: %d", eid_length);
1699     proto_item_set_len(conv_item, sdnv_length + eid_length + 8);
1700     eid_item = proto_tree_add_text(conv_tree, tvb, sdnv_length + 8, eid_length, " ");
1701     sptr = (char *) tvb_get_ephemeral_string(tvb, sdnv_length + 8, eid_length);
1702     proto_item_set_text(eid_item, "Local EID: %s", sptr);
1703     return(sdnv_length + eid_length + 8);
1704 }
1705
1706 static int
1707 display_metadata_block(proto_tree *tree, tvbuff_t *tvb, int offset, int *lastheader)
1708 {
1709     proto_item *block_item = NULL;
1710     proto_tree *block_tree = NULL;
1711     proto_item *hdr_length_item = NULL;
1712     proto_item *type_item = NULL;
1713     int sdnv_length;
1714     int header_start;
1715     int block_length;
1716     guint8 type;
1717     int control_flags;
1718     proto_item *block_flag_item = NULL;
1719
1720     type = tvb_get_guint8(tvb, offset);
1721     header_start = offset;      /*Used to compute total payload length*/
1722     offset = 0;
1723     block_item = proto_tree_add_text(tree, tvb,
1724                                 header_start + offset, -1, "Metadata Block");
1725     block_tree = proto_item_add_subtree(block_item, ett_metadata_hdr);
1726
1727     type_item = proto_tree_add_text(block_tree, tvb, header_start + offset, 1, " ");
1728     proto_item_set_text(type_item, "Block Type: %d", type);
1729     ++offset;
1730
1731     control_flags = evaluate_sdnv(tvb, header_start + offset, &sdnv_length);
1732     if(control_flags & BLOCK_CONTROL_LAST_BLOCK) {
1733         *lastheader = 1;
1734     }
1735     else {
1736         *lastheader = 0;
1737     }
1738     block_flag_item = proto_tree_add_text(block_tree, tvb, header_start + offset, 1, " ");
1739     proto_item_set_text(block_flag_item, "Block Flags: 0x%x", control_flags);
1740     offset += sdnv_length;
1741
1742     block_length = evaluate_sdnv(tvb, header_start + offset, &sdnv_length);
1743     proto_item_set_len(block_item, offset + sdnv_length + block_length);
1744     hdr_length_item = proto_tree_add_text(block_tree, tvb,
1745                                         header_start + offset, sdnv_length, " ");
1746     if(block_length < 0) {
1747         proto_item_set_text(hdr_length_item, "Metadata Block Length: Error");
1748         return 0;
1749     }
1750     proto_item_set_text(hdr_length_item, "Block Length: %d", block_length);
1751     offset += (sdnv_length + block_length);
1752
1753     return offset;
1754 }
1755 /*
1756  * SDNV has a zero in high-order bit position of last byte. The high-order
1757  * bit of all preceding bytes is set to one. This returns the numeric value
1758  * in an integer and sets the value of the second argument to the number of
1759  * bytes used to code the SDNV. A -1 is returned if the evaluation fails
1760  * (value exceeds maximum for signed integer). 0 is an acceptable value.
1761  */
1762
1763 #define SDNV_MASK       0x7f
1764
1765 /*3rd arg is number of bytes in field (returned)*/
1766 static int
1767 evaluate_sdnv(tvbuff_t *tvb, int offset, int *bytecount)
1768 {
1769     int value = 0;
1770     guint8 curbyte;
1771
1772     *bytecount = 0;
1773
1774     /*
1775      * Get 1st byte and continue to get them while high-order bit is 1
1776      */
1777
1778     while((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK) {
1779         if(*bytecount >= (int) sizeof(int)) {
1780             *bytecount = 0;
1781             return -1;
1782         }
1783         value = value << 7;
1784         value |= (curbyte & SDNV_MASK);
1785         ++offset;
1786         ++*bytecount;
1787     }
1788
1789     /*
1790      * Add in the byte whose high-order bit is 0 (last one)
1791      */
1792
1793     value = value << 7;
1794     value |= (curbyte & SDNV_MASK);
1795     ++*bytecount;
1796     return value;
1797 }
1798
1799 /* Special Function to evaluate 64 bit SDNVs */
1800 static gint64
1801 evaluate_sdnv_64(tvbuff_t *tvb, int offset, int *bytecount)
1802 {
1803     gint64 value = 0;
1804     guint8 curbyte;
1805
1806     *bytecount = 0;
1807
1808     /*
1809      * Get 1st byte and continue to get them while high-order bit is 1
1810      */
1811
1812     while((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK) {
1813         if(*bytecount >= (int) sizeof(gint64)) {
1814             *bytecount = 0;
1815             return -1;
1816         }
1817         value = value << 7;
1818         value |= (curbyte & SDNV_MASK);
1819         ++offset;
1820         ++*bytecount;
1821     }
1822
1823     /*
1824      * Add in the byte whose high-order bit is 0 (last one)
1825      */
1826
1827     value = value << 7;
1828     value |= (curbyte & SDNV_MASK);
1829     ++*bytecount;
1830     return value;
1831 }
1832
1833 static int
1834 add_sdnv_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id)
1835 {
1836     int sdnv_length;
1837     int sdnv_value;
1838
1839     sdnv_value = evaluate_sdnv(tvb, offset, &sdnv_length);
1840     if(sdnv_value < 0) {
1841         return 0;
1842     }
1843     proto_tree_add_text(tree, tvb, offset, sdnv_length, "%s: %d", field_id, sdnv_value);
1844     return sdnv_length;
1845 }
1846
1847 /*
1848  * Adds the result of 2 SDNVs to tree: First SDNV is seconds, next is nanoseconds.
1849  * Returns bytes in both SDNVs or 0 if something goes wrong.
1850  */
1851 static int
1852 add_dtn_time_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id)
1853 {
1854     int sdnv_length, sdnv2_length;
1855     int sdnv_value;
1856     time_t time_since_2000;
1857     char *time_string;
1858
1859     sdnv_value = evaluate_sdnv(tvb, offset, &sdnv_length);
1860     if(sdnv_value < 0) {
1861         return 0;
1862     }
1863     time_since_2000 = (time_t) (sdnv_value + 946684800);
1864     time_string = ctime(&time_since_2000);
1865     time_string[strlen(time_string) - 1] = 0; /*Remove Newline at enc*/
1866     proto_tree_add_text(tree, tvb, offset, sdnv_length,
1867                         "%s (sec): %d [%s]", field_id, sdnv_value, time_string);
1868     offset += sdnv_length;
1869
1870     sdnv_value = evaluate_sdnv(tvb, offset, &sdnv2_length);
1871     if(sdnv_value < 0) {
1872         return 0;
1873     }
1874     proto_tree_add_text(tree, tvb, offset, sdnv2_length,
1875                                 "%s (ns): %d", field_id, sdnv_value);
1876     return (sdnv_length + sdnv2_length);
1877 }
1878
1879 /*
1880  * Adds the result of SDNV which is a time since 2000 to tree.
1881  * Returns bytes in SDNV or 0 if something goes wrong.
1882  */
1883 static int
1884 add_sdnv_time_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, char *field_id)
1885 {
1886     int sdnv_length;
1887     int sdnv_value;
1888     time_t time_since_2000;
1889     char *time_string;
1890
1891     sdnv_value = evaluate_sdnv(tvb, offset, &sdnv_length);
1892     if(sdnv_value < 0) {
1893         return 0;
1894     }
1895     time_since_2000 = (time_t) (sdnv_value + 946684800);
1896     time_string = ctime(&time_since_2000);
1897     time_string[strlen(time_string) - 1] = 0; /*Remove Newline at enc*/
1898     proto_tree_add_text(tree, tvb, offset, sdnv_length,
1899                         "%s: %d [%s]", field_id, sdnv_value, time_string);
1900     return sdnv_length;
1901 }
1902
1903 static void
1904 bundle_defragment_init(void) {
1905     fragment_table_init(&msg_fragment_table);
1906     reassembled_table_init(&msg_reassembled_table);
1907 }
1908
1909 void
1910 proto_register_bundle(void)
1911 {
1912
1913   static hf_register_info hf[] = {
1914     {&hf_bundle_pdu_version,
1915         {"Bundle Version", "bundle.version",
1916                 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
1917     },
1918     {&hf_contact_hdr_version,
1919         {"Version", "bundle.tcp_conv.contact_hdr.version",
1920                 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
1921     },
1922     {&hf_contact_hdr_flags,
1923         {"Flags", "bundle.tcp_conv.contact_hdr.flags",
1924                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
1925     },
1926     {&hf_contact_hdr_flags_ack_req,
1927         {"Bundle Acks Requested", "bundle.tcp_conv.contact_hdr.flags.ackreq",
1928                 FT_BOOLEAN, 8, NULL, TCP_CONV_BUNDLE_ACK_FLAG, NULL, HFILL}
1929     },
1930     {&hf_contact_hdr_flags_frag_enable,
1931         {"Reactive Fragmentation Enabled", "bundle.tcp_conv.contact_hdr.flags.fragen",
1932                 FT_BOOLEAN, 8, NULL, TCP_CONV_REACTIVE_FRAG_FLAG, NULL, HFILL}
1933     },
1934     {&hf_contact_hdr_flags_nak,
1935         {"Support Negative Acknowledgements", "bundle.tcp_conv.contact_hdr.flags.nak",
1936                 FT_BOOLEAN, 8, NULL, TCP_CONV_CONNECTOR_RCVR_FLAG, NULL, HFILL}
1937     },
1938     {&hf_contact_hdr_keep_alive,
1939         {"Keep Alive", "bundle.tcp_conv.contact_hdr.keep_alive",
1940                 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
1941     },
1942     {&hf_tcp_convergence_data_procflags,
1943         {"TCP Convergence Data Flags", "bundle.tcp_conv.data.proc.flag",
1944                 FT_UINT8, BASE_HEX, NULL, TCP_CONVERGENCE_DATA_FLAGS, NULL, HFILL}
1945     },
1946     {&hf_tcp_convergence_data_procflags_start,
1947         {"Segment contains start of bundle", "bundle.tcp_conv.data.proc.start",
1948                 FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_DATA_START_FLAG, NULL, HFILL}
1949     },
1950     {&hf_tcp_convergence_data_procflags_end,
1951         {"Segment contains end of Bundle", "bundle.tcp_conv.data.proc.end",
1952                 FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_DATA_END_FLAG, NULL, HFILL}
1953     },
1954     {&hf_tcp_convergence_shutdown_flags,
1955         {"TCP Convergence Shutdown Flags", "bundle.tcp_conv.shutdown.flags",
1956                 FT_UINT8, BASE_HEX, NULL, TCP_CONVERGENCE_SHUTDOWN_FLAGS, NULL, HFILL}
1957     },
1958     {&hf_tcp_convergence_shutdown_flags_reason,
1959         {"Shutdown includes Reason Code", "bundle.tcp_conv.shutdown.reason.flag",
1960                 FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_SHUTDOWN_REASON, NULL, HFILL}
1961     },
1962     {&hf_tcp_convergence_shutdown_flags_delay,
1963         {"Shutdown includes Reconnection Delay", "bundle.tcp_conv.shutdown.delay.flag",
1964                 FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_SHUTDOWN_DELAY, NULL, HFILL}
1965     },
1966     {&hf_tcp_convergence_shutdown_reason,
1967         {"Shutdown Reason Code", "bundle.tcp_conv.shutdown.reason",
1968                 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
1969     },
1970     {&hf_tcp_convergence_shutdown_delay,
1971         {"Shutdown Reconnection Delay", "bundle.tcp_conv.shutdown.delay",
1972                 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
1973     },
1974
1975     {&hf_msg_fragments,
1976         {"Message Fragments", "bundle.msg.fragments",
1977                 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
1978     },
1979     {&hf_msg_fragment,
1980         {"Message Fragment", "bundle.msg.fragment",
1981                 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
1982     },
1983     {&hf_msg_fragment_overlap,
1984         {"Message fragment overlap", "bundle.msg.fragment.overlap",
1985                 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
1986     },
1987     {&hf_msg_fragment_overlap_conflicts,
1988         {"Message fragment overlapping with conflicting data",
1989          "bundle.msg.fragment.overlap.conflicts",
1990                 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
1991     },
1992     {&hf_msg_fragment_multiple_tails,
1993         {"Message has multiple tails", "bundle.msg.fragment.multiple_tails",
1994                 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
1995     },
1996     {&hf_msg_fragment_too_long_fragment,
1997         {"Message fragment too long", "bundle.msg.fragment.too_long_fragment",
1998                 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
1999     },
2000     {&hf_msg_fragment_error,
2001         {"Message defragmentation error", "bundle.msg.fragment.error",
2002                 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
2003     },
2004     {&hf_msg_reassembled_in,
2005         {"Reassembled in", "bundle.msg.reassembled.in",
2006                 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
2007     },
2008     {&hf_bundle_procflags,
2009         {"Primary Header Processing Flags", "bundle.primary.proc.flag",
2010                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
2011     },
2012     {&hf_bundle_procflags_fragment,
2013         {"Bundle is a Fragment", "bundle.primary.proc.frag",
2014                 FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_FRAG_MASK, NULL, HFILL}
2015     },
2016     {&hf_bundle_procflags_admin,
2017         {"Administrative Record", "bundle.primary.proc.admin",
2018                 FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_ADMIN_MASK, NULL, HFILL}
2019     },
2020     {&hf_bundle_procflags_dont_fragment,
2021         {"Do Not Fragment Bundle", "bundle.primary.proc.dontfrag",
2022                 FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_DONTFRAG_MASK, NULL, HFILL}
2023     },
2024     {&hf_bundle_procflags_cust_xfer_req,
2025         {"Request Custody Transfer", "bundle.primary.proc.xferreq",
2026                 FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_XFERREQ_MASK, NULL, HFILL}
2027     },
2028     {&hf_bundle_procflags_dest_singleton,
2029         {"Destination is Singleton", "bundle.primary.proc.single",
2030                 FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_SINGLETON_MASK, NULL, HFILL}
2031     },
2032     {&hf_bundle_procflags_application_ack,
2033         {"Request Acknowledgement by Application", "bundle.primary.proc.ack",
2034                 FT_BOOLEAN, 8, NULL, BUNDLE_PROCFLAGS_APP_ACK_MASK, NULL, HFILL}
2035     },
2036     {&hf_bundle_control_flags,
2037         {"Bundle Processing Control Flags", "bundle.primary.proc.flag",
2038                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
2039     },
2040     {&hf_bundle_procflags_general,
2041         {"General Flags", "bundle.primary.proc.gen",
2042                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
2043     },
2044     {&hf_bundle_procflags_cos,
2045         {"Cloass of Service Flags", "bundle.primary.proc.cos",
2046                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
2047     },
2048     {&hf_bundle_procflags_status,
2049         {"Status Report Flags", "bundle.primary.proc.status",
2050                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
2051     },
2052     {&hf_bundle_cosflags,
2053         {"Primary Header COS Flags", "bundle.primary.cos.flags",
2054                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
2055     },
2056     {&hf_bundle_cosflags_priority,
2057         {"Priority", "bundle.primary.cos.priority",
2058                 FT_UINT8, BASE_DEC, NULL, BUNDLE_COSFLAGS_PRIORITY_MASK, NULL, HFILL}
2059     },
2060     {&hf_bundle_srrflags,
2061         {"Primary Header Report Request Flags", "bundle.primary.srr.flag",
2062                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
2063     },
2064     {&hf_bundle_srrflags_report_receipt,
2065         {"Request Reception Report", "bundle.primary.srr.report",
2066                 FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_REPORT_MASK, NULL, HFILL}
2067     },
2068     {&hf_bundle_srrflags_report_cust_accept,
2069         {"Request Report of Custody Acceptance", "bundle.primary.srr.custaccept",
2070                 FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_CUSTODY_MASK, NULL, HFILL}
2071     },
2072     {&hf_bundle_srrflags_report_forward,
2073         {"Request Report of Bundle Forwarding", "bundle.primary.srr.forward",
2074                 FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_FORWARD_MASK, NULL, HFILL}
2075     },
2076     {&hf_bundle_srrflags_report_delivery,
2077         {"Request Report of Bundle Delivery", "bundle.primary.srr.delivery",
2078                 FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_DELIVERY_MASK, NULL, HFILL}
2079     },
2080     {&hf_bundle_srrflags_report_deletion,
2081         {"Request Report of Bundle Deletion", "bundle.primary.srr.delete",
2082                 FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_DELETION_MASK, NULL, HFILL}
2083     },
2084     {&hf_bundle_srrflags_report_ack,
2085         {"Request Report of Application Ack", "bundle.primary.srr.ack",
2086                 FT_BOOLEAN, 8, NULL, BUNDLE_SRRFLAGS_ACK_MASK, NULL, HFILL}
2087     },
2088     {&hf_bundle_primary_header_len,
2089         {"Bundle Header Length", "bundle.primary.len",
2090                 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
2091     },
2092     {&hf_bundle_dest_scheme_offset,
2093         {"Destination Scheme Offset", "bundle.primary.destschemeoff",
2094                 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
2095     },
2096     {&hf_bundle_dest_ssp_offset,
2097         {"Destination SSP Offset", "bundle.primary.destssspoff",
2098                 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
2099     },
2100     {&hf_bundle_source_scheme_offset,
2101         {"Source Scheme Offset", "bundle.primary.srcschemeoff",
2102                 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
2103     },
2104     {&hf_bundle_source_ssp_offset,
2105         {"Source SSP Offset", "bundle.primary.srcsspoff",
2106                 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
2107     },
2108     {&hf_bundle_report_scheme_offset,
2109         {"Report Scheme Offset", "bundle.primary.rptschemeoff",
2110                 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
2111     },
2112     {&hf_bundle_report_ssp_offset,
2113         {"Report SSP Offset", "bundle.primary.rptsspoff",
2114                 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
2115     },
2116     {&hf_bundle_cust_scheme_offset,
2117         {"Custodian Scheme Offset", "bundle.primary.custschemeoff",
2118                 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
2119     },
2120     {&hf_bundle_cust_ssp_offset,
2121         {"Custodian SSP Offset", "bundle.primary.custsspoff",
2122                 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
2123     },
2124     {&hf_bundle_dest_scheme,
2125         {"Destination Scheme", "bundle.primary.destination_scheme",
2126                 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
2127     },
2128     {&hf_bundle_dest_ssp,
2129         {"Destination", "bundle.primary.destination",
2130                 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
2131     },
2132     {&hf_bundle_source_scheme,
2133         {"Source Scheme", "bundle.primary.source_scheme",
2134                 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
2135     },
2136     {&hf_bundle_source_ssp,
2137         {"Source", "bundle.primary.source",
2138                 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
2139     },
2140     {&hf_bundle_report_scheme,
2141         {"Report Scheme", "bundle.primary.report_scheme",
2142                 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
2143     },
2144     {&hf_bundle_report_ssp,
2145         {"Report", "bundle.primary.report",
2146                 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
2147     },
2148     {&hf_bundle_custodian_scheme,
2149         {"Custodian Scheme", "bundle.primary.custodian_scheme",
2150                 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
2151     },
2152     {&hf_bundle_custodian_ssp,
2153         {"Custodian", "bundle.primary.custodian",
2154                 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
2155     },
2156     {&hf_bundle_creation_timestamp,
2157         {"Creation Timestamp", "bundle.primary.timestamp",
2158                 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
2159     },
2160     {&hf_bundle_lifetime,
2161         {"Lifetime", "bundle.primary.lifetime",
2162                 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
2163     },
2164     {&hf_bundle_payload_flags,
2165         {"Payload Header Processing Flags", "bundle.payload.proc.flag",
2166                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
2167     },
2168     {&hf_bundle_payload_flags_replicate_hdr,
2169         {"Replicate Header in Every Fragment", "bundle.payload.proc.replicate",
2170                 FT_BOOLEAN, 8, NULL, PAYLOAD_PROCFLAGS_REPLICATE_MASK, NULL, HFILL}
2171     },
2172     {&hf_bundle_payload_flags_xmit_report,
2173         {"Report if Can't Process Header", "bundle.payload.proc.report",
2174                 FT_BOOLEAN, 8, NULL, PAYLOAD_PROCFLAGS_XMIT_STATUS, NULL, HFILL}
2175     },
2176     {&hf_bundle_payload_flags_discard_on_fail,
2177         {"Discard if Can't Process Header", "bundle.payload.proc.discard",
2178                 FT_BOOLEAN, 8, NULL, PAYLOAD_PROCFLAGS_DISCARD_FAILURE, NULL, HFILL}
2179     },
2180     {&hf_bundle_payload_flags_last_header,
2181         {"Last Header", "bundle.payload.proc.lastheader",
2182                 FT_BOOLEAN, 8, NULL, PAYLOAD_PROCFLAGS_LAST_HEADER, NULL, HFILL}
2183     },
2184     {&hf_bundle_admin_statflags,
2185         {"Administrative Record Status Flags", "bundle.admin.status.flag",
2186                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
2187     },
2188     {&hf_bundle_admin_rcvd,
2189         {"Reporting Node Received Bundle", "bundle.admin.status.rcvd",
2190                 FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_RECEIVED, NULL, HFILL}
2191     },
2192     {&hf_bundle_admin_accepted,
2193         {"Reporting Node Accepted Custody", "bundle.admin.status.accept",
2194                 FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_ACCEPTED, NULL, HFILL}
2195     },
2196     {&hf_bundle_admin_forwarded,
2197         {"Reporting Node Forwarded Bundle", "bundle.admin.status.forward",
2198                 FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_FORWARDED, NULL, HFILL}
2199     },
2200     {&hf_bundle_admin_delivered,
2201         {"Reporting Node Delivered Bundle", "bundle.admin.status.delivered",
2202                 FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_DELIVERED, NULL, HFILL}
2203     },
2204     {&hf_bundle_admin_deleted,
2205         {"Reporting Node Deleted Bundle", "bundle.admin.status.delete",
2206                 FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_DELETED, NULL, HFILL}
2207     },
2208     {&hf_bundle_admin_acked,
2209         {"Acknowledged by Application", "bundle.admin.status.ack",
2210                 FT_BOOLEAN, 8, NULL, ADMIN_STATUS_FLAGS_ACKNOWLEDGED, NULL, HFILL}
2211     },
2212     {&hf_bundle_admin_receipt_time,
2213         {"Time of Receipt", "bundle.admin.status.receipttime",
2214                 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
2215     },
2216     {&hf_bundle_admin_accept_time,
2217         {"Time of Custody Acceptance", "bundle.admin.status.accepttime",
2218                 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
2219     },
2220     {&hf_bundle_admin_forward_time,
2221         {"Time of Forwarding", "bundle.admin.status.forwardtime",
2222                 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
2223     },
2224     {&hf_bundle_admin_delivery_time,
2225         {"Time of Delivery", "bundle.admin.status.deliverytime",
2226                 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
2227     },
2228     {&hf_bundle_admin_delete_time,
2229         {"Time of Deletion", "bundle.admin.status.deletetime",
2230                 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
2231     },
2232     {&hf_bundle_admin_ack_time,
2233         {"Time of Acknowledgement", "bundle.admin.status.acktime",
2234                 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
2235     },
2236     {&hf_bundle_admin_timestamp_copy,
2237         {"Copy of Creation Timestamp", "bundle.admin.status.timecopy",
2238                 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
2239     },
2240     {&hf_bundle_admin_signal_time,
2241         {"Time of Signal", "bundle.admin.signal.time",
2242                 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}
2243     },
2244     {&hf_block_control_flags,
2245         {"Block Processing Control Flags", "bundle.block.control.flags",
2246                 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
2247     },
2248     {&hf_block_control_replicate,
2249         {"Replicate Block in Every Fragment", "bundle.block.control.replicate",
2250                 FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_REPLICATE, NULL, HFILL}
2251     },
2252     {&hf_block_control_transmit_status,
2253         {"Transmit Status if Block Can't be Processeed", "bundle.block.control.status",
2254                 FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_TRANSMIT_STATUS, NULL, HFILL}
2255     },
2256     {&hf_block_control_delete_bundle,
2257         {"Delete Bundle if Block Can't be Processeed", "bundle.block.control.delete",
2258                 FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_DELETE_BUNDLE, NULL, HFILL}
2259     },
2260     {&hf_block_control_last_block,
2261         {"Last Block", "bundle.block.control.last",
2262                 FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_LAST_BLOCK, NULL, HFILL}
2263     },
2264     {&hf_block_control_discard_block,
2265         {"Discard Block If Can't Process", "bundle.block.control.discard",
2266                 FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_DISCARD_BLOCK, NULL, HFILL}
2267     },
2268     {&hf_block_control_not_processed,
2269         {"Block Was Forwarded Without Processing", "bundle.block.control.process",
2270                 FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_NOT_PROCESSED, NULL, HFILL}
2271     },
2272     {&hf_block_control_eid_reference,
2273         {"Block Contains an EID-reference Field", "bundle.block.control.eid",
2274                 FT_BOOLEAN, 8, NULL, BLOCK_CONTROL_EID_REFERENCE, NULL, HFILL}
2275     }
2276   };
2277
2278   static gint *ett[] = {
2279     &ett_bundle,
2280     &ett_tcp_conv,
2281     &ett_tcp_conv_hdr,
2282     &ett_msg_fragment,
2283     &ett_msg_fragments,
2284     &ett_bundle_hdr,
2285     &ett_primary_hdr,
2286     &ett_proc_flags,
2287     &ett_gen_flags,
2288     &ett_cos_flags,
2289     &ett_srr_flags,
2290     &ett_dictionary,
2291     &ett_payload_hdr,
2292     &ett_payload_flags,
2293     &ett_block_flags,
2294     &ett_contact_hdr_flags,
2295     &ett_conv_flags,
2296     &ett_shutdown_flags,
2297     &ett_admin_record,
2298     &ett_admin_rec_status,
2299     &ett_metadata_hdr
2300   };
2301
2302   module_t *bundle_module;
2303
2304   proto_bundle = proto_register_protocol (
2305                         "Bundle Protocol",
2306                         "Bundle",
2307                         "bundle"
2308                    );
2309   bundle_module = prefs_register_protocol(proto_bundle, proto_reg_handoff_bundle);
2310
2311   proto_tcp_conv = proto_register_protocol (
2312                         "DTN TCP Convergence Layer Protocol",
2313                         "TCPCL",
2314                         "tcpcl"
2315                 );
2316
2317   prefs_register_uint_preference(bundle_module, "tcp.port",
2318                                         "Bundle Protocol TCP Port",
2319                                         "TCP Port to Accept Bundle Protocol Connections",
2320                                         10,
2321                                         &bundle_tcp_port);
2322
2323   prefs_register_uint_preference(bundle_module, "udp.port",
2324                                         "Bundle Protocol UDP Port",
2325                                         "UDP Port to Accept Bundle Protocol Connections",
2326                                         10,
2327                                         &bundle_udp_port);
2328
2329   proto_register_field_array(proto_bundle, hf, array_length(hf));
2330   proto_register_subtree_array(ett, array_length(ett));
2331   register_init_routine(bundle_defragment_init);
2332 }
2333
2334 void
2335 proto_reg_handoff_bundle(void)
2336 {
2337     static dissector_handle_t tcp_bundle_handle;
2338     static dissector_handle_t udp_bundle_handle;
2339     static int Initialized = FALSE;
2340
2341     if (!Initialized) {
2342         tcp_bundle_handle = create_dissector_handle(dissect_tcp_bundle, proto_bundle);
2343         udp_bundle_handle = create_dissector_handle(dissect_udp_bundle, proto_bundle);
2344         Initialized = TRUE;
2345     }
2346     else {
2347         dissector_delete("tcp.port", tcp_port, tcp_bundle_handle);
2348         dissector_delete("udp.port", udp_port, udp_bundle_handle);
2349     }
2350     tcp_port = bundle_tcp_port;
2351     udp_port = bundle_udp_port;
2352     dissector_add("tcp.port", tcp_port, tcp_bundle_handle);
2353     dissector_add("udp.port", udp_port, udp_bundle_handle);
2354 }