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