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  */
69 namespace Lowpan {
70 
71 /**
72  * Represents a LOWPAN_IPHC Context.
73  *
74  */
75 struct Context : public Clearable<Context>
76 {
77     Ip6::Prefix mPrefix;       ///< The Prefix
78     uint8_t     mContextId;    ///< The Context ID.
79     bool        mCompressFlag; ///< The Context compression flag.
80     bool        mIsValid;      ///< Indicates whether the context is valid.
81 };
82 
83 /**
84  * Implements LOWPAN_IPHC header compression.
85  *
86  */
87 class Lowpan : public InstanceLocator, private NonCopyable
88 {
89 public:
90     /**
91      * Initializes the object.
92      *
93      * @param[in]  aInstance     A reference to the OpenThread instance.
94      *
95      */
96     explicit Lowpan(Instance &aInstance);
97 
98     /**
99      * Indicates whether or not the header is a LOWPAN_IPHC header.
100      *
101      * @param[in]  aHeader  A pointer to the header.
102      *
103      * @retval TRUE   If the header matches the LOWPAN_IPHC dispatch value.
104      * @retval FALSE  If the header does not match the LOWPAN_IPHC dispatch value.
105      */
IsLowpanHc(const uint8_t * aHeader)106     static bool IsLowpanHc(const uint8_t *aHeader)
107     {
108         return (aHeader[0] & (Lowpan::kHcDispatchMask >> 8)) == (Lowpan::kHcDispatch >> 8);
109     }
110 
111     /**
112      * Indicates whether or not header in a given frame is a LOWPAN_IPHC header.
113      *
114      * @param[in] aFrameData    The frame data.
115      *
116      * @retval TRUE   If the header matches the LOWPAN_IPHC dispatch value.
117      * @retval FALSE  If the header does not match the LOWPAN_IPHC dispatch value.
118      */
IsLowpanHc(const FrameData & aFrameData)119     static bool IsLowpanHc(const FrameData &aFrameData)
120     {
121         return (aFrameData.GetLength() > 0) && IsLowpanHc(aFrameData.GetBytes());
122     }
123 
124     /**
125      * Compresses an IPv6 header.
126      *
127      * @param[in]   aMessage       A reference to the IPv6 message.
128      * @param[in]   aMacAddrs      The MAC source and destination addresses.
129      * @param[in]   aFrameBuilder  The `FrameBuilder` to use to append the compressed headers.
130      *
131      * @returns The size of the compressed header in bytes.
132      *
133      */
134     Error Compress(Message &aMessage, const Mac::Addresses &aMacAddrs, FrameBuilder &aFrameBuilder);
135 
136     /**
137      * Decompresses a LOWPAN_IPHC header.
138      *
139      * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
140      *
141      * @param[out]    aMessage         A reference where the IPv6 header will be placed.
142      * @param[in]     aMacAddrs        The MAC source and destination addresses.
143      * @param[in,out] aFrameData       A frame data containing the LOWPAN_IPHC header.
144      * @param[in]     aDatagramLength  The IPv6 datagram length.
145      *
146      * @retval kErrorNone    The header was decompressed successfully. @p aMessage and @p aFrameData are updated.
147      * @retval kErrorParse   Failed to parse the lowpan header.
148      * @retval kErrorNoBufs  Could not grow @p aMessage to write the parsed IPv6 header.
149      *
150      */
151     Error Decompress(Message              &aMessage,
152                      const Mac::Addresses &aMacAddrs,
153                      FrameData            &aFrameData,
154                      uint16_t              aDatagramLength);
155 
156     /**
157      * Decompresses a LOWPAN_IPHC header.
158      *
159      * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
160      *
161      * @param[out]    aIp6Header             A reference where the IPv6 header will be placed.
162      * @param[out]    aCompressedNextHeader  A boolean reference to output whether next header is compressed or not.
163      * @param[in]     aMacAddrs              The MAC source and destination addresses
164      * @param[in,out] aFrameData             A frame data containing the LOWPAN_IPHC header.
165      *
166      * @retval kErrorNone    The header was decompressed successfully. @p aIp6Header and @p aFrameData are updated.
167      * @retval kErrorParse   Failed to parse the lowpan header.
168      *
169      */
170     Error DecompressBaseHeader(Ip6::Header          &aIp6Header,
171                                bool                 &aCompressedNextHeader,
172                                const Mac::Addresses &aMacAddrs,
173                                FrameData            &aFrameData);
174 
175     /**
176      * Decompresses a LOWPAN_NHC UDP header.
177      *
178      * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
179      *
180      * @param[out]    aUdpHeader    A reference where the UDP header will be placed.
181      * @param[in,out] aFrameData    A frame data containing the LOWPAN_NHC header.
182      *
183      * @retval kErrorNone    The header was decompressed successfully. @p aUdpHeader and @p aFrameData are updated.
184      * @retval kErrorParse   Failed to parse the lowpan header.
185      *
186      */
187     Error DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, FrameData &aFrameData);
188 
189     /**
190      * Decompresses the IPv6 ECN field in a LOWPAN_IPHC header.
191      *
192      * @param[in] aMessage  The message to read the IPHC header from.
193      * @param[in] aOffset   The offset in @p aMessage to start of IPHC header.
194      *
195      * @returns The decompressed ECN field. If the IPHC header is not valid `kEcnNotCapable` is returned.
196      *
197      */
198     Ip6::Ecn DecompressEcn(const Message &aMessage, uint16_t aOffset) const;
199 
200     /**
201      * Updates the compressed ECN field in a LOWPAN_IPHC header to `kEcnMarked`.
202      *
203      * MUST be used when the ECN field is not elided in the IPHC header. Note that the ECN is not elided
204      * when it is not zero (`kEcnNotCapable`).
205      *
206      * @param[in,out] aMessage  The message containing the IPHC header and to update.
207      * @param[in]     aOffset   The offset in @p aMessage to start of IPHC header.
208      *
209      */
210     void MarkCompressedEcn(Message &aMessage, uint16_t aOffset);
211 
212 private:
213     static constexpr uint16_t kHcDispatch     = 3 << 13;
214     static constexpr uint16_t kHcDispatchMask = 7 << 13;
215 
216     static constexpr uint16_t kHcTrafficClass    = 1 << 11;
217     static constexpr uint16_t kHcFlowLabel       = 2 << 11;
218     static constexpr uint16_t kHcTrafficFlow     = 3 << 11;
219     static constexpr uint16_t kHcTrafficFlowMask = 3 << 11;
220     static constexpr uint16_t kHcNextHeader      = 1 << 10;
221     static constexpr uint16_t kHcHopLimit1       = 1 << 8;
222     static constexpr uint16_t kHcHopLimit64      = 2 << 8;
223     static constexpr uint16_t kHcHopLimit255     = 3 << 8;
224     static constexpr uint16_t kHcHopLimitMask    = 3 << 8;
225     static constexpr uint16_t kHcContextId       = 1 << 7;
226     static constexpr uint16_t kHcSrcAddrContext  = 1 << 6;
227     static constexpr uint16_t kHcSrcAddrMode0    = 0 << 4;
228     static constexpr uint16_t kHcSrcAddrMode1    = 1 << 4;
229     static constexpr uint16_t kHcSrcAddrMode2    = 2 << 4;
230     static constexpr uint16_t kHcSrcAddrMode3    = 3 << 4;
231     static constexpr uint16_t kHcSrcAddrModeMask = 3 << 4;
232     static constexpr uint16_t kHcMulticast       = 1 << 3;
233     static constexpr uint16_t kHcDstAddrContext  = 1 << 2;
234     static constexpr uint16_t kHcDstAddrMode0    = 0 << 0;
235     static constexpr uint16_t kHcDstAddrMode1    = 1 << 0;
236     static constexpr uint16_t kHcDstAddrMode2    = 2 << 0;
237     static constexpr uint16_t kHcDstAddrMode3    = 3 << 0;
238     static constexpr uint16_t kHcDstAddrModeMask = 3 << 0;
239 
240     static constexpr uint8_t kEcnOffset = 6;
241     static constexpr uint8_t kEcnMask   = 3 << kEcnOffset;
242 
243     static constexpr uint8_t kExtHdrDispatch     = 0xe0;
244     static constexpr uint8_t kExtHdrDispatchMask = 0xf0;
245 
246     static constexpr uint8_t kExtHdrEidHbh      = 0x00;
247     static constexpr uint8_t kExtHdrEidRouting  = 0x02;
248     static constexpr uint8_t kExtHdrEidFragment = 0x04;
249     static constexpr uint8_t kExtHdrEidDst      = 0x06;
250     static constexpr uint8_t kExtHdrEidMobility = 0x08;
251     static constexpr uint8_t kExtHdrEidIp6      = 0x0e;
252     static constexpr uint8_t kExtHdrEidMask     = 0x0e;
253 
254     static constexpr uint8_t  kExtHdrNextHeader = 0x01;
255     static constexpr uint16_t kExtHdrMaxLength  = 255;
256 
257     static constexpr uint8_t kUdpDispatch     = 0xf0;
258     static constexpr uint8_t kUdpDispatchMask = 0xf8;
259 
260     static constexpr uint8_t kUdpChecksum = 1 << 2;
261     static constexpr uint8_t kUdpPortMask = 3 << 0;
262 
263     void  FindContextForId(uint8_t aContextId, Context &aContext) const;
264     void  FindContextToCompressAddress(const Ip6::Address &aIp6Address, Context &aContext) const;
265     Error Compress(Message              &aMessage,
266                    const Mac::Addresses &aMacAddrs,
267                    FrameBuilder         &aFrameBuilder,
268                    uint8_t              &aHeaderDepth);
269 
270     Error CompressExtensionHeader(Message &aMessage, FrameBuilder &aFrameBuilder, uint8_t &aNextHeader);
271     Error CompressSourceIid(const Mac::Address &aMacAddr,
272                             const Ip6::Address &aIpAddr,
273                             const Context      &aContext,
274                             uint16_t           &aHcCtl,
275                             FrameBuilder       &aFrameBuilder);
276     Error CompressDestinationIid(const Mac::Address &aMacAddr,
277                                  const Ip6::Address &aIpAddr,
278                                  const Context      &aContext,
279                                  uint16_t           &aHcCtl,
280                                  FrameBuilder       &aFrameBuilder);
281     Error CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, FrameBuilder &aFrameBuilder);
282     Error CompressUdp(Message &aMessage, FrameBuilder &aFrameBuilder);
283 
284     Error DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData);
285     Error DecompressUdpHeader(Message &aMessage, FrameData &aFrameData, uint16_t aDatagramLength);
286     Error DispatchToNextHeader(uint8_t aDispatch, uint8_t &aNextHeader);
287 
288     static Error ComputeIid(const Mac::Address &aMacAddr, const Context &aContext, Ip6::InterfaceIdentifier &aIid);
289 };
290 
291 /**
292  * Implements Mesh Header generation and processing.
293  *
294  */
295 class MeshHeader
296 {
297 public:
298     /**
299      * Initializes the Mesh Header with a given Mesh Source, Mesh Destination and Hops Left value.
300      *
301      * @param[in]  aSource       The Mesh Source address.
302      * @param[in]  aDestination  The Mesh Destination address.
303      * @param[in]  aHopsLeft     The Hops Left value.
304      *
305      */
306     void Init(uint16_t aSource, uint16_t aDestination, uint8_t aHopsLeft);
307 
308     /**
309      * Indicates whether or not the header (in a given frame) is a Mesh Header.
310      *
311      * @note This method checks whether the first byte in header/frame (dispatch byte) matches the Mesh Header dispatch
312      * It does not fully parse and validate the Mesh Header. `ParseFrom()` method can be used to fully parse and
313      * validate the header.
314      *
315      * @retval TRUE   If the header matches the Mesh Header dispatch value.
316      * @retval FALSE  If the header does not match the Mesh Header dispatch value.
317      *
318      */
319     static bool IsMeshHeader(const FrameData &aFrameData);
320 
321     /**
322      * Parses the Mesh Header from a frame @p aFrame.
323      *
324      * @param[in]  aFrame        The pointer to the frame.
325      * @param[in]  aFrameLength  The length of the frame.
326      * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success).
327      *
328      * @retval kErrorNone     Mesh Header parsed successfully.
329      * @retval kErrorParse    Mesh Header could not be parsed.
330      *
331      */
332     Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
333 
334     /**
335      * Parses the Mesh Header from a given frame data.
336      *
337      * If the Mesh Header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
338      *
339      * @param[in,out]  aFrameData    The frame data to parse from.
340      *
341      * @retval kErrorNone     Mesh Header parsed successfully. @p aFrameData is updated to skip over parsed header.
342      * @retval kErrorParse    Mesh Header could not be parsed.
343      *
344      */
345     Error ParseFrom(FrameData &aFrameData);
346 
347     /**
348      * Parses the Mesh Header from a given message.
349      *
350      * @note The Mesh Header is read from offset zero within the @p aMessage.
351      *
352      * @param[in]  aMessage    The message to read from.
353      *
354      * @retval kErrorNone   Mesh Header parsed successfully.
355      * @retval kErrorParse  Mesh Header could not be parsed.
356      *
357      */
358     Error ParseFrom(const Message &aMessage);
359 
360     /**
361      * Parses the Mesh Header from a given message.
362      *
363      * @note The Mesh Header is read from offset zero within the @p aMessage.
364      *
365      * @param[in]  aMessage       The message to read from.
366      * @param[out] aHeaderLength  A reference to a variable to output the parsed header length (on success).
367      *
368      * @retval kErrorNone   Mesh Header parsed successfully.
369      * @retval kErrorParse  Mesh Header could not be parsed.
370      *
371      */
372     Error ParseFrom(const Message &aMessage, uint16_t &aHeaderLength);
373 
374     /**
375      * Returns the the Mesh Header length when written to a frame.
376      *
377      * @note The returned value from this method gives the header length (number of bytes) when the header is written
378      * to a frame or message. This should not be used to determine the parsed length (number of bytes read) when the
379      * Mesh Header is parsed from a frame/message (using `ParseFrom()` methods).
380      *
381      * @returns The length of the Mesh Header (in bytes) when written to a frame.
382      *
383      */
384     uint16_t GetHeaderLength(void) const;
385 
386     /**
387      * Returns the Hops Left value.
388      *
389      * @returns The Hops Left value.
390      *
391      */
GetHopsLeft(void) const392     uint8_t GetHopsLeft(void) const { return mHopsLeft; }
393 
394     /**
395      * Decrements the Hops Left value (if it is not zero).
396      *
397      */
398     void DecrementHopsLeft(void);
399 
400     /**
401      * Returns the Mesh Source address.
402      *
403      * @returns The Mesh Source address.
404      *
405      */
GetSource(void) const406     uint16_t GetSource(void) const { return mSource; }
407 
408     /**
409      * Returns the Mesh Destination address.
410      *
411      * @returns The Mesh Destination address.
412      *
413      */
GetDestination(void) const414     uint16_t GetDestination(void) const { return mDestination; }
415 
416     /**
417      * Appends the Mesh Header into a given frame.
418      *
419      * @param[out]  aFrameBuilder  The `FrameBuilder` to append to.
420      *
421      * @retval kErrorNone    Successfully appended the MeshHeader to @p aFrameBuilder.
422      * @retval kErrorNoBufs  Insufficient available buffers.
423      *
424      */
425     Error AppendTo(FrameBuilder &aFrameBuilder) const;
426 
427     /**
428      * Appends the Mesh Header to a given message.
429      *
430      *
431      * @param[out] aMessage  A message to append the Mesh Header to.
432      *
433      * @retval kErrorNone    Successfully appended the Mesh Header to @p aMessage.
434      * @retval kErrorNoBufs  Insufficient available buffers to grow @p aMessage.
435      *
436      */
437     Error AppendTo(Message &aMessage) const;
438 
439 private:
440     static constexpr uint8_t kDispatch     = 2 << 6;
441     static constexpr uint8_t kDispatchMask = 3 << 6;
442     static constexpr uint8_t kHopsLeftMask = 0x0f;
443     static constexpr uint8_t kSourceShort  = 1 << 5;
444     static constexpr uint8_t kDestShort    = 1 << 4;
445     static constexpr uint8_t kDeepHopsLeft = 0x0f;
446 
447     // Dispatch byte + src + dest
448     static constexpr uint16_t kMinHeaderLength      = sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint16_t);
449     static constexpr uint16_t kDeepHopsHeaderLength = kMinHeaderLength + sizeof(uint8_t); // min header + deep hops
450 
451     uint16_t mSource;
452     uint16_t mDestination;
453     uint8_t  mHopsLeft;
454 };
455 
456 /**
457  * Implements Fragment Header generation and parsing.
458  *
459  */
460 class FragmentHeader
461 {
462 public:
463     OT_TOOL_PACKED_BEGIN
464     class FirstFrag
465     {
466     public:
467         /**
468          * Initializes the `FirstFrag`.
469          *
470          * @param[in] aSize  The Datagram Size value.
471          * @param[in] aTag   The Datagram Tag value.
472          *
473          */
Init(uint16_t aSize,uint16_t aTag)474         void Init(uint16_t aSize, uint16_t aTag)
475         {
476             mDispatchSize = BigEndian::HostSwap16(kFirstDispatch | (aSize & kSizeMask));
477             mTag          = BigEndian::HostSwap16(aTag);
478         }
479 
480     private:
481         //                       1                   2                   3
482         //   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
483         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
484         //  |1 1 0 0 0|    datagram_size    |         datagram_tag          |
485         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
486 
487         static constexpr uint16_t kFirstDispatch = 0xc000; // 0b11000_0000_0000_0000
488 
489         uint16_t mDispatchSize;
490         uint16_t mTag;
491     } OT_TOOL_PACKED_END;
492 
493     OT_TOOL_PACKED_BEGIN
494     class NextFrag
495     {
496     public:
497         /**
498          * Initializes the `NextFrag`.
499          *
500          * @param[in] aSize    The Datagram Size value.
501          * @param[in] aTag     The Datagram Tag value.
502          * @param[in] aOffset  The Datagram Offset value.
503          *
504          */
Init(uint16_t aSize,uint16_t aTag,uint16_t aOffset)505         void Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset)
506         {
507             mDispatchSize = BigEndian::HostSwap16(kNextDispatch | (aSize & kSizeMask));
508             mTag          = BigEndian::HostSwap16(aTag);
509             mOffset       = static_cast<uint8_t>(aOffset >> 3);
510         }
511 
512     private:
513         //                       1                   2                   3
514         //   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
515         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516         //  |1 1 1 0 0|    datagram_size    |         datagram_tag          |
517         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
518         //  |datagram_offset|
519         //  +-+-+-+-+-+-+-+-+
520 
521         static constexpr uint16_t kNextDispatch = 0xe000; // 0b11100_0000_0000_0000
522 
523         uint16_t mDispatchSize;
524         uint16_t mTag;
525         uint8_t  mOffset;
526     } OT_TOOL_PACKED_END;
527 
528     /**
529      * Indicates whether or not the header (in a given frame) is a Fragment Header.
530      *
531      * @note This method checks whether the frame has the minimum required length and that the first byte in
532      * header (dispatch byte) matches the Fragment Header dispatch value. It does not fully parse and validate the
533      * Fragment Header. `ParseFrom()` method can be used to fully parse and validate the header.
534      *
535      * @param[in] aFrameData   The frame data.
536      *
537      * @retval TRUE   If the header matches the Fragment Header dispatch value.
538      * @retval FALSE  If the header does not match the Fragment Header dispatch value.
539      *
540      */
541     static bool IsFragmentHeader(const FrameData &aFrameData);
542 
543     /**
544      * Parses the Fragment Header from a given frame data.
545      *
546      * If the Fragment Header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes.
547      *
548      * @param[in,out]  aFrameData    The frame data to parse from.
549      *
550      * @retval kErrorNone     Fragment Header parsed successfully. @p aFrameData is updated to skip over parsed header.
551      * @retval kErrorParse    Fragment header could not be parsed.
552      *
553      */
554     Error ParseFrom(FrameData &aFrameData);
555 
556     /**
557      * Parses the Fragment Header from a message.
558      *
559      * @param[in]  aMessage      The message to read from.
560      * @param[in]  aOffset       The offset within the message to start reading from.
561      * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success).
562      *
563      * @retval kErrorNone     Fragment Header parsed successfully.
564      * @retval kErrorParse    Fragment header could not be parsed from @p aFrame.
565      *
566      */
567     Error ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t &aHeaderLength);
568 
569     /**
570      * Returns the Datagram Size value.
571      *
572      * @returns The Datagram Size value.
573      *
574      */
GetDatagramSize(void) const575     uint16_t GetDatagramSize(void) const { return mSize; }
576 
577     /**
578      * Returns the Datagram Tag value.
579      *
580      * @returns The Datagram Tag value.
581      *
582      */
GetDatagramTag(void) const583     uint16_t GetDatagramTag(void) const { return mTag; }
584 
585     /**
586      * Returns the Datagram Offset value.
587      *
588      * The returned offset value is always multiple of 8.
589      *
590      * @returns The Datagram Offset value (multiple of 8).
591      *
592      */
GetDatagramOffset(void) const593     uint16_t GetDatagramOffset(void) const { return mOffset; }
594 
595 private:
596     static constexpr uint8_t kDispatch     = 0xc0;   // 0b1100_0000
597     static constexpr uint8_t kDispatchMask = 0xd8;   // 0b1101_1000 accepts first (0b1100_0xxx) and next (0b1110_0xxx).
598     static constexpr uint8_t kOffsetFlag   = 1 << 5; // Indicate first (no offset) vs. next (offset present) fragment.
599 
600     static constexpr uint16_t kSizeMask   = 0x7ff;  // 0b0111_1111_1111 (first 11 bits).
601     static constexpr uint16_t kOffsetMask = 0xfff8; // Clears the last 3 bits to ensure offset is a multiple of 8.
602 
603     static constexpr uint8_t kSizeIndex   = 0; // Start index of Size field in the Fragment Header byte sequence.
604     static constexpr uint8_t kTagIndex    = 2; // Start index of Tag field in the Fragment Header byte sequence.
605     static constexpr uint8_t kOffsetIndex = 4; // Start index of Offset field in the Fragment Header byte sequence.
606 
607     static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength);
608 
609     Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
610 
611     uint16_t mSize;
612     uint16_t mTag;
613     uint16_t mOffset;
614 };
615 
616 /**
617  * @}
618  */
619 
620 } // namespace Lowpan
621 } // namespace ot
622 
623 #endif // LOWPAN_HPP_
624