Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


added network server files
[palacios.git] / misc / network_servers / vtl / test / vtl_harness.cc
1 #include <stdlib.h>
2 #include <stdio.h>
3 #ifdef linux
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <sys/poll.h>
7 #endif
8
9 #include "vtl_harness.h"
10
11 DEBUG_DECLARE();
12
13
14 #define F_NONE 0
15 #define F_LOCAL_ACK 1
16
17 unsigned short g_fflags;
18
19
20 int g_do_local_ack = 0;
21 /* IP Address utility functions */
22
23
24
25 /* Global Pipe Descriptors */
26 int vtp_in_fd, vtp_out_fd;
27
28
29 /* Connection List Handling */
30 struct VTP_CON g_vtp_cons[MAX_VTP_CONS];
31 int g_first_vtp;
32 int g_last_vtp;
33 int g_num_vtp_cons;
34
35 int add_vtp_con(RawEthernetPacket * pkt, unsigned long seq_num);
36 int find_vtp_con(RawEthernetPacket * pkt);
37 int find_remote_vtp_con(RawEthernetPacket * pkt);
38
39 /* Packet Handlers */
40 int handle_fifo_pkt(RawEthernetPacket * pkt, struct in_addr  server_addr);
41 int handle_tcp_pkt(RawEthernetPacket * pkt, struct in_addr  server_addr);
42 int handle_rem_tcp_pkt(RawEthernetPacket * pkt);
43 int handle_control_pkt(RawEthernetPacket * pkt, struct in_addr  server_addr);
44 int handle_config_pkt(RawEthernetPacket * pkt);
45
46 /* Packet functions */
47 int make_ack_pkt(RawEthernetPacket * pkt, int vcon_i);
48 int init_ack_template(RawEthernetPacket * pkt);
49
50
51 int main(int argc, char ** argv) {
52
53   fd_set all_set, rset;
54   int maxfd = 0;
55   int conns;
56   timeval timeout;
57   timeval * tm_ptr;
58   RawEthernetPacket pkt;
59   RawEthernetPacket * recv_pkts;
60   int vtp_socket;
61   int i = 0;
62
63   debug_init("/tmp/vtp.1");
64
65   JRLDBG("Starting VTP Daemon\n");
66
67   for (i = 0; i < MAX_VTP_CONS; i++) {
68     g_vtp_cons[i].rem_seq_num = 0;
69     g_vtp_cons[i].dest_ip = 0;
70     g_vtp_cons[i].src_ip = 0;
71     g_vtp_cons[i].src_port = 0;
72     g_vtp_cons[i].dest_port = 0;
73     g_vtp_cons[i].tcp_timestamp = 0;
74     g_vtp_cons[i].in_use = false;
75     g_vtp_cons[i].next = -1;
76     g_vtp_cons[i].prev = -1;
77   }
78
79   g_last_vtp = -1;
80   g_first_vtp = -1;
81
82   g_num_vtp_cons = 0;
83
84   vtp_in_fd = open(VTP_FIFO_RECVFILE, O_WRONLY);
85   JRLDBG("Opened RECVFILE pipe\n");
86
87   vtp_out_fd = open(VTP_FIFO_SENDFILE, O_RDONLY);
88   JRLDBG("Opened SENDFILE pipe\n");
89
90
91   if ((vtp_socket = vtp_init()) < 0) {
92     JRLDBG("VTP Transport Layer failed to initialize\n");
93     exit(-1);
94   }
95
96   FD_ZERO(&all_set);
97   FD_SET(vtp_out_fd, &all_set);
98
99   if (vtp_socket > 0) {
100     FD_SET(vtp_socket, &all_set);
101   
102     maxfd = (vtp_out_fd > vtp_socket) ? vtp_out_fd : vtp_socket ;
103
104     // block indefinately, because we have all the socks in the FDSET
105     tm_ptr = NULL;
106   } else {  
107     timeout.tv_sec = 0;
108     timeout.tv_usec = 0;
109     
110     tm_ptr = &timeout;
111   }
112
113
114   while(1) {
115     int n_pkts_recvd = 0;
116     rset = all_set;
117
118     conns = select(maxfd + 1, &rset, NULL, NULL, tm_ptr);
119     if ((conns > 0) && (FD_ISSET(vtp_out_fd, &rset))) {
120       struct in_addr server_addr;
121       JRLDBG("Reception on vtp_out_fd\n");
122       // we got a packet on the FIFO
123       if (pkt.VtpUnserialize(vtp_out_fd, &server_addr) <= 0) {
124         JRLDBG("VNET Connection has closed. We are exiting\n");
125         exit(0);
126       }
127       handle_fifo_pkt(&pkt, server_addr);
128     }
129
130     //JRLDBG("Calling VTP Receive routine\n");
131     if ((vtp_socket == 0) || ((conns > 0) && (vtp_socket > 0) && FD_ISSET(vtp_socket, &rset))) {
132       if ((n_pkts_recvd = vtp_recv(&recv_pkts)) > 0) {
133         int i = 0;
134         struct in_addr tmp;
135         JRLDBG("Receive returned %d packets\n", n_pkts_recvd);
136         
137         for (i = 0; i < n_pkts_recvd; i++) {
138
139           if (is_tcp_pkt(&(recv_pkts[i])) == 1) {
140             JRLDBG("Received a TCP packet\n");
141             if (g_do_local_ack == 1) {
142               handle_rem_tcp_pkt(&(recv_pkts[i]));
143             }
144           }
145
146           JRLDBG("Serializing packet %d to VNET\n", i);
147           recv_pkts[i].VtpSerialize(vtp_in_fd, &tmp);
148           usleep(50000);
149         }
150         
151         //delete recv_pkts;
152       }
153     }
154   }
155
156   fclose(logfile);
157   close(vtp_in_fd);
158   close(vtp_out_fd);
159
160   return(0);
161 }
162
163 int handle_fifo_pkt(RawEthernetPacket * pkt, struct in_addr  server_addr) {
164   JRLDBG("Received a packet\n");
165   //  if (strncmp(pkt->type,"et",2) == 0) {
166   if ((pkt->type[0] == 'e') && (pkt->type[1] == 't')) {
167     JRLDBG("Packet is Ethernet\n");
168     if (is_tcp_pkt(pkt) == 0) {
169       JRLDBG("Packet is a non-TCP Packet\n");
170       vtp_send(pkt, server_addr);
171     } else {
172       JRLDBG("Packet is a TCP Packet\n");
173       handle_tcp_pkt(pkt, server_addr);
174     }
175
176   } else if (strncmp(pkt->type,"lc",2) == 0) {
177     JRLDBG("Packet is a Link Control Packet\n");
178     handle_control_pkt(pkt, server_addr);
179   } else if (strncmp(pkt->type, "cf", 2) == 0) {
180     JRLDBG("Packet is a Configuration packet\n");
181     handle_config_pkt(pkt);
182   }
183   return 0;
184 }
185
186
187 int handle_config_pkt(RawEthernetPacket * pkt) {
188
189   return 0;
190 }
191
192
193 int handle_control_pkt(RawEthernetPacket* pkt, struct in_addr  server_addr) {
194   if (strncmp(pkt->data,"con",3) == 0) {
195     struct in_addr con_addr;
196     unsigned short con_port = 0;
197     unsigned int offset = 3;
198 #ifdef DEBUG
199     char ip[256];
200     do_binary_to_string((unsigned char*)(&server_addr),ip);
201     JRLDBG("Control Message: Connect to %s\n", ip);
202 #endif
203     memcpy(&con_addr, pkt->data + offset,sizeof(struct in_addr));
204     offset += sizeof(struct in_addr);
205     con_port = *((unsigned short *)(pkt->data + offset));
206
207     vtp_connect(con_addr, con_port);
208   } else if (strncmp(pkt->data, "gwc", 3) == 0) {
209     struct in_addr con_addr;
210     unsigned short con_port;
211     unsigned int offset = 3;
212
213     memcpy(&con_addr, pkt->data + offset, sizeof(struct in_addr));
214     offset += sizeof(struct in_addr);
215     con_port = *((unsigned short *)(pkt->data + offset));
216
217     vtp_connect(con_addr, con_port);
218
219   } else if (strncmp(pkt->data, "stop", 4) == 0) {
220     exit(0);
221   }
222
223   return 0;
224 }
225
226
227 int handle_tcp_pkt(RawEthernetPacket *pkt, struct in_addr  server_addr) {
228
229   if (g_do_local_ack == 1) {
230     unsigned short ip_pkt_len = 0;
231     // unsigned char ip_hdr_len = (*(pkt->data + ETH_HDR_LEN) & 0x0f) << 2;
232     unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
233     unsigned short * ip_pkt_len_ptr = (unsigned short *)(pkt->data + ETH_HDR_LEN + 2); 
234     ip_pkt_len = ntohs(*ip_pkt_len_ptr);
235     
236     JRLDBG("IP Header Length = %d(%x)\n", ip_hdr_len, *(pkt->data + ETH_HDR_LEN));
237     JRLDBG("IP Packet Length = %hu\n", ip_pkt_len);
238     
239     if (is_syn_pkt(pkt) == 0) {
240       // we don't mess with connection establishment
241       int vcon_i;
242       unsigned long  payload_len = 0;
243       unsigned short tcp_hdr_len = 0;
244       struct in_addr tmp;
245       
246       
247       tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
248       payload_len = ip_pkt_len  - (ip_hdr_len + tcp_hdr_len);
249       
250       if ((payload_len == 0) && (is_ack_pkt(pkt) == 1)) {
251         // we just kill empty acks. 
252         //return 0;
253       }
254       
255       vcon_i = find_remote_vtp_con(pkt);
256       
257       // Create ACK and send it.
258       make_ack_pkt(pkt, vcon_i);
259       
260       g_vtp_cons[vcon_i].ack_template.VtpSerialize(vtp_in_fd, &tmp);
261       
262     } else {
263       if(is_ack_pkt(pkt) == 1) {
264         int vcon_i = find_remote_vtp_con(pkt);
265         struct in_addr tmp;
266         make_ack_pkt(pkt, vcon_i);
267         
268         g_vtp_cons[vcon_i].ack_template.VtpSerialize(vtp_in_fd, &tmp);
269       }
270 #ifdef DEBUG 
271       unsigned long * seq_num_ptr ;
272       unsigned long seq_num = 0;
273       unsigned long  payload_len = 0;
274       unsigned short tcp_hdr_len = 0;
275       unsigned long ack = 0;
276       
277       JRLDBG("Packet is a Syn Packet\n");
278       
279       seq_num_ptr = (unsigned long *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 4);
280       seq_num = ntohl(*seq_num_ptr);
281       JRLDBG("Sequence Number = %lu\n", seq_num);
282       
283       tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
284       payload_len = ip_pkt_len  - (ip_hdr_len + tcp_hdr_len);
285       
286       JRLDBG("TCP Header Length = %hu\n", tcp_hdr_len);
287       JRLDBG("Payload Length = %lu\n", payload_len);
288       
289       
290       
291       ack = (payload_len > 0) ? (seq_num + payload_len) : (seq_num + 1);
292       JRLDBG("Ack Num = %lu\n", ack);
293 #endif
294     }
295
296   }
297
298   vtp_send(pkt, server_addr);
299
300   return 0;
301 }
302
303 int handle_rem_tcp_pkt(RawEthernetPacket * pkt) {
304   unsigned long * seq_num_ptr;
305   unsigned long seq_num;
306   unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
307   
308   seq_num_ptr = (unsigned long *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 4);
309   seq_num = ntohl(*seq_num_ptr);
310   JRLDBG("Received Packet, SeqNum = %lu\n", seq_num);
311
312   if (is_syn_pkt(pkt) == 1) {
313     // syn packet
314     seq_num++;
315     add_vtp_con(pkt, seq_num);
316     JRLDBG("Received Syn Packet, SeqNum = %lu\n", seq_num);
317   } else {
318     unsigned short ip_pkt_len = 0;
319     unsigned short * ip_pkt_len_ptr = (unsigned short *)(pkt->data + ETH_HDR_LEN + 2); 
320     unsigned long  payload_len = 0;
321     unsigned short tcp_hdr_len = 0;
322     int i_vcon = find_vtp_con(pkt);
323     
324     ip_pkt_len = ntohs(*ip_pkt_len_ptr);
325
326     tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
327
328     if (tcp_hdr_len > 20) {
329       unsigned long ts = get_tcp_timestamp(pkt->data + ETH_HDR_LEN + ip_hdr_len + 20, tcp_hdr_len - 20);
330       JRLDBG("TCP Timestamp = %lu(%lu)\n", ts, (unsigned long)ntohl(ts));
331       g_vtp_cons[i_vcon].tcp_timestamp = ts;
332     }
333
334     payload_len = ip_pkt_len  - (ip_hdr_len + tcp_hdr_len);
335     seq_num += payload_len;
336     JRLDBG("Received Data Packet, SeqNum = %lu\n", seq_num);
337     g_vtp_cons[i_vcon].rem_seq_num = seq_num;
338     JRLDBG("Remote Sequence Number (con: %d) = %lu\n", i_vcon, seq_num);
339
340 #if 0
341     {
342       int offset = 0;
343       unsigned short tcp_cksum = 0;
344       // Zero Ack Field
345       *(unsigned long *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 8) = 0;
346       
347       // Zero Ack Flag
348       offset = ETH_HDR_LEN + ip_hdr_len + 13;
349       *(pkt->data + offset) &= 0xef;
350       
351       // Zero TCP chksum
352       *(unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 16) = 0;
353       
354       // Get TCP chksum
355       tcp_cksum = get_tcp_checksum(pkt, ip_pkt_len - ip_hdr_len);
356       
357       // Set TCP chksum
358       *(unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 16) = tcp_cksum;
359     }
360 #endif 
361
362
363   }
364   return 0;
365 }
366
367
368
369 int make_ack_pkt(RawEthernetPacket * pkt, int vcon_i) {
370   unsigned long * seq_num_ptr ;
371   unsigned long seq_num = 0;
372   unsigned long rem_seq_num = 0;
373   unsigned long  payload_len = 0;
374   unsigned short tcp_hdr_len = 0;
375   unsigned long ack = 0;
376   unsigned long local_ts = 0;
377   unsigned short tcp_cksum = 0;
378   unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
379   unsigned short ip_pkt_len = *(unsigned short *)(pkt->data + ETH_HDR_LEN + 2);
380   RawEthernetPacket * ack_pkt = &(g_vtp_cons[vcon_i].ack_template);
381   unsigned short ack_ip_pkt_len = *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + 2);
382   unsigned char ack_ip_hdr_len = IP_HDR_LEN(ack_pkt->data);
383
384   ip_pkt_len = ntohs(ip_pkt_len);
385   ack_ip_pkt_len = ntohs(ack_ip_pkt_len);
386
387   seq_num_ptr = (unsigned long *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 4);
388   seq_num = ntohl(*seq_num_ptr);
389   JRLDBG("Sequence Number = %lu\n", seq_num);
390
391   tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
392
393   if (is_syn_pkt(pkt) == 1) {
394     ack = seq_num + 1;
395   } else {    
396     payload_len = ip_pkt_len  - (ip_hdr_len + tcp_hdr_len);
397     
398     JRLDBG("TCP Header Length = %hu\n", tcp_hdr_len);
399     JRLDBG("Payload Length = %lu\n", payload_len);
400     
401     ack = seq_num + payload_len;
402     JRLDBG("Ack Num = %lu\n", ack);
403   }
404
405   // Set IP id 
406   g_vtp_cons[vcon_i].ip_id--;
407   *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + 4) = htons(g_vtp_cons[vcon_i].ip_id);
408
409   // Recompute IP checksum
410   *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + 10) = 0;
411   *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + 10) = get_ip_checksum(ack_pkt);
412
413   //return 0;
414   // Set Sequence Number
415   rem_seq_num = htonl(g_vtp_cons[vcon_i].rem_seq_num);
416   *(unsigned long *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 4) = rem_seq_num;
417  
418   // Set ACK Number
419   ack = htonl(ack);
420   *(unsigned long *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 8) = ack;
421
422   // Set TCP Timestamp option
423   local_ts = get_tcp_timestamp(pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 20, tcp_hdr_len - 20);
424
425   /* We use this for debugging:
426    * If the TCPDump trace shows timestamps with the value of '5' then they are our packets
427    */
428   
429   *(unsigned long *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 24) = g_vtp_cons[vcon_i].tcp_timestamp;
430   //*(unsigned long *)(ack_pkt->data + ETH_HDR_LEN + ip_hdr_len + 24) = htonl(5);
431
432
433   *(unsigned long *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 28) = local_ts;
434
435   // Zero TCP chksum
436   *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 16) = 0;
437
438   // Get TCP chksum
439   tcp_cksum = get_tcp_checksum(ack_pkt, ack_ip_pkt_len - ack_ip_hdr_len);
440
441   // Set TCP chksum
442   *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 16) = tcp_cksum;
443
444   return 0;
445 }
446
447
448
449
450
451 /* Connection List Handling */
452
453 int find_vtp_con(RawEthernetPacket * pkt) {
454   int index = -1;
455   int i = 0;
456   unsigned long * src_addr;
457   unsigned long * dest_addr;
458   unsigned short * src_port;
459   unsigned short * dest_port;
460   unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
461
462   src_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 12);
463   dest_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 16);
464   src_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len);
465   dest_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 2);
466
467   //  for (i = 0; i < MAX_CONS; i++) {
468   FOREACH_VTP_CON(i,g_vtp_cons) {
469     if ((g_vtp_cons[i].dest_ip == *dest_addr) && (g_vtp_cons[i].src_ip == *src_addr) &&
470         (g_vtp_cons[i].dest_port = *dest_port) && (g_vtp_cons[i].src_port == *src_port)) {
471       index = i;
472       break;
473     }
474   }
475   return index;
476 }
477
478
479 /* An received packet has the header fields reversed wrt src/dest
480  * So we have to be able to index remote packets as well
481  */
482 int find_remote_vtp_con(RawEthernetPacket * pkt) {
483   int index = -1;
484   int i = 0;
485   unsigned long * src_addr;
486   unsigned long * dest_addr;
487   unsigned short * src_port;
488   unsigned short * dest_port;
489   unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
490
491   src_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 12);
492   dest_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 16);
493   src_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len);
494   dest_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 2);
495
496   //  for (i = 0; i < MAX_CONS; i++) {
497   FOREACH_VTP_CON(i,g_vtp_cons) {
498     if ((g_vtp_cons[i].src_ip == *dest_addr) && (g_vtp_cons[i].dest_ip == *src_addr) &&
499         (g_vtp_cons[i].src_port = *dest_port) && (g_vtp_cons[i].dest_port == *src_port)) {
500       index = i;
501       break;
502     }
503   }
504   return index;
505 }
506
507
508 int add_vtp_con(RawEthernetPacket * pkt, unsigned long seq_num) {
509   int i;
510   unsigned long * src_addr;
511   unsigned long * dest_addr;
512   unsigned short * src_port;
513   unsigned short * dest_port;
514   unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
515   unsigned short tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
516
517   src_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 12);
518   dest_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 16);
519   src_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len);
520   dest_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 2);
521   
522   for (i = 0; i < MAX_VTP_CONS; i++) {
523     if (!(g_vtp_cons[i].in_use)) {
524       JRLDBG("Adding connection in slot %d\n", i);
525       g_vtp_cons[i].rem_seq_num = seq_num;
526       
527       // ADD PACKET CONNECTION INFO
528       g_vtp_cons[i].dest_ip = *dest_addr;
529       g_vtp_cons[i].src_ip = *src_addr;
530       g_vtp_cons[i].src_port = *src_port;
531       g_vtp_cons[i].dest_port = *dest_port;
532       g_vtp_cons[i].ack_template = *pkt;
533       g_vtp_cons[i].ip_id = ntohs(*(unsigned short *)(pkt->data + ETH_HDR_LEN + 4));
534         
535       init_ack_template(&(g_vtp_cons[i].ack_template));
536
537       if (tcp_hdr_len > 20) {
538         unsigned long ts = get_tcp_timestamp(pkt->data + ETH_HDR_LEN + ip_hdr_len + 20, tcp_hdr_len - 20);
539         JRLDBG("TCP Timestamp = %lu(%lu)\n", ts, (unsigned long)ntohl(ts));
540         g_vtp_cons[i].tcp_timestamp = ts;
541       }
542       
543       g_vtp_cons[i].in_use = true;
544       
545       if (g_first_vtp == -1)
546         g_first_vtp = i;
547
548       g_vtp_cons[i].prev = g_last_vtp;
549       g_vtp_cons[i].next = -1;
550
551       if (g_last_vtp != -1) {
552         g_vtp_cons[g_last_vtp].next = i;
553       }
554       
555       g_last_vtp = i;
556
557       g_num_vtp_cons++;
558       return 0;
559     }
560   }
561   return -1;
562 }
563
564
565 int init_ack_template(RawEthernetPacket * pkt) {
566   // We assume here that the ethernet and ip headers are ok, except for ip pkt length
567   // TCP is mostly right because its pulled off of a syn packet
568   // we need to zero the data, and reset the syn flag.
569
570   unsigned short IP_PACKET_LEN = 52;
571   unsigned short TCP_HEADER_LEN = 32;
572   unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
573   unsigned short ip_pkt_len = 0;
574   unsigned short tcp_hdr_len = 0;
575   unsigned short payload_len = 0;
576   unsigned short * ip_pkt_len_ptr = (unsigned short *)(pkt->data + ETH_HDR_LEN + 2); 
577   unsigned int offset = 0;
578   unsigned short ip_chksum = 0;
579
580   JRLDBG("--> Initializing ACK Template <--\n");
581
582   ip_pkt_len = ntohs(*ip_pkt_len_ptr);
583   JRLDBG("ip_pkt_len = %hu\n", ip_pkt_len);
584   
585   tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
586   payload_len = ip_pkt_len  - (ip_hdr_len + tcp_hdr_len);
587   JRLDBG("tcp_hdr_len = %hu\n", tcp_hdr_len);
588   JRLDBG("payload_len = %hu\n", payload_len);
589
590   // set only the ack flags
591   offset = ETH_HDR_LEN + ip_hdr_len + 13;
592   *(pkt->data + offset)  |= 0x10;
593   *(pkt->data + offset)  &= 0xd0;
594
595   // set up tcp options
596   offset = ETH_HDR_LEN + ip_hdr_len + 20;
597   *(pkt->data + offset) = 0x01;
598   offset++;
599   *(pkt->data + offset) = 0x01;
600   offset++;
601   *(pkt->data + offset) = 0x08;
602   offset++;
603   *(pkt->data + offset) = 0x0a;
604
605   // Set Header Lengths
606   // IP HEADER = 20 (same)
607   // IP PACKET LEN = 52
608   // TCP Header len = 32
609   
610   ip_pkt_len = htons(IP_PACKET_LEN);
611   memcpy(pkt->data + ETH_HDR_LEN + 2, &ip_pkt_len, 2);
612   tcp_hdr_len = (TCP_HEADER_LEN << 2);
613   *(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) &= 0x0f;
614   *(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) |= tcp_hdr_len;
615
616   JRLDBG("Setting TEMPLATE TCPLEN = %2x\n", *(pkt->data + ETH_HDR_LEN +ip_hdr_len + 12));
617
618   // Set IP Header chksum
619   *(unsigned short *)(pkt->data + ETH_HDR_LEN + 10) = 0;
620   ip_chksum = get_ip_checksum(pkt);
621   *(unsigned short *)(pkt->data + ETH_HDR_LEN + 10) = ip_chksum;
622
623
624   // Set RawEthernetPacket size
625   pkt->set_size(IP_PACKET_LEN + ETH_HDR_LEN);
626   pkt->set_type("et");
627
628   JRLDBG("--> ACK Template Initialized <--\n");
629
630
631   return 0;
632 }
633