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