4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 /** \mainpage libPackets: How to define and use a new Packet Type
25 This howto will introduce the facilities needed to define a new packet type. As example, the
26 \c GREPacket type is defined.
28 \section howto_newpacket_start Getting started
30 Before starting with the implementation, we look at the specification of the GRE packet. This is
31 found in <a href="http://tools.ietf.org/html/rfc2784">RFC 2784</a> in Section 2.1:
34 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
35 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 |C| Reserved0 | Ver | Protocol Type |
37 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 | Checksum (optional) | Reserved1 (Optional) |
39 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 Using this protocol definition, we can decide the first important question: Whether the packet
43 header is fixed size or dynamically sized. As we see above, the header incorporates optional
44 fields. Therefore it must be dynamically sized. The RFC further details, that if the \a Checksum
45 \a Present bit \a C is set, both \a Checksum and \a Reserved1 are present, otherwise they must
48 Another information we take from the RFC is, that the \a Protocol \a Type is used to define the
49 type of payload which directly follows the GRE header. This value is the <a
50 href="http://www.iana.org/assignments/ethernet-numbers">ETHERTYPE</a> value. To allow the packet
51 library to automatically parse the GRE payload data, we need to tell the packet library which
52 ETHERTYPE represents which packet type. This association already exists in form of the
53 senf::EtherTypes registry. Our GRE packet will therefore utilize this registry.
55 To summarize, we have gathered the following information:
57 \li The GRE packet header is a dynamically sized header.
58 \li The GRE packet header utilizes the senf::EtherTypes registry for next-header selection
60 \section howto_newpacket_impl Implementing the GRE Parser
62 The next step in creating a new packet type is to implement the parser. The parser is
63 responsible for turning a bunch of bytes into an interpreted header with specific fields. The
64 parser will later be constructed with an iterator (pointer) to the first byte to be interpreted
65 as a GRE header and will provide member functions to access the header fields. You can implement
66 these members manually but the SENF library provides a large set of helper macros which simplify
67 this task considerably.
70 struct GREParser : public senf::PacketParser
72 # include SENF_PARSER()
76 SENF_PARSER_FINALIZE(GREParser);
80 This is the standard skeleton of any parser class: We need to inherit senf::PacketParser and
81 start out by including either \ref SENF_PARSER() or \ref SENF_FIXED_PARSER(). Which, depends on
82 whether we define a fixed size or a dynamically sized parser. As \c GREParser is dynamically
83 sized, we include \ref SENF_PARSER().
85 After the fields are defined, we need to call the \ref SENF_PARSER_FINALIZE() macro to close of
86 the parser definition. This call takes the name of the parser being defined as it's sole
89 This is already a valid parser, albeit not a very usable one since it defines no fields. We now
90 go back to define the parser fields and begin with the simple part: Those fields which are
94 SENF_PARSER_BITFIELD ( checksumPresent, 1, bool );
95 SENF_PARSER_SKIP_BITS ( 12 );
96 SENF_PARSER_BITFIELD ( version, 3, unsigned );
97 SENF_PARSER_BITFIELD ( protocolType, 16, unsigned );
100 This is a direct transcript of the field definition above. However, we can optimize this a
101 little bit: Since the \a protocolType field is aligned on a byte boundary, instead of defining
102 it as a bitfield, we can define it as a UInt16 field:
105 SENF_PARSER_BITFIELD ( checksumPresent, 1, bool );
106 SENF_PARSER_SKIP_BITS ( 12 );
107 SENF_PARSER_BITFIELD ( version, 3, unsigned );
109 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
112 There are quite a number of such \c SENF_PARSER_ macros. They are all listed in \ref
113 packetparsermacros. The basic field types (like senf::UInt16Parser) are listed in \ref parseint.
115 What happens in the above macros? Most of the macros define an accessor for a specific field: \a
116 checksumPresent() or \a protocolType(). They also manage a <em>current Offset</em>. This value
117 is advanced according to the field size whenever a new field is defined (and since this parser
118 is defined as a dynamically sized parser, this offset is not a constant, it is an expression
119 which calculates the offset of a field depending on the preceding data).
121 It is important to understand, that the accessors do \e not return the parsed field value. They
122 return another \e parser which is used to further interpret the value. This is the inherent
123 recursive nature of the SENF packet parsers. This allows to define wildly complex header formats
124 if needed. Of course, at some point we need the real value. This is, what the so called
125 <em>value parsers</em> do: They interpret some bytes or bits and return the value of that field
126 (not a parser). Examples are the bitfield parsers returnd by the accessors generated by
127 SENF_PARSER_BITFIELD (like senf::UIntFieldParser) or the senf::UInt16Parser.
129 We now come to the optional fields. Since there are two fields which need to be disabled/enabled
130 together, we first need to define an additional sub-parser which parses those two fields. After
131 this parser is defined, we can use \ref SENF_PARSER_VARIANT() to add this parser as an optional
132 parser to the GRE header.
135 struct GREParser_OptFields : public senf::PacketParser
137 # include SENF_FIXED_PARSER()
139 SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
140 SENF_PARSER_SKIP ( 2 );
142 SENF_PARSER_FINALIZE(GREParser_OptFields);
146 This parser only parses the two optional fields of which the reserved field is just skipped. The
147 parser this time is a fixed size parser. We can now use this parser to continue the \c GREParser
151 SENF_PARSER_BITFIELD ( checksumPresent, 1, bool );
152 SENF_PARSER_SKIP_BITS ( 12 );
153 SENF_PARSER_BITFIELD ( version, 3, unsigned );
155 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
157 SENF_PARSER_VARIANT ( optionalFields, checksumPresent,
158 (senf::VoidPacketParser)
159 (GREParser_OptFields) );
162 How does this work? For a variant parser, two things need to be specified: A selector and a list
163 of variant parsers. The selector is another parser field which is used to decide, which variant
164 to choose. In this simple case, the field must be an unsigned integer (more precisely a value
165 parser which returns a value which is implicitly convertible to \c unsigned). This value is used
166 as index into the list of variant types. So in our case, 0 is associated with
167 senf::VoidPacketParser whereas 1 is associated with \c GREParser_OptFields.
169 This parser will work, it is however not very safe and not very usable. If \a p is a GREParser
170 instance, than we access the fields via:
175 p.optionalFields().get<1>().checksum()
178 There are two problems here:
179 \li accessing the checksum field is not straight forward
180 \li changing the checksumPresent() value will break the parser
182 The reason for the second problem lies in the fact, that the variant parser needs to be informed
183 whenever the selector (here \a checksumPresent) is changed since the variant parser must ensure,
184 that the header data stays consistent. In this example, whenever the checksumPresent field is
185 enabled, the variant parser needs to insert additional 4 bytes of data and remove those bytes,
186 when the checksumPresent field is disabled. We therefore make the checksumPresent field
190 SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool );
193 To change the checksumPresent value, we now need to use the variant parsers \a init member:
196 p.optionalFields().init<0>();
197 p.optionalFields().init<1>();
200 The first statements switches to the first variant and therefore in this case disables the
201 checksum field. The second statement will switch to the second variant and enable the checksum
202 field. This again is not very usable. So we complete the parser by providing simple additional
203 members which access the fields in a more readable way. While doing this, we also mark the
204 variant as a private field so it is not directly accessible any more. Here the final \c
208 struct GREParser_OptFields : public senf::PacketParser
210 # include SENF_FIXED_PARSER()
212 SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
213 SENF_PARSER_SKIP ( 2 );
215 SENF_PARSER_FINALIZE(GREParser_OptFields);
218 struct GREParser : public senf::PacketParser
220 # include SENF_PARSER()
222 SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool );
223 SENF_PARSER_SKIP_BITS ( 12 );
224 SENF_PARSER_BITFIELD ( version, 3, unsigned );
226 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
228 SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
229 (senf::VoidPacketParser)
230 (GREParser_OptFields) );
232 typedef GREParser_OptFields::checksum_t checksum_t;
233 checksum_t checksum() const
234 { return optionalFields_().get<1>().checksum(); }
236 void enableChecksum() const { optionalFields_().init<1>(); }
237 void disableChecksum() const { optionalFields_().init<0>(); }
239 SENF_PARSER_FINALIZE(GREParser);
248 // comment-column: 40
249 // c-file-style: "senf"
250 // indent-tabs-mode: nil
251 // ispell-local-dictionary: "american"
252 // compile-command: "scons -u doc"