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.
27 * Licklider Transmission Protocol - RFC 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 reassembly_table ltp_reassembly_table
;
49 /* Initialize the protocol and registered fields */
50 static int proto_ltp
= -1;
52 /* LTP Header variables */
53 static int hf_ltp_version
= -1;
54 static int hf_ltp_type
= -1;
55 static int hf_ltp_session_id
= -1;
56 static int hf_ltp_session_orig
= -1;
57 static int hf_ltp_session_no
= -1;
58 static int hf_ltp_hdr_extn_cnt
= -1;
59 static int hf_ltp_trl_extn_cnt
= -1;
61 /* LTP Data Segment variable */
62 static int hf_ltp_data_clid
= -1;
63 static int hf_ltp_data_offset
= -1;
64 static int hf_ltp_data_length
= -1;
65 static int hf_ltp_data_chkp
= -1;
66 static int hf_ltp_data_rpt
= -1;
67 /* static int hf_ltp_data_clidata = -1; */
69 /* LTP Report Segment variable */
70 static int hf_ltp_rpt_sno
= -1;
71 static int hf_ltp_rpt_chkp
= -1;
72 static int hf_ltp_rpt_ub
= -1;
73 static int hf_ltp_rpt_lb
= -1;
74 static int hf_ltp_rpt_clm_cnt
= -1;
75 static int hf_ltp_rpt_clm_off
= -1;
76 static int hf_ltp_rpt_clm_len
= -1;
78 /* LTP Report Ack Segment Variable */
79 static int hf_ltp_rpt_ack_sno
= -1;
81 /* LTP Session Management Segment Variable */
82 static int hf_ltp_cancel_code
= -1;
84 /* LTP Header Extension Segment */
85 static int hf_ltp_hdr_extn_tag
= -1;
86 static int hf_ltp_hdr_extn_len
= -1;
87 static int hf_ltp_hdr_extn_val
= -1;
89 /* LTP Trailer Extension Segment */
90 static int hf_ltp_trl_extn_tag
= -1;
91 static int hf_ltp_trl_extn_len
= -1;
92 static int hf_ltp_trl_extn_val
= -1;
95 static int hf_ltp_fragments
= -1;
96 static int hf_ltp_fragment
= -1;
97 static int hf_ltp_fragment_overlap
= -1;
98 static int hf_ltp_fragment_overlap_conflicts
= -1;
99 static int hf_ltp_fragment_multiple_tails
= -1;
100 static int hf_ltp_fragment_too_long_fragment
= -1;
101 static int hf_ltp_fragment_error
= -1;
102 static int hf_ltp_fragment_count
= -1;
103 static int hf_ltp_reassembled_in
= -1;
104 static int hf_ltp_reassembled_length
= -1;
106 static expert_field ei_ltp_neg_reception_claim_count
= EI_INIT
;
107 static expert_field ei_ltp_mal_reception_claim
= EI_INIT
;
109 static dissector_handle_t bundle_handle
;
111 static const value_string ltp_type_codes
[] = {
112 {0x0, "Red data, NOT {Checkpoint, EORP or EOB}"},
113 {0x1, "Red data, Checkpoint, NOT {EORP or EOB}"},
114 {0x2, "Red data, Checkpoint, EORP, NOT EOB"},
115 {0x3, "Red data, Checkpoint, EORP, EOB"},
116 {0x4, "Green data, NOT EOB"},
117 {0x5, "Green data, undefined"},
118 {0x6, "Green data, undefined"},
119 {0x7, "Green data, EOB"},
120 {0x8, "Report segment"},
121 {0x9, "Report-acknowledgment segment"},
122 {0xa, "Control segment, undefined"},
123 {0xb, "Control segment, undefined"},
124 {0xc, "Cancel segment from block sender"},
125 {0xd, "Cancel-acknowledgment segment to block sender"},
126 {0xe, "Cancel segment from block receiver"},
127 {0xf, "Cancel-acknowledgment segment to block receiver"},
131 static const value_string ltp_type_col_info
[] = {
140 {0x8, "Report segment"},
141 {0x9, "Report ack segment"},
142 {0xa, "Control segment"},
143 {0xb, "Control segment"},
144 {0xc, "Cancel segment"},
145 {0xd, "Cancel ack segment"},
146 {0xe, "Cancel segment"},
147 {0xf, "Cancel ack segment"},
151 static const value_string ltp_cancel_codes
[] = {
152 {0x00, "Client service canceled session"},
153 {0x01, "Unreachable client service"},
154 {0x02, "Retransmission limit exceeded"},
155 {0x03, "Miscolored segment"},
156 {0x04, "A system error"},
157 {0x05, "Exceeded the Retransmission-Cycles limit"},
161 static const value_string extn_tag_codes
[] = {
162 {0x00, "LTP authentication extension"},
163 {0x01, "LTP cookie extension"},
168 static guint ltp_port
= 1113;
170 /* Initialize the subtree pointers */
171 static gint ett_ltp
= -1;
172 static gint ett_ltp_hdr
= -1;
173 static gint ett_hdr_session
= -1;
174 static gint ett_hdr_extn
= -1;
175 static gint ett_data_segm
= -1;
176 static gint ett_data_data_segm
= -1;
177 static gint ett_rpt_segm
= -1;
178 static gint ett_rpt_clm
= -1;
179 static gint ett_rpt_ack_segm
= -1;
180 static gint ett_session_mgmt
= -1;
181 static gint ett_trl_extn
= -1;
182 static gint ett_ltp_fragment
= -1;
183 static gint ett_ltp_fragments
= -1;
185 static const fragment_items ltp_frag_items
= {
186 /*Fragment subtrees*/
192 &hf_ltp_fragment_overlap
,
193 &hf_ltp_fragment_overlap_conflicts
,
194 &hf_ltp_fragment_multiple_tails
,
195 &hf_ltp_fragment_too_long_fragment
,
196 &hf_ltp_fragment_error
,
197 &hf_ltp_fragment_count
,
198 /*Reassembled in field*/
199 &hf_ltp_reassembled_in
,
200 /*Reassembled length field*/
201 &hf_ltp_reassembled_length
,
202 /* Reassembled data field */
209 dissect_data_segment(proto_tree
*ltp_tree
, tvbuff_t
*tvb
,packet_info
*pinfo
,int frame_offset
,int ltp_type
, guint64 session_num
){
213 guint64 chkp_sno
= 0;
216 int segment_offset
= 0;
227 int dissected_data_size
= 0;
230 proto_item
*ltp_data_item
;
231 proto_item
*ltp_data_data_item
;
233 proto_tree
*ltp_data_tree
;
234 proto_tree
*ltp_data_data_tree
;
238 fragment_head
*frag_msg
= NULL
;
239 gboolean more_frags
= TRUE
;
241 tvbuff_t
*new_tvb
= NULL
;
243 /* Extract the info for the data segment */
244 client_id
= evaluate_sdnv_64(tvb
,frame_offset
+ segment_offset
,&client_id_size
);
245 segment_offset
+= client_id_size
;
247 if((unsigned)(frame_offset
+ segment_offset
) >= tvb_length(tvb
)){
248 /* This would mean the data segment is incomplete */
251 offset
= evaluate_sdnv_64(tvb
,frame_offset
+ segment_offset
,&offset_size
);
252 segment_offset
+= offset_size
;
254 if((unsigned)(frame_offset
+ segment_offset
) >= tvb_length(tvb
)){
255 /* This would mean the data segment is incomplete */
259 length
= evaluate_sdnv_64(tvb
,frame_offset
+ segment_offset
,&length_size
);
260 segment_offset
+= length_size
;
262 if((unsigned)(frame_offset
+ segment_offset
) >= tvb_length(tvb
)){
263 /* This would mean the data segment is incomplete */
269 chkp_sno
= evaluate_sdnv_64(tvb
,frame_offset
+ segment_offset
,&chkp_sno_size
);
270 segment_offset
+= chkp_sno_size
;
272 if((unsigned)(frame_offset
+ segment_offset
) >= tvb_length(tvb
)){
273 /* This would mean the data segment is incomplete */
277 rpt_sno
= evaluate_sdnv_64(tvb
,frame_offset
+ segment_offset
,&rpt_sno_size
);
278 segment_offset
+= rpt_sno_size
;
280 if((unsigned)(frame_offset
+ segment_offset
) >= tvb_length(tvb
)){
281 /* This would mean the data segment is incomplete */
285 /* Adding size of the data */
286 if ((segment_offset
+ (int)length
< segment_offset
) || (segment_offset
+ (int)length
< (int)length
)) {
287 /* Addition result has wrapped */
290 segment_offset
+= (int)length
;
292 if ((segment_offset
+ frame_offset
< segment_offset
) || (segment_offset
+ frame_offset
< frame_offset
)) {
293 /* Addition result has wrapped */
296 if((unsigned)(frame_offset
+ segment_offset
) > tvb_length(tvb
)){
297 /* This would mean the data segment is incomplete */
301 /* Create a subtree for data segment and add the other fields under it */
302 ltp_data_item
= proto_tree_add_text(ltp_tree
, tvb
,frame_offset
, segment_offset
, "Data Segment");
303 ltp_data_tree
= proto_item_add_subtree(ltp_data_item
, ett_data_segm
);
305 proto_tree_add_uint64(ltp_data_tree
,hf_ltp_data_clid
, tvb
, frame_offset
,client_id_size
,client_id
);
306 frame_offset
+= client_id_size
;
308 proto_tree_add_uint64(ltp_data_tree
, hf_ltp_data_offset
, tvb
, frame_offset
,offset_size
, offset
);
309 frame_offset
+= offset_size
;
311 proto_tree_add_uint64(ltp_data_tree
,hf_ltp_data_length
, tvb
, frame_offset
,length_size
,length
);
312 frame_offset
+= length_size
;
316 proto_tree_add_uint64(ltp_data_tree
, hf_ltp_data_chkp
, tvb
, frame_offset
,chkp_sno_size
, chkp_sno
);
317 frame_offset
+= chkp_sno_size
;
319 proto_tree_add_uint64(ltp_data_tree
, hf_ltp_data_rpt
, tvb
, frame_offset
,rpt_sno_size
, rpt_sno
);
320 frame_offset
+= rpt_sno_size
;
323 frag_msg
= fragment_add_check(<p_reassembly_table
,
324 tvb
, frame_offset
, pinfo
, (guint32
)session_num
, NULL
,
325 (guint32
)offset
, (guint32
)length
, more_frags
);
330 frag_msg
= fragment_add_check(<p_reassembly_table
,
331 tvb
, frame_offset
, pinfo
, (guint32
)session_num
, NULL
,
332 (guint32
)offset
, (guint32
)length
, more_frags
);
339 /* Checking if the segment is completely reassembled */
340 if(!(frag_msg
->flags
& FD_PARTIAL_REASSEMBLY
))
342 /* if the segment has not been fragmented, then no reassembly is needed */
343 if(!more_frags
&& offset
== 0)
345 new_tvb
= tvb_new_subset(tvb
,frame_offset
,tvb_length(tvb
)-frame_offset
,-1);
349 new_tvb
= process_reassembled_data(tvb
, frame_offset
, pinfo
, "Reassembled LTP Segment",
350 frag_msg
, <p_frag_items
,NULL
, ltp_data_tree
);
358 data_length
= tvb_length(new_tvb
);
359 while(dissected_data_size
< data_length
)
361 ltp_data_data_item
= proto_tree_add_text(ltp_data_tree
, tvb
,frame_offset
, 0, "Data[%d]",data_count
);
362 ltp_data_data_tree
= proto_item_add_subtree(ltp_data_data_item
, ett_data_data_segm
);
364 datatvb
= tvb_new_subset(new_tvb
, data_offset
, (int)data_length
- dissected_data_size
, tvb_length(new_tvb
));
365 bundle_size
= call_dissector(bundle_handle
, datatvb
, pinfo
, ltp_data_data_tree
);
366 if(bundle_size
== 0) { /*Couldn't parse bundle*/
367 col_set_str(pinfo
->cinfo
, COL_INFO
, "Dissection Failed");
368 return 0; /*Give up*/
370 data_offset
+= bundle_size
;
371 dissected_data_size
+= bundle_size
;
377 if(frag_msg
&& more_frags
)
379 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "[Reassembled in %d] ",frag_msg
->reassembled_in
);
383 col_append_str(pinfo
->cinfo
, COL_INFO
, "[Unfinished LTP Segment] ");
388 return segment_offset
;
393 dissect_report_segment(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*ltp_tree
, int frame_offset
) {
404 int upper_bound_size
;
405 int lower_bound_size
;
406 int rcpt_clm_cnt_size
;
410 int segment_offset
= 0;
413 proto_item
*ltp_rpt_item
;
414 proto_item
*ltp_rpt_clm_item
;
416 proto_tree
*ltp_rpt_tree
;
417 proto_tree
*ltp_rpt_clm_tree
;
419 /* Create the subtree for report segment under the main LTP tree and all the report segment fields under it */
420 ltp_rpt_item
= proto_tree_add_text(ltp_tree
, tvb
, frame_offset
, -1, "Report Segment");
421 ltp_rpt_tree
= proto_item_add_subtree(ltp_rpt_item
, ett_rpt_segm
);
423 /* Extract the report segment info */
424 rpt_sno
= evaluate_sdnv_64(tvb
, frame_offset
, &rpt_sno_size
);
425 proto_tree_add_uint64(ltp_rpt_tree
, hf_ltp_rpt_sno
, tvb
, frame_offset
+ segment_offset
, rpt_sno_size
, rpt_sno
);
426 segment_offset
+= rpt_sno_size
;
428 chkp_sno
= evaluate_sdnv_64(tvb
, frame_offset
+ segment_offset
, &chkp_sno_size
);
429 proto_tree_add_uint64(ltp_rpt_tree
, hf_ltp_rpt_chkp
, tvb
, frame_offset
+ segment_offset
, chkp_sno_size
, chkp_sno
);
430 segment_offset
+= chkp_sno_size
;
432 upper_bound
= evaluate_sdnv(tvb
, frame_offset
+ segment_offset
, &upper_bound_size
);
433 proto_tree_add_uint64(ltp_rpt_tree
, hf_ltp_rpt_ub
, tvb
, frame_offset
+ segment_offset
, upper_bound_size
, upper_bound
);
434 segment_offset
+= upper_bound_size
;
436 lower_bound
= evaluate_sdnv(tvb
, frame_offset
+ segment_offset
, &lower_bound_size
);
437 proto_tree_add_uint64(ltp_rpt_tree
, hf_ltp_rpt_lb
, tvb
, frame_offset
+ segment_offset
, lower_bound_size
, lower_bound
);
438 segment_offset
+= lower_bound_size
;
440 rcpt_clm_cnt
= evaluate_sdnv(tvb
, frame_offset
+ segment_offset
, &rcpt_clm_cnt_size
);
441 if (rcpt_clm_cnt
< 0){
442 proto_item_set_end(ltp_rpt_item
, tvb
, frame_offset
+ segment_offset
);
443 expert_add_info_format(pinfo
, ltp_tree
, &ei_ltp_neg_reception_claim_count
,
444 "Negative reception claim count: %d", rcpt_clm_cnt
);
447 /* Each reception claim is at least 2 bytes, so if the count is larger than the
448 * max number of claims we can possibly squeeze into the remaining tvbuff, then
449 * the packet is malformed.
451 if (rcpt_clm_cnt
> tvb_length_remaining(tvb
, frame_offset
+ segment_offset
) / 2) {
452 proto_item_set_end(ltp_rpt_item
, tvb
, frame_offset
+ segment_offset
);
453 expert_add_info_format(pinfo
, ltp_tree
, &ei_ltp_mal_reception_claim
,
454 "Reception claim count impossibly large: %d > %d", rcpt_clm_cnt
,
455 tvb_length_remaining(tvb
, frame_offset
+ segment_offset
) / 2);
458 proto_tree_add_uint(ltp_rpt_tree
, hf_ltp_rpt_clm_cnt
, tvb
, frame_offset
+ segment_offset
, rcpt_clm_cnt_size
, rcpt_clm_cnt
);
459 segment_offset
+= rcpt_clm_cnt_size
;
461 ltp_rpt_clm_item
= proto_tree_add_text(ltp_rpt_tree
, tvb
, frame_offset
+ segment_offset
, -1, "Reception claims");
462 ltp_rpt_clm_tree
= proto_item_add_subtree(ltp_rpt_clm_item
, ett_rpt_clm
);
464 /* There can be multiple reception claims in the same report segment */
465 for(i
= 0; i
<rcpt_clm_cnt
; i
++){
466 offset
= evaluate_sdnv(tvb
,frame_offset
+ segment_offset
, &offset_size
);
467 proto_tree_add_uint64_format(ltp_rpt_clm_tree
, hf_ltp_rpt_clm_off
, tvb
, frame_offset
+ segment_offset
, offset_size
, offset
,
468 "Offset[%d] : %"G_GINT64_MODIFIER
"d", i
, offset
);
469 segment_offset
+= offset_size
;
471 length
= evaluate_sdnv(tvb
,frame_offset
+ segment_offset
, &length_size
);
472 proto_tree_add_uint64_format(ltp_rpt_clm_tree
, hf_ltp_rpt_clm_len
, tvb
, frame_offset
+ segment_offset
, length_size
, length
,
473 "Length[%d] : %"G_GINT64_MODIFIER
"d",i
, length
);
474 segment_offset
+= length_size
;
476 proto_item_set_end(ltp_rpt_clm_item
, tvb
, frame_offset
+ segment_offset
);
477 proto_item_set_end(ltp_rpt_item
, tvb
, frame_offset
+ segment_offset
);
478 return segment_offset
;
483 dissect_report_ack_segment(proto_tree
*ltp_tree
, tvbuff_t
*tvb
,int frame_offset
){
487 int segment_offset
= 0;
489 proto_item
*ltp_rpt_ack_item
;
490 proto_tree
*ltp_rpt_ack_tree
;
492 /* Extracing receipt serial number info */
493 rpt_sno
= evaluate_sdnv_64(tvb
,frame_offset
, &rpt_sno_size
);
494 segment_offset
+= rpt_sno_size
;
496 if((unsigned)(frame_offset
+ segment_offset
) > tvb_length(tvb
)){
500 /* Creating tree for the report ack segment */
501 ltp_rpt_ack_item
= proto_tree_add_text(ltp_tree
, tvb
,frame_offset
, segment_offset
, "Report Ack Segment");
502 ltp_rpt_ack_tree
= proto_item_add_subtree(ltp_rpt_ack_item
, ett_rpt_ack_segm
);
504 proto_tree_add_uint64(ltp_rpt_ack_tree
, hf_ltp_rpt_ack_sno
, tvb
, frame_offset
,rpt_sno_size
, rpt_sno
);
505 return segment_offset
;
510 dissect_cancel_segment(proto_tree
* ltp_tree
, tvbuff_t
*tvb
,int frame_offset
){
513 proto_item
*ltp_cancel_item
;
514 proto_tree
*ltp_cancel_tree
;
516 /* The cancel segment has only one byte, which contains the reason code. */
517 reason_code
= tvb_get_guint8(tvb
,frame_offset
);
519 /* Creating tree for the cancel segment */
520 ltp_cancel_item
= proto_tree_add_text(ltp_tree
, tvb
,frame_offset
, 1, "Cancel Segment");
521 ltp_cancel_tree
= proto_item_add_subtree(ltp_cancel_item
, ett_session_mgmt
);
523 proto_tree_add_uint_format_value(ltp_cancel_tree
, hf_ltp_cancel_code
, tvb
, frame_offset
, 1, reason_code
,
524 "%x (%s)", reason_code
, val_to_str_const(reason_code
,ltp_cancel_codes
,"Reserved"));
529 dissect_header_extn(proto_tree
*ltp_tree
, tvbuff_t
*tvb
,int frame_offset
,int hdr_extn_cnt
){
530 guint8 extn_type
[LTP_MAX_HDR_EXTN
];
531 guint64 length
[LTP_MAX_HDR_EXTN
];
532 guint64 value
[LTP_MAX_HDR_EXTN
];
534 int length_size
[LTP_MAX_HDR_EXTN
];
535 int value_size
[LTP_MAX_HDR_EXTN
];
540 proto_item
*ltp_hdr_extn_item
;
541 proto_tree
*ltp_hdr_extn_tree
;
543 /* There can be more than one header extensions */
544 for(i
= 0; i
< hdr_extn_cnt
; i
++){
545 extn_type
[i
] = tvb_get_guint8(tvb
,frame_offset
);
548 if((unsigned)(frame_offset
+ extn_offset
) >= tvb_length(tvb
)){
551 length
[i
] = evaluate_sdnv_64(tvb
,frame_offset
,&length_size
[i
]);
552 extn_offset
+= length_size
[i
];
553 if((unsigned)(frame_offset
+ extn_offset
) >= tvb_length(tvb
)){
556 value
[i
] = evaluate_sdnv_64(tvb
,frame_offset
,&value_size
[i
]);
557 extn_offset
+= value_size
[i
];
558 if((unsigned)(frame_offset
+ extn_offset
) >= tvb_length(tvb
)){
562 ltp_hdr_extn_item
= proto_tree_add_text(ltp_tree
, tvb
,frame_offset
, extn_offset
, "Header Extension");
563 ltp_hdr_extn_tree
= proto_item_add_subtree(ltp_hdr_extn_item
, ett_hdr_extn
);
565 for(i
= 0; i
< hdr_extn_cnt
; i
++){
566 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_const(extn_type
[i
],extn_tag_codes
,"Unassigned/Reserved"));
568 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
]);
569 frame_offset
+= length_size
[i
];
571 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
]);
572 frame_offset
+= value_size
[i
];
578 dissect_trailer_extn(proto_tree
*ltp_tree
, tvbuff_t
*tvb
,int frame_offset
,int trl_extn_cnt
){
579 guint8 extn_type
[LTP_MAX_TRL_EXTN
];
580 guint64 length
[LTP_MAX_TRL_EXTN
];
581 guint64 value
[LTP_MAX_TRL_EXTN
];
583 int length_size
[LTP_MAX_TRL_EXTN
];
584 int value_size
[LTP_MAX_TRL_EXTN
];
589 proto_item
*ltp_trl_extn_item
;
590 proto_tree
*ltp_trl_extn_tree
;
592 DISSECTOR_ASSERT(trl_extn_cnt
< LTP_MAX_TRL_EXTN
);
594 for(i
= 0; i
< trl_extn_cnt
; i
++){
595 extn_type
[i
] = tvb_get_guint8(tvb
,frame_offset
);
598 if((unsigned)(frame_offset
+ extn_offset
) >= tvb_length(tvb
)){
602 length
[i
] = evaluate_sdnv_64(tvb
,frame_offset
,&length_size
[i
]);
603 extn_offset
+= length_size
[i
];
605 if((unsigned)(frame_offset
+ extn_offset
) >= tvb_length(tvb
)){
609 value
[i
] = evaluate_sdnv_64(tvb
,frame_offset
,&value_size
[i
]);
610 extn_offset
+= value_size
[i
];
612 if((unsigned)(frame_offset
+ extn_offset
) >= tvb_length(tvb
)){
616 ltp_trl_extn_item
= proto_tree_add_text(ltp_tree
, tvb
,frame_offset
, extn_offset
, "Header Extension");
617 ltp_trl_extn_tree
= proto_item_add_subtree(ltp_trl_extn_item
, ett_trl_extn
);
619 for(i
= 0; i
< trl_extn_cnt
; i
++){
620 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_const(extn_type
[i
],extn_tag_codes
,"Unassigned/Reserved"));
622 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
]);
623 frame_offset
+= length_size
[i
];
625 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
]);
626 frame_offset
+= value_size
[i
];
633 dissect_ltp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
635 proto_item
*ti
= NULL
;
636 proto_tree
*ltp_tree
= NULL
;
639 int segment_offset
= 0;
640 int hdr_extn_offset
= 0;
641 int trl_extn_offset
= 0;
652 int session_num_size
;
654 proto_item
*ltp_header_item
= NULL
;
655 proto_item
*ltp_session_item
= NULL
;
657 proto_tree
*ltp_header_tree
= NULL
;
658 proto_tree
*ltp_session_tree
= NULL
;
660 /* Check that there's enough data */
661 if(tvb_length(tvb
) < LTP_MIN_DATA_BUFFER
){
667 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "LTP Segment");
669 /* Extract all the header info from the packet */
670 ltp_hdr
= tvb_get_guint8(tvb
, frame_offset
);
673 engine_id
= evaluate_sdnv_64(tvb
,frame_offset
+ header_offset
,&engine_id_size
);
674 header_offset
+= engine_id_size
;
675 if((unsigned)header_offset
>= tvb_length(tvb
)){
676 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
680 session_num
= evaluate_sdnv_64(tvb
,frame_offset
+ header_offset
,&session_num_size
);
681 header_offset
+= session_num_size
;
682 if((unsigned)header_offset
>= tvb_length(tvb
)){
683 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
687 ti
= proto_tree_add_item(tree
, proto_ltp
, tvb
, 0, -1, ENC_NA
);
688 ltp_tree
= proto_item_add_subtree(ti
, ett_ltp
);
690 /* Adding Header Subtree */
691 ltp_header_item
= proto_tree_add_text(ltp_tree
, tvb
, frame_offset
, header_offset
+1, "LTP Header");
692 ltp_header_tree
= proto_item_add_subtree(ltp_header_item
, ett_ltp_hdr
);
694 proto_tree_add_uint(ltp_header_tree
,hf_ltp_version
,tvb
,frame_offset
,1,hi_nibble(ltp_hdr
));
695 ltp_type
= lo_nibble(ltp_hdr
);
696 proto_tree_add_uint_format_value(ltp_header_tree
,hf_ltp_type
,tvb
,frame_offset
,1,ltp_type
,"%x (%s)",
697 ltp_type
,val_to_str_const(ltp_type
,ltp_type_codes
,"Invalid"));
700 /* Adding the session id subtree */
701 ltp_session_item
= proto_tree_add_item(ltp_header_item
,hf_ltp_session_id
,tvb
,frame_offset
, engine_id_size
+ session_num_size
,ENC_NA
);
702 ltp_session_tree
= proto_item_add_subtree(ltp_session_item
,ett_hdr_session
);
703 proto_tree_add_uint64(ltp_session_tree
,hf_ltp_session_orig
,tvb
,frame_offset
,engine_id_size
,engine_id
);
704 frame_offset
+=engine_id_size
;
705 proto_tree_add_uint64(ltp_session_tree
,hf_ltp_session_no
, tvb
, frame_offset
,session_num_size
,session_num
);
706 frame_offset
+=session_num_size
;
708 /* Adding Extension count to the header tree */
709 ltp_extn_cnt
= tvb_get_guint8(tvb
,frame_offset
);
710 hdr_extn_cnt
= hi_nibble(ltp_extn_cnt
);
711 trl_extn_cnt
= lo_nibble(ltp_extn_cnt
);
713 proto_tree_add_uint(ltp_header_tree
,hf_ltp_hdr_extn_cnt
,tvb
,frame_offset
,1,hdr_extn_cnt
);
714 proto_tree_add_uint(ltp_header_tree
,hf_ltp_trl_extn_cnt
,tvb
,frame_offset
,1,trl_extn_cnt
);
717 col_set_str(pinfo
->cinfo
, COL_INFO
, val_to_str_const(ltp_type
,ltp_type_col_info
,"Protocol Error"));
719 if((unsigned)frame_offset
>= tvb_length(tvb
)){
720 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
724 /* Check if there are any header extensions */
725 if(hdr_extn_cnt
> 0){
726 hdr_extn_offset
= dissect_header_extn(ltp_tree
, tvb
, frame_offset
,hdr_extn_cnt
);
727 if(hdr_extn_offset
== 0){
728 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
731 frame_offset
+= hdr_extn_offset
;
734 if((unsigned)frame_offset
>= tvb_length(tvb
)){
735 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
739 /* Call sub routines to handle the segment content*/
740 if((ltp_type
>= 0) && (ltp_type
< 8)){
741 segment_offset
= dissect_data_segment(ltp_tree
,tvb
,pinfo
,frame_offset
,ltp_type
,session_num
);
742 if(segment_offset
== 0){
743 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
747 else if(ltp_type
== 8){
748 segment_offset
= dissect_report_segment(tvb
, pinfo
, ltp_tree
,frame_offset
);
749 if(segment_offset
== 0){
750 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
754 else if(ltp_type
== 9){
755 segment_offset
= dissect_report_ack_segment(ltp_tree
,tvb
,frame_offset
);
756 if(segment_offset
== 0){
757 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
761 else if(ltp_type
== 12 || ltp_type
== 14){
762 segment_offset
= dissect_cancel_segment(ltp_tree
,tvb
,frame_offset
);
763 if(segment_offset
== 0){
764 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
768 frame_offset
+= segment_offset
;
769 /* Check to see if there are any trailer extensions */
770 if(trl_extn_cnt
> 0){
771 if((unsigned)frame_offset
>= tvb_length(tvb
)){
772 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
775 trl_extn_offset
= dissect_trailer_extn(ltp_tree
, tvb
, frame_offset
,trl_extn_cnt
);
776 if(trl_extn_offset
== 0){
777 col_set_str(pinfo
->cinfo
, COL_INFO
, "Protocol Error");
781 /* Return the amount of data this dissector was able to dissect */
782 return tvb_length(tvb
);
786 ltp_defragment_init(void) {
787 reassembly_table_init(<p_reassembly_table
,
788 &addresses_reassembly_table_functions
);
791 /* Register the protocol with Wireshark */
793 proto_register_ltp(void)
795 module_t
*ltp_module
;
797 static hf_register_info hf
[] = {
799 {"LTP Version","ltp.version",
800 FT_UINT8
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
803 {"LTP Type","ltp.type",
804 FT_UINT8
,BASE_HEX
,NULL
, 0x0, NULL
, HFILL
}
807 {"Session ID","ltp.session",
808 FT_NONE
,BASE_NONE
,NULL
, 0x0, NULL
, HFILL
}
810 {&hf_ltp_session_orig
,
811 {"Session originator","ltp.session.orig",
812 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
815 {"Session number","ltp.session.number",
816 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
818 {&hf_ltp_hdr_extn_cnt
,
819 {"Header Extension Count","ltp.hdr.extn.cnt",
820 FT_UINT8
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
822 {&hf_ltp_trl_extn_cnt
,
823 {"Trailer Extension Count","ltp.trl.extn.cnt",
824 FT_UINT8
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
827 {"Client service ID","ltp.data.client.id",
828 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
830 {&hf_ltp_data_offset
,
831 {"Offset","ltp.data.offset",
832 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
834 {&hf_ltp_data_length
,
835 {"Length","ltp.data.length",
836 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
839 {"Checkpoint serial number","ltp.data.chkp",
840 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
843 {"Report serial number","ltp.data.rpt",
844 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
847 {&hf_ltp_data_clidata
,
848 {"Client service data","ltp.data.data",
849 FT_BYTES
,BASE_NONE
,NULL
, 0x0, NULL
, HFILL
}
853 {"Report serial number","ltp.rpt.sno",
854 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
857 {"Checkpoint serial number","ltp.rpt.chkp",
858 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
861 {"Upper bound","ltp.rpt.ub",
862 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
865 {"Lower bound","ltp.rpt.lb",
866 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
868 {&hf_ltp_rpt_clm_cnt
,
869 {"Reception claim count","ltp.rpt.clm.cnt",
870 FT_UINT8
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
872 {&hf_ltp_rpt_clm_off
,
873 {"Offset","ltp.rpt.clm.off",
874 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
876 {&hf_ltp_rpt_clm_len
,
877 {"Length","ltp.rpt.clm.len",
878 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
880 {&hf_ltp_rpt_ack_sno
,
881 {"Report serial number","ltp.rpt.ack.sno",
882 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
884 {&hf_ltp_cancel_code
,
885 {"Cancel code","ltp.cancel.code",
886 FT_UINT8
,BASE_HEX
,NULL
, 0x0, NULL
, HFILL
}
888 {&hf_ltp_hdr_extn_tag
,
889 {"Extension tag","ltp.hdr.extn.tag",
890 FT_UINT8
,BASE_HEX
,NULL
, 0x0, NULL
, HFILL
}
892 {&hf_ltp_hdr_extn_len
,
893 {"Length","ltp.hdr.extn.len",
894 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
896 {&hf_ltp_hdr_extn_val
,
897 {"Value","ltp.hdr.extn.val",
898 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
900 {&hf_ltp_trl_extn_tag
,
901 {"Extension tag","ltp.trl.extn.tag",
902 FT_UINT8
,BASE_HEX
,NULL
, 0x0, NULL
, HFILL
}
904 {&hf_ltp_trl_extn_len
,
905 {"Length","ltp.trl.extn.len",
906 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
908 {&hf_ltp_trl_extn_val
,
909 {"Value","ltp.trl.extn.val",
910 FT_UINT64
,BASE_DEC
,NULL
, 0x0, NULL
, HFILL
}
913 {"LTP Fragments", "ltp.fragments",
914 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
917 {"LTP Fragment", "ltp.fragment",
918 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
920 {&hf_ltp_fragment_overlap
,
921 {"LTP fragment overlap", "ltp.fragment.overlap",
922 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
924 {&hf_ltp_fragment_overlap_conflicts
,
925 {"LTP fragment overlapping with conflicting data",
926 "ltp.fragment.overlap.conflicts",
927 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
929 {&hf_ltp_fragment_multiple_tails
,
930 {"LTP has multiple tails", "ltp.fragment.multiple_tails",
931 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
933 {&hf_ltp_fragment_too_long_fragment
,
934 {"LTP fragment too long", "ltp.fragment.too_long_fragment",
935 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
937 {&hf_ltp_fragment_error
,
938 {"LTP defragmentation error", "ltp.fragment.error",
939 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
941 {&hf_ltp_fragment_count
,
942 {"LTP fragment count", "ltp.fragment.count",
943 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
945 {&hf_ltp_reassembled_in
,
946 {"LTP reassembled in", "ltp.reassembled.in",
947 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
949 {&hf_ltp_reassembled_length
,
950 {"LTP reassembled length", "ltp.reassembled.length",
951 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
955 /* Setup protocol subtree array */
956 static gint
*ett
[] = {
972 static ei_register_info ei
[] = {
973 { &ei_ltp_neg_reception_claim_count
, { "ltp.neg_reception_claim_count", PI_UNDECODED
, PI_ERROR
, "Negative reception claim count", EXPFILL
}},
974 { &ei_ltp_mal_reception_claim
, { "ltp.mal_reception_claim", PI_MALFORMED
, PI_ERROR
, "Reception claim count impossibly large", EXPFILL
}},
977 expert_module_t
* expert_ltp
;
979 /* Register the protocol name and description */
980 proto_ltp
= proto_register_protocol("Licklider Transmission Protocol",
983 proto_register_field_array(proto_ltp
, hf
, array_length(hf
));
984 proto_register_subtree_array(ett
, array_length(ett
));
985 expert_ltp
= expert_register_protocol(proto_ltp
);
986 expert_register_field_array(expert_ltp
, ei
, array_length(ei
));
988 ltp_module
= prefs_register_protocol(proto_ltp
, proto_reg_handoff_ltp
);
990 prefs_register_obsolete_preference(ltp_module
, "udp.port");
991 prefs_register_uint_preference(ltp_module
, "port", "LTP Port",
992 "The UDP or DCCP port to accept LTP Connections",
994 register_init_routine(ltp_defragment_init
);
998 proto_reg_handoff_ltp(void)
1000 static gboolean initialized
= FALSE
;
1001 static dissector_handle_t ltp_handle
;
1002 static int currentPort
;
1005 ltp_handle
= new_create_dissector_handle(dissect_ltp
, proto_ltp
);
1006 bundle_handle
= find_dissector("bundle");
1009 dissector_delete_uint("udp.port", currentPort
, ltp_handle
);
1010 dissector_delete_uint("dccp.port", currentPort
, ltp_handle
);
1013 currentPort
= ltp_port
;
1015 dissector_add_uint("udp.port", currentPort
, ltp_handle
);
1016 dissector_add_uint("dccp.port", currentPort
, ltp_handle
);