Reputation: 83
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)
Upvotes: 6
Views: 5396
Reputation: 405
The ARM architecture can run both little and big endianess, but the Android platform runs little endian.
Upvotes: 1
Reputation: 283921
There's the order of fields within the struct, and then there's the order of bytes within a multibyte field.
0x003C
isn'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:
ip->tot_len = htons(60);
when storing a 16-bit field into a packet. There's also htonl
for 32-bit fields, and ntohs
and ntohl
for reading fields from network packets.
Upvotes: 7