For proto_tree_add_item(..., proto_xxx, ...)use ENC_NA as the encoding arg.
[obnox/wireshark/wip.git] / epan / dissectors / packet-ltp.c
1 /* packet-ltp.c
2  * Routines for LTP dissection
3  * Copyright 2009, Mithun Roy <mithunroy13@gmail.com>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
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.
15  *
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.
20  *
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.
24  */
25
26 /*
27  * Licklider Transmission Protocol - RFC 5326.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <glib.h>
35 #include <epan/packet.h>
36 #include <epan/prefs.h>
37 #include <epan/expert.h>
38 #include <epan/reassemble.h>
39
40 #include "packet-dtn.h"
41
42 #define LTP_MIN_DATA_BUFFER  5
43 #define LTP_MAX_HDR_EXTN    16
44 #define LTP_MAX_TRL_EXTN    16
45
46 void proto_reg_handoff_ltp(void);
47
48 /* For reassembling LTP segments */
49 static GHashTable *ltp_fragment_table = NULL;
50 static GHashTable *ltp_reassembled_table = NULL;
51
52 /* Initialize the protocol and registered fields */
53 static int proto_ltp = -1;
54
55 /* LTP Header variables */
56 static int hf_ltp_version       = -1;
57 static int hf_ltp_type          = -1;
58 static int hf_ltp_session_id    = -1;
59 static int hf_ltp_session_orig  = -1;
60 static int hf_ltp_session_no    = -1;
61 static int hf_ltp_hdr_extn_cnt  = -1;
62 static int hf_ltp_trl_extn_cnt  = -1;
63
64 /* LTP Data Segment variable */
65 static int hf_ltp_data_clid     = -1;
66 static int hf_ltp_data_offset   = -1;
67 static int hf_ltp_data_length   = -1;
68 static int hf_ltp_data_chkp     = -1;
69 static int hf_ltp_data_rpt      = -1;
70 static int hf_ltp_data_clidata  = -1;
71
72 /* LTP Report Segment variable */
73 static int hf_ltp_rpt_sno       = -1;
74 static int hf_ltp_rpt_chkp      = -1;
75 static int hf_ltp_rpt_ub        = -1;
76 static int hf_ltp_rpt_lb        = -1;
77 static int hf_ltp_rpt_clm_cnt   = -1;
78 static int hf_ltp_rpt_clm_off   = -1;
79 static int hf_ltp_rpt_clm_len   = -1;
80
81 /* LTP Report Ack Segment Variable */
82 static int hf_ltp_rpt_ack_sno   = -1;
83
84 /* LTP Session Management Segment Variable */
85 static int hf_ltp_cancel_code   = -1;
86
87 /* LTP Header Extension Segment */
88 static int hf_ltp_hdr_extn_tag  = -1;
89 static int hf_ltp_hdr_extn_len  = -1;
90 static int hf_ltp_hdr_extn_val  = -1;
91
92 /* LTP Trailer Extension Segment */
93 static int hf_ltp_trl_extn_tag  = -1;
94 static int hf_ltp_trl_extn_len  = -1;
95 static int hf_ltp_trl_extn_val  = -1;
96
97 /*LTP reassembly */
98 static int hf_ltp_fragments = -1;
99 static int hf_ltp_fragment = -1;
100 static int hf_ltp_fragment_overlap = -1;
101 static int hf_ltp_fragment_overlap_conflicts = -1;
102 static int hf_ltp_fragment_multiple_tails = -1;
103 static int hf_ltp_fragment_too_long_fragment = -1;
104 static int hf_ltp_fragment_error = -1;
105 static int hf_ltp_fragment_count = -1;
106 static int hf_ltp_reassembled_in = -1;
107 static int hf_ltp_reassembled_length = -1;
108
109 static const value_string ltp_type_codes[] = {
110         {0x0, "Red data, NOT {Checkpoint, EORP or EOB}"},
111         {0x1, "Red data, Checkpoint, NOT {EORP or EOB}"},
112         {0x2, "Red data, Checkpoint, EORP, NOT EOB"},
113         {0x3, "Red data, Checkpoint, EORP, EOB"},
114         {0x4, "Green data, NOT EOB"},
115         {0x5, "Green data, undefined"},
116         {0x6, "Green data, undefined"},
117         {0x7, "Green data, EOB"},
118         {0x8, "Report segment"},
119         {0x9, "Report-acknowledgment segment"},
120         {0xa, "Control segment, undefined"},
121         {0xb, "Control segment, undefined"},
122         {0xc, "Cancel segment from block sender"},
123         {0xd, "Cancel-acknowledgment segment to block sender"},
124         {0xe, "Cancel segment from block receiver"},
125         {0xf, "Cancel-acknowledgment segment to block receiver"},
126         {0,NULL}
127 };
128
129 static const value_string ltp_type_col_info[] = {
130         {0x0, "Red data"},
131         {0x1, "Red data"},
132         {0x2, "Red data"},
133         {0x3, "Red data"},
134         {0x4, "Green data"},
135         {0x5, "Green data"},
136         {0x6, "Green data"},
137         {0x7, "Green data"},
138         {0x8, "Report segment"},
139         {0x9, "Report ack segment"},
140         {0xa, "Control segment"},
141         {0xb, "Control segment"},
142         {0xc, "Cancel segment"},
143         {0xd, "Cancel ack segment"},
144         {0xe, "Cancel segment"},
145         {0xf, "Cancel ack segment"},
146         {0, NULL}
147 };
148
149 static const value_string ltp_cancel_codes[] = {
150         {0x00, "Client service canceled session"},
151         {0x01, "Unreachable client service"},
152         {0x02, "Retransmission limit exceeded"},
153         {0x03, "Miscolored segment"},
154         {0x04, "A system error"},
155         {0x05, "Exceeded the Retransmission-Cycles limit"},
156         {0, NULL}
157 };
158
159 static const value_string extn_tag_codes[] = {
160         {0x00, "LTP authentication extension"},
161         {0x01, "LTP cookie extension"},
162         {0, NULL}
163 };
164
165
166 static guint ltp_port = 1113;
167
168 /* Initialize the subtree pointers */
169 static gint ett_ltp             = -1;
170 static gint ett_ltp_hdr         = -1;
171 static gint ett_hdr_session     = -1;
172 static gint ett_hdr_extn        = -1;
173 static gint ett_data_segm       = -1;
174 static gint ett_data_data_segm  = -1;
175 static gint ett_rpt_segm        = -1;
176 static gint ett_rpt_clm         = -1;
177 static gint ett_rpt_ack_segm    = -1;
178 static gint ett_session_mgmt    = -1;
179 static gint ett_trl_extn        = -1;
180 static gint ett_ltp_fragment    = -1;
181 static gint ett_ltp_fragments   = -1;
182
183 static const fragment_items ltp_frag_items = {
184     /*Fragment subtrees*/
185     &ett_ltp_fragment,
186     &ett_ltp_fragments,
187     /*Fragment Fields*/
188     &hf_ltp_fragments,
189     &hf_ltp_fragment,
190     &hf_ltp_fragment_overlap,
191     &hf_ltp_fragment_overlap_conflicts,
192     &hf_ltp_fragment_multiple_tails,
193     &hf_ltp_fragment_too_long_fragment,
194     &hf_ltp_fragment_error,
195     &hf_ltp_fragment_count,
196     /*Reassembled in field*/
197     &hf_ltp_reassembled_in,
198     /*Reassembled length field*/
199     &hf_ltp_reassembled_length,
200     /*Tag*/
201     "LTP fragments"
202 };
203
204 static int
205 dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int frame_offset,int ltp_type, guint64 session_num){
206         guint64 client_id;
207         guint64 offset;
208         guint64 length;
209         guint64 chkp_sno = 0;
210         guint64 rpt_sno = 0;
211
212         int segment_offset = 0;
213
214         int client_id_size;
215         int offset_size;
216         int length_size;
217         int chkp_sno_size;
218         int rpt_sno_size;
219
220         int data_offset = 0;
221         int data_length;
222         int bundle_size = 0;
223         int dissected_data_size = 0;
224         int data_count = 1;
225
226         proto_item *ltp_data_item;
227         proto_item *ltp_data_data_item;
228
229         proto_tree *ltp_data_tree;
230         proto_tree *ltp_data_data_tree;
231
232         tvbuff_t *datatvb;
233
234         fragment_data *frag_msg = NULL;
235         gboolean more_frags = TRUE;
236
237         tvbuff_t *new_tvb = NULL;
238
239         /* Extract the info for the data segment */
240         client_id = evaluate_sdnv_64(tvb,frame_offset + segment_offset,&client_id_size);
241         segment_offset+= client_id_size;
242
243         if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
244         /* This would mean the data segment is incomplete */
245                 return 0;
246         }
247         offset = evaluate_sdnv_64(tvb,frame_offset + segment_offset,&offset_size);
248         segment_offset+= offset_size;
249
250         if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
251         /* This would mean the data segment is incomplete */
252                 return 0;
253         }
254
255         length = evaluate_sdnv_64(tvb,frame_offset + segment_offset,&length_size);
256         segment_offset+= length_size;
257
258         if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
259         /* This would mean the data segment is incomplete */
260                 return 0;
261         }
262
263         if(ltp_type != 0 )
264         {
265                 chkp_sno = evaluate_sdnv_64(tvb,frame_offset + segment_offset,&chkp_sno_size);
266                 segment_offset+= chkp_sno_size;
267
268                 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
269                 /* This would mean the data segment is incomplete */
270                         return 0;
271                 }
272
273                 rpt_sno = evaluate_sdnv_64(tvb,frame_offset + segment_offset,&rpt_sno_size);
274                 segment_offset+= rpt_sno_size;
275
276                 if((unsigned)(frame_offset + segment_offset) >= tvb_length(tvb)){
277                 /* This would mean the data segment is incomplete */
278                         return 0;
279                 }
280         }
281         /* Adding size of the data */
282         if ((segment_offset + (int)length < segment_offset) || (segment_offset + (int)length < (int)length)) {
283         /* Addition result has wrapped */
284                 return 0;
285         }
286         segment_offset+= (int)length;
287
288         if ((segment_offset + frame_offset < segment_offset) || (segment_offset + frame_offset < frame_offset)) {
289         /* Addition result has wrapped */
290                 return 0;
291         }
292         if((unsigned)(frame_offset + segment_offset) > tvb_length(tvb)){
293         /* This would mean the data segment is incomplete */
294                 return 0;
295         }
296
297         /* Create a subtree for data segment and add the other fields under it */
298         ltp_data_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, segment_offset, "Data Segment");
299         ltp_data_tree = proto_item_add_subtree(ltp_data_item, ett_data_segm);
300
301         proto_tree_add_uint64(ltp_data_tree,hf_ltp_data_clid, tvb, frame_offset,client_id_size,client_id);
302         frame_offset += client_id_size;
303
304         proto_tree_add_uint64(ltp_data_tree, hf_ltp_data_offset, tvb, frame_offset,offset_size, offset);
305         frame_offset += offset_size;
306
307         proto_tree_add_uint64(ltp_data_tree,hf_ltp_data_length, tvb, frame_offset,length_size,length);
308         frame_offset += length_size;
309
310         if(ltp_type != 0 )
311         {
312                 proto_tree_add_uint64(ltp_data_tree, hf_ltp_data_chkp, tvb, frame_offset,chkp_sno_size, chkp_sno);
313                 frame_offset += chkp_sno_size;
314
315                 proto_tree_add_uint64(ltp_data_tree, hf_ltp_data_rpt, tvb, frame_offset,rpt_sno_size, rpt_sno);
316                 frame_offset += rpt_sno_size;
317
318                 more_frags = FALSE;
319                 frag_msg = fragment_add_check(tvb, frame_offset, pinfo, (guint32)session_num, ltp_fragment_table,
320                           ltp_reassembled_table, (guint32)offset, (guint32)length, more_frags);
321         }
322         else
323         {
324                 more_frags = TRUE;
325                 frag_msg = fragment_add_check(tvb, frame_offset, pinfo, (guint32)session_num, ltp_fragment_table,
326                          ltp_reassembled_table, (guint32)offset, (guint32)length, more_frags);
327
328         }
329
330
331         if(frag_msg)
332         {
333                 /* Checking if the segment is completely reassembled */
334                 if(!(frag_msg->flags & FD_PARTIAL_REASSEMBLY))
335                 {
336                         /* if the segment has not been fragmented, then no reassembly is needed */
337                         if(!more_frags && offset == 0)
338                         {
339                                 new_tvb = tvb_new_subset(tvb,frame_offset,tvb_length(tvb)-frame_offset,-1);
340                         }
341                         else
342                         {
343                                 new_tvb = process_reassembled_data(tvb, frame_offset, pinfo, "Reassembled LTP Segment",
344                                         frag_msg, &ltp_frag_items,NULL, ltp_data_tree);
345
346                         }
347                 }
348         }
349
350         if(new_tvb)
351         {
352                 data_length = tvb_length(new_tvb);
353                 while((unsigned)dissected_data_size < length)
354                 {
355                         ltp_data_data_item = proto_tree_add_text(ltp_data_tree, tvb,frame_offset, 0, "Data[%d]",data_count);
356                         ltp_data_data_tree = proto_item_add_subtree(ltp_data_data_item, ett_data_data_segm);
357
358                         datatvb = tvb_new_subset(new_tvb, data_offset, (int)data_length - dissected_data_size, tvb_length(new_tvb));
359                         bundle_size = dissect_complete_bundle(datatvb, pinfo, ltp_data_data_tree);
360                         if(bundle_size == 0) {  /*Couldn't parse bundle*/
361                                 col_set_str(pinfo->cinfo, COL_INFO, "Dissection Failed");
362                                 return 0;           /*Give up*/
363                         }
364                         data_offset += bundle_size;
365                         dissected_data_size += bundle_size;
366                         data_count++;
367                 }
368         }
369         else
370         {
371                 if(frag_msg && more_frags)
372                 {
373                         col_append_fstr(pinfo->cinfo, COL_INFO, "[Reassembled in %d] ",frag_msg->reassembled_in);
374                 }
375                 else
376                 {
377                         col_append_str(pinfo->cinfo, COL_INFO, "[Unfinished LTP Segment] ");
378                 }
379
380         }
381
382         return segment_offset;
383 }
384
385
386 static int
387 dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, int frame_offset) {
388         guint64 rpt_sno;
389         guint64 chkp_sno;
390         guint64 upper_bound;
391         guint64 lower_bound;
392         int rcpt_clm_cnt;
393         guint64 offset;
394         guint64 length;
395
396         int rpt_sno_size;
397         int chkp_sno_size;
398         int upper_bound_size;
399         int lower_bound_size;
400         int rcpt_clm_cnt_size;
401         int offset_size;
402         int length_size;
403
404         int segment_offset = 0;
405         int i;
406
407         proto_item *ltp_rpt_item;
408         proto_item *ltp_rpt_clm_item;
409
410         proto_tree *ltp_rpt_tree;
411         proto_tree *ltp_rpt_clm_tree;
412
413         /* Create the subtree for report segment under the main LTP tree and all the report segment fields under it */
414         ltp_rpt_item = proto_tree_add_text(ltp_tree, tvb, frame_offset, -1, "Report Segment");
415         ltp_rpt_tree = proto_item_add_subtree(ltp_rpt_item, ett_rpt_segm);
416
417         /* Extract the report segment info */
418         rpt_sno = evaluate_sdnv_64(tvb, frame_offset, &rpt_sno_size);
419         proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_sno, tvb, frame_offset + segment_offset, rpt_sno_size, rpt_sno);
420         segment_offset += rpt_sno_size;
421
422         chkp_sno = evaluate_sdnv_64(tvb, frame_offset + segment_offset, &chkp_sno_size);
423         proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_chkp, tvb, frame_offset + segment_offset, chkp_sno_size, chkp_sno);
424         segment_offset += chkp_sno_size;
425
426         upper_bound = evaluate_sdnv(tvb, frame_offset + segment_offset, &upper_bound_size);
427         proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_ub, tvb, frame_offset + segment_offset, upper_bound_size, upper_bound);
428         segment_offset += upper_bound_size;
429
430         lower_bound = evaluate_sdnv(tvb, frame_offset + segment_offset, &lower_bound_size);
431         proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_lb, tvb, frame_offset + segment_offset, lower_bound_size, lower_bound);
432         segment_offset += lower_bound_size;
433
434         rcpt_clm_cnt = evaluate_sdnv(tvb, frame_offset + segment_offset, &rcpt_clm_cnt_size);
435         if (rcpt_clm_cnt < 0){
436                 proto_item_set_end(ltp_rpt_item, tvb, frame_offset + segment_offset);
437                 expert_add_info_format(pinfo, ltp_tree, PI_UNDECODED, PI_ERROR, "Negative reception claim count: %d", rcpt_clm_cnt);
438                 return 0;
439         }
440         proto_tree_add_uint(ltp_rpt_tree, hf_ltp_rpt_clm_cnt, tvb, frame_offset + segment_offset, rcpt_clm_cnt_size, rcpt_clm_cnt);
441         segment_offset += rcpt_clm_cnt_size;
442
443         ltp_rpt_clm_item = proto_tree_add_text(ltp_rpt_tree, tvb, frame_offset + segment_offset, -1, "Reception claims");
444         ltp_rpt_clm_tree = proto_item_add_subtree(ltp_rpt_clm_item, ett_rpt_clm);
445
446         /* There can be multiple reception claims in the same report segment */
447         for(i = 0; i<rcpt_clm_cnt; i++){
448                 offset = evaluate_sdnv(tvb,frame_offset + segment_offset, &offset_size);
449                 proto_tree_add_uint64_format(ltp_rpt_clm_tree, hf_ltp_rpt_clm_off, tvb, frame_offset + segment_offset, offset_size, offset,
450                                 "Offset[%d] : %"G_GINT64_MODIFIER"d", i, offset);
451                 segment_offset += offset_size;
452
453                 length = evaluate_sdnv(tvb,frame_offset + segment_offset, &length_size);
454                 proto_tree_add_uint64_format(ltp_rpt_clm_tree, hf_ltp_rpt_clm_len, tvb, frame_offset + segment_offset, length_size, length,
455                                 "Length[%d] : %"G_GINT64_MODIFIER"d",i, length);
456                 segment_offset += length_size;
457         }
458         proto_item_set_end(ltp_rpt_clm_item, tvb, frame_offset + segment_offset);
459         proto_item_set_end(ltp_rpt_item, tvb, frame_offset + segment_offset);
460         return segment_offset;
461 }
462
463
464 static int
465 dissect_report_ack_segment(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset){
466         guint64 rpt_sno;
467
468         int rpt_sno_size;
469         int segment_offset = 0;
470
471         proto_item *ltp_rpt_ack_item;
472         proto_tree *ltp_rpt_ack_tree;
473
474         /* Extracing receipt serial number info */
475         rpt_sno = evaluate_sdnv_64(tvb,frame_offset, &rpt_sno_size);
476         segment_offset += rpt_sno_size;
477
478         if((unsigned)(frame_offset + segment_offset) > tvb_length(tvb)){
479                 return 0;
480         }
481
482         /* Creating tree for the report ack segment */
483         ltp_rpt_ack_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, segment_offset, "Report Ack Segment");
484         ltp_rpt_ack_tree = proto_item_add_subtree(ltp_rpt_ack_item, ett_rpt_ack_segm);
485
486         proto_tree_add_uint64(ltp_rpt_ack_tree, hf_ltp_rpt_ack_sno, tvb, frame_offset,rpt_sno_size, rpt_sno);
487         return segment_offset;
488 }
489
490
491 static int
492 dissect_cancel_segment(proto_tree * ltp_tree, tvbuff_t *tvb,int frame_offset){
493         guint8 reason_code;
494
495         proto_item *ltp_cancel_item;
496         proto_tree *ltp_cancel_tree;
497
498         /* The cancel segment has only one byte, which contains the reason code. */
499         reason_code = tvb_get_guint8(tvb,frame_offset);
500
501         /* Creating tree for the cancel segment */
502         ltp_cancel_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, 1, "Cancel Segment");
503         ltp_cancel_tree = proto_item_add_subtree(ltp_cancel_item, ett_session_mgmt);
504
505         proto_tree_add_uint_format_value(ltp_cancel_tree, hf_ltp_cancel_code, tvb, frame_offset, 1, reason_code,
506                         "%x (%s)", reason_code, val_to_str(reason_code,ltp_cancel_codes,"Reserved"));
507         return 1;
508 }
509
510 static int
511 dissect_header_extn(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset,int hdr_extn_cnt){
512         guint8 extn_type[LTP_MAX_HDR_EXTN];
513         guint64 length[LTP_MAX_HDR_EXTN];
514         guint64 value[LTP_MAX_HDR_EXTN];
515
516         int length_size[LTP_MAX_HDR_EXTN];
517         int value_size[LTP_MAX_HDR_EXTN];
518
519         int i;
520         int extn_offset = 0;
521
522         proto_item *ltp_hdr_extn_item;
523         proto_tree *ltp_hdr_extn_tree;
524
525         /*  There can be more than one header extensions */
526         for(i = 0; i < hdr_extn_cnt; i++){
527                 extn_type[i] = tvb_get_guint8(tvb,frame_offset);
528                 extn_offset++;
529
530                 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
531                         return 0;
532                 }
533                 length[i] = evaluate_sdnv_64(tvb,frame_offset,&length_size[i]);
534                 extn_offset += length_size[i];
535                 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
536                         return 0;
537                 }
538                 value[i] = evaluate_sdnv_64(tvb,frame_offset,&value_size[i]);
539                 extn_offset += value_size[i];
540                 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
541                         return 0;
542                 }
543         }
544         ltp_hdr_extn_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, extn_offset, "Header Extension");
545         ltp_hdr_extn_tree = proto_item_add_subtree(ltp_hdr_extn_item, ett_hdr_extn);
546
547         for(i = 0; i < hdr_extn_cnt; i++){
548                 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"));
549
550                 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]);
551                 frame_offset += length_size[i];
552
553                 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]);
554                 frame_offset += value_size[i];
555         }
556         return extn_offset;
557 }
558
559 static int
560 dissect_trailer_extn(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset,int trl_extn_cnt){
561         guint8 extn_type[LTP_MAX_TRL_EXTN];
562         guint64 length[LTP_MAX_TRL_EXTN];
563         guint64 value[LTP_MAX_TRL_EXTN];
564
565         int length_size[LTP_MAX_TRL_EXTN];
566         int value_size[LTP_MAX_TRL_EXTN];
567
568         int i;
569         int extn_offset = 0;
570
571         proto_item *ltp_trl_extn_item;
572         proto_tree *ltp_trl_extn_tree;
573
574         DISSECTOR_ASSERT(trl_extn_cnt < LTP_MAX_TRL_EXTN);
575
576         for(i = 0; i < trl_extn_cnt; i++){
577                 extn_type[i] = tvb_get_guint8(tvb,frame_offset);
578                 extn_offset++;
579
580                 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
581                         return 0;
582                 }
583
584                 length[i] = evaluate_sdnv_64(tvb,frame_offset,&length_size[i]);
585                 extn_offset += length_size[i];
586
587                 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
588                         return 0;
589                 }
590
591                 value[i] = evaluate_sdnv_64(tvb,frame_offset,&value_size[i]);
592                 extn_offset += value_size[i];
593
594                 if((unsigned)(frame_offset + extn_offset) >= tvb_length(tvb)){
595                         return 0;
596                 }
597         }
598         ltp_trl_extn_item = proto_tree_add_text(ltp_tree, tvb,frame_offset, extn_offset, "Header Extension");
599         ltp_trl_extn_tree = proto_item_add_subtree(ltp_trl_extn_item, ett_trl_extn);
600
601         for(i = 0; i < trl_extn_cnt; i++){
602                 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"));
603
604                 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]);
605                 frame_offset += length_size[i];
606
607                 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]);
608                 frame_offset += value_size[i];
609         }
610         return extn_offset;
611 }
612
613
614 static int
615 dissect_ltp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
616 {
617         proto_item *ti = NULL;
618         proto_tree *ltp_tree = NULL;
619         int frame_offset;
620         int header_offset;
621         int segment_offset = 0;
622         int hdr_extn_offset = 0;
623         int trl_extn_offset = 0;
624
625         guint8  ltp_hdr;
626         gint    ltp_type;
627         guint8  ltp_extn_cnt;
628         gint    hdr_extn_cnt;
629         gint    trl_extn_cnt;
630
631         guint64 engine_id;
632         guint64 session_num;
633         int engine_id_size;
634         int session_num_size;
635
636         proto_item *ltp_header_item = NULL;
637         proto_item *ltp_session_item = NULL;
638
639         proto_tree *ltp_header_tree = NULL;
640         proto_tree *ltp_session_tree = NULL;
641
642         /* Check that there's enough data */
643         if(tvb_length(tvb) < LTP_MIN_DATA_BUFFER){
644                 return 0;
645         }
646         frame_offset = 0;
647         header_offset = 0;
648
649         col_set_str(pinfo->cinfo, COL_PROTOCOL, "LTP Segment");
650
651         /* Extract all the header info from the packet */
652         ltp_hdr = tvb_get_guint8(tvb, frame_offset);
653         header_offset++;
654
655         engine_id = evaluate_sdnv_64(tvb,frame_offset + header_offset,&engine_id_size);
656         header_offset += engine_id_size;
657         if((unsigned)header_offset >= tvb_length(tvb)){
658                 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
659                 return 0;
660         }
661
662         session_num = evaluate_sdnv_64(tvb,frame_offset + header_offset,&session_num_size);
663         header_offset += session_num_size;
664         if((unsigned)header_offset >= tvb_length(tvb)){
665                 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
666                 return 0;
667         }
668
669         ti = proto_tree_add_item(tree, proto_ltp, tvb, 0, -1, ENC_NA);
670         ltp_tree = proto_item_add_subtree(ti, ett_ltp);
671
672         /* Adding Header Subtree */
673         ltp_header_item = proto_tree_add_text(ltp_tree, tvb, frame_offset, header_offset+1, "LTP Header");
674         ltp_header_tree = proto_item_add_subtree(ltp_header_item, ett_ltp_hdr);
675
676         proto_tree_add_uint(ltp_header_tree,hf_ltp_version,tvb,frame_offset,1,hi_nibble(ltp_hdr));
677         ltp_type = lo_nibble(ltp_hdr);
678         proto_tree_add_uint_format_value(ltp_header_tree,hf_ltp_type,tvb,frame_offset,1,ltp_type,"%x (%s)",
679                          ltp_type,val_to_str(ltp_type,ltp_type_codes,"Invalid"));
680
681         frame_offset++;
682         /* Adding the session id subtree */
683         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);
684         ltp_session_tree = proto_item_add_subtree(ltp_session_item,ett_hdr_session);
685         proto_tree_add_uint64(ltp_session_tree,hf_ltp_session_orig,tvb,frame_offset,engine_id_size,engine_id);
686         frame_offset+=engine_id_size;
687         proto_tree_add_uint64(ltp_session_tree,hf_ltp_session_no, tvb, frame_offset,session_num_size,session_num);
688         frame_offset+=session_num_size;
689
690         /* Adding Extension count to the header tree */
691         ltp_extn_cnt = tvb_get_guint8(tvb,frame_offset);
692         hdr_extn_cnt = hi_nibble(ltp_extn_cnt);
693         trl_extn_cnt = lo_nibble(ltp_extn_cnt);
694
695         proto_tree_add_uint(ltp_header_tree,hf_ltp_hdr_extn_cnt,tvb,frame_offset,1,hdr_extn_cnt);
696         proto_tree_add_uint(ltp_header_tree,hf_ltp_trl_extn_cnt,tvb,frame_offset,1,trl_extn_cnt);
697         frame_offset++;
698
699         col_add_str(pinfo->cinfo, COL_INFO, val_to_str_const(ltp_type,ltp_type_col_info,"Protocol Error"));
700
701         if((unsigned)frame_offset >= tvb_length(tvb)){
702                 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
703                 return 0;
704         }
705
706         /* Check if there are any header extensions */
707         if(hdr_extn_cnt > 0){
708                 hdr_extn_offset = dissect_header_extn(ltp_tree, tvb, frame_offset,hdr_extn_cnt);
709                 if(hdr_extn_offset == 0){
710                         col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
711                         return 0;
712                 }
713                 frame_offset += hdr_extn_offset;
714         }
715
716         if((unsigned)frame_offset >= tvb_length(tvb)){
717                 col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
718                 return 0;
719         }
720
721         /* Call sub routines to handle the segment content*/
722         if((ltp_type >= 0) && (ltp_type < 8)){
723                 segment_offset = dissect_data_segment(ltp_tree,tvb,pinfo,frame_offset,ltp_type,session_num);
724                 if(segment_offset == 0){
725                         col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
726                         return 0;
727                 }
728         }
729         else if(ltp_type == 8){
730                 segment_offset = dissect_report_segment(tvb, pinfo, ltp_tree,frame_offset);
731                 if(segment_offset == 0){
732                         col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
733                         return 0;
734                 }
735         }
736         else if(ltp_type == 9){
737                 segment_offset = dissect_report_ack_segment(ltp_tree,tvb,frame_offset);
738                 if(segment_offset == 0){
739                         col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
740                         return 0;
741                 }
742         }
743         else if(ltp_type == 12 || ltp_type == 14){
744                 segment_offset = dissect_cancel_segment(ltp_tree,tvb,frame_offset);
745                 if(segment_offset == 0){
746                         col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
747                         return 0;
748                 }
749         }
750         frame_offset += segment_offset;
751         /* Check to see if there are any trailer extensions */
752         if(trl_extn_cnt > 0){
753                 if((unsigned)frame_offset >= tvb_length(tvb)){
754                     col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
755                     return 0;
756                 }
757                 trl_extn_offset = dissect_trailer_extn(ltp_tree, tvb, frame_offset,trl_extn_cnt);
758                 if(trl_extn_offset == 0){
759                     col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
760                     return 0;
761                 }
762         }
763         /* Return the amount of data this dissector was able to dissect */
764         return tvb_length(tvb);
765 }
766
767 static void
768 ltp_defragment_init(void) {
769     fragment_table_init(&ltp_fragment_table);
770     reassembled_table_init(&ltp_reassembled_table);
771 }
772
773 /* Register the protocol with Wireshark */
774 void
775 proto_register_ltp(void)
776 {
777         module_t *ltp_module;
778
779         static hf_register_info hf[] = {
780           {&hf_ltp_version,
781                   {"LTP Version","ltp.version",
782                   FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
783           },
784           {&hf_ltp_type,
785                   {"LTP Type","ltp.type",
786                   FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
787           },
788           {&hf_ltp_session_id,
789                   {"Session ID","ltp.session",
790                   FT_NONE,BASE_NONE,NULL, 0x0, NULL, HFILL}
791           },
792           {&hf_ltp_session_orig,
793                   {"Session originator","ltp.session.orig",
794                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
795           },
796           {&hf_ltp_session_no,
797                   {"Session number","ltp.session.number",
798                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
799           },
800           {&hf_ltp_hdr_extn_cnt,
801                   {"Header Extension Count","ltp.hdr.extn.cnt",
802                   FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
803           },
804           {&hf_ltp_trl_extn_cnt,
805                   {"Trailer Extension Count","ltp.trl.extn.cnt",
806                   FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
807           },
808           {&hf_ltp_data_clid,
809                   {"Client service ID","ltp.data.client.id",
810                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
811           },
812           {&hf_ltp_data_offset,
813                   {"Offset","ltp.data.offset",
814                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
815           },
816           {&hf_ltp_data_length,
817                   {"Length","ltp.data.length",
818                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
819           },
820           {&hf_ltp_data_chkp,
821                   {"Checkpoint serial number","ltp.data.chkp",
822                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
823           },
824           {&hf_ltp_data_rpt,
825                   {"Report serial number","ltp.data.rpt",
826                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
827           },
828           {&hf_ltp_data_clidata,
829                   {"Client service data","ltp.data.data",
830                   FT_BYTES,BASE_NONE,NULL, 0x0, NULL, HFILL}
831           },
832           {&hf_ltp_rpt_sno,
833                   {"Report serial number","ltp.rpt.sno",
834                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
835           },
836           {&hf_ltp_rpt_chkp,
837                   {"Checkpoint serial number","ltp.rpt.chkp",
838                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
839           },
840           {&hf_ltp_rpt_ub,
841                   {"Upper bound","ltp.rpt.ub",
842                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
843           },
844           {&hf_ltp_rpt_lb,
845                   {"Lower bound","ltp.rpt.lb",
846                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
847           },
848           {&hf_ltp_rpt_clm_cnt,
849                   {"Reception claim count","ltp.rpt.clm.cnt",
850                   FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
851           },
852           {&hf_ltp_rpt_clm_off,
853                   {"Offset","ltp.rpt.clm.off",
854                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
855           },
856           {&hf_ltp_rpt_clm_len,
857                   {"Length","ltp.rpt.clm.len",
858                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
859           },
860           {&hf_ltp_rpt_ack_sno,
861                   {"Report serial number","ltp.rpt.ack.sno",
862                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
863           },
864           {&hf_ltp_cancel_code,
865                   {"Cancel code","ltp.cancel.code",
866                   FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
867           },
868           {&hf_ltp_hdr_extn_tag,
869                   {"Extension tag","ltp.hdr.extn.tag",
870                   FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
871           },
872           {&hf_ltp_hdr_extn_len,
873                   {"Length","ltp.hdr.extn.len",
874                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
875           },
876           {&hf_ltp_hdr_extn_val,
877                   {"Value","ltp.hdr.extn.val",
878                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
879           },
880           {&hf_ltp_trl_extn_tag,
881                   {"Extension tag","ltp.hdr.extn.tag",
882                   FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
883           },
884           {&hf_ltp_trl_extn_len,
885                   {"Length","ltp.hdr.extn.len",
886                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
887           },
888           {&hf_ltp_trl_extn_val,
889                   {"Value","ltp.hdr.extn.val",
890                   FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
891           },
892           {&hf_ltp_fragments,
893                   {"LTP Fragments", "ltp.fragments",
894                   FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
895           },
896           {&hf_ltp_fragment,
897                   {"LTP Fragment", "ltp.fragment",
898                   FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
899           },
900           {&hf_ltp_fragment_overlap,
901                   {"LTP fragment overlap", "ltp.fragment.overlap",
902                   FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
903           },
904           {&hf_ltp_fragment_overlap_conflicts,
905                   {"LTP fragment overlapping with conflicting data",
906                    "ltp.fragment.overlap.conflicts",
907                   FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
908           },
909           {&hf_ltp_fragment_multiple_tails,
910                   {"LTP has multiple tails", "ltp.fragment.multiple_tails",
911                   FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
912           },
913           {&hf_ltp_fragment_too_long_fragment,
914                   {"LTP fragment too long", "ltp.fragment.too_long_fragment",
915                   FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
916           },
917           {&hf_ltp_fragment_error,
918                   {"LTP defragmentation error", "ltp.fragment.error",
919                   FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
920           },
921           {&hf_ltp_fragment_count,
922                   {"LTP fragment count", "ltp.fragment.count",
923                   FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
924           },
925           {&hf_ltp_reassembled_in,
926                   {"LTP reassembled in", "ltp.reassembled.in",
927                   FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
928           },
929           {&hf_ltp_reassembled_length,
930                   {"LTP reassembled length", "ltp.reassembled.length",
931                   FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
932           }
933         };
934
935 /* Setup protocol subtree array */
936         static gint *ett[] = {
937                 &ett_ltp,
938                 &ett_ltp_hdr,
939                 &ett_hdr_session,
940                 &ett_hdr_extn,
941                 &ett_data_segm,
942                 &ett_data_data_segm,
943                 &ett_rpt_segm,
944                 &ett_rpt_clm,
945                 &ett_rpt_ack_segm,
946                 &ett_session_mgmt,
947                 &ett_trl_extn,
948                 &ett_ltp_fragment,
949                 &ett_ltp_fragments
950         };
951
952 /* Register the protocol name and description */
953         proto_ltp = proto_register_protocol("Licklider Transmission Protocol",
954                 "LTP", "ltp");
955
956         proto_register_field_array(proto_ltp, hf, array_length(hf));
957         proto_register_subtree_array(ett, array_length(ett));
958         ltp_module = prefs_register_protocol(proto_ltp, proto_reg_handoff_ltp);
959
960         prefs_register_uint_preference(ltp_module, "udp.port", "LTP UDP Port",
961                 "UDP Port to accept LTP Connections",
962                 10, &ltp_port);
963         register_init_routine(ltp_defragment_init);
964 }
965
966 void
967 proto_reg_handoff_ltp(void)
968 {
969         static gboolean initialized = FALSE;
970         static dissector_handle_t ltp_handle;
971         static int currentPort;
972
973         if (!initialized) {
974                 ltp_handle = new_create_dissector_handle(dissect_ltp, proto_ltp);
975                 initialized = TRUE;
976         } else {
977                 dissector_delete_uint("udp.port", currentPort, ltp_handle);
978         }
979
980         currentPort = ltp_port;
981
982         dissector_add_uint("udp.port", currentPort, ltp_handle);
983 }