• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for 6LoWPAN header compression.
32  */
33 
34 #ifndef LOWPAN_HPP_
35 #define LOWPAN_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include "common/clearable.hpp"
40 #include "common/debug.hpp"
41 #include "common/frame_builder.hpp"
42 #include "common/frame_data.hpp"
43 #include "common/locator.hpp"
44 #include "common/message.hpp"
45 #include "common/non_copyable.hpp"
46 #include "mac/mac_types.hpp"
47 #include "net/ip6.hpp"
48 #include "net/ip6_address.hpp"
49 #include "net/ip6_types.hpp"
50 
51 namespace ot {
52 
53 /**
54  * @addtogroup core-6lowpan
55  *
56  * @brief
57  *   This module includes definitions for 6LoWPAN header compression.
58  *
59  * @{
60  */
61 
62 /**
63  * @namespace ot::Lowpan
64  *
65  * @brief
66  *   This namespace includes definitions for 6LoWPAN message processing.
67  */
68 namespace Lowpan {
69 
70 /**
71  * Represents a LOWPAN_IPHC Context.
72  */
73 struct Context : public Clearable<Context>
74 {
75     Ip6::Prefix mPrefix;       ///< The Prefix
76     uint8_t     mContextId;    ///< The Context ID.
77     bool        mCompressFlag; ///< The Context compression flag.
78     bool        mIsValid;      ///< Indicates whether the context is valid.
79 };
80 
81 /**
82  * Implements LOWPAN_IPHC header compression.
83  */
84 class Lowpan : public InstanceLocator, private NonCopyable
85 {
86 public:
87     /**
88      * Initializes the object.
89      *
90      * @param[in]  aInstance     A reference to the OpenThread instance.
91      */
92     explicit Lowpan(Instance &aInstance);
93 
94     /**
95      * Indicates whether or not the header is a LOWPAN_IPHC header.
96      *
97      * @param[in]  aHeader  A pointer to the header.
98      *
99      * @retval TRUE   If the header matches the LOWPAN_IPHC dispatch value.
100      * @retval FALSE  If the header does not match the LOWPAN_IPHC dispatch value.
101      */
IsLowpanHc(const uint8_t * aHeader)102     static bool IsLowpanHc(const uint8_t *aHeader)
103     {
104         return (aHeader[0] & (Lowpan::kHcDispatchMask >> 8)) == (Lowpan::kHcDispatch >> 8);
105     }
106 
107     /**
108      * Indicates whether or not header in a given frame is a LOWPAN_IPHC header.
109      *
110      * @param[in] aFrameData    The frame data.
111      *
112      * @retval TRUE   If the header matches the LOWPAN_IPHC dispatch value.
113      * @retval FALSE  If the header does not match the LOWPAN_IPHC dispatch value.
114      */
IsLowpanHc(const FrameData & aFrameData)115     static bool IsLowpanHc(const FrameData &aFrameData)
116     {
117         return (aFrameData.GetLength() > 0) && IsLowpanHc(aFrameData.GetBytes());
118     }
119 
120     /**
121      * Compresses an IPv6 header.
122      *
123      * @param[in]   aMessage       A reference to the IPv6 message.
124      * @param[in]   aMacAddrs      The MAC source and destination addresses.
125      * @param[in]   aFrameBuilder  The `FrameBuilder` to use to append the compressed headers.
126      *
127      * @returns The size of the compressed header in bytes.
128      */
129     Error Compress(Message &aMessage, const Mac::Addresses &aMacAddrs, FrameBuilder &aFrameBuilder);
130 
131     /**
132      * Decompresses a LOWPAN_IPHC header.
133      *
134      * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
135      *
136      * @param[out]    aMessage         A reference where the IPv6 header will be placed.
137      * @param[in]     aMacAddrs        The MAC source and destination addresses.
138      * @param[in,out] aFrameData       A frame data containing the LOWPAN_IPHC header.
139      * @param[in]     aDatagramLength  The IPv6 datagram length.
140      *
141      * @retval kErrorNone    The header was decompressed successfully. @p aMessage and @p aFrameData are updated.
142      * @retval kErrorParse   Failed to parse the lowpan header.
143      * @retval kErrorNoBufs  Could not grow @p aMessage to write the parsed IPv6 header.
144      */
145     Error Decompress(Message              &aMessage,
146                      const Mac::Addresses &aMacAddrs,
147                      FrameData            &aFrameData,
148                      uint16_t              aDatagramLength);
149 
150     /**
151      * Decompresses a LOWPAN_IPHC header.
152      *
153      * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
154      *
155      * @param[out]    aIp6Header             A reference where the IPv6 header will be placed.
156      * @param[out]    aCompressedNextHeader  A boolean reference to output whether next header is compressed or not.
157      * @param[in]     aMacAddrs              The MAC source and destination addresses
158      * @param[in,out] aFrameData             A frame data containing the LOWPAN_IPHC header.
159      *
160      * @retval kErrorNone    The header was decompressed successfully. @p aIp6Header and @p aFrameData are updated.
161      * @retval kErrorParse   Failed to parse the lowpan header.
162      */
163     Error DecompressBaseHeader(Ip6::Header          &aIp6Header,
164                                bool                 &aCompressedNextHeader,
165                                const Mac::Addresses &aMacAddrs,
166                                FrameData            &aFrameData);
167 
168     /**
169      * Decompresses a LOWPAN_NHC UDP header.
170      *
171      * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
172      *
173      * @param[out]    aUdpHeader    A reference where the UDP header will be placed.
174      * @param[in,out] aFrameData    A frame data containing the LOWPAN_NHC header.
175      *
176      * @retval kErrorNone    The header was decompressed successfully. @p aUdpHeader and @p aFrameData are updated.
177      * @retval kErrorParse   Failed to parse the lowpan header.
178      */
179     Error DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, FrameData &aFrameData);
180 
181     /**
182      * Decompresses the IPv6 ECN field in a LOWPAN_IPHC header.
183      *
184      * @param[in] aMessage  The message to read the IPHC header from.
185      * @param[in] aOffset   The offset in @p aMessage to start of IPHC header.
186      *
187      * @returns The decompressed ECN field. If the IPHC header is not valid `kEcnNotCapable` is returned.
188      */
189     Ip6::Ecn DecompressEcn(const Message &aMessage, uint16_t aOffset) const;
190 
191     /**
192      * Updates the compressed ECN field in a LOWPAN_IPHC header to `kEcnMarked`.
193      *
194      * MUST be used when the ECN field is not elided in the IPHC header. Note that the ECN is not elided
195      * when it is not zero (`kEcnNotCapable`).
196      *
197      * @param[in,out] aMessage  The message containing the IPHC header and to update.
198      * @param[in]     aOffset   The offset in @p aMessage to start of IPHC header.
199      */
200     void MarkCompressedEcn(Message &aMessage, uint16_t aOffset);
201 
202 private:
203     static constexpr uint16_t kHcDispatch     = 3 << 13;
204     static constexpr uint16_t kHcDispatchMask = 7 << 13;
205 
206     static constexpr uint16_t kHcTrafficClass    = 1 << 11;
207     static constexpr uint16_t kHcFlowLabel       = 2 << 11;
208     static constexpr uint16_t kHcTrafficFlow     = 3 << 11;
209     static constexpr uint16_t kHcTrafficFlowMask = 3 << 11;
210     static constexpr uint16_t kHcNextHeader      = 1 << 10;
211     static constexpr uint16_t kHcHopLimit1       = 1 << 8;
212     static constexpr uint16_t kHcHopLimit64      = 2 << 8;
213     static constexpr uint16_t kHcHopLimit255     = 3 << 8;
214     static constexpr uint16_t kHcHopLimitMask    = 3 << 8;
215     static constexpr uint16_t kHcContextId       = 1 << 7;
216     static constexpr uint16_t kHcSrcAddrContext  = 1 << 6;
217     static constexpr uint16_t kHcSrcAddrMode0    = 0 << 4;
218     static constexpr uint16_t kHcSrcAddrMode1    = 1 << 4;
219     static constexpr uint16_t kHcSrcAddrMode2    = 2 << 4;
220     static constexpr uint16_t kHcSrcAddrMode3    = 3 << 4;
221     static constexpr uint16_t kHcSrcAddrModeMask = 3 << 4;
222     static constexpr uint16_t kHcMulticast       = 1 << 3;
223     static constexpr uint16_t kHcDstAddrContext  = 1 << 2;
224     static constexpr uint16_t kHcDstAddrMode0    = 0 << 0;
225     static constexpr uint16_t kHcDstAddrMode1    = 1 << 0;
226     static constexpr uint16_t kHcDstAddrMode2    = 2 << 0;
227     static constexpr uint16_t kHcDstAddrMode3    = 3 << 0;
228     static constexpr uint16_t kHcDstAddrModeMask = 3 << 0;
229 
230     static constexpr uint8_t kEcnOffset = 6;
231     static constexpr uint8_t kEcnMask   = 3 << kEcnOffset;
232 
233     static constexpr uint8_t kExtHdrDispatch     = 0xe0;
234     static constexpr uint8_t kExtHdrDispatchMask = 0xf0;
235 
236     static constexpr uint8_t kExtHdrEidHbh      = 0x00;
237     static constexpr uint8_t kExtHdrEidRouting  = 0x02;
238     static constexpr uint8_t kExtHdrEidFragment = 0x04;
239     static constexpr uint8_t kExtHdrEidDst      = 0x06;
240     static constexpr uint8_t kExtHdrEidMobility = 0x08;
241     static constexpr uint8_t kExtHdrEidIp6      = 0x0e;
242     static constexpr uint8_t kExtHdrEidMask     = 0x0e;
243 
244     static constexpr uint8_t  kExtHdrNextHeader = 0x01;
245     static constexpr uint16_t kExtHdrMaxLength  = 255;
246 
247     static constexpr uint8_t kUdpDispatch     = 0xf0;
248     static constexpr uint8_t kUdpDispatchMask = 0xf8;
249 
250     static constexpr uint8_t kUdpChecksum = 1 << 2;
251     static constexpr uint8_t kUdpPortMask = 3 << 0;
252 
253     void  FindContextForId(uint8_t aContextId, Context &aContext) const;
254     void  FindContextToCompressAddress(const Ip6::Address &aIp6Address, Context &aContext) const;
255     Error Compress(Message              &aMessage,
256                    const Mac::Addresses &aMacAddrs,
257                    FrameBuilder         &aFrameBuilder,
258                    uint8_t              &aHeaderDepth);
259 
260     Error CompressExtensionHeader(Message &aMessage, FrameBuilder &aFrameBuilder, uint8_t &aNextHeader);
261     Error CompressSourceIid(const Mac::Address &aMacAddr,
262                             const Ip6::Address &aIpAddr,
263                             const Context      &aContext,
264                             uint16_t           &aHcCtl,
265                             FrameBuilder       &aFrameBuilder);
266     Error CompressDestinationIid(const Mac::Address &aMacAddr,
267                                  const Ip6::Address &aIpAddr,
268                                  const Context      &aContext,
269                                  uint16_t           &aHcCtl,
270                                  FrameBuilder       &aFrameBuilder);
271     Error CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, FrameBuilder &aFrameBuilder);
272     Error CompressUdp(Message &aMessage, FrameBuilder &aFrameBuilder);
273 
274     Error DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData);
275     Error DecompressUdpHeader(Message &aMessage, FrameData &aFrameData, uint16_t aDatagramLength);
276     Error DispatchToNextHeader(uint8_t aDispatch, uint8_t &aNextHeader);
277 
278     static Error ComputeIid(const Mac::Address &aMacAddr, const Context &aContext, Ip6::InterfaceIdentifier &aIid);
279 };
280 
281 /**
282  * Implements Mesh Header generation and processing.
283  */
284 class MeshHeader
285 {
286 public:
287     /**
288      * Initializes the Mesh Header with a given Mesh Source, Mesh Destination and Hops Left value.
289      *
290      * @param[in]  aSource       The Mesh Source address.
291      * @param[in]  aDestination  The Mesh Destination address.
292      * @param[in]  aHopsLeft     The Hops Left value.
293      */
294     void Init(uint16_t aSource, uint16_t aDestination, uint8_t aHopsLeft);
295 
296     /**
297      * Indicates whether or not the header (in a given frame) is a Mesh Header.
298      *
299      * @note This method checks whether the first byte in header/frame (dispatch byte) matches the Mesh Header dispatch
300      * It does not fully parse and validate the Mesh Header. `ParseFrom()` method can be used to fully parse and
301      * validate the header.
302      *
303      * @retval TRUE   If the header matches the Mesh Header dispatch value.
304      * @retval FALSE  If the header does not match the Mesh Header dispatch value.
305      */
306     static bool IsMeshHeader(const FrameData &aFrameData);
307 
308     /**
309      * Parses the Mesh Header from a frame @p aFrame.
310      *
311      * @param[in]  aFrame        The pointer to the frame.
312      * @param[in]  aFrameLength  The length of the frame.
313      * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success).
314      *
315      * @retval kErrorNone     Mesh Header parsed successfully.
316      * @retval kErrorParse    Mesh Header could not be parsed.
317      */
318     Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
319 
320     /**
321      * Parses the Mesh Header from a given frame data.
322      *
323      * If the Mesh Header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
324      *
325      * @param[in,out]  aFrameData    The frame data to parse from.
326      *
327      * @retval kErrorNone     Mesh Header parsed successfully. @p aFrameData is updated to skip over parsed header.
328      * @retval kErrorParse    Mesh Header could not be parsed.
329      */
330     Error ParseFrom(FrameData &aFrameData);
331 
332     /**
333      * Parses the Mesh Header from a given message.
334      *
335      * @note The Mesh Header is read from offset zero within the @p aMessage.
336      *
337      * @param[in]  aMessage    The message to read from.
338      *
339      * @retval kErrorNone   Mesh Header parsed successfully.
340      * @retval kErrorParse  Mesh Header could not be parsed.
341      */
342     Error ParseFrom(const Message &aMessage);
343 
344     /**
345      * Parses the Mesh Header from a given message.
346      *
347      * @note The Mesh Header is read from offset zero within the @p aMessage.
348      *
349      * @param[in]  aMessage       The message to read from.
350      * @param[out] aHeaderLength  A reference to a variable to output the parsed header length (on success).
351      *
352      * @retval kErrorNone   Mesh Header parsed successfully.
353      * @retval kErrorParse  Mesh Header could not be parsed.
354      */
355     Error ParseFrom(const Message &aMessage, uint16_t &aHeaderLength);
356 
357     /**
358      * Returns the the Mesh Header length when written to a frame.
359      *
360      * @note The returned value from this method gives the header length (number of bytes) when the header is written
361      * to a frame or message. This should not be used to determine the parsed length (number of bytes read) when the
362      * Mesh Header is parsed from a frame/message (using `ParseFrom()` methods).
363      *
364      * @returns The length of the Mesh Header (in bytes) when written to a frame.
365      */
366     uint16_t GetHeaderLength(void) const;
367 
368     /**
369      * Returns the Hops Left value.
370      *
371      * @returns The Hops Left value.
372      */
GetHopsLeft(void) const373     uint8_t GetHopsLeft(void) const { return mHopsLeft; }
374 
375     /**
376      * Decrements the Hops Left value (if it is not zero).
377      */
378     void DecrementHopsLeft(void);
379 
380     /**
381      * Returns the Mesh Source address.
382      *
383      * @returns The Mesh Source address.
384      */
GetSource(void) const385     uint16_t GetSource(void) const { return mSource; }
386 
387     /**
388      * Returns the Mesh Destination address.
389      *
390      * @returns The Mesh Destination address.
391      */
GetDestination(void) const392     uint16_t GetDestination(void) const { return mDestination; }
393 
394     /**
395      * Appends the Mesh Header into a given frame.
396      *
397      * @param[out]  aFrameBuilder  The `FrameBuilder` to append to.
398      *
399      * @retval kErrorNone    Successfully appended the MeshHeader to @p aFrameBuilder.
400      * @retval kErrorNoBufs  Insufficient available buffers.
401      */
402     Error AppendTo(FrameBuilder &aFrameBuilder) const;
403 
404     /**
405      * Appends the Mesh Header to a given message.
406      *
407      *
408      * @param[out] aMessage  A message to append the Mesh Header to.
409      *
410      * @retval kErrorNone    Successfully appended the Mesh Header to @p aMessage.
411      * @retval kErrorNoBufs  Insufficient available buffers to grow @p aMessage.
412      */
413     Error AppendTo(Message &aMessage) const;
414 
415 private:
416     static constexpr uint8_t kDispatch     = 2 << 6;
417     static constexpr uint8_t kDispatchMask = 3 << 6;
418     static constexpr uint8_t kHopsLeftMask = 0x0f;
419     static constexpr uint8_t kSourceShort  = 1 << 5;
420     static constexpr uint8_t kDestShort    = 1 << 4;
421     static constexpr uint8_t kDeepHopsLeft = 0x0f;
422 
423     // Dispatch byte + src + dest
424     static constexpr uint16_t kMinHeaderLength      = sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint16_t);
425     static constexpr uint16_t kDeepHopsHeaderLength = kMinHeaderLength + sizeof(uint8_t); // min header + deep hops
426 
427     uint16_t mSource;
428     uint16_t mDestination;
429     uint8_t  mHopsLeft;
430 };
431 
432 /**
433  * Implements Fragment Header generation and parsing.
434  */
435 class FragmentHeader
436 {
437 public:
438     OT_TOOL_PACKED_BEGIN
439     class FirstFrag
440     {
441     public:
442         /**
443          * Initializes the `FirstFrag`.
444          *
445          * @param[in] aSize  The Datagram Size value.
446          * @param[in] aTag   The Datagram Tag value.
447          */
Init(uint16_t aSize,uint16_t aTag)448         void Init(uint16_t aSize, uint16_t aTag)
449         {
450             mDispatchSize = BigEndian::HostSwap16(kFirstDispatch | (aSize & kSizeMask));
451             mTag          = BigEndian::HostSwap16(aTag);
452         }
453 
454     private:
455         //                       1                   2                   3
456         //   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
457         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
458         //  |1 1 0 0 0|    datagram_size    |         datagram_tag          |
459         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
460 
461         static constexpr uint16_t kFirstDispatch = 0xc000; // 0b11000_0000_0000_0000
462 
463         uint16_t mDispatchSize;
464         uint16_t mTag;
465     } OT_TOOL_PACKED_END;
466 
467     OT_TOOL_PACKED_BEGIN
468     class NextFrag
469     {
470     public:
471         /**
472          * Initializes the `NextFrag`.
473          *
474          * @param[in] aSize    The Datagram Size value.
475          * @param[in] aTag     The Datagram Tag value.
476          * @param[in] aOffset  The Datagram Offset value.
477          */
Init(uint16_t aSize,uint16_t aTag,uint16_t aOffset)478         void Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset)
479         {
480             mDispatchSize = BigEndian::HostSwap16(kNextDispatch | (aSize & kSizeMask));
481             mTag          = BigEndian::HostSwap16(aTag);
482             mOffset       = static_cast<uint8_t>(aOffset >> 3);
483         }
484 
485     private:
486         //                       1                   2                   3
487         //   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
488         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
489         //  |1 1 1 0 0|    datagram_size    |         datagram_tag          |
490         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
491         //  |datagram_offset|
492         //  +-+-+-+-+-+-+-+-+
493 
494         static constexpr uint16_t kNextDispatch = 0xe000; // 0b11100_0000_0000_0000
495 
496         uint16_t mDispatchSize;
497         uint16_t mTag;
498         uint8_t  mOffset;
499     } OT_TOOL_PACKED_END;
500 
501     /**
502      * Indicates whether or not the header (in a given frame) is a Fragment Header.
503      *
504      * @note This method checks whether the frame has the minimum required length and that the first byte in
505      * header (dispatch byte) matches the Fragment Header dispatch value. It does not fully parse and validate the
506      * Fragment Header. `ParseFrom()` method can be used to fully parse and validate the header.
507      *
508      * @param[in] aFrameData   The frame data.
509      *
510      * @retval TRUE   If the header matches the Fragment Header dispatch value.
511      * @retval FALSE  If the header does not match the Fragment Header dispatch value.
512      */
513     static bool IsFragmentHeader(const FrameData &aFrameData);
514 
515     /**
516      * Parses the Fragment Header from a given frame data.
517      *
518      * If the Fragment Header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
519      *
520      * @param[in,out]  aFrameData    The frame data to parse from.
521      *
522      * @retval kErrorNone     Fragment Header parsed successfully. @p aFrameData is updated to skip over parsed header.
523      * @retval kErrorParse    Fragment header could not be parsed.
524      */
525     Error ParseFrom(FrameData &aFrameData);
526 
527     /**
528      * Parses the Fragment Header from a message.
529      *
530      * @param[in]  aMessage      The message to read from.
531      * @param[in]  aOffset       The offset within the message to start reading from.
532      * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success).
533      *
534      * @retval kErrorNone     Fragment Header parsed successfully.
535      * @retval kErrorParse    Fragment header could not be parsed from @p aFrame.
536      */
537     Error ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t &aHeaderLength);
538 
539     /**
540      * Returns the Datagram Size value.
541      *
542      * @returns The Datagram Size value.
543      */
GetDatagramSize(void) const544     uint16_t GetDatagramSize(void) const { return mSize; }
545 
546     /**
547      * Returns the Datagram Tag value.
548      *
549      * @returns The Datagram Tag value.
550      */
GetDatagramTag(void) const551     uint16_t GetDatagramTag(void) const { return mTag; }
552 
553     /**
554      * Returns the Datagram Offset value.
555      *
556      * The returned offset value is always multiple of 8.
557      *
558      * @returns The Datagram Offset value (multiple of 8).
559      */
GetDatagramOffset(void) const560     uint16_t GetDatagramOffset(void) const { return mOffset; }
561 
562 private:
563     static constexpr uint8_t kDispatch     = 0xc0;   // 0b1100_0000
564     static constexpr uint8_t kDispatchMask = 0xd8;   // 0b1101_1000 accepts first (0b1100_0xxx) and next (0b1110_0xxx).
565     static constexpr uint8_t kOffsetFlag   = 1 << 5; // Indicate first (no offset) vs. next (offset present) fragment.
566 
567     static constexpr uint16_t kSizeMask   = 0x7ff;  // 0b0111_1111_1111 (first 11 bits).
568     static constexpr uint16_t kOffsetMask = 0xfff8; // Clears the last 3 bits to ensure offset is a multiple of 8.
569 
570     static constexpr uint8_t kSizeIndex   = 0; // Start index of Size field in the Fragment Header byte sequence.
571     static constexpr uint8_t kTagIndex    = 2; // Start index of Tag field in the Fragment Header byte sequence.
572     static constexpr uint8_t kOffsetIndex = 4; // Start index of Offset field in the Fragment Header byte sequence.
573 
574     static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength);
575 
576     Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
577 
578     uint16_t mSize;
579     uint16_t mTag;
580     uint16_t mOffset;
581 };
582 
583 /**
584  * @}
585  */
586 
587 } // namespace Lowpan
588 } // namespace ot
589 
590 #endif // LOWPAN_HPP_
591