1
votes

So, long story short: my program receives a raw byte (u_char) buffer that represents a network packet. I'm trying to parse the information in that packet, and am doing so using the system defined header structures (ether_header, ip, ip6, tcphdr, udphdr). I've implemented this on both Linux and AIX and it worked, but for some reason I keep getting a Bus Error when I do this on Solaris.

The way that I am getting the data is basically just casting each part of the buffer as one of the structs and reading the data. For example, if I have

u_char buffer[] = {...some bytes...};
struct ether_header *ethdr = (struct ether_header *)buffer;
struct ip *iphdr = (struct ip *) (buffer + sizeof(struct ether_header));
etc. etc.

I can then get the information I need like:

iphdr->ip_v; //to get the version
etc->etc; //to get whatever piece of data I need

Normally, on Linux and AIX this works fine (certain structs have different names across systems, but that's besides the point), but upon trying to run this on Solaris, I keep getting a Bus Error when it gets to iphdr->ip_v; after struct ip *iphdr = (struct ip *) (buffer + sizeof(struct ether_header)); . After some investigation, I found that this is caused by trying to access unaligned memory. This makes sense because the size of an ethernet header is only 14 bytes, therefore the IP header is not byte aligned within the array.

The way I tried getting around this was to copy the relevant pieces into a separate buffer before I try reading it

memcpy(&buffer_copy, buffer + sizeof(struct ether_header), sizeof(struct ip));
struct ip *iphdr = &buffer_copy;
iphdr->ip_v;
etc.

This works, but I don't understand why. Why doesn't memcpy throw a Bus Error when it is trying to access the same memory location? I don't like the solution I came up with that much and am trying to better understand the situation so I can come up with something else. Am I maybe missing a piece of the puzzle?

1
memcpy() copies bytes, they are never misaligned.Hans Passant
The system requires data to be aligned by 4 bytes. I'm not trying to read from the middle of a byte, but from a byte position that is not a multiple of 4 (which is what memory alignment refers to).monkeygame7
No, it requires variables larger than a byte to be aligned.Hans Passant
What hardware? SPARC hardware isn't x86 hardware.Andrew Henle
Then, can someone explain why struct ip *iphdr = (struct ip *) (buffer + sizeof(struct ether_header)); throws a Bus Error then? Or rather, why trying to access data inside it throws the error.monkeygame7

1 Answers

1
votes

On SPARC hardware, you have two options:

  1. Don't write code that accesses memory in a way that causes a bus error.
  2. Compile with Solaris Studio compilers and use the -xmemalign=1i command-line option. This will result in a binary that runs slower than a binary that assumes properly-aligned memory access.

Also see this question.