Stack Organization
Overview
Protocol layers are wired together to form a stack. Click on the image to the right to see the stack organization diagram of the OpenWSN protocol stack. Send
functions are used to push packets down the stack; Receive
functions to pull them up. The bytes of a packet live in the OpenQueue
component. A packet is a variable of type OpenQueueEntry_t
and is defined in openwsn.h; components pass a pointer to an OpenQueueEntry_t
variables in the Send
and Receive
functions.
OpenQueueEntry_t and metadata
An OpenQueueEntry_t
consists of the actual bytes in the packet, plus a number of metadata fields. Metadata is used for an upper (resp. lower) layer to set parameters a lower (resp. upper) layer will need, when sending a packet down (resp. up) the stack. One example is that the MAC layer sets l1_channel
to instruct the driver about which channel it needs to transmit the packet on. Another example is that RPL layer specifies l2_nextORpreviousHop
, indicating to the MAC layer to which neighbor this packet needs to go.
No parameters are sent in the Send
interfaces other than the pointer to the OpenQueueEntry_t
. All Send
interfaces have the same two functions:
error_t send (OpenQueueEntry_t* msg); void sendDone(OpenQueueEntry_t* msg, error_t error);
Similarly, when receiving:
void receive(OpenQueueEntry_t* msg);
Instead of adding and adding parameters in the interface, they go as metadata as are attached to the OpenQueueEntry_t
variable. A packet is thereby self-contained: a component should never have to maintain state linked to a particular packet.
Metadata fields have names which indicates which layer should use them, from l7_
for the application to l1_
for the radio driver. Some field are used for administration by all the layers:
creator
indicates the component which created this packet, i.e. which requested an unusedOpenQueueEntry_t
to theOpenQueue
component. When sending a packet down the stack, the convention is that only the creator of a packet can free that packet, i.e. instruct theOpenQueue
component it doesn't need it anymore. Typically,OpenQueueEntry_t
variables will be created by all application-layer component when sending a packet, or by the drivers when receiving.owner
indicates the components which currently holds the packet. The convention is that a component can only change the content of anOpenQueueEntry_t
if it is currently the owner.- The
packet
part of theOpenQueueEntry_t
holds the actual bytes of the packet. Because OpenWSN does not allow for dynamic memory allocation,packet
is the maximal allowed size.payload
is a pointer to the first used by inpacket
;length
indicates how many bytes are used.
Adding/removing protocol headers
When a component requests an unused OpenQueueEntry_t
from the OpenQueue
component, payload
points to the end packet
and length
is zero. If a components needs to add n
bytes of data to the packet pkt
, it calls:
packetfunctions_reserveHeaderSize(OpenQueueEntry_t* pkt, uint8_t header_length)
This function modifies the payload
and length
fields of the OpenQueueEntry_t
to make space for a header of header_length
bytes. After this function is called, you can write a header starting at the byte pointed at by pkt->payload
, of exactly header_length
bytes.
Similarly, when a components needs to remove n
bytes of data from the packet pkt
, it does:
void packetfunctions_tossHeader(OpenQueueEntry_t* pkt, uint8_t header_length)
In practice, fixed-length header might be defined in a header file. The TCP header, for example, is defined in tcp.h as
typedef struct { uint16_t source_port; uint16_t destination_port; uint32_t sequence_number; uint32_t ack_number; uint8_t data_offset; uint8_t control_bits; uint16_t window_size; uint16_t checksum; uint16_t urgent_pointer; } tcp_ht;
tcp.c, which implements the TCP protocol, reserves space for the header by calling:
packetfunctions_reserveHeaderSize(msg,sizeof(tcp_ht));
Story of a packet
This section tells the story about what each layer does in the OpenWSN implementation, including which layers read and write metadata. There are two parts: one which details what happens when a packet is generated at the application layer, and travels down the stack until the drivers; one the other way.
Each of these sections end with a table stating which layer write (w
) or read (r
) which metadata.
- Down the stack*
- Application
- gets a free
OpenQueueEntry_t
- fills in the following metadata:
creator
(to itself)owner
(to itself)l4_source_port
(to be used by self to route to appropriate L4)l4_destination_port
(to be used by L4 to build header)l3_destinationORsource
ADDR_128B (to be used by RPL to find next hop)
- fills in the payload according to its own format
- sends to L4
- gets a free
- L4(TCP or UDP)
- fills in the following metadata:
owner
(to itself)l4_payload
(to remember where the l4 payload starts, in case needs to resend)l4_length
(to remember where the l4 payload starts, in case needs to resend)
- adds transport header based on:
l4_source_port
(filled in by Application)l4_destination_port
(filled in by Application)
- sends to RPL
- fills in the following metadata:
- RPL
- fills in the following metadata:
owner
(to itself)l2_nextORpreviousHop
(which is obtains by calling getNextHop)
- sends to IPHC
- fills in the following metadata:
- IPHC
- fills in the following metadata:
owner
(to itself)
- add 6LoWPAN header
- sends to RES
- fills in the following metadata:
- RES
- fills in the following metadata:
owner
(to itself)l2_frameType
(to data if from above, to beacon if from Neighbors)
- sends to MAC
- fills in the following metadata:
- MAC(IEEE802154E or stupidMAC)
- fills in the following metadata:
owner
(to itself)l2_retriesLeft
l1_txPower
l1_channel
- adds the MAC header based on:
l2_nextORpreviousHop
(filled in by RPL)l2_frameType
(filled in by RES)
- sends to drivers
- fills in the following metadata:
- drivers
- does not put owner to itself to allow MAC to retransmit (in case something goes wrong in the drivers)
- configures the radio according to:
l1_txPower
(set by MAC)l1_channel
(set by MAC)
| App | L4 | RPL | IPHC | RES | MAC | drivers |
creator | w |
|
|
|
|
|
|
owner | w | w | w | w | w | w | w |
l4_protocol | w/r |
|
|
|
|
|
|
l4_source_port | w | r |
|
|
|
|
|
l4_destination_port | w | r |
|
|
|
|
|
l4_payload |
| w/r |
|
|
|
|
|
l4_length |
| w/r |
|
|
|
|
|
l3_destinationORsource | w |
| r | r |
|
|
|
l2_nextORpreviousHop |
|
| w |
|
| r |
|
l2_frameType |
|
|
|
| w | r |
|
l2_retriesLeft |
|
|
|
|
| w/r |
|
l1_txPower |
|
|
|
|
| w | r |
l1_channel |
|
|
|
|
| w | r |
l1_rssi |
|
|
|
|
|
|
|
l1_lqi |
|
|
|
|
|
|
|
l1_crc |
|
|
|
|
|
|
|
l1_rxTimestamp |
|
|
|
|
|
|
|
- Up the stack*
- drivers
- gets a free an
OpenQueueEntry_t
- fills in the following metadata:
creator
(to itself)owner
(to itself)l1_rxTimestamp
(for the MAC layer to possibly resynchronize)l1_crc
(in fact always true as in the current drivers a packet with a false CRC is discarded)l1_lqi
(not used in upper layers, for the moment)l1_rssi
(used by theNeighbors
components to select stable neighbors)
- sends to MAC
- gets a free an
- MAC(IEEE802154E or stupidMAC)
- fills in the following metadata:
owner
(to itself)l2_frameType
l2_nextORpreviousHop
to the 64b/16b address of the previous hop
- if IEEE802.15.4E, resynchronizes using
l1_rxTimestamp
filled in by the drivers - removes the MAC header
- sends to RES
- fills in the following metadata:
- RES
- fills in the following metadata:
owner
(to itself)
- filters using
l2_frameType
filled in by MAC - sends to IPHC
- fills in the following metadata:
- IPHC
- fills in the following metadata:
owner
(to itself)
- inflates the IPv6 header
- removes the 6LoWPAN header
- sends the message with the inflated IPv6 header to RPL
- fills in the following metadata:
- RPL
- fills in the following metadata:
owner
(to itself)l4_protocol
(according to thenext_header
field in the inflated IPv6 header provided by theIPHC
componnent)
- sends to the appropriate L4 according to
l4_protocol
- fills in the following metadata:
- L4(TCP or UDP)
- fills in the following metadata:
owner
(to itself)l4_source_port
l4_destination_port
- remove the L4 header
- sends to App
- fills in the following metadata:
- Application
- discards the packet
| drivers | MAC | RES | IPHC | RPL | L4 | App |
creator | w |
|
|
|
|
|
|
owner | w | w | w | w | w | w | w |
l4_protocol |
|
|
|
| w/r |
|
|
l4_source_port |
|
|
|
|
| w | r |
l4_destination_port |
|
|
|
|
| w | r |
l4_payload |
|
|
|
|
|
|
|
l4_length |
|
|
|
|
|
|
|
l3_destinationORsource |
|
|
|
| w |
|
|
l2_nextORpreviousHop |
| w |
|
|
|
|
|
l2_frameType |
| w | r |
|
|
|
|
l2_retriesLeft |
|
|
|
|
|
|
|
l1_txPower |
|
|
|
|
|
|
|
l1_channel |
|
|
|
|
|
|
|
l1_rssi | w |
|
|
|
|
|
|
l1_lqi | w |
|
|
|
|
|
|
l1_crc | w/r |
|
|
|
|
|
|
l1_rxTimestamp | w | r |
|
|
|
|
|