MSWSP: fix dissect_mswsp_smb()
[wireshark-wip.git] / epan / dissectors / packet-ltp.c
blob624c9745c84f0b20026ba48897e2907426dc517a
1 /* packet-ltp.c
2 * Routines for LTP dissection
3 * Copyright 2009, Mithun Roy <mithunroy13@gmail.com>
5 * $Id$
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.
30 #include "config.h"
32 #include <glib.h>
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;
94 /*LTP reassembly */
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"},
128 {0,NULL}
131 static const value_string ltp_type_col_info[] = {
132 {0x0, "Red data"},
133 {0x1, "Red data"},
134 {0x2, "Red data"},
135 {0x3, "Red data"},
136 {0x4, "Green data"},
137 {0x5, "Green data"},
138 {0x6, "Green data"},
139 {0x7, "Green data"},
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"},
148 {0, NULL}
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"},
158 {0, NULL}
161 static const value_string extn_tag_codes[] = {
162 {0x00, "LTP authentication extension"},
163 {0x01, "LTP cookie extension"},
164 {0, NULL}
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*/
187 &ett_ltp_fragment,
188 &ett_ltp_fragments,
189 /*Fragment Fields*/
190 &hf_ltp_fragments,
191 &hf_ltp_fragment,
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 */
203 NULL,
204 /*Tag*/
205 "LTP fragments"
208 static int
209 dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int frame_offset,int ltp_type, guint64 session_num){
210 guint64 client_id;
211 guint64 offset;
212 guint64 length;
213 guint64 chkp_sno = 0;
214 guint64 rpt_sno = 0;
216 int segment_offset = 0;
218 int client_id_size;
219 int offset_size;
220 int length_size;
221 int chkp_sno_size;
222 int rpt_sno_size;
224 int data_offset = 0;
225 int data_length;
226 int bundle_size = 0;
227 int dissected_data_size = 0;
228 int data_count = 1;
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;
236 tvbuff_t *datatvb;
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 */
249 return 0;
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 */
256 return 0;
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 */
264 return 0;
267 if(ltp_type != 0 )
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 */
274 return 0;
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 */
282 return 0;
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 */
288 return 0;
290 segment_offset+= (int)length;
292 if ((segment_offset + frame_offset < segment_offset) || (segment_offset + frame_offset < frame_offset)) {
293 /* Addition result has wrapped */
294 return 0;
296 if((unsigned)(frame_offset + segment_offset) > tvb_length(tvb)){
297 /* This would mean the data segment is incomplete */
298 return 0;
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;
314 if(ltp_type != 0 )
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;
322 more_frags = FALSE;
323 frag_msg = fragment_add_check(&ltp_reassembly_table,
324 tvb, frame_offset, pinfo, (guint32)session_num, NULL,
325 (guint32)offset, (guint32)length, more_frags);
327 else
329 more_frags = TRUE;
330 frag_msg = fragment_add_check(&ltp_reassembly_table,
331 tvb, frame_offset, pinfo, (guint32)session_num, NULL,
332 (guint32)offset, (guint32)length, more_frags);
337 if(frag_msg)
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);
347 else
349 new_tvb = process_reassembled_data(tvb, frame_offset, pinfo, "Reassembled LTP Segment",
350 frag_msg, &ltp_frag_items,NULL, ltp_data_tree);
356 if(new_tvb)
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;
372 data_count++;
375 else
377 if(frag_msg && more_frags)
379 col_append_fstr(pinfo->cinfo, COL_INFO, "[Reassembled in %d] ",frag_msg->reassembled_in);
381 else
383 col_append_str(pinfo->cinfo, COL_INFO, "[Unfinished LTP Segment] ");
388 return segment_offset;
392 static int
393 dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, int frame_offset) {
394 guint64 rpt_sno;
395 guint64 chkp_sno;
396 guint64 upper_bound;
397 guint64 lower_bound;
398 int rcpt_clm_cnt;
399 guint64 offset;
400 guint64 length;
402 int rpt_sno_size;
403 int chkp_sno_size;
404 int upper_bound_size;
405 int lower_bound_size;
406 int rcpt_clm_cnt_size;
407 int offset_size;
408 int length_size;
410 int segment_offset = 0;
411 int i;
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);
445 return 0;
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);
456 return 0;
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;
482 static int
483 dissect_report_ack_segment(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset){
484 guint64 rpt_sno;
486 int rpt_sno_size;
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)){
497 return 0;
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;
509 static int
510 dissect_cancel_segment(proto_tree * ltp_tree, tvbuff_t *tvb,int frame_offset){
511 guint8 reason_code;
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"));
525 return 1;
528 static int
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];
537 int i;
538 int extn_offset = 0;
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);
546 extn_offset++;
548 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
549 return 0;
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)){
554 return 0;
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)){
559 return 0;
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];
574 return extn_offset;
577 static int
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];
586 int i;
587 int extn_offset = 0;
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);
596 extn_offset++;
598 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
599 return 0;
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)){
606 return 0;
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)){
613 return 0;
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];
628 return extn_offset;
632 static int
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;
637 int frame_offset;
638 int header_offset;
639 int segment_offset = 0;
640 int hdr_extn_offset = 0;
641 int trl_extn_offset = 0;
643 guint8 ltp_hdr;
644 gint ltp_type;
645 guint8 ltp_extn_cnt;
646 gint hdr_extn_cnt;
647 gint trl_extn_cnt;
649 guint64 engine_id;
650 guint64 session_num;
651 int engine_id_size;
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){
662 return 0;
664 frame_offset = 0;
665 header_offset = 0;
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);
671 header_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");
677 return 0;
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");
684 return 0;
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"));
699 frame_offset++;
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);
715 frame_offset++;
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");
721 return 0;
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");
729 return 0;
731 frame_offset += hdr_extn_offset;
734 if((unsigned)frame_offset >= tvb_length(tvb)){
735 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
736 return 0;
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");
744 return 0;
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");
751 return 0;
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");
758 return 0;
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");
765 return 0;
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");
773 return 0;
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");
778 return 0;
781 /* Return the amount of data this dissector was able to dissect */
782 return tvb_length(tvb);
785 static void
786 ltp_defragment_init(void) {
787 reassembly_table_init(&ltp_reassembly_table,
788 &addresses_reassembly_table_functions);
791 /* Register the protocol with Wireshark */
792 void
793 proto_register_ltp(void)
795 module_t *ltp_module;
797 static hf_register_info hf[] = {
798 {&hf_ltp_version,
799 {"LTP Version","ltp.version",
800 FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
802 {&hf_ltp_type,
803 {"LTP Type","ltp.type",
804 FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
806 {&hf_ltp_session_id,
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}
814 {&hf_ltp_session_no,
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}
826 {&hf_ltp_data_clid,
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}
838 {&hf_ltp_data_chkp,
839 {"Checkpoint serial number","ltp.data.chkp",
840 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
842 {&hf_ltp_data_rpt,
843 {"Report serial number","ltp.data.rpt",
844 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
846 #if 0
847 {&hf_ltp_data_clidata,
848 {"Client service data","ltp.data.data",
849 FT_BYTES,BASE_NONE,NULL, 0x0, NULL, HFILL}
851 #endif
852 {&hf_ltp_rpt_sno,
853 {"Report serial number","ltp.rpt.sno",
854 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
856 {&hf_ltp_rpt_chkp,
857 {"Checkpoint serial number","ltp.rpt.chkp",
858 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
860 {&hf_ltp_rpt_ub,
861 {"Upper bound","ltp.rpt.ub",
862 FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
864 {&hf_ltp_rpt_lb,
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}
912 {&hf_ltp_fragments,
913 {"LTP Fragments", "ltp.fragments",
914 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
916 {&hf_ltp_fragment,
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[] = {
957 &ett_ltp,
958 &ett_ltp_hdr,
959 &ett_hdr_session,
960 &ett_hdr_extn,
961 &ett_data_segm,
962 &ett_data_data_segm,
963 &ett_rpt_segm,
964 &ett_rpt_clm,
965 &ett_rpt_ack_segm,
966 &ett_session_mgmt,
967 &ett_trl_extn,
968 &ett_ltp_fragment,
969 &ett_ltp_fragments
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",
981 "LTP", "ltp");
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",
993 10, &ltp_port);
994 register_init_routine(ltp_defragment_init);
997 void
998 proto_reg_handoff_ltp(void)
1000 static gboolean initialized = FALSE;
1001 static dissector_handle_t ltp_handle;
1002 static int currentPort;
1004 if (!initialized) {
1005 ltp_handle = new_create_dissector_handle(dissect_ltp, proto_ltp);
1006 bundle_handle = find_dissector("bundle");
1007 initialized = TRUE;
1008 } else {
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);