Click here to Skip to main content
15,887,083 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello Guys,
I am trying to find out checksum of TCP over IPV6. Please see the below cod

What I have tried:

char src_addr[] = {
  0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xa1, 0xe4, 0x22, 0x2c, 0x0c, 0x9b, 0x57, 0x22
};

char dest_addr[] = {
  0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x18, 0xd7, 0xc9, 0x57, 0x52, 0xd7, 0x0f, 0xcd
};

_inline unsigned short TOWORD(unsigned int a)
{
    return (unsigned short)( ((a>>8)&0x00FFL) + ((a<<8)&0xFF00L) );
}


int _tmain(int argc, _TCHAR* argv[])
{
	unsigned int sum=0;

	for(int i = 0; i < 8; i++)
	{
		sum += *((unsigned short*)(src_addr+i));
	}

	for(int i = 0; i < 8; i++)
	{
		sum += *(((unsigned short*)dest_addr+i));
	}
	
	unsigned short type = 0x06; // TCP protocol
	sum += TOWORD(type);

	unsigned int tcplen = 0x1c; // 28 bytes length

	sum += ((tcplen <<8) & 0xFFFF) + (tcplen >> 8);

	sum = (sum>>16)+(sum&0xffff);
	sum += (sum>>16);

	sum = (~sum & 0xFFFF);
	unsigned short sum1 =  sum;

	printf("Checksum = %x\n", sum1);
	return 0;
}


gives output of 3a96.

However WireShak shows checksum of 0x3c3b.

Can you please help?
Posted
Updated 24-Jan-18 8:07am

This is obviously wrong and a fine example why casting can be unsafe:
for(int i = 0; i < 8; i++)
{
    sum += *((unsigned short*)(src_addr+i));
}

You are casting a char pointer to unsigned short*. While this might be used, you forgot at least that you have to increment the pointer by two then.

I don't know about the byte order in this case, so a possible solution might be one of these:
for(int i = 0; i < 16; i += 2)
{
    sum += src_addr[i] + (src_addr[i+1] << 8U);
    // Or this (EDIT: I guess this is it)
    sum += (src_addr[i] << 8U) + src_addr[i+1];
}

[EDIT]
There may be also other errors and/or a wrong implementation. The IPv6 TCP checksum is generated on the TCP header, the pseudo header, and the data.
Your code calculates the checksum for the pseudo header. I don't know which checksum is reported by WireShark but would expect that it is the complete one.
[/EDIT]
 
Share this answer
 
v3
Tried below code as per above suggestion.

char src_addr[] = {
  0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xa1, 0xe4, 0x22, 0x2c, 0x0c, 0x9b, 0x57, 0x22
};

char dest_addr[] = {
  0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x18, 0xd7, 0xc9, 0x57, 0x52, 0xd7, 0x0f, 0xcd
};


_inline unsigned short TOWORD(unsigned int a)
{
    return (unsigned short)( ((a>>8)&0x00FFL) + ((a<<8)&0xFF00L) );
}


int _tmain(int argc, _TCHAR* argv[])
{
	unsigned int sum=0;

	for(int i = 0; i < 16; i += 2)
	{
		sum += src_addr[i] + (src_addr[i+1] << 8U);
	}

	for(int i = 0; i < 16; i += 2)
	{
		sum += dest_addr[i] + (dest_addr[i+1] << 8U);
	}

	
	unsigned short type = 0x06; // TCP protocol
	sum += TOWORD(type);

	unsigned int tcplen = 0x1c; // 28 bytes length
	sum += ((tcplen <<8) & 0xFFFF) + (tcplen >> 8);

	sum = (sum>>16)+(sum&0xffff);
	sum += (sum>>16);

	sum = (~sum & 0xFFFF);
	unsigned short sum1 =  sum;

	printf("Checksum = %x\n", sum1);
	return 0;
}


results into checksum of 3e9c
 
Share this answer
 
The TCP header + data was missing. Thanks Jochen.
 
Share this answer
 
Comments
Member 13641570 24-Jan-18 14:08pm    
Share the code that worked for you?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900