I am writing a simple packet processing program. Here is code excerpt:

void print_ethernet_header(unsigned char* buffer)
        struct ethhdr *eth = (struct ethhdr *)buffer;
        fprintf(logfile , "   |-Protocol  : %x \n",eth->h_proto);

This simple function should print to logfile the hex value of protocol type. And indeed it does print value '8'. However, both in source /usr/include/net/ethernet.h and online (https://en.wikipedia.org/wiki/EtherType) I see that IP protocol type is defined as 0x0800. So I actually expected to see value 800 (in hex) or 2048 (in dec) to be printed to file, not 8. I thought that maybe this has something to do with endianess and a need to convert from net byte order to host, but have not found anything about this in recvfrom() man page. Here is the call that fills up the buffer variable:

sock_raw = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
//some code here...
data_size = recvfrom(sock_raw , buffer , bufsize , 0 , (struct sockaddr*)&saddr , (socklen_t*)&saddr_size);

The machine I work on is little-endian (Ubuntu 16.04). Why does the protocol type show 8 ?


The structure definition shows that h_proto is a big-endian 16-bit integer:

struct ethhdr {
        unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
        unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
        __be16          h_proto;                /* packet type ID field */
} __attribute__((packed));

So you do need to process it with ntohs before reading it. Once you do that, you’ll see the correct value, 0x0800.

  • Nice :). But how can I check that the bytes are indeed big-endian? I can simply replace __be16 with __le16 as both are basically same data type in git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/… typedef __u16 __bitwise __le16; typedef __u16 __bitwise __be16; – dmytro.poliarush Apr 3 '18 at 9:55
  • @ortymd The only stable way to determine endianness is to read specifications or usage code. Also reverse engineering can give some results, but not in this case. Specs for 802.2, 802.3 are freely available. – Netch Apr 3 '18 at 10:03
  • 1
    @ortymd __le16 and __be16 aren’t the same data type; they have the same underlying representation but their contents are different. – Stephen Kitt Apr 3 '18 at 11:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.