/* set tcp checksum: given IP header and tcp segment */ void compute_tcp_checksum(struct iphdr *pIph, unsigned short *ipPayload) { register unsigned long sum = 0; unsigned short tcpLen = ntohs(pIph->tot_len) - (pIph->ihl << 2); struct tcphdr *tcphdrp = (struct tcphdr *)(ipPayload); //add the pseudo header //the source ip sum += (pIph->saddr >> 16) & 0xFFFF; sum += (pIph->saddr) & 0xFFFF; //the dest ip sum += (pIph->daddr >> 16) & 0xFFFF; sum += (pIph->daddr) & 0xFFFF; //protocol and reserved: 6 sum += htons(IPPROTO_TCP); //the length sum += htons(tcpLen); //add the IP payload //initialize checksum to 0 tcphdrp->check = 0; while (tcpLen > 1) { sum += * ipPayload++; tcpLen -= 2; } //if any bytes left, pad the bytes and add if (tcpLen > 0) { sum += ((*ipPayload)&htons(0xFF00)); } //Fold 32-bit sum to 16 bits: add carrier to result while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); sum = ~sum; //set computation result tcphdrp->check = (unsigned short)sum; }