I work on embedded systems, so frequently, I am required to implement protocols. When I do this I like to make nice clean layers.

However, this become difficult where the fields used by different layers are shared.

I like to think of the layers as offering a number of services following the spirit of OSI model:

1. start byte / sequence (SOF)
2. length of packet / message
3. message integrity (CRC, xor checksum)

4. Source / Destination

5. Command / Response Type (how to interpret payload).

(I realize this is not the ISO model, but you get the point I hope.)

Sometimes the protocol exists on a point to point link (RS232 or tcp socket) so there is no concept of source and destination.

I would typically have a software layer for each of: Framing, Network and Application. The layer is typically a state machine processing bytes, or frames or packets. At the top, there is a hook point for the application specific functionality.

Typically as a packet moves up the stack and the layers are stripped off, I simply pass a pointer to the next inner scope. First pointer to SOF, then pointer to network fields and finally a pointer to the application payload.

As the fields are parsed they are added to a structure specific to the layer producing it. (A structure with a name like: Frame, Packet, Message / Command / Response) Each structure has a pointer to the packet buffer.

At the top I can deallocate the structure by calling free on each layer until at the bottom a pointer is available to free. (or return to a pool)

The question is how can I cleanly handle cases where the fields have dual use or are bit fields in a byte. (upper nibble is payload length, lower nibble is packet type, etc...)

An example of this is a simple packet format like this:
<SOF> <CMD> <command specific payload> <CRC>

In this case the length of the packet is implied by the command code. So the CMD field (a single byte in this case) is shared between the framing and application layers.

I think in this case the framing layer has a lookup table for command to length and passes a pointer to the CMD field up to the application layer for handling in a structure.


If you are dealing with a protocol that is so badly designed that the header fields of the difference conceptual layers are all over the place, then you don't really have much of a choice and you just have to treat it all as one big layer. Fortunately, I have never encountered such a protocol and I think they tend to get obsoleted rather fast.

If you have a protocol where a layer boundary falls somewhere in the middle of a byte, then the lower layer's parsing code should not advance the buffer pointer past that byte (as it has not been fully consumed) and both layers should be aware that the spare bits of that byte might contain valuable data for another layer and treat them accordingly. They don't have to know what those bits mean to the other layer.

To avoid buffer overruns if length fields in a message get corrupted, the parsing functions should always be informed how large the buffer is that they can inspect. If some protocol layer has part of its information at the tail end of the buffer (like often the case with CRC checksums), then the buffer length information can be used both for finding the CRC (the last two bytes of the buffer) and to avoid that the upper layers misinterpret the CRC bytes as data for them (by telling the upper layer that the buffer ends earlier).

This way, in the packet format

<SOF> <CMD> <command specific payload> <CRC>

the framing layer does not have to have any knowledge about the commands (or even the possibility that there might be more than one command in the message). The framing layer just checks the <SOF>, extracts the <CRC> from the end and validates the <CRC> by checking the intervening bytes as raw data. Then it tells the application layer that there is a message in the buffer starting at <CMD> and ending just before <CRC>.

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.