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