:TEP: 111
:Group: Core Working Group
:Type: Documentary
-:Status: Draft
+:Status: Final
:TinyOS-Version: 2.x
:Author: Philip Levis
-:Draft-Created: 11-Jul-2005
-:Draft-Version: $Revision$
-:Draft-Modified: $Date$
-:Draft-Discuss: TinyOS Developer List <tinyos-devel at mail.millennium.berkeley.edu>
-
.. Note::
This memo documents a part of TinyOS for the TinyOS Community, and
This memo covers the TinyOS 2.x message buffer abstraction, ``message_t``.
It describes the message buffer design considerations, how and where
-``message_t`` is specified, and how data link layers should access it.
+``message_t`` is specified, and how data link layers should access it.
+The major goal of ``message_t`` is to allow datagrams to be passed between
+different link layers as a contiguous region of memory with zero copies.
1. Introduction
====================================================================
uint8_t receiveSecurityMode;
} TOS_Msg;
-while on a mote with a CC420 radio (e.g., micaZ), ``TOS_Msg`` is defined as::
+while on a mote with a CC2420 radio (e.g., micaZ), ``TOS_Msg`` is defined as::
typedef struct TOS_Msg {
// The following fields are transmitted/received on the radio.
header fields. This is very difficult to do in C.
The ``data`` payload is especially problematic. Many
-components refer to this field, so it must be at a fixed offset.
+components refer to this field, so it must be at a fixed offset
+from the beginning of the structure.
Depending on the underlying link layer, the header fields
preceding it might have different lengths, and packet-level radios
often require packets to be contiguous memory regions. Overall, these
complexities make specifying the format of ``TOS_Msg`` very difficult.
+TinyOS has traditionally used statically sized packet buffers,
+rather than more dynamic approaches, such as scatter-gather I/O
+in UNIX sockets (see the man page for ``recv(2)`` for details).
+TinyOS 2.x continues this approach.
+
2. message_t
====================================================================
nx_uint8_t metadata[sizeof(message_metadata_t)];
} message_t;
-This format keeps data at a fixed offset, which is important when
+This format keeps data at a fixed offset on a platform, which
+is important when
passing a message buffer between two different link layers. If the
data payload were at different offsets for different link layers, then
passing a packet between two link layers would require a ``memmove(3)``
-operation (essentially, a copy).
+operation (essentially, a copy). Unlike in TinyOS 1.x, where TOS_Msg
+as explicitly an active messaging packet, message_t is a more general
+data-link buffer. In practice, most data-link layers in TinyOS 2.x
+provide active messaging, but it is possible for a non-AM stack to
+share message_t with AM stacks.
The header, footer, and metadata formats are all opaque. Source code
cannot access fields directly. Instead, data-link layers provide access
Every link layer defines its header, footer, and metadata
structures. These structures MUST be external structs (``nx_struct``),
and all of their fields MUST be external types (``nx_*``), for two
-reasons. First, external types ensure cross-platform compatibility.
+reasons. First, external types ensure cross-platform compatibility [1]_.
Second, it forces structures to be aligned on byte boundaries,
circumventing issues with the
-alignment of packet buffers and field offsets within them.
+alignment of packet buffers and field offsets within them. Metadata fields
+must be nx_structs for when complete packets are forwarded to the serial
+port in order to log traffic.
For example, the CC1000 radio implementation defines
its structures in ``CC1000Msg.h``::
needed. These definitions MUST be in a file in a platform directory
named ``platform_message.h``. The mica2 platform, for example, has
two data link layers: the CC1000 radio and the TinyOS serial
-stack [1]_. The serial packet format does not have a footer
+stack [2]_. The serial packet format does not have a footer
or metadata section. The ``platform_message.h`` of the mica2
looks like this::
Components above the basic data-link layer MUST always access
packet fields through interfaces. A component that introduces
new packet fields SHOULD provide an interface to those that
-are of interest to other components.
+are of interest to other components. These interfaces SHOULD take
+the form of get/set operations that take and return values, rather
+than offsts into the structure.
+
For example, active messages have an interface named ``AMPacket``
which provides access commands to AM fields. In TinyOS 1.x, a
component would directly access ``TOS_Msg.addr``; in TinyOS 2.x,
a component calls ``AMPacket.getAddress(msg)``.
The most basic of these interfaces is Packet, which provides
access to a packet payload. TEP 116 describes common TinyOS
-packet ADT interfaces [2]_.
+packet ADT interfaces [3]_.
Link layer components MAY access packet fields differently than other
components, as they are aware of the actual packet format. They can
therefore implement the interfaces that provide access to the fields
-for other components.
+for other components.
+
3.1 Headers
----------------------------------------------------------------
The message_t header field is an array of bytes whose size is
the size of a platform's union of data-link headers.
-Because packets are stored contiguously, the layout of a packet
-in memory is not the same as the layout of its nesC structure.
+Because radio stacks often prefer packets to be stored contiguously,
+the layout of a packet in memory does not necessarily reflect the
+layout of its nesC structure.
-A packet header does not necessarily start at the beginning of
+A packet header MAY start somewhere besides the beginning of
the message_t. For example, consider the Telos platform::
typedef union message_header {
Serial | hdr | data |
+-----+------------+
+
Neither the CC2420 nor the serial stack has packet footers, and
the serial stack does not have any metadata.
Because this value can be reconfigured, it is possible that two
different versions of an application can have different MTU sizes.
If a packet layer receives a packet whose payload size is
-longer than TOSH_DATA_LENGTH, it MUST discard the packet.
+longer than TOSH_DATA_LENGTH, it MUST discard the packet. As
+headers are right justified to the beginning of the data payload,
+the data payloads of all link layers on a platform start
+at the same fixed offset from the beginning of the message buffer.
3.3 Footer
----------------------------------------------------------------
nx_uint16_t time;
} cc2420_metadata_t;
-5. Implementation
+3.5 Variable Sized Structures
+----------------------------------------------------------------
+
+The message_t structure is optimized for packets with fixed-size
+headers and footers. Variable-sized footers are generally easy
+to implement. Variable-sized headers are a bit more difficult.
+There are three general approaches that can be used.
+
+If the underlying link hardware is byte-based, the header can
+just be stored at the beginning of the message_t, giving it
+a known offset. There may be padding between the header and
+the data region, but assuming a byte-based send path this merely
+requires adjusting the index.
+
+If the underlying link hardware is packet-based, then the
+protocol stack can either include metadata (e.g., in the
+metadata structure) stating where the header begins or it
+can place the header at a fixed position and use ``memmove(3)``
+on reception and transmit. In this latter case, on
+reception the packet is continguously read into the message_t
+beginning at the offset of the header structure. Once the
+packet is completely received, the header can be decoded,
+its length calculated, and the data region of the packet
+can be moved to the ``data`` field. On transmission,
+the opposite occurs: the data region (and footer if need
+be) are moved to be contiguous with the header. Note that
+on completion of transmission, they need to be moved back.
+Alternatively, the radio stack can institute a single
+copy at the botttom layer.
+
+
+
+4. Implementation
====================================================================
The definition of message_t can be found in
-``tinyos-2.x/tos/types/message.h``. The definition of the CC2420
+``tinyos-2.x/tos/types/message.h``.
+
+The definition of the CC2420
message format can be found in ``tinyos-2.x/tos/chips/cc2420/CC2420.h``.
+
The defintion of the CC1000 message format can be found in
-``tinyos-2.x/tos/chips/cc1000/CC1000Msg.h``. The definition
+``tinyos-2.x/tos/chips/cc1000/CC1000Msg.h``.
+
+The definition
of the standard serial stack packet format can be found in
-``tinyos-2.x/tos/lib/serial/Serial.h''. The definition of
-the telosb packet format can be found in
+``tinyos-2.x/tos/lib/serial/Serial.h``
+
+The definition of
+the telos family packet format can be found in
``tinyos-2.x/tos/platform/telosa/platform_message.h`` and the micaz format can be found in
``tinyos-2.x/tos/platforms/micaz/platform_message.h``.
-6. Author's Address
+5. Author's Address
====================================================================
| Philip Levis
6. Citations
====================================================================
-.. [1] TEP 113: Serial Communication.
+.. [1] `nesC: A Programming Language for Deeply Embedded Networks. <http://nescc.sourceforge.net>`_
+
+.. [2] TEP 113: Serial Communication.
-.. [2] TEP 116: Packet Protocols.
+.. [3] TEP 116: Packet Protocols.