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
diff --git a/misc/network_servers/vtl/test/vtl_harness.cc b/misc/network_servers/vtl/test/vtl_harness.cc
new file mode 100755 (executable)
index 0000000..6125b45
--- /dev/null
@@ -0,0 +1,633 @@
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef linux
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#endif
+
+#include "vtl_harness.h"
+
+DEBUG_DECLARE();
+
+
+#define F_NONE 0
+#define F_LOCAL_ACK 1
+
+unsigned short g_fflags;
+
+
+int g_do_local_ack = 0;
+/* IP Address utility functions */
+
+
+
+/* Global Pipe Descriptors */
+int vtp_in_fd, vtp_out_fd;
+
+
+/* Connection List Handling */
+struct VTP_CON g_vtp_cons[MAX_VTP_CONS];
+int g_first_vtp;
+int g_last_vtp;
+int g_num_vtp_cons;
+
+int add_vtp_con(RawEthernetPacket * pkt, unsigned long seq_num);
+int find_vtp_con(RawEthernetPacket * pkt);
+int find_remote_vtp_con(RawEthernetPacket * pkt);
+
+/* Packet Handlers */
+int handle_fifo_pkt(RawEthernetPacket * pkt, struct in_addr  server_addr);
+int handle_tcp_pkt(RawEthernetPacket * pkt, struct in_addr  server_addr);
+int handle_rem_tcp_pkt(RawEthernetPacket * pkt);
+int handle_control_pkt(RawEthernetPacket * pkt, struct in_addr  server_addr);
+int handle_config_pkt(RawEthernetPacket * pkt);
+
+/* Packet functions */
+int make_ack_pkt(RawEthernetPacket * pkt, int vcon_i);
+int init_ack_template(RawEthernetPacket * pkt);
+
+
+int main(int argc, char ** argv) {
+
+  fd_set all_set, rset;
+  int maxfd = 0;
+  int conns;
+  timeval timeout;
+  timeval * tm_ptr;
+  RawEthernetPacket pkt;
+  RawEthernetPacket * recv_pkts;
+  int vtp_socket;
+  int i = 0;
+
+  debug_init("/tmp/vtp.1");
+
+  JRLDBG("Starting VTP Daemon\n");
+
+  for (i = 0; i < MAX_VTP_CONS; i++) {
+    g_vtp_cons[i].rem_seq_num = 0;
+    g_vtp_cons[i].dest_ip = 0;
+    g_vtp_cons[i].src_ip = 0;
+    g_vtp_cons[i].src_port = 0;
+    g_vtp_cons[i].dest_port = 0;
+    g_vtp_cons[i].tcp_timestamp = 0;
+    g_vtp_cons[i].in_use = false;
+    g_vtp_cons[i].next = -1;
+    g_vtp_cons[i].prev = -1;
+  }
+
+  g_last_vtp = -1;
+  g_first_vtp = -1;
+
+  g_num_vtp_cons = 0;
+
+  vtp_in_fd = open(VTP_FIFO_RECVFILE, O_WRONLY);
+  JRLDBG("Opened RECVFILE pipe\n");
+
+  vtp_out_fd = open(VTP_FIFO_SENDFILE, O_RDONLY);
+  JRLDBG("Opened SENDFILE pipe\n");
+
+
+  if ((vtp_socket = vtp_init()) < 0) {
+    JRLDBG("VTP Transport Layer failed to initialize\n");
+    exit(-1);
+  }
+
+  FD_ZERO(&all_set);
+  FD_SET(vtp_out_fd, &all_set);
+
+  if (vtp_socket > 0) {
+    FD_SET(vtp_socket, &all_set);
+  
+    maxfd = (vtp_out_fd > vtp_socket) ? vtp_out_fd : vtp_socket ;
+
+    // block indefinately, because we have all the socks in the FDSET
+    tm_ptr = NULL;
+  } else {  
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+    
+    tm_ptr = &timeout;
+  }
+
+
+  while(1) {
+    int n_pkts_recvd = 0;
+    rset = all_set;
+
+    conns = select(maxfd + 1, &rset, NULL, NULL, tm_ptr);
+    if ((conns > 0) && (FD_ISSET(vtp_out_fd, &rset))) {
+      struct in_addr server_addr;
+      JRLDBG("Reception on vtp_out_fd\n");
+      // we got a packet on the FIFO
+      if (pkt.VtpUnserialize(vtp_out_fd, &server_addr) <= 0) {
+       JRLDBG("VNET Connection has closed. We are exiting\n");
+       exit(0);
+      }
+      handle_fifo_pkt(&pkt, server_addr);
+    }
+
+    //JRLDBG("Calling VTP Receive routine\n");
+    if ((vtp_socket == 0) || ((conns > 0) && (vtp_socket > 0) && FD_ISSET(vtp_socket, &rset))) {
+      if ((n_pkts_recvd = vtp_recv(&recv_pkts)) > 0) {
+       int i = 0;
+       struct in_addr tmp;
+       JRLDBG("Receive returned %d packets\n", n_pkts_recvd);
+       
+       for (i = 0; i < n_pkts_recvd; i++) {
+
+         if (is_tcp_pkt(&(recv_pkts[i])) == 1) {
+           JRLDBG("Received a TCP packet\n");
+           if (g_do_local_ack == 1) {
+             handle_rem_tcp_pkt(&(recv_pkts[i]));
+           }
+         }
+
+         JRLDBG("Serializing packet %d to VNET\n", i);
+         recv_pkts[i].VtpSerialize(vtp_in_fd, &tmp);
+         usleep(50000);
+       }
+       
+       //delete recv_pkts;
+      }
+    }
+  }
+
+  fclose(logfile);
+  close(vtp_in_fd);
+  close(vtp_out_fd);
+
+  return(0);
+}
+
+int handle_fifo_pkt(RawEthernetPacket * pkt, struct in_addr  server_addr) {
+  JRLDBG("Received a packet\n");
+  //  if (strncmp(pkt->type,"et",2) == 0) {
+  if ((pkt->type[0] == 'e') && (pkt->type[1] == 't')) {
+    JRLDBG("Packet is Ethernet\n");
+    if (is_tcp_pkt(pkt) == 0) {
+      JRLDBG("Packet is a non-TCP Packet\n");
+      vtp_send(pkt, server_addr);
+    } else {
+      JRLDBG("Packet is a TCP Packet\n");
+      handle_tcp_pkt(pkt, server_addr);
+    }
+
+  } else if (strncmp(pkt->type,"lc",2) == 0) {
+    JRLDBG("Packet is a Link Control Packet\n");
+    handle_control_pkt(pkt, server_addr);
+  } else if (strncmp(pkt->type, "cf", 2) == 0) {
+    JRLDBG("Packet is a Configuration packet\n");
+    handle_config_pkt(pkt);
+  }
+  return 0;
+}
+
+
+int handle_config_pkt(RawEthernetPacket * pkt) {
+
+  return 0;
+}
+
+
+int handle_control_pkt(RawEthernetPacket* pkt, struct in_addr  server_addr) {
+  if (strncmp(pkt->data,"con",3) == 0) {
+    struct in_addr con_addr;
+    unsigned short con_port = 0;
+    unsigned int offset = 3;
+#ifdef DEBUG
+    char ip[256];
+    do_binary_to_string((unsigned char*)(&server_addr),ip);
+    JRLDBG("Control Message: Connect to %s\n", ip);
+#endif
+    memcpy(&con_addr, pkt->data + offset,sizeof(struct in_addr));
+    offset += sizeof(struct in_addr);
+    con_port = *((unsigned short *)(pkt->data + offset));
+
+    vtp_connect(con_addr, con_port);
+  } else if (strncmp(pkt->data, "gwc", 3) == 0) {
+    struct in_addr con_addr;
+    unsigned short con_port;
+    unsigned int offset = 3;
+
+    memcpy(&con_addr, pkt->data + offset, sizeof(struct in_addr));
+    offset += sizeof(struct in_addr);
+    con_port = *((unsigned short *)(pkt->data + offset));
+
+    vtp_connect(con_addr, con_port);
+
+  } else if (strncmp(pkt->data, "stop", 4) == 0) {
+    exit(0);
+  }
+
+  return 0;
+}
+
+
+int handle_tcp_pkt(RawEthernetPacket *pkt, struct in_addr  server_addr) {
+
+  if (g_do_local_ack == 1) {
+    unsigned short ip_pkt_len = 0;
+    // unsigned char ip_hdr_len = (*(pkt->data + ETH_HDR_LEN) & 0x0f) << 2;
+    unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
+    unsigned short * ip_pkt_len_ptr = (unsigned short *)(pkt->data + ETH_HDR_LEN + 2); 
+    ip_pkt_len = ntohs(*ip_pkt_len_ptr);
+    
+    JRLDBG("IP Header Length = %d(%x)\n", ip_hdr_len, *(pkt->data + ETH_HDR_LEN));
+    JRLDBG("IP Packet Length = %hu\n", ip_pkt_len);
+    
+    if (is_syn_pkt(pkt) == 0) {
+      // we don't mess with connection establishment
+      int vcon_i;
+      unsigned long  payload_len = 0;
+      unsigned short tcp_hdr_len = 0;
+      struct in_addr tmp;
+      
+      
+      tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
+      payload_len = ip_pkt_len  - (ip_hdr_len + tcp_hdr_len);
+      
+      if ((payload_len == 0) && (is_ack_pkt(pkt) == 1)) {
+       // we just kill empty acks. 
+       //return 0;
+      }
+      
+      vcon_i = find_remote_vtp_con(pkt);
+      
+      // Create ACK and send it.
+      make_ack_pkt(pkt, vcon_i);
+      
+      g_vtp_cons[vcon_i].ack_template.VtpSerialize(vtp_in_fd, &tmp);
+      
+    } else {
+      if(is_ack_pkt(pkt) == 1) {
+       int vcon_i = find_remote_vtp_con(pkt);
+       struct in_addr tmp;
+       make_ack_pkt(pkt, vcon_i);
+       
+       g_vtp_cons[vcon_i].ack_template.VtpSerialize(vtp_in_fd, &tmp);
+      }
+#ifdef DEBUG 
+      unsigned long * seq_num_ptr ;
+      unsigned long seq_num = 0;
+      unsigned long  payload_len = 0;
+      unsigned short tcp_hdr_len = 0;
+      unsigned long ack = 0;
+      
+      JRLDBG("Packet is a Syn Packet\n");
+      
+      seq_num_ptr = (unsigned long *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 4);
+      seq_num = ntohl(*seq_num_ptr);
+      JRLDBG("Sequence Number = %lu\n", seq_num);
+      
+      tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
+      payload_len = ip_pkt_len  - (ip_hdr_len + tcp_hdr_len);
+      
+      JRLDBG("TCP Header Length = %hu\n", tcp_hdr_len);
+      JRLDBG("Payload Length = %lu\n", payload_len);
+      
+      
+      
+      ack = (payload_len > 0) ? (seq_num + payload_len) : (seq_num + 1);
+      JRLDBG("Ack Num = %lu\n", ack);
+#endif
+    }
+
+  }
+
+  vtp_send(pkt, server_addr);
+
+  return 0;
+}
+
+int handle_rem_tcp_pkt(RawEthernetPacket * pkt) {
+  unsigned long * seq_num_ptr;
+  unsigned long seq_num;
+  unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
+  
+  seq_num_ptr = (unsigned long *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 4);
+  seq_num = ntohl(*seq_num_ptr);
+  JRLDBG("Received Packet, SeqNum = %lu\n", seq_num);
+
+  if (is_syn_pkt(pkt) == 1) {
+    // syn packet
+    seq_num++;
+    add_vtp_con(pkt, seq_num);
+    JRLDBG("Received Syn Packet, SeqNum = %lu\n", seq_num);
+  } else {
+    unsigned short ip_pkt_len = 0;
+    unsigned short * ip_pkt_len_ptr = (unsigned short *)(pkt->data + ETH_HDR_LEN + 2); 
+    unsigned long  payload_len = 0;
+    unsigned short tcp_hdr_len = 0;
+    int i_vcon = find_vtp_con(pkt);
+    
+    ip_pkt_len = ntohs(*ip_pkt_len_ptr);
+
+    tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
+
+    if (tcp_hdr_len > 20) {
+      unsigned long ts = get_tcp_timestamp(pkt->data + ETH_HDR_LEN + ip_hdr_len + 20, tcp_hdr_len - 20);
+      JRLDBG("TCP Timestamp = %lu(%lu)\n", ts, (unsigned long)ntohl(ts));
+      g_vtp_cons[i_vcon].tcp_timestamp = ts;
+    }
+
+    payload_len = ip_pkt_len  - (ip_hdr_len + tcp_hdr_len);
+    seq_num += payload_len;
+    JRLDBG("Received Data Packet, SeqNum = %lu\n", seq_num);
+    g_vtp_cons[i_vcon].rem_seq_num = seq_num;
+    JRLDBG("Remote Sequence Number (con: %d) = %lu\n", i_vcon, seq_num);
+
+#if 0
+    {
+      int offset = 0;
+      unsigned short tcp_cksum = 0;
+      // Zero Ack Field
+      *(unsigned long *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 8) = 0;
+      
+      // Zero Ack Flag
+      offset = ETH_HDR_LEN + ip_hdr_len + 13;
+      *(pkt->data + offset) &= 0xef;
+      
+      // Zero TCP chksum
+      *(unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 16) = 0;
+      
+      // Get TCP chksum
+      tcp_cksum = get_tcp_checksum(pkt, ip_pkt_len - ip_hdr_len);
+      
+      // Set TCP chksum
+      *(unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 16) = tcp_cksum;
+    }
+#endif 
+
+
+  }
+  return 0;
+}
+
+
+
+int make_ack_pkt(RawEthernetPacket * pkt, int vcon_i) {
+  unsigned long * seq_num_ptr ;
+  unsigned long seq_num = 0;
+  unsigned long rem_seq_num = 0;
+  unsigned long  payload_len = 0;
+  unsigned short tcp_hdr_len = 0;
+  unsigned long ack = 0;
+  unsigned long local_ts = 0;
+  unsigned short tcp_cksum = 0;
+  unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
+  unsigned short ip_pkt_len = *(unsigned short *)(pkt->data + ETH_HDR_LEN + 2);
+  RawEthernetPacket * ack_pkt = &(g_vtp_cons[vcon_i].ack_template);
+  unsigned short ack_ip_pkt_len = *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + 2);
+  unsigned char ack_ip_hdr_len = IP_HDR_LEN(ack_pkt->data);
+
+  ip_pkt_len = ntohs(ip_pkt_len);
+  ack_ip_pkt_len = ntohs(ack_ip_pkt_len);
+
+  seq_num_ptr = (unsigned long *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 4);
+  seq_num = ntohl(*seq_num_ptr);
+  JRLDBG("Sequence Number = %lu\n", seq_num);
+
+  tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
+
+  if (is_syn_pkt(pkt) == 1) {
+    ack = seq_num + 1;
+  } else {    
+    payload_len = ip_pkt_len  - (ip_hdr_len + tcp_hdr_len);
+    
+    JRLDBG("TCP Header Length = %hu\n", tcp_hdr_len);
+    JRLDBG("Payload Length = %lu\n", payload_len);
+    
+    ack = seq_num + payload_len;
+    JRLDBG("Ack Num = %lu\n", ack);
+  }
+
+  // Set IP id 
+  g_vtp_cons[vcon_i].ip_id--;
+  *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + 4) = htons(g_vtp_cons[vcon_i].ip_id);
+
+  // Recompute IP checksum
+  *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + 10) = 0;
+  *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + 10) = get_ip_checksum(ack_pkt);
+
+  //return 0;
+  // Set Sequence Number
+  rem_seq_num = htonl(g_vtp_cons[vcon_i].rem_seq_num);
+  *(unsigned long *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 4) = rem_seq_num;
+  // Set ACK Number
+  ack = htonl(ack);
+  *(unsigned long *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 8) = ack;
+
+  // Set TCP Timestamp option
+  local_ts = get_tcp_timestamp(pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 20, tcp_hdr_len - 20);
+
+  /* We use this for debugging:
+   * If the TCPDump trace shows timestamps with the value of '5' then they are our packets
+   */
+  
+  *(unsigned long *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 24) = g_vtp_cons[vcon_i].tcp_timestamp;
+  //*(unsigned long *)(ack_pkt->data + ETH_HDR_LEN + ip_hdr_len + 24) = htonl(5);
+
+
+  *(unsigned long *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 28) = local_ts;
+
+  // Zero TCP chksum
+  *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 16) = 0;
+
+  // Get TCP chksum
+  tcp_cksum = get_tcp_checksum(ack_pkt, ack_ip_pkt_len - ack_ip_hdr_len);
+
+  // Set TCP chksum
+  *(unsigned short *)(ack_pkt->data + ETH_HDR_LEN + ack_ip_hdr_len + 16) = tcp_cksum;
+
+  return 0;
+}
+
+
+
+
+
+/* Connection List Handling */
+
+int find_vtp_con(RawEthernetPacket * pkt) {
+  int index = -1;
+  int i = 0;
+  unsigned long * src_addr;
+  unsigned long * dest_addr;
+  unsigned short * src_port;
+  unsigned short * dest_port;
+  unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
+
+  src_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 12);
+  dest_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 16);
+  src_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len);
+  dest_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 2);
+
+  //  for (i = 0; i < MAX_CONS; i++) {
+  FOREACH_VTP_CON(i,g_vtp_cons) {
+    if ((g_vtp_cons[i].dest_ip == *dest_addr) && (g_vtp_cons[i].src_ip == *src_addr) &&
+       (g_vtp_cons[i].dest_port = *dest_port) && (g_vtp_cons[i].src_port == *src_port)) {
+      index = i;
+      break;
+    }
+  }
+  return index;
+}
+
+
+/* An received packet has the header fields reversed wrt src/dest
+ * So we have to be able to index remote packets as well
+ */
+int find_remote_vtp_con(RawEthernetPacket * pkt) {
+  int index = -1;
+  int i = 0;
+  unsigned long * src_addr;
+  unsigned long * dest_addr;
+  unsigned short * src_port;
+  unsigned short * dest_port;
+  unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
+
+  src_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 12);
+  dest_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 16);
+  src_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len);
+  dest_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 2);
+
+  //  for (i = 0; i < MAX_CONS; i++) {
+  FOREACH_VTP_CON(i,g_vtp_cons) {
+    if ((g_vtp_cons[i].src_ip == *dest_addr) && (g_vtp_cons[i].dest_ip == *src_addr) &&
+       (g_vtp_cons[i].src_port = *dest_port) && (g_vtp_cons[i].dest_port == *src_port)) {
+      index = i;
+      break;
+    }
+  }
+  return index;
+}
+
+
+int add_vtp_con(RawEthernetPacket * pkt, unsigned long seq_num) {
+  int i;
+  unsigned long * src_addr;
+  unsigned long * dest_addr;
+  unsigned short * src_port;
+  unsigned short * dest_port;
+  unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
+  unsigned short tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
+
+  src_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 12);
+  dest_addr = (unsigned long *)(pkt->data + ETH_HDR_LEN + 16);
+  src_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len);
+  dest_port = (unsigned short *)(pkt->data + ETH_HDR_LEN + ip_hdr_len + 2);
+  
+  for (i = 0; i < MAX_VTP_CONS; i++) {
+    if (!(g_vtp_cons[i].in_use)) {
+      JRLDBG("Adding connection in slot %d\n", i);
+      g_vtp_cons[i].rem_seq_num = seq_num;
+      
+      // ADD PACKET CONNECTION INFO
+      g_vtp_cons[i].dest_ip = *dest_addr;
+      g_vtp_cons[i].src_ip = *src_addr;
+      g_vtp_cons[i].src_port = *src_port;
+      g_vtp_cons[i].dest_port = *dest_port;
+      g_vtp_cons[i].ack_template = *pkt;
+      g_vtp_cons[i].ip_id = ntohs(*(unsigned short *)(pkt->data + ETH_HDR_LEN + 4));
+       
+      init_ack_template(&(g_vtp_cons[i].ack_template));
+
+      if (tcp_hdr_len > 20) {
+       unsigned long ts = get_tcp_timestamp(pkt->data + ETH_HDR_LEN + ip_hdr_len + 20, tcp_hdr_len - 20);
+       JRLDBG("TCP Timestamp = %lu(%lu)\n", ts, (unsigned long)ntohl(ts));
+       g_vtp_cons[i].tcp_timestamp = ts;
+      }
+      
+      g_vtp_cons[i].in_use = true;
+      
+      if (g_first_vtp == -1)
+       g_first_vtp = i;
+
+      g_vtp_cons[i].prev = g_last_vtp;
+      g_vtp_cons[i].next = -1;
+
+      if (g_last_vtp != -1) {
+       g_vtp_cons[g_last_vtp].next = i;
+      }
+      
+      g_last_vtp = i;
+
+      g_num_vtp_cons++;
+      return 0;
+    }
+  }
+  return -1;
+}
+
+
+int init_ack_template(RawEthernetPacket * pkt) {
+  // We assume here that the ethernet and ip headers are ok, except for ip pkt length
+  // TCP is mostly right because its pulled off of a syn packet
+  // we need to zero the data, and reset the syn flag.
+
+  unsigned short IP_PACKET_LEN = 52;
+  unsigned short TCP_HEADER_LEN = 32;
+  unsigned char ip_hdr_len = IP_HDR_LEN(pkt->data);
+  unsigned short ip_pkt_len = 0;
+  unsigned short tcp_hdr_len = 0;
+  unsigned short payload_len = 0;
+  unsigned short * ip_pkt_len_ptr = (unsigned short *)(pkt->data + ETH_HDR_LEN + 2); 
+  unsigned int offset = 0;
+  unsigned short ip_chksum = 0;
+
+  JRLDBG("--> Initializing ACK Template <--\n");
+
+  ip_pkt_len = ntohs(*ip_pkt_len_ptr);
+  JRLDBG("ip_pkt_len = %hu\n", ip_pkt_len);
+  
+  tcp_hdr_len = (*(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) & 0xf0) >> 2;
+  payload_len = ip_pkt_len  - (ip_hdr_len + tcp_hdr_len);
+  JRLDBG("tcp_hdr_len = %hu\n", tcp_hdr_len);
+  JRLDBG("payload_len = %hu\n", payload_len);
+
+  // set only the ack flags
+  offset = ETH_HDR_LEN + ip_hdr_len + 13;
+  *(pkt->data + offset)  |= 0x10;
+  *(pkt->data + offset)  &= 0xd0;
+
+  // set up tcp options
+  offset = ETH_HDR_LEN + ip_hdr_len + 20;
+  *(pkt->data + offset) = 0x01;
+  offset++;
+  *(pkt->data + offset) = 0x01;
+  offset++;
+  *(pkt->data + offset) = 0x08;
+  offset++;
+  *(pkt->data + offset) = 0x0a;
+
+  // Set Header Lengths
+  // IP HEADER = 20 (same)
+  // IP PACKET LEN = 52
+  // TCP Header len = 32
+  
+  ip_pkt_len = htons(IP_PACKET_LEN);
+  memcpy(pkt->data + ETH_HDR_LEN + 2, &ip_pkt_len, 2);
+  tcp_hdr_len = (TCP_HEADER_LEN << 2);
+  *(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) &= 0x0f;
+  *(pkt->data + ETH_HDR_LEN + ip_hdr_len + 12) |= tcp_hdr_len;
+
+  JRLDBG("Setting TEMPLATE TCPLEN = %2x\n", *(pkt->data + ETH_HDR_LEN +ip_hdr_len + 12));
+
+  // Set IP Header chksum
+  *(unsigned short *)(pkt->data + ETH_HDR_LEN + 10) = 0;
+  ip_chksum = get_ip_checksum(pkt);
+  *(unsigned short *)(pkt->data + ETH_HDR_LEN + 10) = ip_chksum;
+
+
+  // Set RawEthernetPacket size
+  pkt->set_size(IP_PACKET_LEN + ETH_HDR_LEN);
+  pkt->set_type("et");
+
+  JRLDBG("--> ACK Template Initialized <--\n");
+
+
+  return 0;
+}
+