Stack

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 unused OpenQueueEntry_t to the OpenQueue 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 the OpenQueue 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 an OpenQueueEntry_t if it is currently the owner.
  • The packet part of the OpenQueueEntry_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 in packetlength 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
  • 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
  • RPL
    • fills in the following metadata:
      • owner (to itself)
      • l2_nextORpreviousHop (which is obtains by calling getNextHop)
    • sends to IPHC
  • IPHC
    • fills in the following metadata:
      • owner (to itself)
    • add 6LoWPAN header
    • sends to RES
  • RES
    • fills in the following metadata:
      • owner (to itself)
      • l2_frameType (to data if from above, to beacon if from Neighbors)
    • sends to MAC
  • 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
  • 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

 

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 the Neighbors components to select stable neighbors)
    • sends to MAC
  • 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
  • RES
    • fills in the following metadata:
      • owner (to itself)
    • filters using l2_frameType filled in by MAC
    • sends to IPHC
  • 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
  • RPL
    • fills in the following metadata:
      • owner (to itself)
      • l4_protocol (according to the next_header field in the inflated IPv6 header provided by the IPHC componnent)
    • sends to the appropriate L4 according to l4_protocol
  • 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
  • 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