I'm working on an Ubuntu box in C.
The checksum calculation code is as follows:
unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
for(sum=0; nwords>0; nwords=nwords-2){
sum += *buf;
//printf("%04x\n", *buf);
buf++;
}
if(nwords>0)
sum += *buf++;
while(sum >> 16)
sum = (sum >> 16) + (sum &0xffff);
/* sum += (sum >> 16);*/
return (unsigned short)(~sum);
}
This has been working fine for IP and ICMP segments, though, so I highly doubt this is the problem.
In an attempt to discern the problem, I am currently capturing random packets, constructing the pseudo header + deepcopy of the tcp header portion, then printing out the original checksum and calculated checksum.
struct tcphdr *tcph = (struct tcphdr *)(buffer + sizeof(struct ethhdr) + iphdrlen);
int tcphdrlen = size - sizeof(struct ethhdr) - iphdrlen;
int pseudo_len = sizeof(iph->saddr) + sizeof(iph->daddr) + 1 + sizeof(iph->protocol) + 2 + tcphdrlen;
test = (u_char *) malloc(pseudo_len);
memset(test, 0, pseudo_len);
memcpy(test, &(iph->saddr), sizeof(iph->saddr));
int pos = sizeof(iph->saddr);
memcpy(test + pos, &(iph->daddr), sizeof(iph->daddr));
pos += sizeof(iph->daddr);
memset(test + pos, 0, 1);
pos += 1;
memcpy(test + pos, &(iph->protocol), sizeof(iph->protocol));
int tcphdrlenhtons = htons(tcphdrlen);
pos += sizeof(iph->protocol);
memcpy(test + pos, &tcphdrlenhtons, 2);
pos += 2;
memcpy(test + pos, tcph, tcphdrlen);
struct tcphdr *t_tcph = (struct tcphdr *)(test + pos);
memset(&(t_tcph->check), 0, sizeof(t_tcph->check));
printf("correct tcp checksum: %d\n", ntohs(tcph->check));
printf("my tcp checksum: %d\n", ntohs((unsigned short) csum((unsigned short *)test, pseudo_len)));
In testing, I've found that the calculated checksum will be correct, but only if the packet had no payload.
If anyone could give me an idea what I might be doing wrong, I'd appreciate it.