Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-ltp.c
blob9a06bcfe14fc856a42a91626296610108549c73f
1 /* packet-ltp.c
2 * Routines for LTP dissection
3 * Copyright 2009, Mithun Roy <mithunroy13@gmail.com>
4 * Copyright 2017, Krishnamurthy Mayya <krishnamurthymayya@gmail.com>
5 Revision: Minor modifications to Header and Trailer extensions
6 by correcting the offset handling.
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
15 * Modifications were made to this file under designation MFS-33289-1 and
16 * are Copyright 2015 United States Government as represented by NASA
17 * Marshall Space Flight Center. All Rights Reserved.
19 * Released under the GNU GPL with NASA legal approval granted 2016-06-10.
21 * The subject software is provided "AS IS" WITHOUT ANY WARRANTY of any kind,
22 * either expressed, implied or statutory and this agreement does not,
23 * in any manner, constitute an endorsement by government agency of any
24 * results, designs or products resulting from use of the subject software.
25 * See the Agreement for the specific language governing permissions and
26 * limitations.
30 * Licklider Transmission Protocol - RFC 5326.
33 #include "config.h"
35 #include <epan/packet.h>
36 #include <epan/expert.h>
37 #include <epan/exceptions.h>
38 #include <epan/conversation.h>
39 #include <epan/conversation_table.h>
40 #include <epan/conversation_filter.h>
41 #include <epan/proto_data.h>
42 #include <epan/reassemble.h>
43 #include <epan/stats_tree.h>
44 #include <epan/to_str.h>
45 #include <epan/unit_strings.h>
46 #include <wsutil/array.h>
47 #include <wsutil/wmem/wmem_map.h>
48 #include <wsutil/wmem/wmem_interval_tree.h>
50 void proto_register_ltp(void);
51 void proto_reg_handoff_ltp(void);
53 static dissector_handle_t ltp_handle;
55 #define LTP_MIN_DATA_BUFFER 5
57 /// Unique session identifier
58 typedef struct {
59 /// Session originator
60 uint64_t orig_eng_id;
61 /// Session number
62 uint64_t sess_num;
63 } ltp_session_id_t;
65 /** Function to match the GHashFunc signature.
67 static unsigned
68 ltp_session_id_hash(const void *ptr)
70 const ltp_session_id_t *obj = ptr;
71 return (
72 g_int64_hash(&(obj->orig_eng_id))
73 ^ g_int64_hash(&(obj->sess_num))
77 /** Function to match the GEqualFunc signature.
79 static gboolean
80 ltp_session_id_equal(const void *a, const void *b)
82 const ltp_session_id_t *aobj = a;
83 const ltp_session_id_t *bobj = b;
84 return (
85 (aobj->orig_eng_id == bobj->orig_eng_id)
86 && (aobj->sess_num == bobj->sess_num)
90 /// Reassembly function
91 static void *
92 ltp_session_new_key(const packet_info *pinfo _U_, const uint32_t id _U_,
93 const void *data)
95 const ltp_session_id_t *obj = data;
96 ltp_session_id_t *key = g_slice_new(ltp_session_id_t);
98 key->orig_eng_id = obj->orig_eng_id;
99 key->sess_num = obj->sess_num;
101 return (void *)key;
104 /// Reassembly function
105 static void
106 ltp_session_free_key(void *ptr)
108 ltp_session_id_t *key = (ltp_session_id_t *)ptr;
109 g_slice_free(ltp_session_id_t, key);
112 typedef struct {
113 uint32_t frame_num;
114 nstime_t abs_ts;
115 } ltp_frame_info_t;
117 static ltp_frame_info_t *
118 ltp_frame_info_new(const packet_info *pinfo)
120 ltp_frame_info_t *obj = wmem_new(wmem_file_scope(), ltp_frame_info_t);
121 obj->frame_num = pinfo->num;
122 obj->abs_ts = pinfo->abs_ts;
123 return obj;
126 /** Function to match the GCompareFunc signature.
128 static int
129 ltp_frame_info_find_pinfo(const void *a, const void *b)
131 const ltp_frame_info_t *aobj = a;
132 const packet_info *bobj = b;
133 if (aobj->frame_num < bobj->num) return -1;
134 if (aobj->frame_num > bobj->num) return 1;
135 return 0;
138 /// A session is an LTP conversation
139 typedef struct {
140 /** Map from first-seen segment data ranges to data frame info (ltp_frame_info_t*) */
141 wmem_itree_t *data_segs;
142 /** Map from report ID (uint64_t) to tree (wmem_itree_t*) of
143 * first-seen segment data ranges to data frame info (ltp_frame_info_t*) */
144 wmem_map_t *rpt_segs;
145 /** Set after seeing EORP */
146 uint64_t *red_size;
147 /** Set after seeing EOB */
148 uint64_t *block_size;
150 /** Map from checkpoint ID (uint64_t) to wmem_list_t of frame info (ltp_frame_info_t*) */
151 wmem_map_t *checkpoints;
152 /** Map from checkpoint ID (uint64_t) to wmem_list_t of frame info (ltp_frame_info_t*) */
153 wmem_map_t *chkp_acks;
154 /** Map from report ID (uint64_t) to wmem_list_t of frame info (ltp_frame_info_t*) */
155 wmem_map_t *reports;
156 /** Map from report ID (uint64_t) to wmem_list_t of frame info (ltp_frame_info_t*) */
157 wmem_map_t *rpt_acks;
158 /** Map from report ID (uint64_t) to wmem_list_t of frame info (ltp_frame_info_t*) */
159 wmem_map_t *rpt_datas;
160 /** Map from cancel segment type (uint64_t) to wmem_list_t of frame info (ltp_frame_info_t*) */
161 wmem_map_t *cancels;
162 /** Map from cancel segment type (uint64_t) to wmem_list_t of frame info (ltp_frame_info_t*) */
163 wmem_map_t *cancel_acks;
164 } ltp_session_data_t;
166 /// Tap info for single segment
167 typedef struct {
168 /// Associated session context (optional)
169 ltp_session_data_t *session;
170 /// Segment type
171 uint8_t seg_type;
172 /// Session ID
173 ltp_session_id_t sess_id;
174 /// Text form of session name, scoped to file
175 const char *sess_name;
176 /// Full segment size
177 unsigned seg_size;
178 /// If non-zero, the size of the contained block
179 unsigned block_size;
180 /// For red data segment or report, is this original
181 bool corr_orig;
182 } ltp_tap_info_t;
184 /* For reassembling LTP segments */
185 static reassembly_table ltp_reassembly_table;
187 /* Initialize the protocol and registered fields */
188 static int proto_ltp;
190 static int ltp_tap;
192 static bool ltp_reassemble_block = true;
193 static bool ltp_analyze_sequence = true;
195 /* LTP Header variables */
196 static int hf_ltp_version;
197 static int hf_ltp_type;
198 static int hf_ltp_session_name;
199 static int hf_ltp_session_orig;
200 static int hf_ltp_session_no;
201 static int hf_ltp_hdr_extn_cnt;
202 static int hf_ltp_trl_extn_cnt;
204 /* LTP Data Segment variable */
205 static int hf_ltp_data_clid;
206 static int hf_ltp_data_offset;
207 static int hf_ltp_data_length;
208 static int hf_ltp_data_chkp;
209 static int hf_ltp_data_chkp_rpt_ref;
210 static int hf_ltp_data_chkp_rpt_time;
211 static int hf_ltp_data_rpt;
212 static int hf_ltp_data_rpt_ref;
213 static int hf_ltp_data_rpt_time;
214 static int hf_ltp_data_sda_clid;
215 static int hf_ltp_data_clidata;
216 static int hf_ltp_data_retrans;
217 static int hf_ltp_data_clm_rpt;
218 static int hf_ltp_block_red_size;
219 static int hf_ltp_block_green_size;
220 static int hf_ltp_block_bundle_size;
221 static int hf_ltp_block_bundle_cnt;
223 /* LTP Report Segment variable */
224 static int hf_ltp_rpt_sno;
225 static int hf_ltp_rpt_sno_ack_ref;
226 static int hf_ltp_rpt_sno_ack_time;
227 static int hf_ltp_rpt_sno_data_ref;
228 static int hf_ltp_rpt_sno_data_time;
229 static int hf_ltp_rpt_chkp;
230 static int hf_ltp_rpt_chkp_ref;
231 static int hf_ltp_rpt_chkp_time;
232 static int hf_ltp_rpt_ub;
233 static int hf_ltp_rpt_lb;
234 static int hf_ltp_rpt_len;
235 static int hf_ltp_rpt_retrans;
236 static int hf_ltp_rpt_clm_cnt;
237 static int hf_ltp_rpt_clm_off;
238 static int hf_ltp_rpt_clm_len;
239 static int hf_ltp_rpt_clm_fst;
240 static int hf_ltp_rpt_clm_lst;
241 static int hf_ltp_rpt_clm_ref;
242 static int hf_ltp_rpt_gap;
243 static int hf_ltp_rpt_gap_fst;
244 static int hf_ltp_rpt_gap_lst;
245 static int hf_ltp_rpt_gap_ref;
246 static int hf_ltp_rpt_gap_total;
248 /* LTP Report Ack Segment Variable */
249 static int hf_ltp_rpt_ack_sno;
250 static int hf_ltp_rpt_ack_dupe_ref;
251 static int hf_ltp_rpt_ack_ref;
252 static int hf_ltp_rpt_ack_time;
254 /* LTP Session Management Segment Variable */
255 static int hf_ltp_cancel_code;
256 static int hf_ltp_cancel_dupe_ref;
257 static int hf_ltp_cancel_ref;
258 static int hf_ltp_cancel_time;
260 static int hf_ltp_cancel_ack;
261 static int hf_ltp_cancel_ack_dupe_ref;
262 static int hf_ltp_cancel_ack_ref;
263 static int hf_ltp_cancel_ack_time;
265 /* LTP Header Extension Segment */
266 static int hf_ltp_hdr_extn_tag;
267 static int hf_ltp_hdr_extn_len;
268 static int hf_ltp_hdr_extn_val;
270 /* LTP Trailer Extension Segment */
271 static int hf_ltp_trl_extn_tag;
272 static int hf_ltp_trl_extn_len;
273 static int hf_ltp_trl_extn_val;
275 /*LTP reassembly */
276 static int hf_ltp_fragments;
277 static int hf_ltp_fragment;
278 static int hf_ltp_fragment_overlap;
279 static int hf_ltp_fragment_overlap_conflicts;
280 static int hf_ltp_fragment_multiple_tails;
281 static int hf_ltp_fragment_too_long_fragment;
282 static int hf_ltp_fragment_error;
283 static int hf_ltp_fragment_count;
284 static int hf_ltp_reassembled_in;
285 static int hf_ltp_reassembled_length;
287 static expert_field ei_ltp_mal_reception_claim;
288 static expert_field ei_ltp_sdnv_length;
289 static expert_field ei_ltp_sno_larger_than_ccsds;
290 static expert_field ei_ltp_report_async;
291 static expert_field ei_ltp_data_chkp_norpt;
292 static expert_field ei_ltp_data_rptno_norpt;
293 static expert_field ei_ltp_rpt_noack;
294 static expert_field ei_ltp_rpt_nochkp;
295 static expert_field ei_ltp_rpt_ack_norpt;
296 static expert_field ei_ltp_cancel_noack;
297 static expert_field ei_ltp_cancel_ack_nocancel;
299 static dissector_handle_t bundle_handle;
301 static const value_string ltp_type_codes[] = {
302 {0x0, "Red data, NOT {Checkpoint, EORP or EOB}"},
303 {0x1, "Red data, Checkpoint, NOT {EORP or EOB}"},
304 {0x2, "Red data, Checkpoint, EORP, NOT EOB"},
305 {0x3, "Red data, Checkpoint, EORP, EOB"},
306 {0x4, "Green data, NOT EOB"},
307 {0x5, "Green data, undefined"},
308 {0x6, "Green data, undefined"},
309 {0x7, "Green data, EOB"},
310 {0x8, "Report segment"},
311 {0x9, "Report-acknowledgment segment"},
312 {0xa, "Control segment, undefined"},
313 {0xb, "Control segment, undefined"},
314 {0xc, "Cancel segment from block sender"},
315 {0xd, "Cancel-acknowledgment segment to block sender"},
316 {0xe, "Cancel segment from block receiver"},
317 {0xf, "Cancel-acknowledgment segment to block receiver"},
318 {0,NULL}
321 static const value_string ltp_type_col_info[] = {
322 {0x0, "Red data"},
323 {0x1, "Red data"},
324 {0x2, "Red data"},
325 {0x3, "Red data"},
326 {0x4, "Green data"},
327 {0x5, "Green data"},
328 {0x6, "Green data"},
329 {0x7, "Green data"},
330 {0x8, "Report segment"},
331 {0x9, "Report ack segment"},
332 {0xa, "Control segment"},
333 {0xb, "Control segment"},
334 {0xc, "Cancel segment"},
335 {0xd, "Cancel ack segment"},
336 {0xe, "Cancel segment"},
337 {0xf, "Cancel ack segment"},
338 {0, NULL}
341 static const value_string ltp_cancel_codes[] = {
342 {0x00, "Client service canceled session"},
343 {0x01, "Unreachable client service"},
344 {0x02, "Retransmission limit exceeded"},
345 {0x03, "Miscolored segment"},
346 {0x04, "A system error"},
347 {0x05, "Exceeded the Retransmission-Cycles limit"},
348 {0, NULL}
351 static const value_string extn_tag_codes[] = {
352 {0x00, "LTP authentication extension"},
353 {0x01, "LTP cookie extension"},
354 {0, NULL}
357 static const val64_string client_service_id_info[] = {
358 {0x01, "Bundle Protocol"},
359 {0x02, "CCSDS LTP Service Data Aggregation"},
360 {0, NULL}
363 #define LTP_PORT 1113
365 /* Initialize the subtree pointers */
366 static int ett_ltp;
367 static int ett_ltp_hdr;
368 static int ett_hdr_session;
369 static int ett_hdr_extn;
370 static int ett_frame_ref;
371 static int ett_data_segm;
372 static int ett_block;
373 static int ett_rpt_segm;
374 static int ett_rpt_clm;
375 static int ett_rpt_gap;
376 static int ett_rpt_ack_segm;
377 static int ett_session_mgmt;
378 static int ett_trl_extn;
379 static int ett_ltp_fragment;
380 static int ett_ltp_fragments;
382 static const fragment_items ltp_frag_items = {
383 /*Fragment subtrees*/
384 &ett_ltp_fragment,
385 &ett_ltp_fragments,
386 /*Fragment Fields*/
387 &hf_ltp_fragments,
388 &hf_ltp_fragment,
389 &hf_ltp_fragment_overlap,
390 &hf_ltp_fragment_overlap_conflicts,
391 &hf_ltp_fragment_multiple_tails,
392 &hf_ltp_fragment_too_long_fragment,
393 &hf_ltp_fragment_error,
394 &hf_ltp_fragment_count,
395 /*Reassembled in field*/
396 &hf_ltp_reassembled_in,
397 /*Reassembled length field*/
398 &hf_ltp_reassembled_length,
399 /* Reassembled data field */
400 NULL,
401 /*Tag*/
402 "LTP fragments"
405 /** Add a cross-reference value source.
406 * @param map The map to add to.
407 * @param ref_num The cross-reference value.
408 * @param pinfo The source frame of the value.
410 static void
411 ltp_ref_src(wmem_map_t *map, uint64_t ref_num, const packet_info *pinfo)
413 wmem_list_t *found = wmem_map_lookup(map, &ref_num);
414 if (!found)
416 uint64_t *key = wmem_new(wmem_file_scope(), uint64_t);
417 *key = ref_num;
418 found = wmem_list_new(wmem_file_scope());
419 wmem_map_insert(map, key, found);
422 if (wmem_list_find_custom(found, pinfo, ltp_frame_info_find_pinfo))
424 return;
426 ltp_frame_info_t *val = ltp_frame_info_new(pinfo);
427 wmem_list_append(found, val);
430 /** Show cross-reference value sources as tree items.
431 * @param map The map to search in.
432 * @param ref_num The cross-reference value.
433 * @param pinfo The frame using the reference (to avoid duplicates).
434 * @param tree The tree to show references under.
435 * @param hf_ref The field index to add source frame numbers.
436 * @param hf_time The field index to report time differences.
437 * @param tap Non-null if this use is an acknowledgement of an earlier segment and should
438 * be later in time than the referenced segment.
440 static void
441 ltp_ref_use(wmem_map_t *map, uint64_t ref_num, packet_info *pinfo, proto_tree *tree, int hf_ref, expert_field *ei_notfound, int hf_time, ltp_tap_info_t *tap)
443 const wmem_list_t *found = wmem_map_lookup(map, &ref_num);
444 if (!found)
446 if (ei_notfound)
448 expert_add_info(pinfo, proto_tree_get_parent(tree), ei_notfound);
450 return;
453 for (wmem_list_frame_t *it = wmem_list_head(found); it != NULL;
454 it = wmem_list_frame_next(it))
456 const ltp_frame_info_t *frame_refd = wmem_list_frame_data(it);
457 if (frame_refd->frame_num == pinfo->num)
459 continue;
461 PROTO_ITEM_SET_GENERATED(
462 proto_tree_add_uint(tree, hf_ref, NULL, 0, 0, frame_refd->frame_num)
465 // tap is present for responses, where the other frame is earlier
466 const nstime_t *ta, *tb;
467 if (tap)
469 tb = &(pinfo->abs_ts);
470 ta = &(frame_refd->abs_ts);
472 else
474 tb = &(frame_refd->abs_ts);
475 ta = &(pinfo->abs_ts);
477 nstime_t td;
478 nstime_delta(&td, tb, ta);
480 if (hf_time >= 0)
482 PROTO_ITEM_SET_GENERATED(
483 proto_tree_add_time(tree, hf_time, NULL, 0, 0, &td)
489 static proto_item *
490 add_sdnv64_to_tree(proto_tree *tree, tvbuff_t *tvb, packet_info* pinfo, int offset, int hf_sdnv, uint64_t *retval, int *lenretval)
492 proto_item *ti;
493 ti = proto_tree_add_item_ret_varint(tree, hf_sdnv, tvb, offset, -1, ENC_VARINT_SDNV, retval, lenretval);
495 if (*lenretval <= 0) {
496 expert_add_info(pinfo, ti, &ei_ltp_sdnv_length);
498 return ti;
501 /// Summary of a data segment tree item
502 typedef struct {
503 /// Data segment packet info
504 packet_info *pinfo;
505 /// Tree of the data segment
506 proto_tree *ltp_data_tree;
507 /// The first offset of this segment
508 uint64_t data_fst;
509 /// The last offset of this segment
510 uint64_t data_lst;
511 } ltp_data_seg_info_t;
513 static void
514 ltp_data_seg_find_report(void *key _U_, void *value, void *user_data)
516 wmem_itree_t *rpt_clms = value;
517 const ltp_data_seg_info_t *data_seg = user_data;
518 if (!(data_seg->data_fst <= data_seg->data_lst))
520 return;
523 wmem_list_t *found = wmem_itree_find_intervals(rpt_clms, data_seg->pinfo->pool, data_seg->data_fst, data_seg->data_lst);
524 for (wmem_list_frame_t *it = wmem_list_head(found); it != NULL;
525 it = wmem_list_frame_next(it))
527 const ltp_frame_info_t *frame = wmem_list_frame_data(it);
528 // report must be after this data segment
529 if (frame->frame_num < data_seg->pinfo->num)
531 continue;
533 PROTO_ITEM_SET_GENERATED(
534 proto_tree_add_uint(data_seg->ltp_data_tree, hf_ltp_data_clm_rpt, NULL, 0, 0, frame->frame_num)
540 static int
541 dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int frame_offset,
542 int *data_len, ltp_tap_info_t *tap)
544 ltp_session_data_t *session = tap->session;
545 int ltp_type = tap->seg_type;
546 uint64_t client_id;
547 uint64_t data_offset;
548 uint64_t data_length;
549 uint64_t chkp_sno = 0;
550 uint64_t rpt_sno = 0;
551 uint64_t sda_client_id = 0;
553 unsigned segment_size = 0;
555 int sdnv_length;
557 proto_tree *ltp_data_tree;
558 proto_item *ti;
560 fragment_head *frag_msg = NULL;
562 tvbuff_t *new_tvb = NULL;
564 /* Create a subtree for data segment and add the other fields under it */
565 ltp_data_tree = proto_tree_add_subtree(ltp_tree, tvb, frame_offset, tvb_captured_length_remaining(tvb, frame_offset), ett_data_segm, NULL, "Data Segment");
567 /* Client ID - 0 = Bundle Protocol, 1 = CCSDS LTP Service Data Aggregation */
568 add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_clid, &client_id, &sdnv_length);
569 frame_offset += sdnv_length;
570 segment_size += sdnv_length;
572 /* data segment offset */
573 add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_offset, &data_offset, &sdnv_length);
574 if (sdnv_length > 0) {
575 frame_offset += sdnv_length;
576 segment_size += sdnv_length;
577 } else {
578 return 0;
581 /* data segment length */
582 add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_length, &data_length, &sdnv_length);
583 if (sdnv_length > 0) {
584 frame_offset += sdnv_length;
585 segment_size += sdnv_length;
587 /* add in the data length also */
588 segment_size += (unsigned int) data_length;
589 } else {
590 return 0;
592 *data_len = (int) data_length;
594 const uint64_t data_fst = data_offset;
595 const uint64_t data_lst = data_offset + data_length - 1;
596 bool newdata = true;
597 if (ltp_analyze_sequence && session)
599 if (data_fst <= data_lst)
601 wmem_list_t *found = wmem_itree_find_intervals(session->data_segs, pinfo->pool, data_fst, data_lst);
602 for (wmem_list_frame_t *it = wmem_list_head(found); it != NULL;
603 it = wmem_list_frame_next(it))
605 const ltp_frame_info_t *frame = wmem_list_frame_data(it);
606 if (frame->frame_num == pinfo->num)
608 continue;
610 PROTO_ITEM_SET_GENERATED(
611 proto_tree_add_uint(ltp_data_tree, hf_ltp_data_retrans, NULL, 0, 0, frame->frame_num)
613 newdata = false;
616 if (newdata)
618 ltp_frame_info_t *val = ltp_frame_info_new(pinfo);
619 wmem_itree_insert(session->data_segs, data_fst, data_lst, val);
623 ltp_data_seg_info_t data_seg_info;
624 data_seg_info.pinfo = pinfo;
625 data_seg_info.ltp_data_tree = ltp_data_tree;
626 data_seg_info.data_fst = data_fst;
627 data_seg_info.data_lst = data_lst;
628 wmem_map_foreach(session->rpt_segs, ltp_data_seg_find_report, &data_seg_info);
631 tap->corr_orig = newdata;
633 if (ltp_type != 0 && ltp_type < 4)
635 /* checkpoint serial number - 32 bits per CCSDS */
636 ti = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_chkp, &chkp_sno, &sdnv_length);
637 if (sdnv_length > 0) {
638 frame_offset += sdnv_length;
639 segment_size += sdnv_length;
641 if (chkp_sno > 4294967295U) {
642 /* just a warning - continue processing */
643 expert_add_info(pinfo, ti, &ei_ltp_sno_larger_than_ccsds);
645 } else {
646 return 0;
648 if (ltp_analyze_sequence && session)
650 proto_tree *tree_chkp_sno = proto_item_add_subtree(ti, ett_frame_ref);
651 ltp_ref_src(session->checkpoints, chkp_sno, pinfo);
652 ltp_ref_use(session->chkp_acks, chkp_sno, pinfo, tree_chkp_sno, hf_ltp_data_chkp_rpt_ref, &ei_ltp_data_chkp_norpt, hf_ltp_data_chkp_rpt_time, NULL);
655 /* report serial number - 32 bits per CCSDS */
656 ti = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_rpt, &rpt_sno, &sdnv_length);
657 if (sdnv_length > 0) {
658 frame_offset += sdnv_length;
659 segment_size += sdnv_length;
661 if (rpt_sno > 4294967295U) {
662 /* just a warning - continue processing */
663 expert_add_info(pinfo, ti, &ei_ltp_sno_larger_than_ccsds);
665 } else {
666 return 0;
668 if (ltp_analyze_sequence && session && (rpt_sno != 0))
670 ltp_ref_src(session->rpt_datas, rpt_sno, pinfo);
671 ltp_ref_use(session->reports, rpt_sno, pinfo, proto_item_add_subtree(ti, ett_frame_ref), hf_ltp_data_rpt_ref, &ei_ltp_data_rptno_norpt, hf_ltp_data_rpt_time, tap);
674 const bool is_green = (ltp_type >= 4) && (ltp_type <= 7);
675 const bool is_eorp = (ltp_type == 2) || (ltp_type == 3);
676 const bool is_eob = (ltp_type == 3) || (ltp_type == 7);
677 if (session)
679 if ((is_green && (data_offset == 0)) && !(session->red_size))
681 session->red_size = wmem_new(wmem_file_scope(), uint64_t);
682 *(session->red_size) = 0;
684 if (is_eorp && !(session->red_size))
686 session->red_size = wmem_new(wmem_file_scope(), uint64_t);
687 *(session->red_size) = data_offset + data_length;
689 if (is_eob && !(session->block_size))
691 session->block_size = wmem_new(wmem_file_scope(), uint64_t);
692 *(session->block_size) = data_offset + data_length;
696 proto_tree_add_item(ltp_data_tree, hf_ltp_data_clidata, tvb, frame_offset, (int) data_length, ENC_NA);
698 col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL,
699 "range %" PRIu64 "-%" PRIu64,
700 data_fst, data_lst);
702 if (ltp_reassemble_block)
704 frag_msg = fragment_add_check(
705 &ltp_reassembly_table,
706 tvb, frame_offset, pinfo, 0, &(tap->sess_id),
707 (uint32_t)data_offset, (uint32_t)data_length, !is_eob
710 if(frag_msg)
712 /* Checking if the segment is completely reassembled */
713 if(!(frag_msg->flags & FD_PARTIAL_REASSEMBLY))
715 /* if the segment has not been fragmented, then no reassembly is needed */
716 if(is_eob && data_offset == 0)
718 new_tvb = tvb_new_subset_length(tvb, frame_offset, (int) data_length);
720 else
722 new_tvb = process_reassembled_data(tvb, frame_offset, pinfo, "Reassembled LTP Block",
723 frag_msg, &ltp_frag_items,NULL, ltp_tree);
729 if(new_tvb)
731 uint64_t data_count = 0;
732 int parse_length = tvb_reported_length(new_tvb);
733 int parse_offset = 0;
734 proto_tree *root_tree = proto_tree_get_parent_tree(ltp_tree);
736 /* Data associated with the full block, not just this segment */
737 proto_tree *block_tree = proto_tree_add_subtree_format(ltp_tree, new_tvb, 0, -1, ett_block, NULL,
738 "Block, size: %d bytes", parse_length);
739 tap->block_size = parse_length;
741 if (session && session->red_size && session->block_size)
743 uint64_t red_size = *(session->red_size);
744 uint64_t green_size = *(session->block_size) - *(session->red_size);
745 PROTO_ITEM_SET_GENERATED(
746 proto_tree_add_uint64(block_tree, hf_ltp_block_red_size, new_tvb, 0, (int)red_size, red_size)
748 PROTO_ITEM_SET_GENERATED(
749 proto_tree_add_uint64(block_tree, hf_ltp_block_green_size, new_tvb, (int)red_size, (int)green_size, green_size)
753 while(parse_offset < parse_length)
755 int bundle_size;
756 tvbuff_t *datatvb;
758 if (client_id == 2) {
759 add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset+parse_offset, hf_ltp_data_sda_clid, &sda_client_id, &sdnv_length);
760 parse_offset += sdnv_length;
761 if (parse_offset == parse_length) {
762 col_set_str(pinfo->cinfo, COL_INFO, "CCSDS LTP SDA Protocol Error");
763 return 0; /* Give up*/
767 datatvb = tvb_new_subset_remaining(new_tvb, parse_offset);
768 bundle_size = call_dissector(bundle_handle, datatvb, pinfo, root_tree);
769 if(bundle_size == 0) { /*Couldn't parse bundle*/
770 col_set_str(pinfo->cinfo, COL_INFO, "Dissection Failed");
771 return 0; /*Give up*/
773 proto_tree_add_uint64(block_tree, hf_ltp_block_bundle_size, datatvb, 0, bundle_size, bundle_size);
775 parse_offset += bundle_size;
776 data_count++;
778 PROTO_ITEM_SET_GENERATED(
779 proto_tree_add_uint64(block_tree, hf_ltp_block_bundle_cnt, new_tvb, 0, parse_offset, data_count)
782 else
784 if(ltp_reassemble_block && frag_msg && (frag_msg->flags & FD_DEFRAGMENTED))
786 col_append_frame_number(pinfo, COL_INFO, " [Reassembled in #%d] ",frag_msg->reassembled_in);
788 else if (!newdata)
790 col_append_str(pinfo->cinfo, COL_INFO, " [Retransmission] ");
792 else if (ltp_reassemble_block)
794 col_append_str(pinfo->cinfo, COL_INFO, " [Unfinished LTP Block] ");
798 return segment_size;
802 static void
803 ltp_check_reception_gap(proto_tree *ltp_rpt_tree, packet_info *pinfo,
804 ltp_session_data_t *session, uint64_t prec_lst, uint64_t next_fst,
805 int *gap_count, uint64_t *gap_total) {
806 const uint64_t gap_len = next_fst - (prec_lst + 1);
807 if (gap_len <= 0) {
808 return;
810 proto_item *gap_item = proto_tree_add_uint64_format(ltp_rpt_tree, hf_ltp_rpt_gap, NULL, 0, 0, gap_len,
811 "Reception gap: %" PRIu64 "-%" PRIu64 " (%" PRIu64 " bytes)",
812 prec_lst + 1, next_fst - 1, gap_len
814 PROTO_ITEM_SET_GENERATED(gap_item);
815 *gap_count += 1;
816 *gap_total += gap_len;
818 if (ltp_analyze_sequence && session)
820 proto_tree *gap_tree = proto_item_add_subtree(gap_item, ett_rpt_gap);
822 const uint64_t gap_fst = prec_lst + 1;
823 const uint64_t gap_lst = next_fst - 1;
824 PROTO_ITEM_SET_GENERATED(
825 proto_tree_add_uint64(gap_tree, hf_ltp_rpt_gap_fst, NULL, 0, 0, gap_fst)
827 PROTO_ITEM_SET_GENERATED(
828 proto_tree_add_uint64(gap_tree, hf_ltp_rpt_gap_lst, NULL, 0, 0, gap_lst)
831 wmem_list_t *found = wmem_itree_find_intervals(session->data_segs, pinfo->pool, gap_fst, gap_lst);
832 for (wmem_list_frame_t *it = wmem_list_head(found); it != NULL;
833 it = wmem_list_frame_next(it))
835 const ltp_frame_info_t *frame = wmem_list_frame_data(it);
836 if (frame->frame_num > pinfo->num)
838 continue;
840 PROTO_ITEM_SET_GENERATED(
841 proto_tree_add_uint(gap_tree, hf_ltp_rpt_gap_ref, NULL, 0, 0, frame->frame_num)
848 static int
849 dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, int frame_offset, ltp_tap_info_t *tap) {
850 ltp_session_data_t *session = tap->session;
851 int64_t rpt_sno;
852 int64_t chkp_sno;
853 uint64_t upper_bound;
854 uint64_t lower_bound;
855 uint64_t rcpt_clm_cnt;
856 uint64_t offset;
857 uint64_t length;
858 uint64_t clm_fst, clm_lst;
860 int rpt_sno_size;
861 int chkp_sno_size;
862 int upper_bound_size;
863 int lower_bound_size;
864 int rcpt_clm_cnt_size;
865 int offset_size;
866 int length_size;
868 int segment_offset = 0;
869 int gap_count = 0;
870 uint64_t gap_total = 0;
872 proto_item *ltp_rpt_item;
873 proto_item *ltp_rpt_clm_cnt;
874 proto_item *ltp_rpt_clm_item;
875 proto_item *item_rpt_sno, *item_chkp_sno;
877 proto_tree *ltp_rpt_tree;
878 proto_tree *ltp_rpt_clm_tree;
880 /* Create the subtree for report segment under the main LTP tree and all the report segment fields under it */
881 ltp_rpt_tree = proto_tree_add_subtree(ltp_tree, tvb, frame_offset, -1, ett_rpt_segm, &ltp_rpt_item, "Report Segment");
883 /* Extract the report segment info */
884 item_rpt_sno = add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_sno, &rpt_sno, &rpt_sno_size);
885 segment_offset += rpt_sno_size;
886 if (ltp_analyze_sequence && session)
888 proto_tree *tree_rpt_sno = proto_item_add_subtree(item_rpt_sno, ett_frame_ref);
889 ltp_ref_src(session->reports, rpt_sno, pinfo);
890 ltp_ref_use(session->rpt_acks, rpt_sno, pinfo, tree_rpt_sno, hf_ltp_rpt_sno_ack_ref, &ei_ltp_rpt_noack, hf_ltp_rpt_sno_ack_time, NULL);
891 ltp_ref_use(session->rpt_datas, rpt_sno, pinfo, tree_rpt_sno, hf_ltp_rpt_sno_data_ref, NULL, hf_ltp_rpt_sno_data_time, NULL);
894 item_chkp_sno = add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_chkp, &chkp_sno, &chkp_sno_size);
895 segment_offset += chkp_sno_size;
896 if (ltp_analyze_sequence && session)
898 if (chkp_sno == 0)
900 expert_add_info(pinfo, item_chkp_sno, &ei_ltp_report_async);
902 else
904 proto_tree *tree_chkp_sno = proto_item_add_subtree(item_chkp_sno, ett_frame_ref);
905 ltp_ref_src(session->chkp_acks, chkp_sno, pinfo);
906 ltp_ref_use(session->checkpoints, chkp_sno, pinfo, tree_chkp_sno, hf_ltp_rpt_chkp_ref, &ei_ltp_rpt_nochkp, hf_ltp_rpt_chkp_time, tap);
910 add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_ub, &upper_bound, &upper_bound_size);
911 segment_offset += upper_bound_size;
913 add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_lb, &lower_bound, &lower_bound_size);
914 segment_offset += lower_bound_size;
916 PROTO_ITEM_SET_GENERATED(
917 proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_len, tvb, 0, 0, upper_bound - lower_bound)
919 col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL,
920 "range %" PRIu64 "-%" PRIu64,
921 lower_bound, upper_bound-1);
923 bool newdata = true;
924 if (ltp_analyze_sequence && session)
926 const uint64_t data_fst = lower_bound;
927 const uint64_t data_lst = upper_bound - 1;
929 // All segments for a single report ID
930 wmem_itree_t *rpt = wmem_map_lookup(session->rpt_segs, &rpt_sno);
931 if (!rpt)
933 uint64_t *key = wmem_new(wmem_file_scope(), uint64_t);
934 *key = rpt_sno;
935 rpt = wmem_itree_new(wmem_file_scope());
936 wmem_map_insert(session->rpt_segs, key, rpt);
939 if (data_fst <= data_lst) {
940 wmem_list_t *found = wmem_itree_find_intervals(rpt, pinfo->pool, data_fst, data_lst);
941 for (wmem_list_frame_t *it = wmem_list_head(found); it != NULL;
942 it = wmem_list_frame_next(it))
944 const ltp_frame_info_t *frame = wmem_list_frame_data(it);
945 if (frame->frame_num == pinfo->num)
947 continue;
949 PROTO_ITEM_SET_GENERATED(
950 proto_tree_add_uint(ltp_rpt_tree, hf_ltp_rpt_retrans, NULL, 0, 0, frame->frame_num)
952 newdata = false;
955 if (newdata)
957 ltp_frame_info_t *val = ltp_frame_info_new(pinfo);
958 wmem_itree_insert(rpt, data_fst, data_lst, val);
962 tap->corr_orig = newdata;
964 ltp_rpt_clm_cnt = add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_clm_cnt, &rcpt_clm_cnt, &rcpt_clm_cnt_size);
965 segment_offset += rcpt_clm_cnt_size;
966 /* Each reception claim is at least 2 bytes, so if the count is larger than the
967 * max number of claims we can possibly squeeze into the remaining tvbuff, then
968 * the packet is malformed.
970 if (rcpt_clm_cnt > (uint64_t)tvb_captured_length_remaining(tvb, frame_offset + segment_offset) / 2) {
971 expert_add_info_format(pinfo, ltp_rpt_clm_cnt, &ei_ltp_mal_reception_claim,
972 "Reception claim count impossibly large: %" PRIu64 " > %d", rcpt_clm_cnt,
973 tvb_captured_length_remaining(tvb, frame_offset + segment_offset) / 2);
974 return 0;
977 clm_lst = lower_bound - 1;
979 /* There can be multiple reception claims in the same report segment */
980 for(uint64_t ix = 0; ix < rcpt_clm_cnt; ix++){
981 /* Peek at the offset to see if there is a preceding gap */
982 tvb_get_varint(tvb, frame_offset + segment_offset, FT_VARINT_MAX_LEN, &offset, ENC_VARINT_SDNV);
983 clm_fst = lower_bound + offset;
984 ltp_check_reception_gap(ltp_rpt_tree, pinfo, session, clm_lst, clm_fst, &gap_count, &gap_total);
986 ltp_rpt_clm_tree = proto_tree_add_subtree(ltp_rpt_tree, tvb, frame_offset + segment_offset, -1, ett_rpt_clm, &ltp_rpt_clm_item, "Reception claim");
988 add_sdnv64_to_tree(ltp_rpt_clm_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_clm_off, &offset, &offset_size);
989 segment_offset += offset_size;
991 add_sdnv64_to_tree(ltp_rpt_clm_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_clm_len, &length, &length_size);
992 segment_offset += length_size;
994 PROTO_ITEM_SET_GENERATED(
995 proto_tree_add_uint64(ltp_rpt_clm_tree, hf_ltp_rpt_clm_fst, tvb, 0, 0, clm_fst)
997 clm_lst = clm_fst + length - 1;
998 PROTO_ITEM_SET_GENERATED(
999 proto_tree_add_uint64(ltp_rpt_clm_tree, hf_ltp_rpt_clm_lst, tvb, 0, 0, clm_lst)
1002 proto_item_append_text(ltp_rpt_clm_item,
1003 ": %" PRIu64 "-%" PRIu64 " (%" PRIu64 " bytes)",
1004 clm_fst, clm_lst, length
1006 proto_item_set_end(ltp_rpt_clm_item, tvb, frame_offset + segment_offset);
1008 if (ltp_analyze_sequence && session && (clm_fst <= clm_lst))
1010 wmem_list_t *found = wmem_itree_find_intervals(session->data_segs, pinfo->pool, clm_fst, clm_lst);
1011 for (wmem_list_frame_t *it = wmem_list_head(found); it != NULL;
1012 it = wmem_list_frame_next(it))
1014 const ltp_frame_info_t *frame = wmem_list_frame_data(it);
1015 if (frame->frame_num > pinfo->num)
1017 continue;
1019 PROTO_ITEM_SET_GENERATED(
1020 proto_tree_add_uint(ltp_rpt_clm_tree, hf_ltp_rpt_clm_ref, NULL, 0, 0, frame->frame_num)
1025 proto_item_set_end(ltp_rpt_item, tvb, frame_offset + segment_offset);
1027 ltp_check_reception_gap(ltp_rpt_tree, pinfo, session, clm_lst, upper_bound, &gap_count, &gap_total);
1028 PROTO_ITEM_SET_GENERATED(
1029 proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_gap_total, NULL, 0, 0, gap_total)
1031 col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "gaps: %d, gap total: %"PRIu64, gap_count, gap_total);
1033 return segment_offset;
1037 static int
1038 dissect_report_ack_segment(proto_tree *ltp_tree, tvbuff_t *tvb, packet_info *pinfo, int frame_offset, ltp_tap_info_t *tap){
1039 ltp_session_data_t *session = tap->session;
1040 int64_t rpt_sno;
1041 int rpt_sno_size;
1042 int segment_offset = 0;
1044 proto_item *ltp_rpt_ack_item, *item_rpt_sno;
1045 proto_tree *ltp_rpt_ack_tree;
1047 /* Creating tree for the report ack segment */
1048 ltp_rpt_ack_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, -1,
1049 ett_rpt_ack_segm, &ltp_rpt_ack_item, "Report Ack Segment");
1051 /* Extracting receipt serial number info */
1052 item_rpt_sno = add_sdnv64_to_tree(ltp_rpt_ack_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_ack_sno, &rpt_sno, &rpt_sno_size);
1053 segment_offset += rpt_sno_size;
1055 proto_item_set_end(ltp_rpt_ack_item, tvb, frame_offset + segment_offset);
1057 if (ltp_analyze_sequence && session)
1059 proto_tree *tree_rpt_sno = proto_item_add_subtree(item_rpt_sno, ett_frame_ref);
1060 ltp_ref_src(session->rpt_acks, rpt_sno, pinfo);
1061 ltp_ref_use(session->rpt_acks, rpt_sno, pinfo, tree_rpt_sno, hf_ltp_rpt_ack_dupe_ref, NULL, -1, NULL);
1062 ltp_ref_use(session->reports, rpt_sno, pinfo, tree_rpt_sno, hf_ltp_rpt_ack_ref, &ei_ltp_rpt_ack_norpt, hf_ltp_rpt_ack_time, tap);
1065 return segment_offset;
1069 static int
1070 dissect_cancel_segment(proto_tree *ltp_tree, tvbuff_t *tvb, packet_info *pinfo, int frame_offset, ltp_tap_info_t *tap){
1071 ltp_session_data_t *session = tap->session;
1073 /* The cancel segment has only one byte, which contains the reason code. */
1074 uint8_t reason_code = tvb_get_uint8(tvb,frame_offset);
1076 /* Creating tree for the cancel segment */
1077 proto_tree *tree_cancel = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, 1, ett_session_mgmt, NULL, "Cancel Segment");
1079 proto_tree_add_uint(tree_cancel, hf_ltp_cancel_code, tvb, frame_offset, 1, reason_code);
1081 if (ltp_analyze_sequence && session)
1083 const uint64_t cancel_type = tap->seg_type;
1084 ltp_ref_src(session->cancels, cancel_type, pinfo);
1085 ltp_ref_use(session->cancels, cancel_type, pinfo, tree_cancel, hf_ltp_cancel_dupe_ref, NULL, -1, NULL);
1086 ltp_ref_use(session->cancel_acks, cancel_type, pinfo, tree_cancel, hf_ltp_cancel_ref, &ei_ltp_cancel_noack, hf_ltp_cancel_time, NULL);
1089 return 1;
1093 static int
1094 dissect_cancel_ack_segment(proto_tree *ltp_tree, tvbuff_t *tvb, packet_info *pinfo, int frame_offset _U_, ltp_tap_info_t *tap){
1095 ltp_session_data_t *session = tap->session;
1096 proto_item *item_ack = proto_tree_add_item(ltp_tree, hf_ltp_cancel_ack, tvb, 0, 0, ENC_NA);
1097 proto_tree *tree_ack = proto_item_add_subtree(item_ack, ett_session_mgmt);
1099 if (ltp_analyze_sequence && session)
1101 const uint64_t cancel_type = tap->seg_type - 1;
1102 ltp_ref_src(session->cancel_acks, cancel_type, pinfo);
1103 ltp_ref_use(session->cancel_acks, cancel_type, pinfo, tree_ack, hf_ltp_cancel_ack_dupe_ref, NULL, -1, NULL);
1104 ltp_ref_use(session->cancels, cancel_type, pinfo, tree_ack, hf_ltp_cancel_ack_ref, &ei_ltp_cancel_ack_nocancel, hf_ltp_cancel_ack_time, tap);
1107 return 0;
1110 static int
1111 dissect_header_extn(proto_tree *ltp_tree, tvbuff_t *tvb, packet_info *pinfo, int frame_offset,int hdr_extn_cnt){
1112 int64_t length;
1113 int length_size;
1115 int extn_offset = 0;
1117 proto_item *ltp_hdr_extn_item;
1118 proto_tree *ltp_hdr_extn_tree;
1120 ltp_hdr_extn_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, -1, ett_hdr_extn, &ltp_hdr_extn_item, "Header Extension");
1122 for(int ix = 0; ix < hdr_extn_cnt; ix++){
1123 /* From RFC-5326, the total length of the Header Extension Tree will be length of the following:
1124 a) Extension type length (1 byte)
1125 b) The length of the 'length' field (as defined by the SDNV which handles dynamic size)
1126 c) The length of the value field which is the decoded length */
1127 proto_tree_add_item(ltp_hdr_extn_tree, hf_ltp_hdr_extn_tag, tvb, frame_offset + extn_offset, 1, ENC_NA);
1128 extn_offset += 1;
1130 add_sdnv64_to_tree(ltp_hdr_extn_tree, tvb, pinfo, frame_offset + extn_offset, hf_ltp_hdr_extn_len, &length, &length_size);
1131 extn_offset += length_size;
1133 proto_tree_add_item(ltp_hdr_extn_tree, hf_ltp_hdr_extn_val, tvb, frame_offset + extn_offset, (int)length, ENC_NA);
1134 extn_offset += (int)length;
1137 proto_item_set_end(ltp_hdr_extn_item, tvb, frame_offset + extn_offset);
1138 return extn_offset;
1141 static int
1142 dissect_trailer_extn(proto_tree *ltp_tree, tvbuff_t *tvb, packet_info *pinfo, int frame_offset,int trl_extn_cnt){
1143 int64_t length;
1144 int length_size;
1146 int extn_offset = 0;
1148 proto_item *ltp_trl_extn_item;
1149 proto_tree *ltp_trl_extn_tree;
1151 ltp_trl_extn_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, -1, ett_trl_extn, &ltp_trl_extn_item, "Trailer Extension");
1153 for(int ix = 0; ix < trl_extn_cnt; ix++){
1154 proto_tree_add_item(ltp_trl_extn_tree, hf_ltp_trl_extn_tag, tvb, frame_offset + extn_offset, 1, ENC_NA);
1155 frame_offset += 1;
1157 add_sdnv64_to_tree(ltp_trl_extn_tree, tvb, pinfo, frame_offset + extn_offset, hf_ltp_hdr_extn_len, &length, &length_size);
1158 frame_offset += length_size;
1160 proto_tree_add_item(ltp_trl_extn_tree, hf_ltp_trl_extn_val, tvb, frame_offset + extn_offset, (int)length, ENC_NA);
1161 frame_offset += (int)length;
1164 proto_item_set_end(ltp_trl_extn_item, tvb, frame_offset + extn_offset);
1165 return extn_offset;
1169 static int
1170 dissect_ltp_segment(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
1172 proto_item *ti = NULL;
1173 proto_tree *ltp_tree = NULL;
1174 int frame_offset = offset;
1175 int segment_offset = 0;
1176 int data_len = 0;
1178 int ltp_type;
1179 uint64_t bitsval;
1180 int hdr_extn_cnt;
1181 int trl_extn_cnt;
1183 int engine_id_size;
1184 int session_num_size;
1185 const char *sess_name;
1186 ltp_session_data_t *session = NULL;
1188 proto_tree *ltp_header_tree = NULL;
1189 proto_item *ltp_header_item = NULL;
1190 proto_tree *ltp_session_tree = NULL;
1191 proto_item *ltp_session_item = NULL;
1193 /* Check that there's enough data */
1194 if(tvb_reported_length(tvb) < LTP_MIN_DATA_BUFFER){
1195 return 0;
1198 /* Extract all the header info from the packet */
1199 ti = proto_tree_add_item(tree, proto_ltp, tvb, offset, -1, ENC_NA);
1200 ltp_tree = proto_item_add_subtree(ti, ett_ltp);
1202 ltp_tap_info_t *tap = wmem_new0(pinfo->pool, ltp_tap_info_t);
1204 /* Adding Header Subtree */
1205 ltp_header_tree = proto_tree_add_subtree(ltp_tree, tvb, frame_offset, 0, ett_ltp_hdr, NULL, "LTP Header");
1206 ltp_header_item = proto_tree_get_parent(ltp_header_tree);
1208 proto_tree_add_bits_ret_val(ltp_header_tree, hf_ltp_version, tvb, frame_offset, 4, &bitsval, ENC_BIG_ENDIAN);
1209 proto_tree_add_bits_ret_val(ltp_header_tree, hf_ltp_type, tvb, frame_offset+4, 4, &bitsval, ENC_BIG_ENDIAN);
1210 ltp_type = (int)bitsval;
1211 tap->seg_type = ltp_type;
1212 frame_offset++;
1214 /* Adding the session id subtree */
1215 ltp_session_tree = proto_tree_add_subtree(ltp_header_tree, tvb, frame_offset, 0, ett_hdr_session, NULL, "Session ID");
1216 ltp_session_item = proto_tree_get_parent(ltp_session_tree);
1218 add_sdnv64_to_tree(ltp_session_tree, tvb, pinfo, frame_offset, hf_ltp_session_orig, &(tap->sess_id.orig_eng_id), &engine_id_size);
1219 frame_offset += engine_id_size;
1221 add_sdnv64_to_tree(ltp_session_tree, tvb, pinfo, frame_offset, hf_ltp_session_no, &(tap->sess_id.sess_num), &session_num_size);
1222 frame_offset += session_num_size;
1224 proto_item_set_end(ltp_session_item, tvb, frame_offset);
1226 sess_name = wmem_strdup_printf(
1227 wmem_file_scope(),
1228 "%" PRId64 "/%" PRIu64,
1229 tap->sess_id.orig_eng_id, tap->sess_id.sess_num
1231 tap->sess_name = sess_name;
1232 PROTO_ITEM_SET_GENERATED(
1233 proto_tree_add_string(ltp_session_tree, hf_ltp_session_name, tvb,
1234 frame_offset - engine_id_size - session_num_size,
1235 engine_id_size + session_num_size, sess_name)
1237 proto_item_append_text(ltp_session_item,": %s", sess_name);
1238 proto_item_append_text(ti,", Session: %s", sess_name);
1239 p_add_proto_data(pinfo->pool, pinfo, proto_ltp, pinfo->curr_layer_num, (void *)sess_name);
1241 if (tree && ltp_analyze_sequence)
1243 // LTP sessions exist independently of network addresses and transport ports
1244 conversation_element_t *conv_key = wmem_alloc_array(pinfo->pool, conversation_element_t, 3);
1245 conv_key[0].type = CE_UINT64;
1246 conv_key[0].uint64_val = tap->sess_id.orig_eng_id;
1247 conv_key[1].type = CE_UINT64;
1248 conv_key[1].uint64_val = tap->sess_id.sess_num;
1249 conv_key[2].type = CE_CONVERSATION_TYPE;
1250 conv_key[2].conversation_type_val = CONVERSATION_LTP;
1252 pinfo->use_conv_addr_port_endpoints = false;
1253 pinfo->conv_addr_port_endpoints = NULL;
1254 pinfo->conv_elements = conv_key;
1255 conversation_t *convo = find_or_create_conversation(pinfo);
1257 session = conversation_get_proto_data(convo, proto_ltp);
1258 if (!session)
1260 session = wmem_new0(wmem_file_scope(), ltp_session_data_t);
1261 session->data_segs = wmem_itree_new(wmem_file_scope());
1262 session->rpt_segs = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
1263 session->checkpoints = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
1264 session->chkp_acks = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
1265 session->reports = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
1266 session->rpt_acks = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
1267 session->rpt_datas = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
1268 session->cancels = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
1269 session->cancel_acks = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
1271 conversation_add_proto_data(convo, proto_ltp, session);
1274 tap->session = session;
1276 /* Adding Extension count to the header tree */
1277 proto_tree_add_bits_ret_val(ltp_header_tree, hf_ltp_hdr_extn_cnt, tvb, 8*frame_offset, 4, &bitsval, ENC_BIG_ENDIAN);
1278 hdr_extn_cnt = (int)bitsval;
1279 proto_tree_add_bits_ret_val(ltp_header_tree, hf_ltp_trl_extn_cnt, tvb, 8*frame_offset+4, 4, &bitsval, ENC_BIG_ENDIAN);
1280 trl_extn_cnt = (int)bitsval;
1281 frame_offset++;
1283 proto_item_set_end(ltp_header_item, tvb, frame_offset);
1285 col_add_fstr(pinfo->cinfo, COL_INFO, "Session %s, %s", sess_name, val_to_str_const(ltp_type,ltp_type_col_info,"Protocol Error"));
1287 /* Check if there are any header extensions */
1288 if(hdr_extn_cnt > 0)
1290 int hdr_extn_offset = dissect_header_extn(ltp_tree, tvb, pinfo, frame_offset,hdr_extn_cnt);
1291 frame_offset += hdr_extn_offset;
1294 /* Call sub routines to handle the segment content*/
1295 if((ltp_type >= 0) && (ltp_type < 8)){
1296 segment_offset = dissect_data_segment(ltp_tree, tvb, pinfo, frame_offset, &data_len, tap);
1297 if(segment_offset == 0){
1298 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
1299 return 0;
1302 else if(ltp_type == 8){
1303 segment_offset = dissect_report_segment(tvb, pinfo, ltp_tree, frame_offset, tap);
1304 if(segment_offset == 0){
1305 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
1306 return 0;
1309 else if(ltp_type == 9){
1310 segment_offset = dissect_report_ack_segment(ltp_tree, tvb, pinfo, frame_offset, tap);
1311 if(segment_offset == 0){
1312 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
1313 return 0;
1316 else if(ltp_type == 12 || ltp_type == 14){
1317 segment_offset = dissect_cancel_segment(ltp_tree, tvb, pinfo, frame_offset, tap);
1318 if(segment_offset == 0){
1319 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
1320 return 0;
1323 else if(ltp_type == 13 || ltp_type == 15){
1324 segment_offset = dissect_cancel_ack_segment(ltp_tree, tvb, pinfo, frame_offset, tap);
1326 frame_offset += segment_offset;
1328 /* Check to see if there are any trailer extensions */
1329 const int trl_start = frame_offset;
1330 if(trl_extn_cnt > 0)
1332 int trl_length = dissect_trailer_extn(ltp_tree, tvb, pinfo, frame_offset,trl_extn_cnt);
1333 frame_offset += trl_length;
1336 const int frame_len = frame_offset - offset;
1337 proto_item_set_len(ti, trl_start - data_len);
1338 proto_tree_set_appendix(ltp_tree, tvb, trl_start, frame_offset - trl_start);
1339 tap->seg_size = frame_len;
1340 if (tree)
1342 tap_queue_packet(ltp_tap, pinfo, tap);
1345 /* Return the amount of data this dissector was able to dissect */
1346 return frame_len;
1349 static int
1350 dissect_ltp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1352 const int packet_len = tvb_reported_length(tvb);
1353 int offset = 0;
1355 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LTP");
1357 while (offset < packet_len)
1359 const int sublen = dissect_ltp_segment(tvb, offset, pinfo, tree);
1360 if (sublen == 0)
1362 break;
1364 offset += sublen;
1366 return offset;
1369 static bool
1370 dissect_ltp_heur_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1372 const int packet_len = tvb_reported_length(tvb);
1373 if (packet_len <= LTP_MIN_DATA_BUFFER)
1375 return false;
1378 int offset = 0;
1379 TRY {
1380 // unlike dissect_ltp() this requires the entire datagram to be dissected
1381 while (offset < packet_len)
1383 const int sublen = dissect_ltp_segment(tvb, offset, pinfo, NULL);
1384 if (sublen == 0)
1386 offset = 0;
1387 break;
1389 offset += sublen;
1392 CATCH_BOUNDS_ERRORS {
1393 offset = 0;
1395 ENDTRY;
1396 if (offset != packet_len)
1398 return false;
1401 dissect_ltp(tvb, pinfo, tree, data);
1402 return true;
1405 /// Conversation address for the session receiver
1406 static const char *const ltp_conv_receiver = "receiver";
1407 /// Assigned during proto_register_ltp()
1408 static address ltp_addr_receiver = ADDRESS_INIT_NONE;
1410 static const char *
1411 ltp_conv_get_filter_type(conv_item_t *conv _U_, conv_filter_type_e filter)
1413 switch (conv->dst_address.type)
1415 case AT_STRINGZ:
1416 switch (filter)
1418 case CONV_FT_SRC_ADDRESS:
1419 case CONV_FT_DST_ADDRESS:
1420 case CONV_FT_ANY_ADDRESS:
1421 return "ltp.session.name";
1422 default:
1423 break;
1425 break;
1426 default:
1427 break;
1430 return CONV_FILTER_INVALID;
1433 static ct_dissector_info_t ltp_ct_dissector_info = {
1434 &ltp_conv_get_filter_type
1437 static tap_packet_status
1438 ltp_conv_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
1440 conv_hash_t *hash = (conv_hash_t*) tapdata;
1441 ltp_tap_info_t *ltp = (ltp_tap_info_t *)data;
1442 address *src = wmem_new0(pinfo->pool, address);
1443 address *dst = wmem_new0(pinfo->pool, address);
1445 address *diraddr, *othaddr;
1446 switch (ltp->seg_type) {
1447 case 0x8:
1448 case 0xd:
1449 case 0xe:
1450 // report, cancel ack to sender, cancel from receiver
1451 diraddr = dst;
1452 othaddr = src;
1453 break;
1454 default:
1455 diraddr = src;
1456 othaddr = dst;
1457 break;
1459 set_address(diraddr, AT_STRINGZ, (int) strlen(ltp->sess_name) + 1, ltp->sess_name);
1460 copy_address_shallow(othaddr, &ltp_addr_receiver);
1462 add_conversation_table_data(hash, src, dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->abs_ts,
1463 &ltp_ct_dissector_info, CONVERSATION_NONE);
1465 return TAP_PACKET_REDRAW;
1468 static const char *
1469 ltp_endp_get_filter_type(endpoint_item_t *host, conv_filter_type_e filter)
1471 switch (filter)
1473 case CONV_FT_SRC_ADDRESS:
1474 case CONV_FT_DST_ADDRESS:
1475 case CONV_FT_ANY_ADDRESS:
1476 if (host->myaddress.type == AT_NUMERIC)
1478 return "ltp.session.orig";
1480 break;
1481 default:
1482 break;
1485 return CONV_FILTER_INVALID;
1488 static et_dissector_info_t ltp_endp_dissector_info = {
1489 &ltp_endp_get_filter_type
1492 static tap_packet_status
1493 ltp_endp_packet(void *tapdata _U_, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *data _U_, tap_flags_t flags _U_)
1495 conv_hash_t *hash = (conv_hash_t*) tapdata;
1496 ltp_tap_info_t *ltp = (ltp_tap_info_t *)data;
1497 address *diraddr = wmem_new0(pinfo->pool, address);
1499 set_address(diraddr, AT_NUMERIC, (int) sizeof(ltp->sess_id.orig_eng_id), &(ltp->sess_id.orig_eng_id));
1500 bool sender;
1501 switch (ltp->seg_type) {
1502 case 0x8:
1503 case 0xd:
1504 case 0xe:
1505 // report, cancel ack to sender, cancel from receiver
1506 sender = false;
1507 break;
1508 default:
1509 sender = true;
1510 break;
1513 add_endpoint_table_data(hash, diraddr, 0, sender, 1, pinfo->fd->pkt_len,
1514 &ltp_endp_dissector_info, ENDPOINT_NONE);
1516 return TAP_PACKET_REDRAW;
1519 static bool
1520 ltp_filter_valid(packet_info *pinfo, void *user_data _U_)
1522 return proto_is_frame_protocol(pinfo->layers, "ltp");
1525 static char*
1526 ltp_build_filter(packet_info *pinfo, void *user_data _U_)
1528 char *result = NULL;
1529 int layer_num = 1;
1530 for (wmem_list_frame_t *protos = wmem_list_head(pinfo->layers);
1531 protos != NULL; protos = wmem_list_frame_next(protos), ++layer_num)
1533 const int proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos));
1534 if (proto_id != proto_ltp)
1536 continue;
1538 const char *sess_name = p_get_proto_data(pinfo->pool, pinfo, proto_ltp, layer_num);
1539 if (!sess_name)
1541 continue;
1544 char *filter = g_strdup_printf(
1545 "ltp.session.name == \"%s\"",
1546 sess_name
1549 if (result)
1551 char *oldresult = result;
1552 result = g_strjoin(" || ", oldresult, filter, NULL);
1553 g_free(oldresult);
1554 g_free(filter);
1556 else
1558 result = filter;
1562 return result;
1565 static const char* st_str_segs = "Segment Size (by Type)";
1566 static const char* st_str_red = "Red Data";
1567 static const char* st_str_corr_orig = "Original";
1568 static const char* st_str_corr_ret = "Retransmission seen";
1569 static const char* st_str_green = "Green Data";
1570 static const char* st_str_rpt = "Report";
1571 static const char* st_str_canc_src = "Cancel by Sender";
1572 static const char* st_str_canc_dst = "Cancel by Receiver";
1573 static const char* st_str_ack = "Report/Cancel Ack";
1574 static const char* st_str_engs = "Segment Addr (by Engine ID)";
1575 static const char* st_str_blks = "Block Size (by Engine ID)";
1576 static int st_node_segs = -1;
1577 static int st_node_red = -1;
1578 static int st_node_green = -1;
1579 static int st_node_rpt = -1;
1580 static int st_node_engs = -1;
1581 static int st_node_blks = -1;
1583 static void
1584 ltp_stats_tree_init(stats_tree *st)
1586 st_node_segs = stats_tree_create_node(st, st_str_segs, 0, STAT_DT_INT, false);
1587 st_node_red = stats_tree_create_node(st, st_str_red, st_node_segs, STAT_DT_INT, true);
1588 stats_tree_create_node(st, st_str_corr_orig, st_node_red, STAT_DT_INT, false);
1589 stats_tree_create_node(st, st_str_corr_ret, st_node_red, STAT_DT_INT, false);
1590 st_node_green = stats_tree_create_node(st, st_str_green, st_node_segs, STAT_DT_INT, false);
1591 st_node_rpt = stats_tree_create_node(st, st_str_rpt, st_node_segs, STAT_DT_INT, true);
1592 stats_tree_create_node(st, st_str_corr_orig, st_node_rpt, STAT_DT_INT, false);
1593 stats_tree_create_node(st, st_str_corr_ret, st_node_rpt, STAT_DT_INT, false);
1594 stats_tree_create_node(st, st_str_canc_src, st_node_segs, STAT_DT_INT, false);
1595 stats_tree_create_node(st, st_str_canc_dst, st_node_segs, STAT_DT_INT, false);
1596 stats_tree_create_node(st, st_str_ack, st_node_segs, STAT_DT_INT, false);
1598 st_node_engs = stats_tree_create_pivot(st, st_str_engs, 0);
1599 st_node_blks = stats_tree_create_pivot(st, st_str_blks, 0);
1602 static tap_packet_status
1603 ltp_stats_tree_packet(stats_tree *st, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *p, tap_flags_t flags _U_)
1605 const ltp_tap_info_t *tap = (const ltp_tap_info_t *)p;
1607 tick_stat_node(st, st_str_segs, 0, false);
1609 switch (tap->seg_type)
1611 case 0x0:
1612 case 0x1:
1613 case 0x2:
1614 case 0x3:
1615 avg_stat_node_add_value_int(st, st_str_red, 0, false, tap->seg_size);
1616 avg_stat_node_add_value_int(st, tap->corr_orig ? st_str_corr_orig : st_str_corr_ret, st_node_red, true, tap->seg_size);
1617 break;
1618 case 0x4:
1619 case 0x7:
1620 avg_stat_node_add_value_int(st, st_str_green, 0, false, tap->seg_size);
1621 break;
1622 case 0x8:
1623 avg_stat_node_add_value_int(st, st_str_rpt, 0, false, tap->seg_size);
1624 avg_stat_node_add_value_int(st, tap->corr_orig ? st_str_corr_orig : st_str_corr_ret, st_node_rpt, true, tap->seg_size);
1625 break;
1626 case 0xc:
1627 avg_stat_node_add_value_int(st, st_str_canc_src, 0, false, tap->seg_size);
1628 break;
1629 case 0xe:
1630 avg_stat_node_add_value_int(st, st_str_canc_dst, 0, false, tap->seg_size);
1631 break;
1632 case 0x9:
1633 case 0xd:
1634 case 0xf:
1635 avg_stat_node_add_value_int(st, st_str_ack, 0, false, tap->seg_size);
1636 break;
1639 tick_stat_node(st, st_str_engs, 0, true);
1640 const char *eng_id = wmem_strdup_printf(pinfo->pool, "%" PRIu64, tap->sess_id.orig_eng_id);
1641 int st_eng_id = tick_stat_node(st, eng_id, st_node_engs, true);
1642 if (tap->block_size > 0)
1644 avg_stat_node_add_value_int(st, st_str_blks, 0, true, tap->block_size);
1645 avg_stat_node_add_value_int(st, eng_id, st_node_blks, false, tap->block_size);
1648 const address *eng_addr = NULL;
1649 switch (tap->seg_type)
1651 case 0x0:
1652 case 0x1:
1653 case 0x2:
1654 case 0x3:
1655 case 0x4:
1656 case 0x7:
1657 case 0x9:
1658 case 0xc: // cancel from sender
1659 case 0xf:
1660 eng_addr = &(pinfo->src);
1661 break;
1662 case 0x8: // report
1663 case 0xd:
1664 case 0xe: // cancel from receiver
1665 eng_addr = &(pinfo->dst);
1666 break;
1668 const char *eng_addr_str = eng_addr ? address_to_display(pinfo->pool, eng_addr) : NULL;
1669 if (eng_addr_str)
1671 tick_stat_node(st, eng_addr_str, st_eng_id, false);
1674 return TAP_PACKET_REDRAW;
1677 /* Register the protocol with Wireshark */
1678 void
1679 proto_register_ltp(void)
1681 static hf_register_info hf[] = {
1682 {&hf_ltp_version,
1683 {"LTP Version","ltp.version",
1684 FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
1686 {&hf_ltp_type,
1687 {"LTP Type","ltp.type",
1688 FT_UINT8,BASE_HEX,VALS(ltp_type_codes), 0x0, NULL, HFILL}
1690 {&hf_ltp_session_orig,
1691 {"Session originator","ltp.session.orig",
1692 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1694 {&hf_ltp_session_no,
1695 {"Session number","ltp.session.number",
1696 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1698 {&hf_ltp_session_name,
1699 {"Session Name","ltp.session.name",
1700 FT_STRING,BASE_NONE,NULL, 0x0, NULL, HFILL}
1702 {&hf_ltp_hdr_extn_cnt,
1703 {"Header Extension Count","ltp.hdr.extn.cnt",
1704 FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
1706 {&hf_ltp_trl_extn_cnt,
1707 {"Trailer Extension Count","ltp.trl.extn.cnt",
1708 FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
1710 {&hf_ltp_data_clid,
1711 {"Client service ID","ltp.data.client.id",
1712 FT_UINT64,BASE_DEC | BASE_VAL64_STRING, VALS64(client_service_id_info), 0x0, NULL, HFILL}
1714 {&hf_ltp_data_offset,
1715 {"Offset","ltp.data.offset",
1716 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1718 {&hf_ltp_data_length,
1719 {"Length","ltp.data.length",
1720 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1722 {&hf_ltp_data_chkp,
1723 {"Checkpoint serial number","ltp.data.chkp",
1724 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1726 {&hf_ltp_data_chkp_rpt_ref,
1727 {"Checkpoint report segment in frame","ltp.data.chkp.rpt",
1728 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_NONE), 0x0, NULL, HFILL}
1730 {&hf_ltp_data_chkp_rpt_time,
1731 {"Time to checkpoint report segment","ltp.data.chkp.rpt.time",
1732 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}
1734 {&hf_ltp_data_rpt,
1735 {"Report serial number","ltp.data.rpt",
1736 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1738 {&hf_ltp_data_rpt_ref,
1739 {"Response to report segment in frame","ltp.data.rpt.ref",
1740 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_NONE), 0x0, NULL, HFILL}
1742 {&hf_ltp_data_rpt_time,
1743 {"Time since report","ltp.data.rpt.time",
1744 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}
1746 {&hf_ltp_data_clidata,
1747 {"Client service data","ltp.data.data",
1748 FT_BYTES,BASE_NONE,NULL, 0x0, NULL, HFILL}
1750 {&hf_ltp_data_retrans,
1751 {"Retransmission of data in frame","ltp.data.retrans",
1752 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RETRANS_PREV), 0x0, NULL, HFILL}
1754 {&hf_ltp_data_clm_rpt,
1755 {"Claimed in report segment in frame","ltp.data.clm_rpt",
1756 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_NONE), 0x0, NULL, HFILL}
1758 {&hf_ltp_block_red_size,
1759 {"Red part size", "ltp.block.red_size",
1760 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1762 {&hf_ltp_block_green_size,
1763 {"Green part size", "ltp.block.green_size",
1764 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1766 {&hf_ltp_block_bundle_size,
1767 {"Bundle size", "ltp.block.bundle_size",
1768 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0,
1769 "The dissected bundle is below in the protocol tree", HFILL}
1771 {&hf_ltp_block_bundle_cnt,
1772 {"Bundles within the block", "ltp.block.bundle_cnt",
1773 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1775 {&hf_ltp_rpt_sno,
1776 {"Report serial number","ltp.rpt.sno",
1777 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1779 {&hf_ltp_rpt_sno_ack_ref,
1780 {"Report ack segment in frame","ltp.rpt.sno.ack",
1781 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_NONE), 0x0, NULL, HFILL}
1783 {&hf_ltp_rpt_sno_ack_time,
1784 {"Time to report ack segment","ltp.rpt.sno.ack.time",
1785 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}
1787 {&hf_ltp_rpt_sno_data_ref,
1788 {"Responding data segment in frame","ltp.rpt.sno.data",
1789 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_NONE), 0x0, NULL, HFILL}
1791 {&hf_ltp_rpt_sno_data_time,
1792 {"Time to checkpoint data segment","ltp.rpt.sno.data.time",
1793 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}
1795 {&hf_ltp_rpt_chkp,
1796 {"Checkpoint serial number","ltp.rpt.chkp",
1797 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1799 {&hf_ltp_rpt_chkp_ref,
1800 {"Checkpoint data segment in frame","ltp.rpt.chkp.ref",
1801 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_ACK), 0x0, NULL, HFILL}
1803 {&hf_ltp_rpt_chkp_time,
1804 {"Time since checkpoint","ltp.rpt.chkp.time",
1805 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}
1807 {&hf_ltp_rpt_ub,
1808 {"Upper bound","ltp.rpt.ub",
1809 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1811 {&hf_ltp_rpt_lb,
1812 {"Lower bound","ltp.rpt.lb",
1813 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1815 {&hf_ltp_rpt_len,
1816 {"Report bound length","ltp.rpt.bound_len",
1817 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1819 {&hf_ltp_rpt_retrans,
1820 {"Retransmission of report in frame","ltp.rpt.retrans",
1821 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RETRANS_PREV), 0x0, NULL, HFILL}
1823 {&hf_ltp_rpt_clm_cnt,
1824 {"Reception claim count","ltp.rpt.clm.cnt",
1825 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1827 {&hf_ltp_rpt_clm_off,
1828 {"Offset","ltp.rpt.clm.off",
1829 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1831 {&hf_ltp_rpt_clm_len,
1832 {"Length","ltp.rpt.clm.len",
1833 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1835 {&hf_ltp_rpt_clm_fst,
1836 {"First block index","ltp.rpt.clm.first",
1837 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1839 {&hf_ltp_rpt_clm_lst,
1840 {"Last block index","ltp.rpt.clm.last",
1841 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1843 {&hf_ltp_rpt_clm_ref,
1844 {"Data segment in frame","ltp.rpt.clm.ref",
1845 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_NONE), 0x0,
1846 "Which previous data segment is this an ACK for", HFILL}
1848 {&hf_ltp_rpt_gap,
1849 {"Reception gap","ltp.rpt.gap",
1850 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1852 {&hf_ltp_rpt_gap_fst,
1853 {"First block index","ltp.rpt.gap.first",
1854 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1856 {&hf_ltp_rpt_gap_lst,
1857 {"Last block index","ltp.rpt.gap.last",
1858 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1860 {&hf_ltp_rpt_gap_ref,
1861 {"Data segment in frame","ltp.rpt.gap.ref",
1862 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_NONE), 0x0,
1863 "Which previous data segment is this an NACK for", HFILL}
1865 {&hf_ltp_rpt_gap_total,
1866 {"Total gap length","ltp.rpt.gap_total",
1867 FT_UINT64,BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL}
1869 {&hf_ltp_rpt_ack_sno,
1870 {"Report serial number","ltp.rpt.ack.sno",
1871 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1873 {&hf_ltp_rpt_ack_dupe_ref,
1874 {"Same ack report number in frame","ltp.rpt.ack.sno.dupe",
1875 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RETRANS_PREV), 0x0, NULL, HFILL}
1877 {&hf_ltp_rpt_ack_ref,
1878 {"Response to report segment in frame","ltp.rpt.ack.sno.ref",
1879 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_ACK), 0x0, NULL, HFILL}
1881 {&hf_ltp_rpt_ack_time,
1882 {"Time since report","ltp.rpt.ack.sno.time",
1883 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}
1885 {&hf_ltp_cancel_code,
1886 {"Cancel code","ltp.cancel.code",
1887 FT_UINT8,BASE_HEX, VALS(ltp_cancel_codes), 0x0, NULL, HFILL}
1889 {&hf_ltp_cancel_dupe_ref,
1890 {"Same session cancel in frame","ltp.cancel.dupe.ref",
1891 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RETRANS_PREV), 0x0, NULL, HFILL}
1893 {&hf_ltp_cancel_ref,
1894 {"Acknowledgement segment in frame", "ltp.cancel.ack.ref",
1895 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_NONE), 0x0, NULL, HFILL}
1897 {&hf_ltp_cancel_time,
1898 {"Time to cancel ack","ltp.cancel.ack.time",
1899 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}
1901 {&hf_ltp_cancel_ack,
1902 {"Cancel Ack", "ltp.cancel_ack",
1903 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
1905 {&hf_ltp_cancel_ack_dupe_ref,
1906 {"Same acknowledgement in frame","ltp.cancel_ack.dupe.ref",
1907 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RETRANS_PREV), 0x0, NULL, HFILL}
1909 {&hf_ltp_cancel_ack_ref,
1910 {"Response to cancel segment in frame", "ltp.cancel_ack.cancel.ref",
1911 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_ACK), 0x0, NULL, HFILL}
1913 {&hf_ltp_cancel_ack_time,
1914 {"Time since cancel","ltp.cancel_ack.cancel.time",
1915 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}
1917 {&hf_ltp_hdr_extn_tag,
1918 {"Extension tag","ltp.hdr.extn.tag",
1919 FT_UINT8,BASE_HEX,VALS(extn_tag_codes), 0x0, NULL, HFILL}
1921 {&hf_ltp_hdr_extn_len,
1922 {"Length","ltp.hdr.extn.len",
1923 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1925 {&hf_ltp_hdr_extn_val,
1926 {"Value","ltp.hdr.extn.val",
1927 FT_BYTES,BASE_NONE,NULL, 0x0, NULL, HFILL}
1929 {&hf_ltp_trl_extn_tag,
1930 {"Extension tag","ltp.trl.extn.tag",
1931 FT_UINT8,BASE_HEX,VALS(extn_tag_codes), 0x0, NULL, HFILL}
1933 {&hf_ltp_trl_extn_len,
1934 {"Length","ltp.trl.extn.len",
1935 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
1937 {&hf_ltp_trl_extn_val,
1938 {"Value","ltp.trl.extn.val",
1939 FT_BYTES,BASE_NONE,NULL, 0x0, NULL, HFILL}
1941 {&hf_ltp_fragments,
1942 {"LTP Fragments", "ltp.fragments",
1943 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
1945 {&hf_ltp_fragment,
1946 {"LTP Fragment", "ltp.fragment",
1947 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
1949 {&hf_ltp_fragment_overlap,
1950 {"LTP fragment overlap", "ltp.fragment.overlap",
1951 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
1953 {&hf_ltp_fragment_overlap_conflicts,
1954 {"LTP fragment overlapping with conflicting data",
1955 "ltp.fragment.overlap.conflicts",
1956 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
1958 {&hf_ltp_fragment_multiple_tails,
1959 {"LTP has multiple tails", "ltp.fragment.multiple_tails",
1960 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
1962 {&hf_ltp_fragment_too_long_fragment,
1963 {"LTP fragment too long", "ltp.fragment.too_long_fragment",
1964 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
1966 {&hf_ltp_fragment_error,
1967 {"LTP defragmentation error", "ltp.fragment.error",
1968 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
1970 {&hf_ltp_fragment_count,
1971 {"LTP fragment count", "ltp.fragment.count",
1972 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
1974 {&hf_ltp_reassembled_in,
1975 {"LTP reassembled in", "ltp.reassembled.in",
1976 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
1978 {&hf_ltp_reassembled_length,
1979 {"LTP reassembled length", "ltp.reassembled.length",
1980 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
1982 {&hf_ltp_data_sda_clid,
1983 {"Client service ID", "ltp.data.sda.client.id",
1984 FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
1988 /* Setup protocol subtree array */
1989 static int *ett[] = {
1990 &ett_ltp,
1991 &ett_ltp_hdr,
1992 &ett_hdr_session,
1993 &ett_hdr_extn,
1994 &ett_frame_ref,
1995 &ett_data_segm,
1996 &ett_block,
1997 &ett_rpt_segm,
1998 &ett_rpt_clm,
1999 &ett_rpt_gap,
2000 &ett_rpt_ack_segm,
2001 &ett_session_mgmt,
2002 &ett_trl_extn,
2003 &ett_ltp_fragment,
2004 &ett_ltp_fragments
2007 static ei_register_info ei[] = {
2008 { &ei_ltp_mal_reception_claim, { "ltp.mal_reception_claim", PI_MALFORMED, PI_ERROR, "Reception claim count impossibly large", EXPFILL }},
2009 { &ei_ltp_sdnv_length, { "ltp.sdnv_length_invalid", PI_PROTOCOL, PI_ERROR, "SDNV length error", EXPFILL }},
2010 { &ei_ltp_sno_larger_than_ccsds, { "ltp.serial_number_too_large", PI_PROTOCOL, PI_WARN, "Serial number larger than CCSDS specification", EXPFILL }},
2011 { &ei_ltp_report_async, { "ltp.report_async", PI_SEQUENCE, PI_CHAT, "Report segment not sent in response to a data checkpoint", EXPFILL }},
2012 { &ei_ltp_data_chkp_norpt, { "ltp.data_chkp_norpt", PI_SEQUENCE, PI_CHAT, "Data with checkpoint has no corresponding report segment", EXPFILL }},
2013 { &ei_ltp_data_rptno_norpt, { "ltp.data_rptno_norpt", PI_SEQUENCE, PI_CHAT, "Data with report serial has no corresponding report segment", EXPFILL }},
2014 { &ei_ltp_rpt_noack, { "ltp.rpt_noack", PI_SEQUENCE, PI_CHAT, "Report segment has no corresponding acknowledgement", EXPFILL }},
2015 { &ei_ltp_rpt_nochkp, { "ltp.rpt_nochkp", PI_SEQUENCE, PI_CHAT, "Report segment has no corresponding checkpoint data segment", EXPFILL }},
2016 { &ei_ltp_rpt_ack_norpt, { "ltp.rpt_ack_norpt", PI_SEQUENCE, PI_CHAT, "Report has no report acknowledgement segment", EXPFILL }},
2017 { &ei_ltp_cancel_noack, { "ltp.cancel_noack", PI_SEQUENCE, PI_CHAT, "Cancel segment has no cancel acknowledgement segment", EXPFILL }},
2018 { &ei_ltp_cancel_ack_nocancel, { "ltp.cancel_ack_nocancel", PI_SEQUENCE, PI_CHAT, "Cancel acknowledgement has no corresponding cancel segment", EXPFILL }}
2021 expert_module_t* expert_ltp;
2023 /* Register the protocol name and description */
2024 proto_ltp = proto_register_protocol("Licklider Transmission Protocol", "LTP", "ltp");
2026 module_t *module_ltp = prefs_register_protocol(proto_ltp, NULL);
2027 prefs_register_bool_preference(
2028 module_ltp,
2029 "analyze_sequence",
2030 "Analyze segment sequences",
2031 "Whether the dissector should analyze the sequencing and "
2032 "cross-references of the segments within each session.",
2033 &ltp_analyze_sequence
2035 prefs_register_bool_preference(
2036 module_ltp,
2037 "reassemble_block",
2038 "Reassemble block segments",
2039 "Whether the dissector should combine block segments "
2040 "together into a full block.",
2041 &ltp_reassemble_block
2044 proto_register_field_array(proto_ltp, hf, array_length(hf));
2045 proto_register_subtree_array(ett, array_length(ett));
2046 expert_ltp = expert_register_protocol(proto_ltp);
2047 expert_register_field_array(expert_ltp, ei, array_length(ei));
2049 ltp_handle = register_dissector("ltp", dissect_ltp, proto_ltp);
2051 set_address(&ltp_addr_receiver, AT_STRINGZ, (int) strlen(ltp_conv_receiver) + 1, ltp_conv_receiver);
2052 register_conversation_table(proto_ltp, true, ltp_conv_packet, ltp_endp_packet);
2053 register_conversation_filter("ltp", "LTP", ltp_filter_valid, ltp_build_filter, NULL);
2054 ltp_tap = register_tap("ltp");
2056 static const reassembly_table_functions ltp_session_reassembly_table_functions = {
2057 ltp_session_id_hash,
2058 ltp_session_id_equal,
2059 ltp_session_new_key,
2060 ltp_session_new_key,
2061 ltp_session_free_key,
2062 ltp_session_free_key
2064 reassembly_table_register(&ltp_reassembly_table,
2065 &ltp_session_reassembly_table_functions);
2068 void
2069 proto_reg_handoff_ltp(void)
2071 bundle_handle = find_dissector_add_dependency("bundle", proto_ltp);
2073 dissector_add_uint_with_preference("udp.port", LTP_PORT, ltp_handle);
2074 dissector_add_uint_with_preference("dccp.port", LTP_PORT, ltp_handle);
2075 heur_dissector_add("udp", dissect_ltp_heur_udp, "LTP over UDP", "ltp_udp", proto_ltp, HEURISTIC_DISABLE);
2077 stats_tree_register("ltp", "ltp", "LTP", ST_SORT_COL_COUNT, ltp_stats_tree_packet, ltp_stats_tree_init, NULL);
2081 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2083 * Local variables:
2084 * c-basic-offset: 8
2085 * tab-width: 8
2086 * indent-tabs-mode: t
2087 * End:
2089 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2090 * :indentSize=8:tabSize=8:noTabs=false: