Arthuer Hames
Arthuer Hames

Reputation: 13

Unclear purpose of code?

I am learning about raw socket programming in Linux and during a tutorial I noticed a coincidence with this code:

struct ipheader {
 unsigned char      iph_ihl:5, iph_ver:4; //<--------------These
 unsigned char      iph_tos;
 unsigned short int iph_len;
 unsigned short int iph_ident;
 unsigned char      iph_flag;
 unsigned short int iph_offset;
 unsigned char      iph_ttl;
 unsigned char      iph_protocol;
 unsigned short int iph_chksum;
 unsigned int       iph_sourceip;
 unsigned int       iph_destip;
};

iph_ver holds the IP version which will be 4, and iph_ihl holds the header length which will be set to 5. Since header length is described in 4 byte words the actual header length comes out to be 5×4=20 bytes. 20 bytes is the minimum length. With that being said I am curious if the bit fields in this structure, set for iph_ver and iph_ihl, are specifically 4 and 5 because it will be IPv4 and the IP header will be 20 bytes in length. However I am unsure how their bit fields would have any effect or correlation on their value. Any explanations would be greatly appreciated.

Link to code: http://www.tenouk.com/Module43a.html

Upvotes: 1

Views: 422

Answers (1)

chqrlie
chqrlie

Reputation: 144695

The code fragment from this tutorial is actually wrong!

Here is a correct definition for the IP packet header:

/*
 * Structure of an internet header, naked of options.
 *
 * We declare ip_len and ip_off to be short, rather than u_short
 * pragmatically since otherwise unsigned comparisons can result
 * against negative integers quite easily, and fail in subtle ways.
 */
struct ip {
#if BYTE_ORDER == LITTLE_ENDIAN 
    u_char  ip_hl:4,        /* header length */
            ip_v:4;         /* version */
#endif
#if BYTE_ORDER == BIG_ENDIAN 
    u_char  ip_v:4,         /* version */
            ip_hl:4;        /* header length */
#endif
    u_char  ip_tos;         /* type of service */
    short   ip_len;         /* total length */
    u_short ip_id;          /* identification */
    short   ip_off;         /* fragment offset field */
#define IP_DF 0x4000        /* dont fragment flag */
#define IP_MF 0x2000        /* more fragments flag */
    u_char  ip_ttl;         /* time to live */
    u_char  ip_p;           /* protocol */
    u_short ip_sum;         /* checksum */
    struct  in_addr ip_src,ip_dst;  /* source and dest address */
};

As you can see, both ip_hl and ip_v are 4 bit wide bitfields. The actual names of the fields do not matter, just their position in the packet header.

They are defined in a different order depending on the platform because the compiler allocates bitfields differently depending on endianness. This behavior is actually not specified in the C Standard, but seems to be consistent across platforms.

Upvotes: 1

Related Questions