Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

tcpchecksum calculator

I've written small code for calculating tcp checksum. This is working fine if TCP payload is of even length. But if it is odd length, it is coming 1 less. Can someone help me identifying where the issue(s) is ....

static uint32_t check_sum_step( uint32_t check_sum, const uint16_t new )
{
     uint32_t over_flow;

     check_sum += htons(new);
     while( check_sum & 0xffff0000 )
     {   
          over_flow = check_sum >> 16; 
          check_sum &= 0x0000ffff;
          check_sum += over_flow;
     }   
     return check_sum;
}

uint16_t tcp_udp_check_sum_16_rfc( char const * const begin_ptr, char * const end_ptr, uint8_t *src_ip_8, uint8_t const *dest_ip_8, const uint8_t ip_addr_size_bits, const uint8_t protocol )
{
     uint16_t const * const begin = (uint16_t*)begin_ptr;
     uint16_t const * const end = (uint16_t*)end_ptr;
     uint16_t const * const src_ip_16 = (uint16_t*)src_ip_8;
     uint16_t const * const dest_ip_16 = (uint16_t*)dest_ip_8;
     const uint8_t ip_addr_size_bits_16 = ip_addr_size_bits/16;
     uint16_t const *addr = begin;
     uint32_t check_sum = 0;
     uint16_t i;

     for( i=0; i<ip_addr_size_bits_16; i++ )
     {
          check_sum = check_sum_step( check_sum, src_ip_16[i] );
          check_sum = check_sum_step( check_sum, dest_ip_16[i] );
     }   
     end_ptr[0] = 0;
     for( ; addr<end; addr++ )
     {   
          check_sum = check_sum_step( check_sum, addr[0] );
     }   
     check_sum = check_sum + protocol + ( (uint16_t)( end_ptr - begin_ptr ) );
     check_sum = check_sum_step( check_sum, 0 );
     check_sum = ~check_sum;
     return (uint16_t)check_sum;
}

/*    int main()
    {
    uint8_t src_ipv4_addr[4] = { 192, 168, 10, 11 };
    uint8_t dest_ipv4_addr[4] = { 192, 168, 10, 22 };
    char tcp_hdr_payload[] = { 0xb3, 0xa4, 0x2a, 0xf8, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0xc9, 0x50, 0x10, 0x1b, 0x5d, 0xc4, 0xad, 0x00, 0x00, 0x62, 0x62, 0x62, 0x62, 0x03 };
    uint16_t checksum = tcp_udp_check_sum_16_rfc( tcp_hdr_payload, tcp_hdr_payload+20+5, src_ipv4_addr, dest_ipv4_addr, 32, IPPROTO_TCP );
    printf( "%s %d checksum: %u\n", __func__, __LINE__, checksum );
    }
*/