2 * Routines for LTP dissection
3 * Copyright 2009, Mithun Roy <mithunroy13@gmail.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * http://www.ietf.org/rfc/rfc5326.txt?number=5326
33 #include <epan/packet.h>
34 #include <epan/prefs.h>
35 #include <epan/expert.h>
36 #include <epan/reassemble.h>
38 #include "packet-dtn.h"
40 #define LTP_MIN_DATA_BUFFER 5
41 #define LTP_MAX_HDR_EXTN 16
42 #define LTP_MAX_TRL_EXTN 16
44 void proto_reg_handoff_ltp(void);
46 /* For reassembling LTP segments */
47 static GHashTable *ltp_fragment_table = NULL;
48 static GHashTable *ltp_reassembled_table = NULL;
50 /* Initialize the protocol and registered fields */
51 static int proto_ltp = -1;
53 /* LTP Header variables */
54 static int hf_ltp_version = -1;
55 static int hf_ltp_type = -1;
56 static int hf_ltp_session_id = -1;
57 static int hf_ltp_session_orig = -1;
58 static int hf_ltp_session_no = -1;
59 static int hf_ltp_hdr_extn_cnt = -1;
60 static int hf_ltp_trl_extn_cnt = -1;
62 /* LTP Data Segment variable */
63 static int hf_ltp_data_clid = -1;
64 static int hf_ltp_data_offset = -1;
65 static int hf_ltp_data_length = -1;
66 static int hf_ltp_data_chkp = -1;
67 static int hf_ltp_data_rpt = -1;
68 static int hf_ltp_data_clidata = -1;
70 /* LTP Report Segment variable */
71 static int hf_ltp_rpt_sno = -1;
72 static int hf_ltp_rpt_chkp = -1;
73 static int hf_ltp_rpt_ub = -1;
74 static int hf_ltp_rpt_lb = -1;
75 static int hf_ltp_rpt_clm_cnt = -1;
76 static int hf_ltp_rpt_clm_off = -1;
77 static int hf_ltp_rpt_clm_len = -1;
79 /* LTP Report Ack Segment Variable */
80 static int hf_ltp_rpt_ack_sno = -1;
82 /* LTP Session Management Segment Variable */
83 static int hf_ltp_cancel_code = -1;
85 /* LTP Header Extension Segment */
86 static int hf_ltp_hdr_extn_tag = -1;
87 static int hf_ltp_hdr_extn_len = -1;
88 static int hf_ltp_hdr_extn_val = -1;
90 /* LTP Trailer Extension Segment */
91 static int hf_ltp_trl_extn_tag = -1;
92 static int hf_ltp_trl_extn_len = -1;
93 static int hf_ltp_trl_extn_val = -1;
96 static int hf_ltp_fragments = -1;
97 static int hf_ltp_fragment = -1;
98 static int hf_ltp_fragment_overlap = -1;
99 static int hf_ltp_fragment_overlap_conflicts = -1;
100 static int hf_ltp_fragment_multiple_tails = -1;
101 static int hf_ltp_fragment_too_long_fragment = -1;
102 static int hf_ltp_fragment_error = -1;
103 static int hf_ltp_reassembled_in = -1;
104 static int hf_ltp_reassembled_length = -1;
106 static const value_string ltp_type_codes[] = {
107 {0x0, "Red data, NOT {Checkpoint, EORP or EOB}"},
108 {0x1, "Red data, Checkpoint, NOT {EORP or EOB}"},
109 {0x2, "Red data, Checkpoint, EORP, NOT EOB"},
110 {0x3, "Red data, Checkpoint, EORP, EOB"},
111 {0x4, "Green data, NOT EOB"},
112 {0x5, "Green data, undefined"},
113 {0x6, "Green data, undefined"},
114 {0x7, "Green data, EOB"},
115 {0x8, "Report segment"},
116 {0x9, "Report-acknowledgment segment"},
117 {0xa, "Control segment, undefined"},
118 {0xb, "Control segment, undefined"},
119 {0xc, "Cancel segment from block sender"},
120 {0xd, "Cancel-acknowledgment segment to block sender"},
121 {0xe, "Cancel segment from block receiver"},
122 {0xf, "Cancel-acknowledgment segment to block receiver"},
126 static const value_string ltp_type_col_info[] = {
135 {0x8, "Report segment"},
136 {0x9, "Report ack segment"},
137 {0xa, "Control segment"},
138 {0xb, "Control segment"},
139 {0xc, "Cancel segment"},
140 {0xd, "Cancel ack segment"},
141 {0xe, "Cancel segment"},
142 {0xf, "Cancel ack segment"},
146 static const value_string ltp_cancel_codes[] = {
147 {0x00, "Client service canceled session"},
148 {0x01, "Unreachable client service"},
149 {0x02, "Retransmission limit exceeded"},
150 {0x03, "Miscolored segment"},
151 {0x04, "A system error"},
152 {0x05, "Exceeded the Retransmission-Cycles limit"},
156 static const value_string extn_tag_codes[] = {
157 {0x00, "LTP authentication extension"},
158 {0x01, "LTP cookie extension"},
163 static guint ltp_port = 1113;
165 /* Initialize the subtree pointers */
166 static gint ett_ltp = -1;
167 static gint ett_ltp_hdr = -1;
168 static gint ett_hdr_session = -1;
169 static gint ett_hdr_extn = -1;
170 static gint ett_data_segm = -1;
171 static gint ett_data_data_segm = -1;
172 static gint ett_rpt_segm = -1;
173 static gint ett_rpt_clm = -1;
174 static gint ett_rpt_ack_segm = -1;
175 static gint ett_session_mgmt = -1;
176 static gint ett_trl_extn = -1;
177 static gint ett_ltp_fragment = -1;
178 static gint ett_ltp_fragments = -1;
180 static const fragment_items ltp_frag_items = {
181 /*Fragment subtrees*/
187 &hf_ltp_fragment_overlap,
188 &hf_ltp_fragment_overlap_conflicts,
189 &hf_ltp_fragment_multiple_tails,
190 &hf_ltp_fragment_too_long_fragment,
191 &hf_ltp_fragment_error,
192 /*Reassembled in field*/
193 &hf_ltp_reassembled_in,
194 /*Reassembled length field*/
195 &hf_ltp_reassembled_length,
201 dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int frame_offset,int ltp_type, guint64 session_num){
205 guint64 chkp_sno = 0;
208 int segment_offset = 0;
219 int dissected_data_size = 0;
222 proto_item *ltp_data_item;
223 proto_item *ltp_data_data_item;
225 proto_tree *ltp_data_tree;
226 proto_tree *ltp_data_data_tree;
230 fragment_data *frag_msg = NULL;
231 gboolean more_frags = TRUE;
233 tvbuff_t *new_tvb = NULL;
235 /* Extract the info for the data segment */
236 client_id = evaluate_sdnv_64(tvb,frame_offset + segment_offset,&client_id_size);
237 segment_offset+= client_id_size;
239 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
240 /* This would mean the data segment is incomplete */
243 offset = evaluate_sdnv_64(tvb,frame_offset + segment_offset,&offset_size);
244 segment_offset+= offset_size;
246 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
247 /* This would mean the data segment is incomplete */
251 length = evaluate_sdnv_64(tvb,frame_offset + segment_offset,&length_size);
252 segment_offset+= length_size;
254 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
255 /* This would mean the data segment is incomplete */
261 chkp_sno = evaluate_sdnv_64(tvb,frame_offset + segment_offset,&chkp_sno_size);
262 segment_offset+= chkp_sno_size;
264 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
265 /* This would mean the data segment is incomplete */
269 rpt_sno = evaluate_sdnv_64(tvb,frame_offset + segment_offset,&rpt_sno_size);
270 segment_offset+= rpt_sno_size;
272 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
273 /* This would mean the data segment is incomplete */
277 /* Adding size of the data */
278 if ((segment_offset + (int)length < segment_offset) || (segment_offset + (int)length < (int)length)) {
279 /* Addition result has wrapped */
282 segment_offset+= (int)length;
284 if ((segment_offset + frame_offset < segment_offset) || (segment_offset + frame_offset < frame_offset)) {
285 /* Addition result has wrapped */
288 if((unsigned)(frame_offset + segment_offset) > tvb_length(tvb)){
289 /* This would mean the data segment is incomplete */
293 /* Create a subtree for data segment and add the other fields under it */
294 ltp_data_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, segment_offset, "Data Segment");
295 ltp_data_tree = proto_item_add_subtree(ltp_data_item, ett_data_segm);
297 proto_tree_add_uint64(ltp_data_tree,hf_ltp_data_clid, tvb, frame_offset,client_id_size,client_id);
298 frame_offset += client_id_size;
300 proto_tree_add_uint64(ltp_data_tree, hf_ltp_data_offset, tvb, frame_offset,offset_size, offset);
301 frame_offset += offset_size;
303 proto_tree_add_uint64(ltp_data_tree,hf_ltp_data_length, tvb, frame_offset,length_size,length);
304 frame_offset += length_size;
308 proto_tree_add_uint64(ltp_data_tree, hf_ltp_data_chkp, tvb, frame_offset,chkp_sno_size, chkp_sno);
309 frame_offset += chkp_sno_size;
311 proto_tree_add_uint64(ltp_data_tree, hf_ltp_data_rpt, tvb, frame_offset,rpt_sno_size, rpt_sno);
312 frame_offset += rpt_sno_size;
315 frag_msg = fragment_add_check(tvb, frame_offset, pinfo, (guint32)session_num, ltp_fragment_table,
316 ltp_reassembled_table, (guint32)offset, (guint32)length, more_frags);
321 frag_msg = fragment_add_check(tvb, frame_offset, pinfo, (guint32)session_num, ltp_fragment_table,
322 ltp_reassembled_table, (guint32)offset, (guint32)length, more_frags);
329 /* Checking if the segment is completely reassembled */
330 if(!(frag_msg->flags & FD_PARTIAL_REASSEMBLY))
332 /* if the segment has not been fragmented, then no reassembly is needed */
333 if(!more_frags && offset == 0)
335 new_tvb = tvb_new_subset(tvb,frame_offset,tvb_length(tvb)-frame_offset,-1);
339 new_tvb = process_reassembled_data(tvb, frame_offset, pinfo, "Reassembled LTP Segment",
340 frag_msg, <p_frag_items,NULL, ltp_data_tree);
348 data_length = tvb_length(new_tvb);
349 while((unsigned)dissected_data_size < length)
351 ltp_data_data_item = proto_tree_add_text(ltp_data_tree, tvb,frame_offset, 0, "Data[%d]",data_count);
352 ltp_data_data_tree = proto_item_add_subtree(ltp_data_data_item, ett_data_data_segm);
354 datatvb = tvb_new_subset(new_tvb, data_offset, (int)data_length - dissected_data_size, tvb_length(new_tvb));
355 bundle_size = dissect_complete_bundle(datatvb, pinfo, ltp_data_data_tree);
356 if(bundle_size == 0) { /*Couldn't parse bundle*/
357 col_set_str(pinfo->cinfo, COL_INFO, "Dissection Failed");
358 return 0; /*Give up*/
360 data_offset += bundle_size;
361 dissected_data_size += bundle_size;
367 if(frag_msg && more_frags)
369 col_append_fstr(pinfo->cinfo, COL_INFO, "[Reassembled in %d] ",frag_msg->reassembled_in);
373 col_append_str(pinfo->cinfo, COL_INFO, "[Unfinished LTP Segment] ");
378 return segment_offset;
383 dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, int frame_offset) {
394 int upper_bound_size;
395 int lower_bound_size;
396 int rcpt_clm_cnt_size;
400 int segment_offset = 0;
403 proto_item *ltp_rpt_item;
404 proto_item *ltp_rpt_clm_item;
406 proto_tree *ltp_rpt_tree;
407 proto_tree *ltp_rpt_clm_tree;
408 /* Extract the report segment info */
409 rpt_sno = evaluate_sdnv_64(tvb,frame_offset, &rpt_sno_size);
410 segment_offset+= rpt_sno_size;
411 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
415 chkp_sno = evaluate_sdnv_64(tvb,frame_offset + segment_offset, &chkp_sno_size);
416 segment_offset+=chkp_sno_size;
417 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
421 upper_bound = evaluate_sdnv(tvb,frame_offset + segment_offset, &upper_bound_size);
422 segment_offset += upper_bound_size;
423 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
427 lower_bound = evaluate_sdnv(tvb,frame_offset + segment_offset, &lower_bound_size);
428 segment_offset += lower_bound_size;
429 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
433 rcpt_clm_cnt = evaluate_sdnv(tvb,frame_offset + segment_offset, &rcpt_clm_cnt_size);
434 if (rcpt_clm_cnt < 0){
435 expert_add_info_format(pinfo, ltp_tree, PI_UNDECODED, PI_ERROR, "Negative reception claim count: %d", rcpt_clm_cnt);
438 segment_offset += rcpt_clm_cnt_size;
439 if((unsigned)(frame_offset + segment_offset) > tvb_length(tvb)){
443 offset = ep_alloc(sizeof(guint64) * rcpt_clm_cnt);
444 offset_size = ep_alloc(sizeof(int) * rcpt_clm_cnt);
445 length = ep_alloc(sizeof(guint64) * rcpt_clm_cnt);
446 length_size = ep_alloc(sizeof(int) * rcpt_clm_cnt);
448 for(i = 0; i<rcpt_clm_cnt; i++){
449 *(offset + i) = evaluate_sdnv(tvb,frame_offset + segment_offset, offset_size + i);
450 segment_offset += *(offset_size + i);
451 if((unsigned)(frame_offset + segment_offset) > tvb_length(tvb)){
455 *(length + i ) = evaluate_sdnv(tvb,frame_offset + segment_offset, length_size + i);
456 segment_offset += *(length_size + i );
457 if((unsigned)(frame_offset + segment_offset) > tvb_length(tvb)){
462 /* Create the subtree for report segment under the main LTP tree and all the report segment fields under it */
463 ltp_rpt_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, segment_offset, "Report Segment");
464 ltp_rpt_tree = proto_item_add_subtree(ltp_rpt_item, ett_rpt_segm);
466 proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_sno, tvb, frame_offset,rpt_sno_size, rpt_sno);
467 frame_offset += rpt_sno_size;
469 proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_chkp, tvb, frame_offset,chkp_sno_size, chkp_sno);
470 frame_offset += chkp_sno_size;
472 proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_ub, tvb, frame_offset,upper_bound_size, upper_bound);
473 frame_offset += upper_bound_size;
475 proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_lb, tvb, frame_offset,lower_bound_size, lower_bound);
476 frame_offset += lower_bound_size;
478 proto_tree_add_uint(ltp_rpt_tree, hf_ltp_rpt_clm_cnt, tvb, frame_offset,rcpt_clm_cnt_size, rcpt_clm_cnt);
479 frame_offset += rcpt_clm_cnt_size;
481 ltp_rpt_clm_item = proto_tree_add_text(ltp_rpt_tree, tvb,frame_offset, segment_offset - frame_offset, "Reception claims");
482 ltp_rpt_clm_tree = proto_item_add_subtree(ltp_rpt_clm_item, ett_rpt_clm);
484 /* There can be multiple reception claims in the same report segment */
485 for(i = 0; i<rcpt_clm_cnt; i++){
486 proto_tree_add_uint64_format(ltp_rpt_clm_tree, hf_ltp_rpt_clm_off, tvb, frame_offset,*(offset_size + i), *(offset + i),
487 "Offset[%d] : %"G_GINT64_MODIFIER"d", i, *(offset + i));
488 frame_offset += *(offset_size + i);
490 proto_tree_add_uint64_format(ltp_rpt_clm_tree, hf_ltp_rpt_clm_len, tvb, frame_offset,*(length_size + i), *(length + i),
491 "Length[%d] : %"G_GINT64_MODIFIER"d",i, *(length + i));
492 frame_offset += *(length_size + i);
494 return segment_offset;
499 dissect_report_ack_segment(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset){
503 int segment_offset = 0;
505 proto_item *ltp_rpt_ack_item;
506 proto_tree *ltp_rpt_ack_tree;
508 /* Extracing receipt serial number info */
509 rpt_sno = evaluate_sdnv_64(tvb,frame_offset, &rpt_sno_size);
510 segment_offset += rpt_sno_size;
512 if((unsigned)(frame_offset + segment_offset) > tvb_length(tvb)){
516 /* Creating tree for the report ack segment */
517 ltp_rpt_ack_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, segment_offset, "Report Ack Segment");
518 ltp_rpt_ack_tree = proto_item_add_subtree(ltp_rpt_ack_item, ett_rpt_ack_segm);
520 proto_tree_add_uint64(ltp_rpt_ack_tree, hf_ltp_rpt_ack_sno, tvb, frame_offset,rpt_sno_size, rpt_sno);
521 return segment_offset;
526 dissect_cancel_segment(proto_tree * ltp_tree, tvbuff_t *tvb,int frame_offset){
529 proto_item *ltp_cancel_item;
530 proto_tree *ltp_cancel_tree;
532 /* The cancel segment has only one byte, which contains the reason code. */
533 reason_code = tvb_get_guint8(tvb,frame_offset);
535 /* Creating tree for the cancel segment */
536 ltp_cancel_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, 1, "Cancel Segment");
537 ltp_cancel_tree = proto_item_add_subtree(ltp_cancel_item, ett_session_mgmt);
539 proto_tree_add_uint_format_value(ltp_cancel_tree, hf_ltp_cancel_code, tvb, frame_offset, 1, reason_code,
540 "%x (%s)", reason_code, val_to_str(reason_code,ltp_cancel_codes,"Reserved"));
545 dissect_header_extn(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset,int hdr_extn_cnt){
546 guint8 extn_type[LTP_MAX_HDR_EXTN];
547 guint64 length[LTP_MAX_HDR_EXTN];
548 guint64 value[LTP_MAX_HDR_EXTN];
550 int length_size[LTP_MAX_HDR_EXTN];
551 int value_size[LTP_MAX_HDR_EXTN];
556 proto_item *ltp_hdr_extn_item;
557 proto_tree *ltp_hdr_extn_tree;
559 /* There can be more than one header extensions */
560 for(i = 0; i < hdr_extn_cnt; i++){
561 extn_type[i] = tvb_get_guint8(tvb,frame_offset);
564 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
567 length[i] = evaluate_sdnv_64(tvb,frame_offset,&length_size[i]);
568 extn_offset += length_size[i];
569 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
572 value[i] = evaluate_sdnv_64(tvb,frame_offset,&value_size[i]);
573 extn_offset += value_size[i];
574 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
578 ltp_hdr_extn_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, extn_offset, "Header Extension");
579 ltp_hdr_extn_tree = proto_item_add_subtree(ltp_hdr_extn_item, ett_hdr_extn);
581 for(i = 0; i < hdr_extn_cnt; i++){
582 proto_tree_add_uint_format_value(ltp_hdr_extn_tree, hf_ltp_hdr_extn_tag, tvb, frame_offset, 1, extn_type[i], "%x (%s)", extn_type[i], val_to_str(extn_type[i],extn_tag_codes,"Unassigned/Reserved"));
584 proto_tree_add_uint64_format(ltp_hdr_extn_tree, hf_ltp_hdr_extn_len, tvb, frame_offset, length_size[i],length[i], "Length [%d]: %"G_GINT64_MODIFIER"d",i+1,length[i]);
585 frame_offset += length_size[i];
587 proto_tree_add_uint64_format(ltp_hdr_extn_tree, hf_ltp_hdr_extn_val, tvb, frame_offset, value_size[i],value[i], "Value [%d]: %"G_GINT64_MODIFIER"d",i+1,value[i]);
588 frame_offset += value_size[i];
594 dissect_trailer_extn(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset,int trl_extn_cnt){
595 guint8 extn_type[LTP_MAX_TRL_EXTN];
596 guint64 length[LTP_MAX_TRL_EXTN];
597 guint64 value[LTP_MAX_TRL_EXTN];
599 int length_size[LTP_MAX_TRL_EXTN];
600 int value_size[LTP_MAX_TRL_EXTN];
605 proto_item *ltp_trl_extn_item;
606 proto_tree *ltp_trl_extn_tree;
608 DISSECTOR_ASSERT(trl_extn_cnt < LTP_MAX_TRL_EXTN);
610 for(i = 0; i < trl_extn_cnt; i++){
611 extn_type[i] = tvb_get_guint8(tvb,frame_offset);
614 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
618 length[i] = evaluate_sdnv_64(tvb,frame_offset,&length_size[i]);
619 extn_offset += length_size[i];
621 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
625 value[i] = evaluate_sdnv_64(tvb,frame_offset,&value_size[i]);
626 extn_offset += value_size[i];
628 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
632 ltp_trl_extn_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, extn_offset, "Header Extension");
633 ltp_trl_extn_tree = proto_item_add_subtree(ltp_trl_extn_item, ett_trl_extn);
635 for(i = 0; i < trl_extn_cnt; i++){
636 proto_tree_add_uint_format_value(ltp_trl_extn_tree, hf_ltp_trl_extn_tag, tvb, frame_offset, 1, extn_type[i], "%x (%s)", extn_type[i], val_to_str(extn_type[i],extn_tag_codes,"Unassigned/Reserved"));
638 proto_tree_add_uint64_format(ltp_trl_extn_tree, hf_ltp_trl_extn_len, tvb, frame_offset, length_size[i], length[i], "Length [%d]: %"G_GINT64_MODIFIER"d",i+1,length[i]);
639 frame_offset += length_size[i];
641 proto_tree_add_uint64_format(ltp_trl_extn_tree, hf_ltp_trl_extn_val, tvb, frame_offset, value_size[i], value[i], "Value [%d]: %"G_GINT64_MODIFIER"d",i+0,value[i]);
642 frame_offset += value_size[i];
649 dissect_ltp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
651 proto_item *ti = NULL;
652 proto_tree *ltp_tree = NULL;
655 int segment_offset = 0;
656 int hdr_extn_offset = 0;
657 int trl_extn_offset = 0;
668 int session_num_size;
670 proto_item *ltp_header_item = NULL;
671 proto_item *ltp_session_item = NULL;
673 proto_tree *ltp_header_tree = NULL;
674 proto_tree *ltp_session_tree = NULL;
676 /* Check that there's enough data */
677 if(tvb_length(tvb) < LTP_MIN_DATA_BUFFER){
683 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LTP Segment");
685 /* Extract all the header info from the packet */
686 ltp_hdr = tvb_get_guint8(tvb, frame_offset);
689 engine_id = evaluate_sdnv_64(tvb,frame_offset + header_offset,&engine_id_size);
690 header_offset += engine_id_size;
691 if((unsigned)header_offset >= tvb_length(tvb)){
692 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
696 session_num = evaluate_sdnv_64(tvb,frame_offset + header_offset,&session_num_size);
697 header_offset += session_num_size;
698 if((unsigned)header_offset >= tvb_length(tvb)){
699 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
703 ti = proto_tree_add_item(tree, proto_ltp, tvb, 0, -1, FALSE);
704 ltp_tree = proto_item_add_subtree(ti, ett_ltp);
706 /* Adding Header Subtree */
707 ltp_header_item = proto_tree_add_text(ltp_tree, tvb, frame_offset, header_offset+1, "LTP Header");
708 ltp_header_tree = proto_item_add_subtree(ltp_header_item, ett_ltp_hdr);
710 proto_tree_add_uint(ltp_header_tree,hf_ltp_version,tvb,frame_offset,1,hi_nibble(ltp_hdr));
711 ltp_type = lo_nibble(ltp_hdr);
712 proto_tree_add_uint_format_value(ltp_header_tree,hf_ltp_type,tvb,frame_offset,1,ltp_type,"%x (%s)",
713 ltp_type,val_to_str(ltp_type,ltp_type_codes,"Invalid"));
716 /* Adding the session id subtree */
717 ltp_session_item = proto_tree_add_item(ltp_header_item,hf_ltp_session_id,tvb,frame_offset, engine_id_size + session_num_size,FALSE);
718 ltp_session_tree = proto_item_add_subtree(ltp_session_item,ett_hdr_session);
719 proto_tree_add_uint64(ltp_session_tree,hf_ltp_session_orig,tvb,frame_offset,engine_id_size,engine_id);
720 frame_offset+=engine_id_size;
721 proto_tree_add_uint64(ltp_session_tree,hf_ltp_session_no, tvb, frame_offset,session_num_size,session_num);
722 frame_offset+=session_num_size;
724 /* Adding Extension count to the header tree */
725 ltp_extn_cnt = tvb_get_guint8(tvb,frame_offset);
726 hdr_extn_cnt = hi_nibble(ltp_extn_cnt);
727 trl_extn_cnt = lo_nibble(ltp_extn_cnt);
729 proto_tree_add_uint(ltp_header_tree,hf_ltp_hdr_extn_cnt,tvb,frame_offset,1,hdr_extn_cnt);
730 proto_tree_add_uint(ltp_header_tree,hf_ltp_trl_extn_cnt,tvb,frame_offset,1,trl_extn_cnt);
733 col_add_str(pinfo->cinfo, COL_INFO, val_to_str_const(ltp_type,ltp_type_col_info,"Protocol Error"));
735 if((unsigned)frame_offset >= tvb_length(tvb)){
736 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
740 /* Check if there are any header extensions */
741 if(hdr_extn_cnt > 0){
742 hdr_extn_offset = dissect_header_extn(ltp_tree, tvb, frame_offset,hdr_extn_cnt);
743 if(hdr_extn_offset == 0){
744 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
747 frame_offset += hdr_extn_offset;
750 if((unsigned)frame_offset >= tvb_length(tvb)){
751 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
755 /* Call sub routines to handle the segment content*/
756 if((ltp_type >= 0) && (ltp_type < 8)){
757 segment_offset = dissect_data_segment(ltp_tree,tvb,pinfo,frame_offset,ltp_type,session_num);
758 if(segment_offset == 0){
759 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
763 else if(ltp_type == 8){
764 segment_offset = dissect_report_segment(tvb, pinfo, ltp_tree,frame_offset);
765 if(segment_offset == 0){
766 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
770 else if(ltp_type == 9){
771 segment_offset = dissect_report_ack_segment(ltp_tree,tvb,frame_offset);
772 if(segment_offset == 0){
773 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
777 else if(ltp_type == 12 || ltp_type == 14){
778 segment_offset = dissect_cancel_segment(ltp_tree,tvb,frame_offset);
779 if(segment_offset == 0){
780 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
784 frame_offset += segment_offset;
785 /* Check to see if there are any trailer extensions */
786 if(trl_extn_cnt > 0){
787 if((unsigned)frame_offset >= tvb_length(tvb)){
788 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
791 trl_extn_offset = dissect_trailer_extn(ltp_tree, tvb, frame_offset,trl_extn_cnt);
792 if(trl_extn_offset == 0){
793 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
797 /* Return the amount of data this dissector was able to dissect */
798 return tvb_length(tvb);
802 ltp_defragment_init(void) {
803 fragment_table_init(<p_fragment_table);
804 reassembled_table_init(<p_reassembled_table);
807 /* Register the protocol with Wireshark */
809 proto_register_ltp(void)
811 module_t *ltp_module;
813 static hf_register_info hf[] = {
815 {"LTP Version","ltp.version",
816 FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
819 {"LTP Type","ltp.type",
820 FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
823 {"Session ID","ltp.session",
824 FT_NONE,BASE_NONE,NULL, 0x0, NULL, HFILL}
826 {&hf_ltp_session_orig,
827 {"Session originator","ltp.session.orig",
828 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
831 {"Session number","ltp.session.number",
832 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
834 {&hf_ltp_hdr_extn_cnt,
835 {"Header Extension Count","ltp.hdr.extn.cnt",
836 FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
838 {&hf_ltp_trl_extn_cnt,
839 {"Trailer Extension Count","ltp.trl.extn.cnt",
840 FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
843 {"Client service ID","ltp.data.client.id",
844 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
846 {&hf_ltp_data_offset,
847 {"Offset","ltp.data.offset",
848 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
850 {&hf_ltp_data_length,
851 {"Length","ltp.data.length",
852 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
855 {"Checkpoint serial number","ltp.data.chkp",
856 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
859 {"Report serial number","ltp.data.rpt",
860 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
862 {&hf_ltp_data_clidata,
863 {"Client service data","ltp.data.data",
864 FT_BYTES,BASE_NONE,NULL, 0x0, NULL, HFILL}
867 {"Report serial number","ltp.rpt.sno",
868 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
871 {"Checkpoint serial number","ltp.rpt.chkp",
872 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
875 {"Upper bound","ltp.rpt.ub",
876 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
879 {"Lower bound","ltp.rpt.lb",
880 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
882 {&hf_ltp_rpt_clm_cnt,
883 {"Reception claim count","ltp.rpt.clm.cnt",
884 FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
886 {&hf_ltp_rpt_clm_off,
887 {"Offset","ltp.rpt.clm.off",
888 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
890 {&hf_ltp_rpt_clm_len,
891 {"Length","ltp.rpt.clm.len",
892 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
894 {&hf_ltp_rpt_ack_sno,
895 {"Report serial number","ltp.rpt.ack.sno",
896 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
898 {&hf_ltp_cancel_code,
899 {"Cancel code","ltp.cancel.code",
900 FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
902 {&hf_ltp_hdr_extn_tag,
903 {"Extension tag","ltp.hdr.extn.tag",
904 FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
906 {&hf_ltp_hdr_extn_len,
907 {"Length","ltp.hdr.extn.len",
908 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
910 {&hf_ltp_hdr_extn_val,
911 {"Value","ltp.hdr.extn.val",
912 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
914 {&hf_ltp_trl_extn_tag,
915 {"Extension tag","ltp.hdr.extn.tag",
916 FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
918 {&hf_ltp_trl_extn_len,
919 {"Length","ltp.hdr.extn.len",
920 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
922 {&hf_ltp_trl_extn_val,
923 {"Value","ltp.hdr.extn.val",
924 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
927 {"LTP Fragments", "ltp.fragments",
928 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
931 {"LTP Fragment", "ltp.fragment",
932 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
934 {&hf_ltp_fragment_overlap,
935 {"LTP fragment overlap", "ltp.fragment.overlap",
936 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
938 {&hf_ltp_fragment_overlap_conflicts,
939 {"LTP fragment overlapping with conflicting data",
940 "ltp.fragment.overlap.conflicts",
941 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
943 {&hf_ltp_fragment_multiple_tails,
944 {"LTP has multiple tails", "ltp.fragment.multiple_tails",
945 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
947 {&hf_ltp_fragment_too_long_fragment,
948 {"LTP fragment too long", "ltp.fragment.too_long_fragment",
949 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
951 {&hf_ltp_fragment_error,
952 {"LTP defragmentation error", "ltp.fragment.error",
953 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
955 {&hf_ltp_reassembled_in,
956 {"LTP reassembled in", "ltp.reassembled.in",
957 FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
959 {&hf_ltp_reassembled_length,
960 {"LTP reassembled length", "ltp.reassembled.length",
961 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
965 /* Setup protocol subtree array */
966 static gint *ett[] = {
982 /* Register the protocol name and description */
983 proto_ltp = proto_register_protocol("Licklider Transmission Protocol",
986 proto_register_field_array(proto_ltp, hf, array_length(hf));
987 proto_register_subtree_array(ett, array_length(ett));
988 ltp_module = prefs_register_protocol(proto_ltp, proto_reg_handoff_ltp);
990 prefs_register_uint_preference(ltp_module, "udp.port", "LTP UDP Port",
991 "UDP Port to accept LTP Connections",
993 register_init_routine(ltp_defragment_init);
997 proto_reg_handoff_ltp(void)
999 static gboolean initialized = FALSE;
1000 static dissector_handle_t ltp_handle;
1001 static int currentPort;
1004 ltp_handle = new_create_dissector_handle(dissect_ltp, proto_ltp);
1007 dissector_delete("udp.port", currentPort, ltp_handle);
1010 currentPort = ltp_port;
1012 dissector_add("udp.port", currentPort, ltp_handle);