title: Inserting IPv4 header checksum into dummy IP header
body: <p>I'm trying to create a packet given only the payload content. Therefore, I will have to create dummy IPv4 and UDP headers. I'm having some problem inserting the IPv4 checksum value into the dummy IP header. The checksum value is calculated using the algorithm used by Wireshark. I've only modified the code slightly so I can insert the checksum value into the IP header.</p>
  
  <p>My code is as follows (using Microsoft Visual Studio .NET 2003):</p>
  
  <pre><code>/********************** main.c ***********************/
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;windows.h&gt;
  #include &lt;string.h&gt;
  #include &lt;tchar.h&gt;
  #include &lt;strsafe.h&gt;
  #include "in_cksum.h"
  
  #define SIZE_IP_HDR 20
  
  unsigned char ip_header[] = {0x45, 0x00, 0x05, 0x30, 0x00, 0x00, 0x40, 0x00, 0x20, 0x11, 0x00, 0x00, 0x21, 0x4f, 0x02, 0x7b, 0xcc, 0x5c, 0x46, 0x00};
  
  int main(int argc, char **argv)
  {
      ip_cal_checksum(ip_header, SIZE_IP_HDR);
      ip_header[12] = 0x2d;
      ip_cal_checksum(ip_header, SIZE_IP_HDR);
      return 0;
  }
  
  
  /********************** in_cksum.h ***********************/
  #ifndef IN_CKSUM_H
  #define IN_CKSUM_H
  
  typedef unsigned __int8 uint8_t;
  typedef unsigned __int16 uint16_t;
  typedef unsigned __int32 uint32_t;
  
  typedef struct
  {
      const uint8_t *ptr;
      int len;
  } vec_t;
  
  int in_cksum(const vec_t *vec, int veclen);
  uint16_t calculate_cksum(const vec_t *vec, int veclen);
  void ip_cal_checksum(const uint8_t *ptr, int len);
  
  #endif /* IN_CKSUM_H */
  
  
  /********************** in_cksum.c ***********************/
  #include "in_cksum.h"
  
  #define ADDCARRY(x)  (x &gt; 65535 ? x -= 65535 : x)
  #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
  
  int in_cksum(const vec_t *vec, int veclen)
  {
      register const uint16_t *w;
      register int sum = 0;
      register int mlen = 0;
      int byte_swapped = 0;
  
      union {
          uint8_t c[2];
          uint16_t s;
      } s_util;
      union {
          uint16_t s[2];
          uint32_t l;
      } l_util;
  
      for (; veclen != 0; vec++, veclen--) {
          if (vec-&gt;len == 0)
              continue;
          w = (const uint16_t *)vec-&gt;ptr;
          if (mlen == -1) {
              /*
               * The first byte of this chunk is the continuation
               * of a word spanning between this chunk and the
               * last chunk.
               *
               * s_util.c[0] is already saved when scanning previous
               * chunk.
               */
              s_util.c[1] = *(const uint8_t *)w;
              sum += s_util.s;
              w = (const uint16_t *)((const uint8_t *)w + 1);
              mlen = vec-&gt;len - 1;
          } else
              mlen = vec-&gt;len;
          /*
           * Force to even boundary.
           */
          if ((1 &amp; (unsigned long) w) &amp;&amp; (mlen &gt; 0)) {
              REDUCE;
              sum &lt;&lt;= 8;
              s_util.c[0] = *(const uint8_t *)w;
              w = (const uint16_t *)((const uint8_t *)w + 1);
              mlen--;
              byte_swapped = 1;
          }
          /*
           * Unroll the loop to make overhead from
           * branches &amp;c small.
           */
          while ((mlen -= 32) &gt;= 0) {
              sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
              sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
              sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
              sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
              w += 16;
          }
          mlen += 32;
          while ((mlen -= 8) &gt;= 0) {
              sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
              w += 4;
          }
          mlen += 8;
          if (mlen == 0 &amp;&amp; byte_swapped == 0)
              continue;
          REDUCE;
          while ((mlen -= 2) &gt;= 0) {
              sum += *w++;
          }
          if (byte_swapped) {
              REDUCE;
              sum &lt;&lt;= 8;
              byte_swapped = 0;
              if (mlen == -1) {
                  s_util.c[1] = *(const uint8_t *)w;
                  sum += s_util.s;
                  mlen = 0;
              } else
                  mlen = -1;
          } else if (mlen == -1)
              s_util.c[0] = *(const uint8_t *)w;
      }
      if (mlen == -1) {
          /* The last mbuf has odd # of bytes. Follow the
             standard (the odd byte may be shifted left by 8 bits
             or not as determined by endian-ness of the machine) */
          s_util.c[1] = 0;
          sum += s_util.s;
      }
      REDUCE;
      return (~sum &amp; 0xffff);
  }
  
  uint16_t calculate_cksum(const vec_t *vec, int veclen)
  {
      register const uint16_t *w;
      register int sum = 0;
      register int mlen = 0;
      int byte_swapped = 0;
  
      union {
          uint8_t c[2];
          uint16_t s;
      } s_util;
      union {
          uint16_t s[2];
          uint32_t l;
      } l_util;
  
      for (; veclen != 0; vec++, veclen--) {
          if (vec-&gt;len == 0)
              continue;
          w = (const uint16_t *)vec-&gt;ptr;
          if (mlen == -1) {
              /*
               * The first byte of this chunk is the continuation
               * of a word spanning between this chunk and the
               * last chunk.
               *
               * s_util.c[0] is already saved when scanning previous
               * chunk.
               */
              s_util.c[1] = *(const uint8_t *)w;
              sum += s_util.s;
              w = (const uint16_t *)((const uint8_t *)w + 1);
              mlen = vec-&gt;len - 1;
          } else
              mlen = vec-&gt;len;
          /*
           * Force to even boundary.
           */
          if ((1 &amp; (unsigned long) w) &amp;&amp; (mlen &gt; 0)) {
              REDUCE;
              sum &lt;&lt;= 8;
              s_util.c[0] = *(const uint8_t *)w;
              w = (const uint16_t *)((const uint8_t *)w + 1);
              mlen--;
              byte_swapped = 1;
          }
          /*
           * Unroll the loop to make overhead from
           * branches &amp;c small.
           */
          while ((mlen -= 32) &gt;= 0) {
              sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
              sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
              sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
              sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
              w += 16;
          }
          mlen += 32;
          while ((mlen -= 8) &gt;= 0) {
              sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
              w += 4;
          }
          mlen += 8;
          if (mlen == 0 &amp;&amp; byte_swapped == 0)
              continue;
          REDUCE;
          while ((mlen -= 2) &gt;= 0) {
              sum += *w++;
          }
          if (byte_swapped) {
              REDUCE;
              sum &lt;&lt;= 8;
              byte_swapped = 0;
              if (mlen == -1) {
                  s_util.c[1] = *(const uint8_t *)w;
                  sum += s_util.s;
                  mlen = 0;
              } else
                  mlen = -1;
          } else if (mlen == -1)
              s_util.c[0] = *(const uint8_t *)w;
      }
      if (mlen == -1) {
          /* The last mbuf has odd # of bytes. Follow the
             standard (the odd byte may be shifted left by 8 bits
             or not as determined by endian-ness of the machine) */
          s_util.c[1] = 0;
          sum += s_util.s;
      }
      REDUCE;
      return (~sum &amp; 0xffff);
  }
  
  void ip_cal_checksum(const uint8_t *ptr, int len)
  {
      vec_t cksum_vec[1];
      uint16_t ip_checksum = 0;
  
      cksum_vec[0].ptr = ptr;
      cksum_vec[0].len = len;
      ip_checksum = calculate_cksum(&amp;cksum_vec[0], 1);
      printf("%x\n", ip_checksum);
      memcpy((void *)&amp;ptr[10], &amp;ip_checksum, 2);  // copy checksum value to IP header
  }
  </code></pre>
  
  <p>The code above is a simplified version. In the actual code, I have created the packet with the headers and content and wrote them into a pcap file. Using Wireshark, I then check if the IP checksum is correct, i.e. the same value as that calculated by Wireshark itself. My problem is that without the memcpy line in ip_cal_checksum(), I get the correct checksum values for all the packets created. However, with the memcpy line, only the first checksum is correct, and most, if not all of the other checksum values are wrong.</p>
  
  <p>For example, using the code above, the first calculated checksum value is 0x971f regardless of the presence of the memcpy line. However, the second calculated checksum value is 0x9713 WITHOUT the memcpy line, and 0xfff3 WITH the memcpy.</p>
  
  <p>Why does the checksum value change depending on whether the memcpy line is present, and how can I resolve this?</p>
  
  <p>Thank you.</p>
  
  <p>Regards,
  Rayne</p>