You cannot use C structs/unions for storing data protocols or create exact memory maps.
This is because a C compiler may insert padding bytes anywhere inside a struct/union except at the very beginning. How this is done, or what values the padding bytes get, is implementation-defined behavior.
That is what's causing your problems. When you attempt to "alias" the raw data buffer to correspond to your structs, you invoke undefined behavior, because the struct memory mapping does not correspond to the raw data.
There are some ways to solve this issue:
Use structs/unions in a safe, deterministic manner. You always need to use a static assert, to ensure that your struct does not contain padding. You can write such an assert as:
static_assert (sizeof(my_struct) == (sizeof(my_struct.member1) +
sizeof(my_struct.member2) +
...),
"Padding detected!");
Once you have this is place, you have prevented the bug from happening. But to actually solve the issue, you'll have to remove the padding in some compiler-specific way, such as the #pragma pack(1)
.
If your compiler has no way of removing the padding, you have to write serialization/de-serialization functions, as suggested in a comment. It is essentially just a data-shovelling function like this:
void mac_serialize (mac_header_t* dest, const uint8_t* source)
{
dest->details.parta = source[BYTE_PARTA];
dest->details.partb = source[BYTE_PARTB];
...
}
Also please note that the way you have created the address union, it is endianess dependant. This may also be another issue, unrelated to padding.