| /* |
| * Copyright (c) 2016, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /** |
| * @file |
| * This file includes definitions for 6LoWPAN header compression. |
| */ |
| |
| #ifndef LOWPAN_HPP_ |
| #define LOWPAN_HPP_ |
| |
| #include "openthread-core-config.h" |
| |
| #include "common/debug.hpp" |
| #include "common/locator.hpp" |
| #include "common/message.hpp" |
| #include "mac/mac_types.hpp" |
| #include "net/ip6.hpp" |
| #include "net/ip6_address.hpp" |
| |
| namespace ot { |
| |
| /** |
| * @addtogroup core-6lowpan |
| * |
| * @brief |
| * This module includes definitions for 6LoWPAN header compression. |
| * |
| * @{ |
| */ |
| |
| /** |
| * @namespace ot::Lowpan |
| * |
| * @brief |
| * This namespace includes definitions for 6LoWPAN message processing. |
| * |
| */ |
| namespace Lowpan { |
| |
| using ot::Encoding::BigEndian::HostSwap16; |
| |
| /** |
| * This structure represents a LOWPAN_IPHC Context. |
| * |
| */ |
| struct Context |
| { |
| const uint8_t *mPrefix; ///< A pointer to the prefix. |
| uint8_t mPrefixLength; ///< The prefix length. |
| uint8_t mContextId; ///< The Context ID. |
| bool mCompressFlag; ///< The Context compression flag. |
| }; |
| |
| /** |
| * This class defines a buffer writer used by the 6LoWPAN compressor. |
| * |
| */ |
| class BufferWriter |
| { |
| public: |
| /** |
| * This constructor initializes the buffer writer. |
| * |
| * @param[in] aBuf A pointer to the write buffer. |
| * @param[in] aLength The size of the write buffer. |
| * |
| */ |
| BufferWriter(uint8_t *aBuf, uint16_t aLength) |
| : mWritePointer(aBuf) |
| , mEndPointer(aBuf + aLength) |
| { |
| } |
| |
| /** |
| * This method indicates whether there is buffer space available to write @p aLength bytes. |
| * |
| * @param[in] aLength Number of bytes to write. |
| * |
| * @retval TRUE Enough buffer space is available to write the requested number of bytes. |
| * @retval FALSE Insufficient buffer space to write the requested number of bytes. |
| * |
| */ |
| bool CanWrite(uint8_t aLength) const { return (mWritePointer + aLength) <= mEndPointer; } |
| |
| /** |
| * This method returns the current write pointer value. |
| * |
| * @returns the current write pointer value. |
| * |
| */ |
| uint8_t *GetWritePointer(void) { return mWritePointer; } |
| |
| /** |
| * This method advances the write pointer. |
| * |
| * @param[in] aLength Number of bytes to advance. |
| * |
| * @retval OT_ERROR_NONE Enough buffer space is available to advance the requested number of bytes. |
| * @retval OT_ERROR_NO_BUFS Insufficient buffer space to advance the requested number of bytes. |
| * |
| */ |
| otError Advance(uint8_t aLength) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| VerifyOrExit(CanWrite(aLength), error = OT_ERROR_NO_BUFS); |
| mWritePointer += aLength; |
| |
| exit: |
| return error; |
| } |
| |
| /** |
| * This method writes a byte into the buffer and updates the write pointer, if space is available. |
| * |
| * @param[in] aByte Byte to write. |
| * |
| * @retval OT_ERROR_NONE Successfully wrote the byte and updated the pointer. |
| * @retval OT_ERROR_NO_BUFS Insufficient buffer space to write the byte. |
| * |
| */ |
| otError Write(uint8_t aByte) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| VerifyOrExit(CanWrite(sizeof(aByte)), error = OT_ERROR_NO_BUFS); |
| |
| *mWritePointer++ = aByte; |
| |
| exit: |
| return error; |
| } |
| |
| /** |
| * This method writes a byte sequence into the buffer and updates the write pointer, if space is available. |
| * |
| * @param[in] aBuf A pointer to the byte sequence. |
| * @param[in] aLength Number of bytes to write. |
| * |
| * @retval OT_ERROR_NONE Successfully wrote the byte sequence and updated the pointer. |
| * @retval OT_ERROR_NO_BUFS Insufficient buffer space to write the byte sequence. |
| * |
| */ |
| otError Write(const void *aBuf, uint8_t aLength) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| VerifyOrExit(CanWrite(aLength), error = OT_ERROR_NO_BUFS); |
| |
| memcpy(mWritePointer, aBuf, aLength); |
| mWritePointer += aLength; |
| |
| exit: |
| return error; |
| } |
| |
| /** |
| * This method writes a byte sequence into the buffer and updates the write pointer, if space is available. |
| * |
| * The byte sequence is taken from a message buffer at the current message buffer's offset. |
| * |
| * @param[in] aMessage A message buffer. |
| * @param[in] aLength Number of bytes to write. |
| * |
| * @retval OT_ERROR_NONE Successfully wrote the byte sequence and updated the pointer. |
| * @retval OT_ERROR_NO_BUFS Insufficient buffer space to write the byte sequence. |
| * |
| */ |
| otError Write(const Message &aMessage, uint8_t aLength) |
| { |
| otError error = OT_ERROR_NONE; |
| int rval; |
| |
| VerifyOrExit(CanWrite(aLength), error = OT_ERROR_NO_BUFS); |
| |
| rval = aMessage.Read(aMessage.GetOffset(), aLength, mWritePointer); |
| assert(rval == aLength); |
| |
| mWritePointer += aLength; |
| |
| exit: |
| return error; |
| } |
| |
| private: |
| uint8_t *mWritePointer; |
| uint8_t *mEndPointer; |
| }; |
| |
| /** |
| * This class implements LOWPAN_IPHC header compression. |
| * |
| */ |
| class Lowpan : public InstanceLocator |
| { |
| public: |
| /** |
| * This constructor initializes the object. |
| * |
| * @param[in] aInstance A reference to the OpenThread instance. |
| * |
| */ |
| explicit Lowpan(Instance &aInstance); |
| |
| /** |
| * This method indicates whether or not the header is a LOWPAN_IPHC header. |
| * |
| * @param[in] aHeader A pointer to the header. |
| * |
| * @retval TRUE If the header matches the LOWPAN_IPHC dispatch value. |
| * @retval FALSE If the header does not match the LOWPAN_IPHC dispatch value. |
| */ |
| static bool IsLowpanHc(const uint8_t *aHeader) |
| { |
| return (aHeader[0] & (Lowpan::kHcDispatchMask >> 8)) == (Lowpan::kHcDispatch >> 8); |
| } |
| |
| /** |
| * This method compresses an IPv6 header. |
| * |
| * @param[in] aMessage A reference to the IPv6 message. |
| * @param[in] aMacSource The MAC source address. |
| * @param[in] aMacDest The MAC destination address. |
| * @param[out] aBuf A pointer where the compressed IPv6 header will be placed. |
| * |
| * @returns The size of the compressed header in bytes. |
| * |
| */ |
| otError Compress(Message & aMessage, |
| const Mac::Address &aMacSource, |
| const Mac::Address &aMacDest, |
| BufferWriter & aBuf); |
| |
| /** |
| * This method decompresses a LOWPAN_IPHC header. |
| * |
| * @param[out] aMessage A reference where the IPv6 header will be placed. |
| * @param[in] aMacSource The MAC source address. |
| * @param[in] aMacDest The MAC destination address. |
| * @param[in] aBuf A pointer to the LOWPAN_IPHC header. |
| * @param[in] aBufLength The number of bytes in @p aBuf. |
| * @param[in] aDatagramLength The IPv6 datagram length. |
| * |
| * @returns The size of the compressed header in bytes. |
| * |
| */ |
| int Decompress(Message & aMessage, |
| const Mac::Address &aMacSource, |
| const Mac::Address &aMacDest, |
| const uint8_t * aBuf, |
| uint16_t aBufLength, |
| uint16_t aDatagramLength); |
| |
| /** |
| * This method decompresses a LOWPAN_IPHC header. |
| * |
| * @param[out] aIp6Header A reference where the IPv6 header will be placed. |
| * @param[out] aCommpressedNextHeader A boolean reference to output whether next header is compressed or not. |
| * @param[in] aMacSource The MAC source address. |
| * @param[in] aMacDest The MAC destination address. |
| * @param[in] aBuf A pointer to the LOWPAN_IPHC header. |
| * @param[in] aBufLength The number of bytes in @p aBuf. |
| * |
| * @returns The size of the compressed header in bytes or -1 if decompression fails. |
| * |
| */ |
| int DecompressBaseHeader(Ip6::Header & aIp6Header, |
| bool & aCompressedNextHeader, |
| const Mac::Address &aMacSource, |
| const Mac::Address &aMacDest, |
| const uint8_t * aBuf, |
| uint16_t aBufLength); |
| |
| /** |
| * This method decompresses a LOWPAN_NHC UDP header. |
| * |
| * @param[out] aUdpHeader A reference where the UDP header will be placed. |
| * @param[in] aBuf A pointer to the LOWPAN_NHC header. |
| * @param[in] aBufLength The number of bytes in @p aBuf. |
| * |
| * @returns The size of the compressed header in bytes or -1 if decompression fails. |
| * |
| */ |
| int DecompressUdpHeader(Ip6::UdpHeader &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength); |
| |
| private: |
| enum |
| { |
| kHcDispatch = 3 << 13, |
| kHcDispatchMask = 7 << 13, |
| |
| kHcTrafficClass = 1 << 11, |
| kHcFlowLabel = 2 << 11, |
| kHcTrafficFlow = 3 << 11, |
| kHcTrafficFlowMask = 3 << 11, |
| kHcNextHeader = 1 << 10, |
| kHcHopLimit1 = 1 << 8, |
| kHcHopLimit64 = 2 << 8, |
| kHcHopLimit255 = 3 << 8, |
| kHcHopLimitMask = 3 << 8, |
| kHcContextId = 1 << 7, |
| kHcSrcAddrContext = 1 << 6, |
| kHcSrcAddrMode0 = 0 << 4, |
| kHcSrcAddrMode1 = 1 << 4, |
| kHcSrcAddrMode2 = 2 << 4, |
| kHcSrcAddrMode3 = 3 << 4, |
| kHcSrcAddrModeMask = 3 << 4, |
| kHcMulticast = 1 << 3, |
| kHcDstAddrContext = 1 << 2, |
| kHcDstAddrMode0 = 0 << 0, |
| kHcDstAddrMode1 = 1 << 0, |
| kHcDstAddrMode2 = 2 << 0, |
| kHcDstAddrMode3 = 3 << 0, |
| kHcDstAddrModeMask = 3 << 0, |
| |
| kExtHdrDispatch = 0xe0, |
| kExtHdrDispatchMask = 0xf0, |
| |
| kExtHdrEidHbh = 0x00, |
| kExtHdrEidRouting = 0x02, |
| kExtHdrEidFragment = 0x04, |
| kExtHdrEidDst = 0x06, |
| kExtHdrEidMobility = 0x08, |
| kExtHdrEidIp6 = 0x0e, |
| kExtHdrEidMask = 0x0e, |
| |
| kExtHdrNextHeader = 0x01, |
| |
| kUdpDispatch = 0xf0, |
| kUdpDispatchMask = 0xf8, |
| kUdpChecksum = 1 << 2, |
| kUdpPortMask = 3 << 0, |
| }; |
| |
| otError CompressExtensionHeader(Message &aMessage, BufferWriter &aBuf, uint8_t &aNextHeader); |
| otError CompressSourceIid(const Mac::Address &aMacAddr, |
| const Ip6::Address &aIpAddr, |
| const Context & aContext, |
| uint16_t & aHcCtl, |
| BufferWriter & aBuf); |
| otError CompressDestinationIid(const Mac::Address &aMacAddr, |
| const Ip6::Address &aIpAddr, |
| const Context & aContext, |
| uint16_t & aHcCtl, |
| BufferWriter & aBuf); |
| otError CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, BufferWriter &aBuf); |
| otError CompressUdp(Message &aMessage, BufferWriter &aBuf); |
| |
| int DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength); |
| int DecompressUdpHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength, uint16_t aDatagramLength); |
| otError DispatchToNextHeader(uint8_t aDispatch, uint8_t &aNextHeader); |
| |
| static void CopyContext(const Context &aContext, Ip6::Address &aAddress); |
| static otError ComputeIid(const Mac::Address &aMacAddr, const Context &aContext, Ip6::Address &aIpAddress); |
| }; |
| |
| /** |
| * This class implements Mesh Header generation and processing. |
| * |
| */ |
| class MeshHeader |
| { |
| public: |
| enum |
| { |
| kAdditionalHopsLeft = 1 ///< The additional value that is added to predicted value of the route cost. |
| }; |
| |
| /** |
| * This method initializes the Mesh Header with a given Mesh Source, Mesh Destination and Hops Left value. |
| * |
| * @param[in] aSource The Mesh Source address. |
| * @param[in] aDestination The Mesh Destination address. |
| * @param[in] aHopsLeft The Hops Left value. |
| * |
| */ |
| void Init(uint16_t aSource, uint16_t aDestination, uint8_t aHopsLeft); |
| |
| /** |
| * This static method indicates whether or not the header (in a given frame) is a Mesh Header. |
| * |
| * @note This method checks whether the first byte in header/frame (dispatch byte) matches the Mesh Header dispatch |
| * It does not fully parse and validate the Mesh Header. `ParseFrom()` method can be used to fully parse and |
| * validate the header. |
| * |
| * @retval TRUE If the header matches the Mesh Header dispatch value. |
| * @retval FALSE If the header does not match the Mesh Header dispatch value. |
| * |
| */ |
| static bool IsMeshHeader(const uint8_t *aFrame, uint16_t aFrameLength); |
| |
| /** |
| * This method parses the Mesh Header from a frame @p aFrame. |
| * |
| * @param[in] aFrame The pointer to the frame. |
| * @param[in] aFrameLength The length of the frame. |
| * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success). |
| * |
| * @retval OT_ERROR_NONE Mesh Header parsed successfully. |
| * @retval OT_ERROR_PARSE Mesh Header could not be parsed. |
| * |
| */ |
| otError ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength); |
| |
| /** |
| * This method parses the Mesh Header from a given message. |
| * |
| * @note The Mesh Header is read from offset zero within the @p aMessage. |
| * |
| * @param[in] aMessage The message to read from. |
| * |
| * @retval OT_ERROR_NONE Mesh Header parsed successfully. |
| * @retval OT_ERROR_PARSE Mesh Header could not be parsed. |
| * |
| */ |
| otError ParseFrom(const Message &aMessage); |
| |
| /** |
| * This method parses the Mesh Header from a given message. |
| * |
| * @note The Mesh Header is read from offset zero within the @p aMessage. |
| * |
| * @param[in] aMessage The message to read from. |
| * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success). |
| * |
| * @retval OT_ERROR_NONE Mesh Header parsed successfully. |
| * @retval OT_ERROR_PARSE Mesh Header could not be parsed. |
| * |
| */ |
| otError ParseFrom(const Message &aMessage, uint16_t &aHeaderLength); |
| |
| /** |
| * This method returns the the Mesh Header length when written to a frame. |
| * |
| * @note The returned value from this method gives the header length (number of bytes) when the header is written |
| * to a frame or message. This should not be used to determine the parsed length (number of bytes read) when the |
| * Mesh Header is parsed from a frame/message (using `ParseFrom()` methods). |
| * |
| * @returns The length of the Mesh Header (in bytes) when written to a frame. |
| * |
| */ |
| uint16_t GetHeaderLength(void) const; |
| |
| /** |
| * This method returns the Hops Left value. |
| * |
| * @returns The Hops Left value. |
| * |
| */ |
| uint8_t GetHopsLeft(void) const { return mHopsLeft; } |
| |
| /** |
| * This method decrements the Hops Left value (if it is not zero). |
| * |
| */ |
| void DecrementHopsLeft(void); |
| |
| /** |
| * This method returns the Mesh Source address. |
| * |
| * @returns The Mesh Source address. |
| * |
| */ |
| uint16_t GetSource(void) const { return mSource; } |
| |
| /** |
| * This method returns the Mesh Destination address. |
| * |
| * @returns The Mesh Destination address. |
| * |
| */ |
| uint16_t GetDestination(void) const { return mDestination; } |
| |
| /** |
| * This method writes the Mesh Header into a given frame. |
| * |
| * @note This method expects the frame buffer to have enough space for the entire Mesh Header. |
| * |
| * @param[out] aFrame The pointer to the frame buffer to write to. |
| * |
| * @returns The header length (number of bytes written). |
| * |
| */ |
| uint16_t WriteTo(uint8_t *aFrame) const; |
| |
| /** |
| * This method writes the Mesh Header to a message at a given offset. |
| * |
| * @note This method expects the @p aMessage length to be already set such that there is enough space for the |
| * entire Mesh Header to be written. |
| * |
| * @param[out] aMessage A message to write the Mesh Header into. |
| * @param[in] aOffset The offset at which to write the header. |
| * |
| * @returns The header length (number of bytes written). |
| * |
| */ |
| uint16_t WriteTo(Message &aMessage, uint16_t aOffset) const; |
| |
| private: |
| enum |
| { |
| kDispatch = 2 << 6, |
| kDispatchMask = 3 << 6, |
| kHopsLeftMask = 0x0f, |
| kSourceShort = 1 << 5, |
| kDestShort = 1 << 4, |
| kDeepHopsLeft = 0x0f, |
| kMinHeaderLength = sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint16_t), // dispatch byte + src + dest |
| kDeepHopsHeaderLength = kMinHeaderLength + sizeof(uint8_t), // min header + deep hops |
| }; |
| |
| uint16_t mSource; |
| uint16_t mDestination; |
| uint8_t mHopsLeft; |
| }; |
| |
| /** |
| * This class implements Fragment Header generation and parsing. |
| * |
| */ |
| class FragmentHeader |
| { |
| public: |
| enum |
| { |
| kFirstFragmentHeaderSize = 4, ///< First fragment header size in octets. |
| kSubsequentFragmentHeaderSize = 5, ///< Subsequent fragment header size in octets. |
| }; |
| |
| /** |
| * This method initializes the Fragment Header as a first fragment. |
| * |
| * A first fragment header starts at offset zero. |
| * |
| * @param[in] aSize The Datagram Size value. |
| * @param[in] aTage The Datagram Tag value. |
| * |
| */ |
| void InitFirstFragment(uint16_t aSize, uint16_t aTag) { Init(aSize, aTag, 0); } |
| |
| /** |
| * This method initializes the Fragment Header. |
| * |
| * The @p aOffset value will be truncated to become a multiple of 8. |
| * |
| * @param[in] aSize The Datagram Size value. |
| * @param[in] aTage The Datagram Tag value. |
| * @param[in] aOffset The Datagram Offset value. |
| * |
| */ |
| void Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset); |
| |
| /** |
| * This static method indicates whether or not the header (in a given frame) is a Fragment Header. |
| * |
| * @note This method checks whether the frame has the minimum required length and that the first byte in |
| * header (dispatch byte) matches the Fragment Header dispatch value. It does not fully parse and validate the |
| * Fragment Header. `ParseFrom()` method can be used to fully parse and validate the header. |
| * |
| * @retval TRUE If the header matches the Fragment Header dispatch value. |
| * @retval FALSE If the header does not match the Fragment Header dispatch value. |
| * |
| */ |
| static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength); |
| |
| /** |
| * This method parses the Fragment Header from a frame @p aFrame. |
| * |
| * @param[in] aFrame The pointer to the frame. |
| * @param[in] aFrameLength The length of the frame. |
| * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success). |
| * |
| * @retval OT_ERROR_NONE Fragment Header parsed successfully. |
| * @retval OT_ERROR_PARSE Fragment header could not be parsed from @p aFrame. |
| * |
| */ |
| otError ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength); |
| |
| /** |
| * This method parses the Fragment Header from a message. |
| * |
| * @param[in] aMessage The message to read from. |
| * @param[in] aOffset The offset within the message to start reading from. |
| * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success). |
| * |
| * @retval OT_ERROR_NONE Fragment Header parsed successfully. |
| * @retval OT_ERROR_PARSE Fragment header could not be parsed from @p aFrame. |
| * |
| */ |
| otError ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t &aHeaderLength); |
| |
| /** |
| * This method returns the Datagram Size value. |
| * |
| * @returns The Datagram Size value. |
| * |
| */ |
| uint16_t GetDatagramSize(void) const { return mSize; } |
| |
| /** |
| * This method returns the Datagram Tag value. |
| * |
| * @returns The Datagram Tag value. |
| * |
| */ |
| uint16_t GetDatagramTag(void) const { return mTag; } |
| |
| /** |
| * This method returns the Datagram Offset value. |
| * |
| * The returned offset value is always multiple of 8. |
| * |
| * @returns The Datagram Offset value (multiple of 8). |
| * |
| */ |
| uint16_t GetDatagramOffset(void) const { return mOffset; } |
| |
| /** |
| * This method writes the Fragment Header into a given frame. |
| * |
| * @note This method expects the frame buffer to have enough space for the entire Fragment Header |
| * |
| * @param[out] aFrame The pointer to the frame buffer to write to. |
| * |
| * @returns The header length (number of bytes written). |
| * |
| */ |
| uint16_t WriteTo(uint8_t *aFrame) const; |
| |
| private: |
| enum |
| { |
| kDispatch = 0xc0, // 0b1100_0000 |
| kDispatchMask = 0xd8, // 0b1101_1000 which accepts first frag (0b1100_0xxx) and next frag (0b1110_0xxx). |
| kOffsetFlag = 1 << 5, // Dispatch flag to indicate first (no offset) vs. next (offset is present) fragment. |
| kSizeMask = 0x7ff, // 0b0111_1111_1111 (first 11 bits). |
| kOffsetMask = 0xfff8, // Clears the last 3 bits to ensure offset is a multiple of 8. |
| kSizeIndex = 0, // Start index of Size field in the Fragment Header byte sequence. |
| kTagIndex = 2, // Start index of Tag field in the Fragment Header byte sequence. |
| kOffsetIndex = 4, // Start index of Offset field in the Fragment Header byte sequence. |
| }; |
| |
| uint16_t mSize; |
| uint16_t mTag; |
| uint16_t mOffset; |
| }; |
| |
| /** |
| * @} |
| */ |
| |
| } // namespace Lowpan |
| } // namespace ot |
| |
| #endif // LOWPAN_HPP_ |