What is the problem with my arp structure?

  • Thread starter Muhammad Farooq-i-Azam
  • Start date
M

Muhammad Farooq-i-Azam

Hi,

I am trying to define an arp structure but having problem
doing so. I think I have define the correct arp structure but
I find myself in a strange problem. The size of structure that
I have defined is 28 bytes, but it is reported to be 32 bytes by
the sizeof() call.

Interestingly, sum of individuals members of the sturcture is 28.
However, the sizeof() the entire structure is returned to be 32.

I tried to display the addresses of various structure members
and found that addresses of arp.src_protoaddr and arp.dst_protoaddr
which are both (4 bytes) are not correct boundaries.

Size of arp.src_hwaddr is 6 bytes. Its address is 0xbfffe848.
Therefore, the size of the next structure member should be
0xbfffe848+6 = 0xbfffe84e. However, the actual address that I get
from my code below is 0xbfffe850 which is larger by 2 bytes.
Same is the problem with arp.dst_protoaddr.

Here is the code listing that I am using:


/**************************************************************
* Why is the structure size returned 32 ?
**************************************************************/


#include <sys/types.h>

int main(void)
{


typedef struct arp_header
{
u_int16_t hwaddr_format; /* Ethernet, Token Ring, etc */
u_int16_t protoaddr_format; /* Same as Ether Type field */
u_int8_t hwaddr_length; /* Lenght of hardware address
*/
u_int8_t protoaddr_length; /* Length of protocol address
*/
u_int16_t opcode; /* Request or Response */
u_int8_t src_hwaddr[6]; /* Source Hardware Address */
u_int32_t src_protoaddr; /* Source Protocol Address */
u_int8_t dst_hwaddr[6]; /* Destination Hardware Address
*/
u_int32_t dst_protoaddr; /* Destination Protocol Address
*/
} arp_header_t;

arp_header_t arp;



printf("sizeof(u_int32_t) = %d\n", sizeof(u_int32_t));
printf("sizeof(arp_header_t) = %d\n", sizeof(arp_header_t));
printf("sizeof(arp) = %d\n", sizeof(arp));
printf("sizeof(arp.hwaddr_format) = %d\n",
sizeof(arp.hwaddr_format));
printf("sizeof(arp.protoaddr_format) = %d\n",
sizeof(arp.protoaddr_format));
printf("sizeof(arp.hwaddr_length) = %d\n",
sizeof(arp.hwaddr_length));
printf("sizeof(arp.protoaddr_length) = %d\n",
sizeof(arp.protoaddr_length));
printf("sizeof(arp.opcode) = %d\n", sizeof(arp.opcode));
printf("sizeof(arp.src_hwaddr) = %d\n", sizeof(arp.src_hwaddr));
printf("sizeof(arp.src_protoaddr) = %d\n",
sizeof(arp.src_protoaddr));
printf("sizeof(arp.dst_hwaddr) = %d\n", sizeof(arp.dst_hwaddr));
printf("sizeof(arp.dst_protoaddr) = %d\n",
sizeof(arp.dst_protoaddr));
printf("\n");

printf("&arp.hwaddr_format = 0x%x\n", &arp.hwaddr_format);
printf("&arp.protoaddr_format = 0x%x\n", &arp.protoaddr_format);
printf("&arp.hwaddr_length = 0x%x\n", &arp.hwaddr_length);
printf("&arp.protoaddr_length = 0x%x\n", &arp.protoaddr_length);
printf("&arp.opcode = 0x%x\n", &arp.opcode);
printf("&arp.src_hwaddr = 0x%x\n", &arp.src_hwaddr);
printf("&arp.src_protoaddr = 0x%x\n", &arp.src_protoaddr);
printf("&arp.dst_hwaddr = 0x%x\n", &arp.dst_hwaddr);
printf("&arp.dst_protoaddr = 0x%x\n", &arp.dst_protoaddr);


return 0;
}



Here is a sample output from the code:

sizeof(u_int32_t) = 4
sizeof(arp_header_t) = 32
sizeof(arp) = 32
sizeof(arp.hwaddr_format) = 2
sizeof(arp.protoaddr_format) = 2
sizeof(arp.hwaddr_length) = 1
sizeof(arp.protoaddr_length) = 1
sizeof(arp.opcode) = 2
sizeof(arp.src_hwaddr) = 6
sizeof(arp.src_protoaddr) = 4
sizeof(arp.dst_hwaddr) = 6
sizeof(arp.dst_protoaddr) = 4

&arp.hwaddr_format = 0xbfffe840
&arp.protoaddr_format = 0xbfffe842
&arp.hwaddr_length = 0xbfffe844
&arp.protoaddr_length = 0xbfffe845
&arp.opcode = 0xbfffe846
&arp.src_hwaddr = 0xbfffe848
&arp.src_protoaddr = 0xbfffe850 [PROBLEM HERE]
&arp.dst_hwaddr = 0xbfffe854 [PROBLEM HERE]
&arp.dst_protoaddr = 0xbfffe85c [PROBLEM HERE]
Thanks in advance for any help.

Muhammad Farooq-i-Azam
 
E

Emmanuel Delahaye

Muhammad Farooq-i-Azam wrote on 17/12/04 :
I am trying to define an arp structure but having problem
doing so. I think I have define the correct arp structure but
I find myself in a strange problem. The size of structure that
I have defined is 28 bytes, but it is reported to be 32 bytes by
the sizeof() call.

Don't indent to map a C structure to a byte pattern. Due to various
reasons (open your C-book), it simply doesn't work. Period.

Use a byte memory stream (array of unsigned char), and read/write the
data from/to it a the required place byte by byte.

Numerical representation format are specified. The hton()/ntoh()
functions can help. Note that these functions are not standard, but
they intend to be portable and available on platforms using a network
acces.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Clearly your code does not meet the original spec."
"You are sentenced to 30 lashes with a wet noodle."
-- Jerry Coffin in a.l.c.c++
 
M

Muhammad Farooq-i-Azam

Emmanuel!

Real thanks for your elaboration. I found the following
link from the faq you pointed to quite helpful:

http://www.eskimo.com/~scs/C-faq/q2.13.html

Yes, when I use

u_int8_t src_protoaddr[4];

instead of

u_int32_t src_protoaddr;
the problem is resolved.

Muhammad Farooq-i-Azam
 
C

Chris Croughton

I am trying to define an arp structure but having problem
doing so. I think I have define the correct arp structure but
I find myself in a strange problem. The size of structure that
I have defined is 28 bytes, but it is reported to be 32 bytes by
the sizeof() call.

Alignment of variables is your problem.
Size of arp.src_hwaddr is 6 bytes. Its address is 0xbfffe848.
Therefore, the size of the next structure member should be
0xbfffe848+6 = 0xbfffe84e.

However, what follows src_hwaddr is a 32 bit value (src_protoaddr). It
seems that on whatever machine you are using 32 bit variables have to be
aligned on a 4-byte boundary, so a 'hole' is left to bring the address
to the correct boundary.

You may be able to get round this with a #pragma or a (non-standard)
attribute, or with a compiler flag (although you have to be careful with
that since it will affect every structure in that module so every other
module needs to use the same flag). Look in your compiler documentation
for terms like 'pack' and 'packed'. However, not only is this
nonstandard but it also isn't guaranteed, your processor may mot work
with misaligned data access (the i86 processors will access unaligned
data, but more slowly, but RISC ones will often fault if you try to
access a 32 bit value which crosses word boundaries).

The C standard deliberately doesn't define how or whether packing is
done. See section 6.7.2.1:

11 Each non-bit-field member of a structure or union object is
aligned in an implementation defined manner appropriate to its
type.

12 Within a structure object, the non-bit-field members and the
units in which bit-fields reside have addresses that increase in
the order in which they are declared. A pointer to a structure
object, suitably converted, points to its initial member (or if
that member is a bit-field, then to the unit in which it
resides), and vice versa. There may be unnamed padding within a
structure object, but not at its beginning.

Any amount of 'padding' can be within a structure, with the exception of
bit fields, so getting a structure which maps onto a specific byte
sequence is not defined. The only sure way to hadle it is to extract
the bytes from memory and reassemble them yourself into the specified
fields (that way you can also handle the 'endianness' in a portable
way).

When dealing with network structures I have written functions to extract
from and write to byte arrays 32 and 16 bit values. For instance:

unsigned long getData16(unsigned char *data, int offset)
{
return (data[offset] << 8) | data[offset+1];
}

unsigned long getData32(unsigned char *data, int offset)
{
return (getData16(data, offset) << 16) | getData16(data, offset+2);
}

void putData16(unsigned char *data, int offset, unsigned long val)
{
data[offset] = (val >> 8) & 0xFF;
data[offset+1] = val & 0xFF;
}

void putData32(unsigned char *data, int offset, unsigned long val)
{
putData16(data, offset, val >> 16);
putData16(data, offset+2, val);
}

Then I use the data buffer and explicit offsets to put and get the
fields and don't have to worry about endianness or alignment...

Chris C
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top