Updated commandline args: Added -V for version, -h for help, changed -d to -v for...
[ltp2tcp] / ltp2tcp.c
1 /******************************************************************************
2 Utility to convert a LTP flow to a TCP flow for LTP analysis via tcptrace.
3
4 Copyright (C) 2013  Samuel Jero <sj323707@ohio.edu>
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19 Author: Samuel Jero <sj323707@ohio.edu>
20 Date: 06/2013
21
22 Notes:
23         1)Only handles one LTP "connection". There isn't a good way to separate
24                 different LTP "connections" from new sessions of the same "connection".
25                 Use Tcpdump filters to separate connections. Libpcap filtering could also
26                 be added in ltp2tcp.
27         2)Uses some special types from Linux (u_char, u_int32_t)
28 ******************************************************************************/
29 #include "ltp2tcp.h"
30
31 #define LTPTRACE_VERSION 0.3
32 #define COPYRIGHT_YEAR 2013
33
34 int debug=0;
35 int MAX_SESSION=500000;
36
37
38
39 /* Forward declarations*/
40 int init_state();
41 int free_state();
42 void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);
43 int convert_packet(struct pcap_pkthdr *h, const u_char *odata, u_char *ndata, int datalength, int newlength);
44 int handle_data(const u_char* odata, struct ltp_hdr_d* ltph, struct tcphdr *tcph, int* dlen, int rbuf);
45 int handle_report(const u_char* odata, struct ltp_hdr_d* ltph, struct tcphdr *tcph, u_char* tcpopt, int* dlen, int rbuf);
46 int claim2sack(const u_char* odata, int ses_id, struct ltp_hdr_d* ltph, struct tcphdr *tcph, u_char* tcpopt, int* dlen, int rbuf);
47 int seq_from_session(struct ltp_hdr_d* ltph, struct tcphdr *tcph);
48 int ack_from_session(struct ltp_hdr_d* ltph, struct tcphdr *tcph);
49 void version();
50 void usage();
51
52
53 /*Parse commandline options and open files*/
54 int main(int argc, char *argv[])
55 {
56         char ebuf[200];
57         char *erbuffer=ebuf;
58         char *lfile=NULL;
59         char *tfile=NULL;
60         char *type=NULL;
61         char *temp;
62         int  tmp;
63
64         /*parse commandline options*/
65         if(argc < 2){
66                 usage();
67         }
68
69         /*loop through commandline options*/
70         for(int i=1; i < argc; i++){
71                 if(argv[i][0]!='-' || (argv[i][0]=='-' && strlen(argv[i])==1)){
72                         if(lfile==NULL  || argv[i][0]=='-'){
73                                 /*assign first non-dash (or only dash) argument to the dccp file*/
74                                 lfile=argv[i];
75                         }else{
76                                 if(tfile==NULL){
77                                         tfile=argv[i]; /*assign second non-dash argument to the dccp file*/
78                                 }else{
79                                         usage();
80                                 }
81                         }
82                 }else{
83                         if(argv[i][1]=='v' && strlen(argv[i])==2){ /*debug option*/
84                                 debug++;
85                         }
86                         if(argv[i][1]=='V' && strlen(argv[i])==2){ /*Version option*/
87                                 version();
88                         }
89                         if(argv[i][1]=='h'&& strlen(argv[i])==2){ /* help*/
90                                 usage();
91                         }
92                         if(argv[i][1]=='t'){ /*Encapsulation option*/
93                                 type=&argv[i][2];
94                         }
95                         if(argv[i][1]=='b'){ /* Block size option*/
96                                 tmp=atoi(&argv[i][2]);
97                                 if(tmp>0){
98                                         MAX_SESSION=tmp;
99                                 }else{
100                                         usage();
101                                 }
102                         }
103                         if(argv[i][1]=='s'){ /*Session range option*/
104                                         state.ses_min=strtol(&argv[i][2],&temp,10);
105                                         temp++;
106                                         state.ses_max=strtol(temp,NULL,10);
107                         }
108                 }
109         }
110         
111         if(lfile==NULL || tfile==NULL || type==NULL){
112                 usage();
113         }
114
115         if(state.ses_min<=0 || state.ses_max<=0){
116                 state.ses_min=-1;
117                 state.ses_max=-1;
118         }
119
120         /*all options validated*/
121
122         if(debug){
123                 dbgprintf(1,"Input file: %s\n", lfile);
124                 dbgprintf(1,"Output file: %s\n", tfile);
125                 dbgprintf(1,"Encapsulation: %s\n", type);
126                 dbgprintf(1,"Block Size: %i\n", MAX_SESSION);
127                 if(state.ses_min>=0){
128                         dbgprintf(1, "Session Range: %i-%i\n", state.ses_min, state.ses_max);
129                 }else{
130                         dbgprintf(1, "Session Range: all\n");
131                 }
132         }
133
134         /*determine encapsulation type*/
135         encap_sel(type);
136
137         /*attempt to open input file*/
138         state.in=pcap_open_offline(lfile, erbuffer);
139         if(state.in==NULL){
140                 printf("Error opening input file\n");
141                 exit(1);
142         }
143
144         /*attempt to open output file*/
145         state.out=pcap_dump_open(state.in,tfile);
146         if(state.out==NULL){
147                 printf("Error opening output file\n");
148                 exit(1);
149         }
150
151         /*setup state*/
152         if(init_state()){
153                 exit(1);
154         }
155
156         /*process packets*/
157         u_char *user=(u_char*)state.out;
158         pcap_loop(state.in, -1, handle_packet, user);
159
160         /*add correct TCP termination, if needed*/
161         if(state.en_ops && state.en_ops->fin){
162                         (*state.en_ops->fin)();
163                         free(state.en_priv);
164         }
165         
166         /*close files*/
167         pcap_close(state.in);
168         pcap_dump_close(state.out);
169 return 0;
170 }
171
172 /*initialize the converter state*/
173 int init_state()
174 {
175         state.seq_num=0;
176         state.ack_num=0;
177         state.win=0;
178         state.started=0;
179         state.seq_ses_id=0;
180         state.ses.size=TBL_SZ;
181         state.ses.max=0;
182         state.en_priv=NULL;
183         state.sender_id=-1;
184         state.ses.table=malloc(TBL_SZ*sizeof(struct tbl));
185         if(state.ses.table==NULL){
186                 dbgprintf(0,"Error: Couldn't allocate Memory!\n");
187                 exit(1);
188         }
189 return 0;
190 }
191
192 /*cleanup state*/
193 int free_state()
194 {
195         struct cl* tmp;
196         struct cl* f;
197
198         /*clean up the session table*/
199         if(state.ses.table){
200
201                 /*cleanup the claims in each session*/
202                 for(int i=0; i < MAX_SESSION; i ++){
203                         if(state.ses.table[i].a_lst!=NULL){
204                                 tmp=state.ses.table[i].a_lst;
205                                 while(tmp){
206                                         f=tmp;
207                                         tmp=tmp->next;
208                                         free(f);
209                                 }
210                         }
211                 }
212
213                 free(state.ses.table);
214         }
215         return 0;
216 }
217
218 /*call back function for pcap_loop--do basic packet handling*/
219 void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
220 {
221         u_char                          *ndata;
222         u_char                          *nptr;
223         const u_char            *optr=bytes;
224         int                             length;
225         int                                     nlength;
226         int                             tlen;
227         struct pcap_pkthdr      nh;
228
229         /*create new libpcap header*/
230         memcpy(&nh, h, sizeof(struct pcap_pkthdr));
231
232         /*create buffer for new packet*/
233         nptr=ndata=malloc(MAX_PACKET);
234         if(ndata==NULL){
235                 dbgprintf(0,"Error: Couldn't allocate Memory\n");
236                 exit(1);
237         }
238
239         /*make sure the packet is all zero*/
240         memset(ndata, 0, MAX_PACKET);
241         length=h->caplen;
242         nlength=MAX_PACKET;
243
244         /*handle encapsulations*/
245         if(state.en_ops && state.en_ops->pre && state.en_ops->post){
246                 if((*state.en_ops->pre)(&nh, &optr, &nptr, &length, &nlength)<0){
247                         return;
248                 }
249                 tlen=convert_packet(&nh, optr, nptr, length, nlength);
250                 if(tlen <0){
251                         free(ndata);
252                         return;
253                 }
254                 if((*state.en_ops->post)(tlen, ndata)<0){
255                         return;
256                 }
257         }else{
258                 return;
259         }
260
261         /*save packet*/
262         pcap_dump(user,&nh, ndata);
263
264         free(ndata);
265 return;
266 }
267
268 /*do all the ltp to tcp conversions---returns length of TCP segment*/
269 int convert_packet(struct pcap_pkthdr *h, const u_char *odata, u_char *ndata, int datalength, int newlength)
270 {       
271         u_char*                         ncur=ndata;
272         struct tcphdr           *tcph;
273         u_char*                         tcpopt;
274         u_char                          ctl;
275         struct ltp_hdr_d        ltph;
276         int                             eaten;
277         int                                     tmp;
278         int                                     hext;
279         int                                     dlen=0;
280         int                                     helen;
281
282         /*safety checks*/
283         if(h==NULL || odata==NULL || ndata==NULL|| datalength<1|| newlength < sizeof(struct tcphdr)){
284                         return -1;
285         }
286
287         /*cast TCP header pointers*/
288         tcph=(struct tcphdr*)ncur;
289         tcpopt=ncur+ sizeof(struct tcphdr);
290
291         /*set TCP standard features*/
292         tcph->source=htons(1113);
293         tcph->dest=htons(1113);
294         tcph->doff=5;
295         tcph->check=htonl(0);
296         tcph->urg_ptr=0;
297         tcph->urg=0;
298         tcph->psh=0;
299
300         /*Grab LTP control/version byte*/
301         ltph.vers_ctl=ctl=*odata;
302         odata++;
303         datalength--;
304
305         /* check LTP version*/
306         if((ctl & 0xF0) !=0){
307                 dbgprintf(1,"Error: Invalid Packet Version\n");
308                 return -1;
309         }
310
311         /* Parse LTP Session ID*/
312         ltph.sender_id=evaluate_sdnv(odata, &eaten);
313         odata+=eaten;
314         datalength-=eaten;
315         if(ltph.sender_id<0 || datalength<0){
316                 dbgprintf(1,"Error: Bad SDNV!\n");
317                 return -1;
318         }
319
320         ltph.session_num=evaluate_sdnv(odata, &eaten);
321         odata+=eaten;
322         datalength-=eaten;
323         if(ltph.session_num<0 || datalength<0){
324                         dbgprintf(1,"Error: Bad SDNV!\n");
325                         return -1;
326         }
327
328         /*Filter sessions*/
329         if(state.ses_min>=0){
330                 if((ltph.session_num < state.ses_min)|| (ltph.session_num > state.ses_max)){
331                         dbgprintf(3, "Filtering session: %i\n", ltph.session_num);
332                         return -1;
333                 }
334         }
335
336         /*Check LTP Sender*/
337         /* We don't want to be confused if we have multiple LTP connections in this capture*/
338         if(state.sender_id==-1){
339                 state.sender_id=ltph.sender_id;
340         }else{
341                 if(state.sender_id!=ltph.sender_id){
342                         dbgprintf(1,"Note: Packet from different Sender!!\n");
343                         return -1;
344                 }
345         }
346
347         /*Parse and Remove LTP header extensions*/
348         helen=0;
349         ltph.extensions=*odata;
350         odata++;
351         hext=ltph.extensions >> 4;
352         while(hext>0){
353                 tmp=evaluate_sdnv(odata+1, &eaten);
354                 if(tmp==0 || tmp < eaten || tmp < 0 || datalength < tmp){
355                         dbgprintf(1,"Error: Packet has bad extension length!\n");
356                         return -1;
357                 }
358                 /* ignore all extensions*/
359                 odata+=tmp;
360                 helen+=tmp;
361                 datalength-=tmp;
362                 hext--;
363         }
364
365
366
367         /*make changes by packet type*/
368         if((ctl & 0x0C)==0x0){//RED DATA
369                 dbgprintf(2,"Packet Type: RED DATA\n");
370
371                 /*Initialize the TCP connection, if this is the start*/
372                 if(state.started==0){
373                         state.started=1;
374                         if(state.en_ops && state.en_ops->handshake){
375                                 (*state.en_ops->handshake)(h);
376                         }
377                 }
378                 
379                 if(handle_data(odata, &ltph, tcph, &dlen, datalength)<0){
380                         return -1;
381                 }
382
383                 /*Finalize TCP Header*/
384                 tcph->fin=0;
385                 tcph->syn=0;
386                 tcph->rst=0;
387                 tcph->ack=1;
388
389                 /*check length*/
390                 if(newlength < dlen + tcph->doff*4){
391                         dbgprintf(1, "Error: Indicated Packet Length is beyond end of buffer!\n");
392                         return -1;
393                 }
394
395                 /*Add data*/
396                 memset(ndata + tcph->doff*4, 'A', dlen);
397
398                 /*Adjust Lengths (packet and TCP segment)*/
399                 h->len+=tcph->doff*4+dlen;
400                 h->caplen+=tcph->doff*4+dlen;
401                 return tcph->doff*4+dlen;
402         }
403
404         if((ctl & 0x0C)==0x4){//GREEN DATA
405                         dbgprintf(2,"Packet Type: GREEN DATA\n");
406
407                 /*Initialize the TCP connection, if this is the start*/
408                 if(state.started==0){
409                         state.started=1;
410                         if(state.en_ops && state.en_ops->handshake){
411                                         (*state.en_ops->handshake)(h);
412                         }
413                 }
414
415                 if(handle_data(odata, &ltph, tcph, &dlen, datalength)<0){
416                         return -1;
417                 }
418
419                 /*Finalize TCP Header*/
420                 tcph->fin=0;
421                 tcph->syn=0;
422                 tcph->rst=0;
423                 tcph->ack=1;
424
425                 /*check length*/
426                 if(newlength < dlen + tcph->doff*4){
427                         dbgprintf(1, "Error: Indicated Packet Length is beyond end of buffer!\n");
428                         return -1;
429                 }
430
431                 /*Add data*/
432                 memset(ndata+ tcph->doff*4, 'A', dlen);
433
434                 /*Adjust Lengths (packet and TCP segment)*/
435                 h->len+=tcph->doff*4+dlen;
436                 h->caplen+=tcph->doff*4+dlen;
437                 return tcph->doff*4+dlen;
438         }
439
440         if((ctl & 0x0F)==0x8){//REPORT SEGMENT
441                 dbgprintf(2,"Packet Type: REPORT SEGMENT\n");
442
443                 /*check length*/
444                 if(newlength < 4*8+4+sizeof(struct tcphdr)){
445                         dbgprintf(1, "Error: Indicated Packet Length is may be beyond end of buffer!\n");
446                         return -1;
447                 }
448
449                 if(handle_report(odata, &ltph, tcph, tcpopt, &dlen, datalength)<0){
450                         return -1;
451                 }
452
453                 /*Finalize TCP Header*/
454                 tcph->fin=0;
455                 tcph->syn=0;
456                 tcph->rst=0;
457                 tcph->ack=1;
458
459                 /*check length*/
460                 if(newlength < tcph->doff*4){
461                         dbgprintf(1, "Error: Indicated Packet Length is beyond end of buffer!\n");
462                         return -1;
463                 }
464
465                 /*Adjust Lengths (packet and TCP segment)*/
466                 h->len+=tcph->doff*4+dlen;
467                 h->caplen+=tcph->doff*4+dlen;
468                 return tcph->doff*4+dlen;
469         }
470
471         if((ctl & 0x0F)==0x9){//REPORT ACK
472                 dbgprintf(2,"Packet Type: REPORT ACK\n");
473
474                 /*Get Seq and Ack Numbers*/
475                 if(seq_from_session(&ltph, tcph)<0){
476                         return -1;
477                 }
478                 tcph->ack_seq=htonl(state.ack_num);
479
480                 /*Finalize TCP Header*/
481                 tcph->window=htons(WIN_FACTOR);
482                 tcph->fin=0;
483                 tcph->syn=0;
484                 tcph->rst=0;
485                 tcph->ack=1;
486
487                 /*check length*/
488                 if(newlength < tcph->doff*4){
489                         dbgprintf(1, "Error: Indicated Packet Length is beyond end of buffer!\n");
490                         return -1;
491                 }
492
493                 /*Adjust Lengths (packet and TCP segment)*/
494                 h->len+=sizeof(struct tcphdr);
495                 h->caplen+=sizeof(struct tcphdr);
496                 return sizeof(struct tcphdr);
497         }
498
499         if((ctl & 0x0D)==0xC){ //CANCEL SEGMENT
500                 dbgprintf(2,"Packet Type: CANCEL SEGMENT\n");
501
502                 /*Get Seq and Ack Numbers*/
503                 if((ctl & 0x02)==0x00){
504                         //Sender cancel
505                         if(seq_from_session(&ltph, tcph)<0){
506                                 return -1;
507                         }
508                         tcph->ack_seq=htonl(state.ack_num);
509                 }else{
510                         //Receiver cancel
511                         if(ack_from_session(&ltph, tcph)<0){
512                                 return -1;
513                         }
514                         tcph->seq=htonl(state.ack_num++);
515                 }
516
517                 /*Finalize TCP Header*/
518                 tcph->window=htons(0);
519                 tcph->fin=0;
520                 tcph->syn=0;
521                 tcph->rst=1;
522                 tcph->ack=0;
523
524                 /*check length*/
525                 if(newlength < tcph->doff*4){
526                         dbgprintf(1, "Error: Indicated Packet Length is beyond end of buffer!\n");
527                         return -1;
528                 }
529
530                 /*Adjust Lengths (packet and TCP segment)*/
531                 h->len+=sizeof(struct tcphdr);
532                 h->caplen+=sizeof(struct tcphdr);
533                 return sizeof(struct tcphdr);
534         }
535
536         if((ctl & 0x0D)==0xD){//CANCEL ACK
537                 dbgprintf(2,"Packet Type: CANCEL ACK\n");
538
539                 /*Get Seq and Ack Numbers*/
540                 if((ctl & 0x02)==0x00){
541                         //Sender ACK
542                         if(seq_from_session(&ltph, tcph)<0){
543                                 return -1;
544                         }
545                         tcph->ack_seq=htonl(state.ack_num);
546                 }else{
547                         //Receiver ACK
548                         if(ack_from_session(&ltph, tcph)<0){
549                                 return -1;
550                         }
551                         tcph->seq=htonl(state.ack_num++);
552                 }
553
554                 /*Finalize TCP Header*/
555                 tcph->window=htons(0);
556                 tcph->fin=0;
557                 tcph->syn=0;
558                 tcph->rst=1;
559                 tcph->ack=0;
560
561                 /*check length*/
562                 if(newlength < tcph->doff*4){
563                         dbgprintf(1, "Error: Indicated Packet Length is beyond end of buffer!\n");
564                         return -1;
565                 }
566
567                 /*Adjust Lengths (packet and TCP segment)*/
568                 h->len+=sizeof(struct tcphdr);
569                 h->caplen+=sizeof(struct tcphdr);
570                 return sizeof(struct tcphdr);
571         }
572
573         /*Anything else is bad!*/
574         dbgprintf(1,"Error: Invalid Packet Type\n");
575 return -1;
576 }
577
578 /* Determine Sequence and Acknowledgment Numbers for Data Segments*/
579 int handle_data(const u_char* odata, struct ltp_hdr_d* ltph, struct tcphdr *tcph, int* dlen, int rbuf)
580 {
581         int eaten;
582         int i;
583         int found;
584
585         /* Get LTP Client Service ID*/
586         ltph->cls_id=evaluate_sdnv(odata, &eaten);
587         odata+=eaten;
588         rbuf-=eaten;
589         if(ltph->cls_id <0 || rbuf <0){
590                 dbgprintf(1,"Error: Bad SDNV!\n");
591                 return -1;
592         }
593
594         /*Get LTP Data Offset*/
595         ltph->offset=evaluate_sdnv(odata, &eaten);
596         odata+=eaten;
597         rbuf-=eaten;
598         if(ltph->offset <0 || rbuf <0){
599                 dbgprintf(1,"Error: Bad SDNV!\n");
600                 return -1;
601         }
602
603         /*Get LTP Data Length*/
604         ltph->length=evaluate_sdnv(odata, &eaten);
605         odata+=eaten;
606         rbuf-=eaten;
607         if(ltph->length <0 || rbuf <0){
608                 dbgprintf(1,"Error: Bad SDNV!\n");
609                 return -1;
610         }
611         
612         /* find LTP session */
613         found=0;
614         for(i=0; i < state.ses.size; i++){
615                 if(ltph->session_num==state.ses.table[i].num){
616                         found=1;
617                         break;
618                 }
619         }
620         
621         /* Not Found, add it*/
622         if(found==0){
623                 i=(state.seq_ses_id++)%state.ses.size;
624                 state.ses.table[i].num=ltph->session_num;
625                 state.ses.table[i].seq_id=state.seq_ses_id;
626                 if(state.seq_ses_id==1){
627                         /*First session*/
628                         state.ses.table[i].start=state.seq_num;
629                 }else{
630                         state.ses.table[i].start=state.seq_num + MAX_SESSION - state.ses.table[(state.seq_ses_id-2)%state.ses.size].length;
631                 }
632         }
633
634         /* Compute TCP Sequence Number */
635         tcph->seq=htonl(state.ses.table[i].start + ltph->offset);
636         if(state.ses.table[i].start + ltph->offset+ltph->length > state.seq_num){
637                 state.seq_num=state.ses.table[i].start + ltph->offset + ltph->length;
638         }
639
640         /* Update LTP Session Length*/
641         if(ltph->offset+ltph->length > state.ses.table[i].length){
642                 state.ses.table[i].length=ltph->offset+ltph->length;
643         }
644
645         /* Computer TCP Ack Number*/
646         tcph->ack_seq=htonl(state.ack_num);
647
648         /* Get Amount of Data in LTP Segment*/
649         *dlen=ltph->length;
650
651         /* Compute TCP Window*/
652         tcph->window=htons(WIN_FACTOR);
653 return 0;
654 }
655
656 /* Get Sequence and Acknowledgment Number for LTP Reports. Add TCP SACKS*/
657 int handle_report(const u_char* odata, struct ltp_hdr_d* ltph, struct tcphdr *tcph, u_char* tcpopt, int* dlen, int rbuf)
658 {
659         int eaten;
660         int found;
661         int i;
662         int data_recv;
663
664         /*Set TCP Data Length*/
665         *dlen=0;
666
667         /*Parse LTP header*/
668         /*Get LTP Report ID*/
669         ltph->report=evaluate_sdnv(odata, &eaten);
670         odata+=eaten;
671         rbuf-=eaten;
672         if(ltph->report <0 || rbuf<0){
673                 dbgprintf(1,"Error: Bad SDNV!\n");
674                 return -1;
675         }
676
677         /*Get LTP Checkpoint ID*/
678         ltph->checkpoint=evaluate_sdnv(odata, &eaten);
679         odata+=eaten;
680         rbuf-=eaten;
681         if(ltph->checkpoint <0 || rbuf<0){
682                 dbgprintf(1,"Error: Bad SDNV!\n");
683                 return -1;
684         }
685
686         /*Get LTP Report Upper Bound*/
687         ltph->ubound=evaluate_sdnv(odata, &eaten);
688         odata+=eaten;
689         rbuf-=eaten;
690         if(ltph->ubound <0 || rbuf<0){
691                 dbgprintf(1,"Error: Bad SDNV!\n");
692                 return -1;
693         }
694
695         /*Get LTP Report Lower Bound*/
696         ltph->lbound=evaluate_sdnv(odata, &eaten);
697         odata+=eaten;
698         rbuf-=eaten;
699         if(ltph->lbound <0 || rbuf<0){
700                 dbgprintf(1,"Error: Bad SDNV!\n");
701                 return -1;
702         }
703
704         /*Get Number of LTP Reception Claims*/
705         ltph->rclaims=evaluate_sdnv(odata, &eaten);
706         odata+=eaten;
707         rbuf-=eaten;
708         if(ltph->rclaims <0 || rbuf<0){
709                 dbgprintf(1,"Error: Bad SDNV!\n");
710                 return -1;
711         }
712
713         /* find LTP session */
714         found=0;
715         for(i=0; i < state.ses.size; i++){
716                 if(ltph->session_num==state.ses.table[i].num){
717                         found=1;
718                         break;
719                 }
720         }
721
722         /* LTP session Not Found*/
723         if(found==0){
724                 if(debug){
725                         dbgprintf(1,"Error: Session for Report Not Found!\n");
726                 }
727                 return -1;
728         }
729
730         /* Add TCP SACKS*/
731         data_recv=claim2sack(odata, i, ltph, tcph, tcpopt, dlen, rbuf);
732         if(data_recv<0){
733                 return -1;
734         }
735
736         /*Add TCP sequence number*/
737         tcph->seq=htonl(state.ack_num);
738         
739         /* Compute TCP Window*/
740         tcph->window=htons(WIN_FACTOR);
741
742         /* Add TCP Ack Number*/
743         tcph->ack_seq=htonl(state.ses.table[i].start + data_recv+1);
744 return 0;
745 }
746
747 /* Convert LTP Reception Claims into TCP SACKS*/
748 int claim2sack(const u_char* odata, int ses_id,struct ltp_hdr_d* ltph, struct tcphdr *tcph, u_char* tcpopt, int* dlen, int rbuf)
749 {
750         int             coffset;
751         int             clength;
752         int             eaten;
753         int             max;
754         int                     done;
755         u_char          *olen;
756         u_int32_t*      t_block;
757         struct cl*      tmp=NULL;
758
759         /*Add the Start of the TCP SACK Option*/
760         *tcpopt=5;
761         tcpopt++;
762         olen=tcpopt;
763         tcpopt++;
764         *olen=2;
765         *dlen=0;
766         tcph->doff+=1;
767
768         /* Cast to TCP SACK BLOCK pointer*/
769         t_block=(u_int32_t*)tcpopt;
770         
771         /* Loop over at most 4 Claims*/
772         if(ltph->rclaims>4){
773                 max=4;
774         }else{
775                 max=ltph->rclaims;
776         }
777
778         for(int i=0; i < max; i++){
779
780                 /* Read LTP Claim*/
781                 coffset=evaluate_sdnv(odata, &eaten);
782                 odata+=eaten;
783                 rbuf-=eaten;
784                 if(coffset <0 || rbuf<0){
785                         dbgprintf(1,"Error: Bad SDNV!\n");
786                         return -1;
787                 }
788                 clength=evaluate_sdnv(odata, &eaten);
789                 odata+=eaten;
790                 rbuf-=eaten;
791                 if(clength <0 || rbuf<0){
792                         dbgprintf(1,"Error: Bad SDNV!\n");
793                         return -1;
794                 }
795
796                 /* Add claim to session info*/
797                 if(!state.ses.table[ses_id].a_lst){
798                         state.ses.table[ses_id].a_lst=malloc(sizeof(struct cl));
799                         if(!state.ses.table[ses_id].a_lst){
800                                 dbgprintf(0,"Error: Couldn't allocate Memory\n");
801                                 exit(1);
802                         }
803                         tmp=state.ses.table[ses_id].a_lst;
804                 }else{
805                         tmp=state.ses.table[ses_id].a_lst;
806                         while(tmp->next){
807                                 tmp=tmp->next;
808                         }
809                         tmp->next=malloc(sizeof(struct cl));
810                         if(!tmp->next){
811                                 dbgprintf(0,"Error: Couldn't allocate Memory\n");
812                                 exit(1);
813                         }
814                 }
815                 tmp->offset=coffset;
816                 tmp->length=clength;
817
818                 /*Create TCP SACK*/
819                 *t_block=htonl(state.ses.table[ses_id].start+coffset); //Left Side
820                 t_block++;
821                 *t_block=htonl(state.ses.table[ses_id].start+coffset+clength+1); //Right Side
822                 t_block++;
823
824                 /*Update TCP header length*/
825                 *olen+=8;
826                 tcph->doff+=2;
827         }
828
829         /*Calculate Ack number*/
830         done=0;
831         coffset=0;
832         while(!done){
833                 tmp=state.ses.table[ses_id].a_lst;
834                 done=1;
835                 while(tmp){
836                         if((tmp->offset<=coffset) && ((tmp->offset+tmp->length) > coffset)){
837                                 coffset=tmp->offset+tmp->length;
838                                 done=0;
839                         }
840                         tmp=tmp->next;
841                 }
842         }
843         state.ses.table[ses_id].acked=coffset;
844 return coffset;
845 }
846
847 /* Get a TCP seq number from the LTP Session ID for Report ACK and Session Cancellation*/
848 int seq_from_session(struct ltp_hdr_d* ltph, struct tcphdr *tcph)
849 {
850         int i;
851         int found;
852
853         /*Find LTP session */
854         found=0;
855         for(i=0; i < state.ses.size; i++){
856                 if(ltph->session_num==state.ses.table[i].num){
857                         found=1;
858                         break;
859                 }
860         }
861
862         /*LTP session Not Found*/
863         if(found==0){
864                 dbgprintf(1,"Error: Session for Segment Not Found!\n");
865                 return -1;
866         }
867
868         /* Add TCP Sequence Number */
869         tcph->seq=htonl(state.ses.table[i].start + state.ses.table[i].length);
870         /* No length, so don't update state.ses.table[i].length*/
871 return 0;
872 }
873
874 /* Get an TCP Ack number from the LTP session ID for session cancellation*/
875 int ack_from_session(struct ltp_hdr_d* ltph, struct tcphdr *tcph)
876 {
877
878         int i;
879         int found;
880
881         /* find LTP session */
882         found=0;
883         for(i=0; i < state.ses.size; i++){
884                 if(ltph->session_num==state.ses.table[i].num){
885                         found=1;
886                         break;
887                 }
888         }
889
890         /* LTP session Not Found*/
891         if(found==0){
892                 if(debug){
893                         dbgprintf(1,"Error: Session for Segment Not Found!\n");
894                 }
895                 return -1;
896         }
897         
898         /* Add TCP Ack Number*/
899         tcph->ack_seq=htonl(state.ses.table[i].start + state.ses.table[i].acked+1);
900 return 0;
901 }
902
903 void version()
904 {
905         dbgprintf(0, "ltp2tcp version %.1f\n",LTPTRACE_VERSION);
906         dbgprintf(0, "Copyright (C) %i Samuel Jero <sj323707@ohio.edu>\n",COPYRIGHT_YEAR);
907         dbgprintf(0, "This program comes with ABSOLUTELY NO WARRANTY.\n");
908         dbgprintf(0, "This is free software, and you are welcome to\n");
909         dbgprintf(0, "redistribute it under certain conditions.\n");
910         exit(0);
911 }
912
913 /*Usage information for program*/
914 void usage()
915 {
916         dbgprintf(0,"Usage: ltp2tcp -t{encapsulation} [-v] [-V] [-h] [-b{block_size}] [-s{start session}-{end session}] ltp_file tcp_file\n");
917         dbgprintf(0, "          -v   verbose. May be repeated for additional verbosity.\n");
918         dbgprintf(0, "          -V   Version information\n");
919         dbgprintf(0, "          -h   Help\n");
920         dbgprintf(0, "          -t   type of encapsulation (udp,dccp,sll)\n");
921         dbgprintf(0, "          -b   LTP block size (NOT the bundle size) that is being used over this connection\n");
922         dbgprintf(0, "          -s   Requests a graph of only the specified range of sessions\n");
923         exit(0);
924 }
925
926 /*Debug Printf*/
927 void dbgprintf(int level, const char *fmt, ...)
928 {
929     va_list args;
930     if(debug>=level){
931         va_start(args, fmt);
932         vfprintf(stderr, fmt, args);
933         va_end(args);
934     }
935 }