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