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/debug.hpp"
40 #include "common/locator.hpp"
41 #include "common/message.hpp"
42 #include "common/non_copyable.hpp"
43 #include "mac/mac_types.hpp"
44 #include "net/ip6.hpp"
45 #include "net/ip6_address.hpp"
46 
47 namespace ot {
48 
49 /**
50  * @addtogroup core-6lowpan
51  *
52  * @brief
53  *   This module includes definitions for 6LoWPAN header compression.
54  *
55  * @{
56  */
57 
58 /**
59  * @namespace ot::Lowpan
60  *
61  * @brief
62  *   This namespace includes definitions for 6LoWPAN message processing.
63  *
64  */
65 namespace Lowpan {
66 
67 using ot::Encoding::BigEndian::HostSwap16;
68 
69 /**
70  * This structure represents a LOWPAN_IPHC Context.
71  *
72  */
73 struct Context
74 {
75     Ip6::Prefix mPrefix;       ///< The Prefix
76     uint8_t     mContextId;    ///< The Context ID.
77     bool        mCompressFlag; ///< The Context compression flag.
78 };
79 
80 /**
81  * This class defines a buffer writer used by the 6LoWPAN compressor.
82  *
83  */
84 class BufferWriter
85 {
86 public:
87     /**
88      * This constructor initializes the buffer writer.
89      *
90      * @param[in]  aBuf     A pointer to the write buffer.
91      * @param[in]  aLength  The size of the write buffer.
92      *
93      */
BufferWriter(uint8_t * aBuf,uint16_t aLength)94     BufferWriter(uint8_t *aBuf, uint16_t aLength)
95         : mWritePointer(aBuf)
96         , mEndPointer(aBuf + aLength)
97     {
98     }
99 
100     /**
101      * This method indicates whether there is buffer space available to write @p aLength bytes.
102      *
103      * @param[in]  aLength  Number of bytes to write.
104      *
105      * @retval  TRUE   Enough buffer space is available to write the requested number of bytes.
106      * @retval  FALSE  Insufficient buffer space to write the requested number of bytes.
107      *
108      */
CanWrite(uint8_t aLength) const109     bool CanWrite(uint8_t aLength) const { return (mWritePointer + aLength) <= mEndPointer; }
110 
111     /**
112      * This method returns the current write pointer value.
113      *
114      * @returns the current write pointer value.
115      *
116      */
GetWritePointer(void)117     uint8_t *GetWritePointer(void) { return mWritePointer; }
118 
119     /**
120      * This method advances the write pointer.
121      *
122      * @param[in]  aLength  Number of bytes to advance.
123      *
124      * @retval kErrorNone    Enough buffer space is available to advance the requested number of bytes.
125      * @retval kErrorNoBufs  Insufficient buffer space to advance the requested number of bytes.
126      *
127      */
Advance(uint8_t aLength)128     Error Advance(uint8_t aLength)
129     {
130         Error error = kErrorNone;
131 
132         VerifyOrExit(CanWrite(aLength), error = kErrorNoBufs);
133         mWritePointer += aLength;
134 
135     exit:
136         return error;
137     }
138 
139     /**
140      * This method writes a byte into the buffer and updates the write pointer, if space is available.
141      *
142      * @param[in]  aByte  Byte to write.
143      *
144      * @retval  kErrorNone     Successfully wrote the byte and updated the pointer.
145      * @retval  kErrorNoBufs  Insufficient buffer space to write the byte.
146      *
147      */
Write(uint8_t aByte)148     Error Write(uint8_t aByte)
149     {
150         Error error = kErrorNone;
151 
152         VerifyOrExit(CanWrite(sizeof(aByte)), error = kErrorNoBufs);
153 
154         *mWritePointer++ = aByte;
155 
156     exit:
157         return error;
158     }
159 
160     /**
161      * This method writes a byte sequence into the buffer and updates the write pointer, if space is available.
162      *
163      * @param[in]  aBuf     A pointer to the byte sequence.
164      * @param[in]  aLength  Number of bytes to write.
165      *
166      * @retval kErrorNone    Successfully wrote the byte sequence and updated the pointer.
167      * @retval kErrorNoBufs  Insufficient buffer space to write the byte sequence.
168      *
169      */
Write(const void * aBuf,uint8_t aLength)170     Error Write(const void *aBuf, uint8_t aLength)
171     {
172         Error error = kErrorNone;
173 
174         VerifyOrExit(CanWrite(aLength), error = kErrorNoBufs);
175 
176         memcpy(mWritePointer, aBuf, aLength);
177         mWritePointer += aLength;
178 
179     exit:
180         return error;
181     }
182 
183     /**
184      * This method writes a byte sequence into the buffer and updates the write pointer, if space is available.
185      *
186      * The byte sequence is taken from a message buffer at the current message buffer's offset.
187      *
188      * @param[in]  aMessage  A message buffer.
189      * @param[in]  aLength   Number of bytes to write.
190      *
191      * @retval kErrorNone    Successfully wrote the byte sequence and updated the pointer.
192      * @retval kErrorNoBufs  Insufficient buffer space to write the byte sequence.
193      *
194      */
Write(const Message & aMessage,uint8_t aLength)195     Error Write(const Message &aMessage, uint8_t aLength)
196     {
197         Error error = kErrorNone;
198         int   rval;
199 
200         OT_UNUSED_VARIABLE(rval);
201 
202         VerifyOrExit(CanWrite(aLength), error = kErrorNoBufs);
203 
204         rval = aMessage.ReadBytes(aMessage.GetOffset(), mWritePointer, aLength);
205         OT_ASSERT(rval == aLength);
206 
207         mWritePointer += aLength;
208 
209     exit:
210         return error;
211     }
212 
213 private:
214     uint8_t *mWritePointer;
215     uint8_t *mEndPointer;
216 };
217 
218 /**
219  * This class implements LOWPAN_IPHC header compression.
220  *
221  */
222 class Lowpan : public InstanceLocator, private NonCopyable
223 {
224 public:
225     /**
226      * This constructor initializes the object.
227      *
228      * @param[in]  aInstance     A reference to the OpenThread instance.
229      *
230      */
231     explicit Lowpan(Instance &aInstance);
232 
233     /**
234      * This method indicates whether or not the header is a LOWPAN_IPHC header.
235      *
236      * @param[in]  aHeader  A pointer to the header.
237      *
238      * @retval TRUE   If the header matches the LOWPAN_IPHC dispatch value.
239      * @retval FALSE  If the header does not match the LOWPAN_IPHC dispatch value.
240      */
IsLowpanHc(const uint8_t * aHeader)241     static bool IsLowpanHc(const uint8_t *aHeader)
242     {
243         return (aHeader[0] & (Lowpan::kHcDispatchMask >> 8)) == (Lowpan::kHcDispatch >> 8);
244     }
245 
246     /**
247      * This method compresses an IPv6 header.
248      *
249      * @param[in]   aMessage     A reference to the IPv6 message.
250      * @param[in]   aMacSource   The MAC source address.
251      * @param[in]   aMacDest     The MAC destination address.
252      * @param[out]  aBuf         A pointer where the compressed IPv6 header will be placed.
253      *
254      * @returns The size of the compressed header in bytes.
255      *
256      */
257     Error Compress(Message &aMessage, const Mac::Address &aMacSource, const Mac::Address &aMacDest, BufferWriter &aBuf);
258 
259     /**
260      * This method decompresses a LOWPAN_IPHC header.
261      *
262      * @param[out]  aMessage         A reference where the IPv6 header will be placed.
263      * @param[in]   aMacSource       The MAC source address.
264      * @param[in]   aMacDest         The MAC destination address.
265      * @param[in]   aBuf             A pointer to the LOWPAN_IPHC header.
266      * @param[in]   aBufLength       The number of bytes in @p aBuf.
267      * @param[in]   aDatagramLength  The IPv6 datagram length.
268      *
269      * @returns The size of the compressed header in bytes.
270      *
271      */
272     int Decompress(Message &           aMessage,
273                    const Mac::Address &aMacSource,
274                    const Mac::Address &aMacDest,
275                    const uint8_t *     aBuf,
276                    uint16_t            aBufLength,
277                    uint16_t            aDatagramLength);
278 
279     /**
280      * This method decompresses a LOWPAN_IPHC header.
281      *
282      * @param[out]  aIp6Header              A reference where the IPv6 header will be placed.
283      * @param[out]  aCommpressedNextHeader  A boolean reference to output whether next header is compressed or not.
284      * @param[in]   aMacSource              The MAC source address.
285      * @param[in]   aMacDest                The MAC destination address.
286      * @param[in]   aBuf                    A pointer to the LOWPAN_IPHC header.
287      * @param[in]   aBufLength              The number of bytes in @p aBuf.
288      *
289      * @returns The size of the compressed header in bytes or -1 if decompression fails.
290      *
291      */
292     int DecompressBaseHeader(Ip6::Header &       aIp6Header,
293                              bool &              aCompressedNextHeader,
294                              const Mac::Address &aMacSource,
295                              const Mac::Address &aMacDest,
296                              const uint8_t *     aBuf,
297                              uint16_t            aBufLength);
298 
299     /**
300      * This method decompresses a LOWPAN_NHC UDP header.
301      *
302      * @param[out]  aUdpHeader    A reference where the UDP header will be placed.
303      * @param[in]   aBuf          A pointer to the LOWPAN_NHC header.
304      * @param[in]   aBufLength    The number of bytes in @p aBuf.
305      *
306      * @returns The size of the compressed header in bytes or -1 if decompression fails.
307      *
308      */
309     int DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength);
310 
311 private:
312     static constexpr uint16_t kHcDispatch     = 3 << 13;
313     static constexpr uint16_t kHcDispatchMask = 7 << 13;
314 
315     static constexpr uint16_t kHcTrafficClass    = 1 << 11;
316     static constexpr uint16_t kHcFlowLabel       = 2 << 11;
317     static constexpr uint16_t kHcTrafficFlow     = 3 << 11;
318     static constexpr uint16_t kHcTrafficFlowMask = 3 << 11;
319     static constexpr uint16_t kHcNextHeader      = 1 << 10;
320     static constexpr uint16_t kHcHopLimit1       = 1 << 8;
321     static constexpr uint16_t kHcHopLimit64      = 2 << 8;
322     static constexpr uint16_t kHcHopLimit255     = 3 << 8;
323     static constexpr uint16_t kHcHopLimitMask    = 3 << 8;
324     static constexpr uint16_t kHcContextId       = 1 << 7;
325     static constexpr uint16_t kHcSrcAddrContext  = 1 << 6;
326     static constexpr uint16_t kHcSrcAddrMode0    = 0 << 4;
327     static constexpr uint16_t kHcSrcAddrMode1    = 1 << 4;
328     static constexpr uint16_t kHcSrcAddrMode2    = 2 << 4;
329     static constexpr uint16_t kHcSrcAddrMode3    = 3 << 4;
330     static constexpr uint16_t kHcSrcAddrModeMask = 3 << 4;
331     static constexpr uint16_t kHcMulticast       = 1 << 3;
332     static constexpr uint16_t kHcDstAddrContext  = 1 << 2;
333     static constexpr uint16_t kHcDstAddrMode0    = 0 << 0;
334     static constexpr uint16_t kHcDstAddrMode1    = 1 << 0;
335     static constexpr uint16_t kHcDstAddrMode2    = 2 << 0;
336     static constexpr uint16_t kHcDstAddrMode3    = 3 << 0;
337     static constexpr uint16_t kHcDstAddrModeMask = 3 << 0;
338 
339     static constexpr uint8_t kExtHdrDispatch     = 0xe0;
340     static constexpr uint8_t kExtHdrDispatchMask = 0xf0;
341 
342     static constexpr uint8_t kExtHdrEidHbh      = 0x00;
343     static constexpr uint8_t kExtHdrEidRouting  = 0x02;
344     static constexpr uint8_t kExtHdrEidFragment = 0x04;
345     static constexpr uint8_t kExtHdrEidDst      = 0x06;
346     static constexpr uint8_t kExtHdrEidMobility = 0x08;
347     static constexpr uint8_t kExtHdrEidIp6      = 0x0e;
348     static constexpr uint8_t kExtHdrEidMask     = 0x0e;
349 
350     static constexpr uint8_t  kExtHdrNextHeader = 0x01;
351     static constexpr uint16_t kExtHdrMaxLength  = 255;
352 
353     static constexpr uint8_t kUdpDispatch     = 0xf0;
354     static constexpr uint8_t kUdpDispatchMask = 0xf8;
355 
356     static constexpr uint8_t kUdpChecksum = 1 << 2;
357     static constexpr uint8_t kUdpPortMask = 3 << 0;
358 
359     Error Compress(Message &           aMessage,
360                    const Mac::Address &aMacSource,
361                    const Mac::Address &aMacDest,
362                    BufferWriter &      aBuf,
363                    uint8_t &           aHeaderDepth);
364 
365     Error CompressExtensionHeader(Message &aMessage, BufferWriter &aBuf, uint8_t &aNextHeader);
366     Error CompressSourceIid(const Mac::Address &aMacAddr,
367                             const Ip6::Address &aIpAddr,
368                             const Context &     aContext,
369                             uint16_t &          aHcCtl,
370                             BufferWriter &      aBuf);
371     Error CompressDestinationIid(const Mac::Address &aMacAddr,
372                                  const Ip6::Address &aIpAddr,
373                                  const Context &     aContext,
374                                  uint16_t &          aHcCtl,
375                                  BufferWriter &      aBuf);
376     Error CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, BufferWriter &aBuf);
377     Error CompressUdp(Message &aMessage, BufferWriter &aBuf);
378 
379     int   DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength);
380     int   DecompressUdpHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength, uint16_t aDatagramLength);
381     Error DispatchToNextHeader(uint8_t aDispatch, uint8_t &aNextHeader);
382 
383     static void  CopyContext(const Context &aContext, Ip6::Address &aAddress);
384     static Error ComputeIid(const Mac::Address &aMacAddr, const Context &aContext, Ip6::Address &aIpAddress);
385 };
386 
387 /**
388  * This class implements Mesh Header generation and processing.
389  *
390  */
391 class MeshHeader
392 {
393 public:
394     /**
395      * The additional value that is added to predicted value of the route cost.
396      *
397      */
398     static constexpr uint8_t kAdditionalHopsLeft = 1;
399 
400     /**
401      * This method initializes the Mesh Header with a given Mesh Source, Mesh Destination and Hops Left value.
402      *
403      * @param[in]  aSource       The Mesh Source address.
404      * @param[in]  aDestination  The Mesh Destination address.
405      * @param[in]  aHopsLeft     The Hops Left value.
406      *
407      */
408     void Init(uint16_t aSource, uint16_t aDestination, uint8_t aHopsLeft);
409 
410     /**
411      * This static method indicates whether or not the header (in a given frame) is a Mesh Header.
412      *
413      * @note This method checks whether the first byte in header/frame (dispatch byte) matches the Mesh Header dispatch
414      * It does not fully parse and validate the Mesh Header. `ParseFrom()` method can be used to fully parse and
415      * validate the header.
416      *
417      * @retval TRUE   If the header matches the Mesh Header dispatch value.
418      * @retval FALSE  If the header does not match the Mesh Header dispatch value.
419      *
420      */
421     static bool IsMeshHeader(const uint8_t *aFrame, uint16_t aFrameLength);
422 
423     /**
424      * This method parses the Mesh Header from a frame @p aFrame.
425      *
426      * @param[in]  aFrame        The pointer to the frame.
427      * @param[in]  aFrameLength  The length of the frame.
428      * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success).
429      *
430      * @retval kErrorNone     Mesh Header parsed successfully.
431      * @retval kErrorParse    Mesh Header could not be parsed.
432      *
433      */
434     Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
435 
436     /**
437      * This method parses the Mesh Header from a given message.
438      *
439      * @note The Mesh Header is read from offset zero within the @p aMessage.
440      *
441      * @param[in]  aMessage    The message to read from.
442      *
443      * @retval kErrorNone   Mesh Header parsed successfully.
444      * @retval kErrorParse  Mesh Header could not be parsed.
445      *
446      */
447     Error ParseFrom(const Message &aMessage);
448 
449     /**
450      * This method parses the Mesh Header from a given message.
451      *
452      * @note The Mesh Header is read from offset zero within the @p aMessage.
453      *
454      * @param[in]  aMessage       The message to read from.
455      * @param[out] aHeaderLength  A reference to a variable to output the parsed header length (on success).
456      *
457      * @retval kErrorNone   Mesh Header parsed successfully.
458      * @retval kErrorParse  Mesh Header could not be parsed.
459      *
460      */
461     Error ParseFrom(const Message &aMessage, uint16_t &aHeaderLength);
462 
463     /**
464      * This method returns the the Mesh Header length when written to a frame.
465      *
466      * @note The returned value from this method gives the header length (number of bytes) when the header is written
467      * to a frame or message. This should not be used to determine the parsed length (number of bytes read) when the
468      * Mesh Header is parsed from a frame/message (using `ParseFrom()` methods).
469      *
470      * @returns The length of the Mesh Header (in bytes) when written to a frame.
471      *
472      */
473     uint16_t GetHeaderLength(void) const;
474 
475     /**
476      * This method returns the Hops Left value.
477      *
478      * @returns The Hops Left value.
479      *
480      */
GetHopsLeft(void) const481     uint8_t GetHopsLeft(void) const { return mHopsLeft; }
482 
483     /**
484      * This method decrements the Hops Left value (if it is not zero).
485      *
486      */
487     void DecrementHopsLeft(void);
488 
489     /**
490      * This method returns the Mesh Source address.
491      *
492      * @returns The Mesh Source address.
493      *
494      */
GetSource(void) const495     uint16_t GetSource(void) const { return mSource; }
496 
497     /**
498      * This method returns the Mesh Destination address.
499      *
500      * @returns The Mesh Destination address.
501      *
502      */
GetDestination(void) const503     uint16_t GetDestination(void) const { return mDestination; }
504 
505     /**
506      * This method writes the Mesh Header into a given frame.
507      *
508      * @note This method expects the frame buffer to have enough space for the entire Mesh Header.
509      *
510      * @param[out]  aFrame  The pointer to the frame buffer to write to.
511      *
512      * @returns The header length (number of bytes written).
513      *
514      */
515     uint16_t WriteTo(uint8_t *aFrame) const;
516 
517     /**
518      * This method writes the Mesh Header to a message at a given offset.
519      *
520      * @note This method expects the @p aMessage length to be already set such that there is enough space for the
521      * entire Mesh Header to be written.
522      *
523      * @param[out] aMessage  A message to write the Mesh Header into.
524      * @param[in]  aOffset   The offset at which to write the header.
525      *
526      * @returns The header length (number of bytes written).
527      *
528      */
529     uint16_t WriteTo(Message &aMessage, uint16_t aOffset) const;
530 
531 private:
532     static constexpr uint8_t kDispatch     = 2 << 6;
533     static constexpr uint8_t kDispatchMask = 3 << 6;
534     static constexpr uint8_t kHopsLeftMask = 0x0f;
535     static constexpr uint8_t kSourceShort  = 1 << 5;
536     static constexpr uint8_t kDestShort    = 1 << 4;
537     static constexpr uint8_t kDeepHopsLeft = 0x0f;
538 
539     // Dispatch byte + src + dest
540     static constexpr uint16_t kMinHeaderLength      = sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint16_t);
541     static constexpr uint16_t kDeepHopsHeaderLength = kMinHeaderLength + sizeof(uint8_t); // min header + deep hops
542 
543     uint16_t mSource;
544     uint16_t mDestination;
545     uint8_t  mHopsLeft;
546 };
547 
548 /**
549  * This class implements Fragment Header generation and parsing.
550  *
551  */
552 class FragmentHeader
553 {
554 public:
555     static constexpr uint16_t kFirstFragmentHeaderSize      = 4; ///< First fragment header size in octets.
556     static constexpr uint16_t kSubsequentFragmentHeaderSize = 5; ///< Subsequent fragment header size in octets.
557 
558     /**
559      * This method initializes the Fragment Header as a first fragment.
560      *
561      * A first fragment header starts at offset zero.
562      *
563      * @param[in] aSize   The Datagram Size value.
564      * @param[in] aTag    The Datagram Tag value.
565      *
566      */
InitFirstFragment(uint16_t aSize,uint16_t aTag)567     void InitFirstFragment(uint16_t aSize, uint16_t aTag) { Init(aSize, aTag, 0); }
568 
569     /**
570      * This method initializes the Fragment Header.
571      *
572      * The @p aOffset value will be truncated to become a multiple of 8.
573      *
574      * @param[in] aSize   The Datagram Size value.
575      * @param[in] aTag    The Datagram Tag value.
576      * @param[in] aOffset The Datagram Offset value.
577      *
578      */
579     void Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset);
580 
581     /**
582      * This static method indicates whether or not the header (in a given frame) is a Fragment Header.
583      *
584      * @note This method checks whether the frame has the minimum required length and that the first byte in
585      * header (dispatch byte) matches the Fragment Header dispatch value. It does not fully parse and validate the
586      * Fragment Header. `ParseFrom()` method can be used to fully parse and validate the header.
587      *
588      * @retval TRUE   If the header matches the Fragment Header dispatch value.
589      * @retval FALSE  If the header does not match the Fragment Header dispatch value.
590      *
591      */
592     static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength);
593 
594     /**
595      * This method parses the Fragment Header from a frame @p aFrame.
596      *
597      * @param[in]  aFrame          The pointer to the frame.
598      * @param[in]  aFrameLength    The length of the frame.
599      * @param[out] aHeaderLength   A reference to a variable to output the parsed header length (on success).
600      *
601      * @retval kErrorNone     Fragment Header parsed successfully.
602      * @retval kErrorParse    Fragment header could not be parsed from @p aFrame.
603      *
604      */
605     Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength);
606 
607     /**
608      * This method parses the Fragment Header from a message.
609      *
610      * @param[in]  aMessage      The message to read from.
611      * @param[in]  aOffset       The offset within the message to start reading from.
612      * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success).
613      *
614      * @retval kErrorNone     Fragment Header parsed successfully.
615      * @retval kErrorParse    Fragment header could not be parsed from @p aFrame.
616      *
617      */
618     Error ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t &aHeaderLength);
619 
620     /**
621      * This method returns the Datagram Size value.
622      *
623      * @returns The Datagram Size value.
624      *
625      */
GetDatagramSize(void) const626     uint16_t GetDatagramSize(void) const { return mSize; }
627 
628     /**
629      * This method returns the Datagram Tag value.
630      *
631      * @returns The Datagram Tag value.
632      *
633      */
GetDatagramTag(void) const634     uint16_t GetDatagramTag(void) const { return mTag; }
635 
636     /**
637      * This method returns the Datagram Offset value.
638      *
639      * The returned offset value is always multiple of 8.
640      *
641      * @returns The Datagram Offset value (multiple of 8).
642      *
643      */
GetDatagramOffset(void) const644     uint16_t GetDatagramOffset(void) const { return mOffset; }
645 
646     /**
647      * This method writes the Fragment Header into a given frame.
648      *
649      * @note This method expects the frame buffer to have enough space for the entire Fragment Header
650      *
651      * @param[out]  aFrame  The pointer to the frame buffer to write to.
652      *
653      * @returns The header length (number of bytes written).
654      *
655      */
656     uint16_t WriteTo(uint8_t *aFrame) const;
657 
658 private:
659     static constexpr uint8_t kDispatch     = 0xc0;   // 0b1100_0000
660     static constexpr uint8_t kDispatchMask = 0xd8;   // 0b1101_1000 accepts first (0b1100_0xxx) and next (0b1110_0xxx).
661     static constexpr uint8_t kOffsetFlag   = 1 << 5; // Indicate first (no offset) vs. next (offset present) fragment.
662 
663     static constexpr uint16_t kSizeMask   = 0x7ff;  // 0b0111_1111_1111 (first 11 bits).
664     static constexpr uint16_t kOffsetMask = 0xfff8; // Clears the last 3 bits to ensure offset is a multiple of 8.
665 
666     static constexpr uint8_t kSizeIndex   = 0; // Start index of Size field in the Fragment Header byte sequence.
667     static constexpr uint8_t kTagIndex    = 2; // Start index of Tag field in the Fragment Header byte sequence.
668     static constexpr uint8_t kOffsetIndex = 4; // Start index of Offset field in the Fragment Header byte sequence.
669 
670     uint16_t mSize;
671     uint16_t mTag;
672     uint16_t mOffset;
673 };
674 
675 /**
676  * @}
677  */
678 
679 } // namespace Lowpan
680 } // namespace ot
681 
682 #endif // LOWPAN_HPP_
683