I’ve just started on some raw network programming in C++ and have been compiling on my Raspberry Pi itself (no cross-compiling). That makes everything little endian.
After constructing my IP header, I calculate the IP checksum, but it was always coming out incorrect (based on an example here http://www.thegeekstuff.com/2012/05/ip-header-checksum/).
Revving up gdb, I’ve worked my issue down to the ordering of the first 32 bits in the IP header. The example uses 0x4500003C, which means version 4 (0x4), IHL 5 (0x5), TOS 0 (0x00), and tot_length 60 (0x003C). So I set my packet up the same.
struct iphdr* ip; // Also some mallocing
ip->version = 4;
ip->ihl = 5;
ip->tos = 0;
ip->tot_len = 60;
Now in gdb, I examined the first 32 bits, expecting 0x3C000045 because of endianness, but instead I get this:
(gdb) print ip
$1 = (iphdr *) 0x11018
(gdb) x/1xw 0x11018
0x11018: 0x003c0045
The first 16 bits are in little endian (0x0045) but the second, containing decimal 60, seem to be in big endian (0x003C)!
What is giving this? Am I crazy? Am I completely wrong about byte order inside structs? (It’s a definite possibility)
There’s the order of fields within the struct, and then there’s the order of bytes within a multibyte field.
0x003Cisn’t endian at all, it’s the hex value for 60. Sure, it’s stored in memory with some endianness, but the order you used to write the field and the order you used to read it back out are the same — both are the native byte order of the Raspberry Pi, and they cancel out.Typically you will want to write:
when storing a 16-bit field into a packet. There’s also
htonlfor 32-bit fields, andntohsandntohlfor reading fields from network packets.