LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Networking (https://www.linuxquestions.org/questions/linux-networking-3/)
-   -   UDP Checksum Algorithm (https://www.linuxquestions.org/questions/linux-networking-3/udp-checksum-algorithm-845618/)

mattd9 11-21-2010 06:58 AM

UDP Checksum Algorithm
 
I am trying to compute a UDP checksum via what the UDF RFC suggests.
From what I have learned the checksum is on a pseudo header and a combined UDP header and data. Essentially the checksum should cover, where all of the fields are in network/bigendian order:

Pseudo Header:
source(32bits) + dest(32bits) + zeros(8bits) + protocol(8bits) + udplength(16bits)

UDP and Data:
source_port(16bits) + dest_port(16bits) + length(16bits) + zeros(16bits)
+ data(384 bits)

To achieve the checsum I copy the pseudo header and the udp+data into one byte array. I then traverse that byte array in blocks of 4 bytes until I reach the end of the array. I compute as follows:
[I]
unsigned short buffer[sizeof(psedudo) + sizeof(udp_and_data)];

/* The data is copied from pseudo and udp_and_data into buffer */

sum = 0;
for (i=0; i<sizeof(buffer); i+=2)
sum += ~(buffer + buffer[i+1]);

return ~sum;


I return the 1's complement. Unfortunately I have yet to get tcpdump to report this as a valid calculation.

I have tried numerous approaches found online, and even some pieces of the Linux kernel to no avail. Any help would be appreciated.

-Matt

neonsignal 11-21-2010 09:15 PM

Code:

traverse that byte array in blocks of 4 bytes until I reach the end of the array
Presumably you mean blocks of 2 bytes, since it is a 16 bit sum.

Code:

sum += ~(buffer + buffer[i+1]);
You should be adding words (big endian), not bytes. And why the complement operator here?

Code:

return ~sum;
You haven't added back in the carries (the sum is a ones-complement sum; since most languages provide only a twos-complement addition, you have to add the carries back in to emulate a ones-complement sum).

jefro 11-22-2010 03:24 PM

Some nics offload checksum.

mattd9 11-23-2010 07:50 AM

Thanks for all the help. Following is the algorithm I am using on a 64bit x86 machine. I am still not having much luck with it.

Code:

static uint16_t udp_checksum(
    const struct iphdr  *ip,
    const struct udphdr *udp,
    const data_pkt      *foo)
{
    pseudo_hdr ps_hdr = {0};
    uint8_t    data[sizeof(pseudo_hdr) + sizeof(struct udphdr) + sizeof(data_pkt)] = {0};

    ps_hdr.source = ip->saddr;
    ps_hdr.dest = ip->daddr;
    ps_hdr.protocol = IPPROTO_UDP;
    ps_hdr.udp_length = udp->len;

    memcpy(data, &ps_hdr, sizeof(pseudo_hdr));
    memcpy(data + sizeof(pseudo_hdr), udp, sizeof(struct udphdr));
    memcpy(data + sizeof(pseudo_hdr) + sizeof(struct udphdr), ntp, sizeof(data_pkt));

    return csum((uint16_t *)data, sizeof(data)/2);
}

/* Not my code */
unsigned short csum (unsigned short *buf, int nwords)
{
    unsigned long sum;

    for (sum = 0; nwords > 0; nwords--)
        sum += *buf++;

    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return ~sum;
}


neonsignal 11-23-2010 05:21 PM

The checksum code is now valid.

If you are still having problems with the actual packet, then one possibility is that it is an endian issue (because presumably you are working on a little-endian, and the packets have to be constructed big-endian). The endian direction doesn't affect the checksum; the checksum is the same no matter what order the bytes are in (since it just does additions, which are commutative).

The other possibility, being on a 64 bit machine, is that you have alignment issues. It is worth printing out the sizeof values of your structures, just to make sure they are the size you think they are.

What are your structure definitions? Do you have any sample data to compare with?

mattd9 11-24-2010 05:02 AM

Quote:

Originally Posted by neonsignal (Post 4168691)
The checksum code is now valid.

If you are still having problems with the actual packet, then one possibility is that it is an endian issue (because presumably you are working on a little-endian, and the packets have to be constructed big-endian). The endian direction doesn't affect the checksum; the checksum is the same no matter what order the bytes are in (since it just does additions, which are commutative).

The other possibility, being on a 64 bit machine, is that you have alignment issues. It is worth printing out the sizeof values of your structures, just to make sure they are the size you think they are.

What are your structure definitions? Do you have any sample data to compare with?

neonsignal,
Ok, I'm baffled. It now works. Thanks for the positive vibes. I'm in Melbourne too ;-)

-Matt


All times are GMT -5. The time now is 11:21 AM.