| /* |
| * 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 "common/locator.hpp" |
| #include "common/message.hpp" |
| #include "mac/mac_frame.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 { |
| |
| /** |
| * 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 implements LOWPAN_IPHC header compression. |
| * |
| */ |
| class Lowpan: public ThreadNetifLocator |
| { |
| public: |
| /** |
| * This constructor initializes the object. |
| * |
| * @param[in] aThreadNetif A reference to the Thread network interface. |
| * |
| */ |
| explicit Lowpan(ThreadNetif &aThreadNetif); |
| |
| /** |
| * 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(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. |
| * |
| */ |
| int Compress(Message &aMessage, const Mac::Address &aMacSource, const Mac::Address &aMacDest, uint8_t *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] aBufLen The number of bytes in @p aBuf. |
| * @param[in] aDatagramLen 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 aBufLen, uint16_t aDatagramLen); |
| |
| /** |
| * This method decompresses a LOWPAN_IPHC header. |
| * |
| * @param[out] aHeader 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. |
| * |
| * @returns The size of the compressed header in bytes. |
| * |
| */ |
| int DecompressBaseHeader(Ip6::Header &aHeader, const Mac::Address &aMacSource, const Mac::Address &aMacDest, |
| 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, |
| }; |
| |
| int CompressExtensionHeader(Message &message, uint8_t *aBuf, uint8_t &nextHeader); |
| int CompressSourceIid(const Mac::Address &macaddr, const Ip6::Address &ipaddr, const Context &aContext, |
| uint16_t &hcCtl, uint8_t *aBuf); |
| int CompressDestinationIid(const Mac::Address &macaddr, const Ip6::Address &ipaddr, const Context &aContext, |
| uint16_t &hcCtl, uint8_t *aBuf); |
| int CompressMulticast(const Ip6::Address &ipaddr, uint16_t &hcCtl, uint8_t *aBuf); |
| int CompressUdp(Message &message, uint8_t *aBuf); |
| |
| int DecompressExtensionHeader(Message &message, const uint8_t *aBuf, uint16_t aBufLength); |
| int DecompressUdpHeader(Message &message, const uint8_t *aBuf, uint16_t aBufLength, uint16_t datagramLength); |
| otError DispatchToNextHeader(uint8_t dispatch, Ip6::IpProto &nextHeader); |
| |
| static otError 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. |
| * |
| */ |
| OT_TOOL_PACKED_BEGIN |
| class MeshHeader |
| { |
| public: |
| enum |
| { |
| kAdditionalHopsLeft = 1 ///< The additional value that is added to predicted value of the route cost. |
| }; |
| |
| /** |
| * Default constructor for the object. |
| * |
| */ |
| MeshHeader(void) { memset(this, 0, sizeof(*this)); } |
| |
| /** |
| * This method initializes the header. |
| * |
| */ |
| void Init(void) { mDispatchHopsLeft = kDispatch | kSourceShort | kDestinationShort; } |
| |
| /** |
| * This method initializes the mesh header from a frame @p aFrame. |
| * |
| * @param[in] aFrame The pointer to the frame. |
| * @param[in] aFrameLength The length of the frame. |
| * |
| * @retval OT_ERROR_NONE Mesh Header initialized successfully. |
| * @retval OT_ERROR_FAILED Mesh header could not be initialized from @p aFrame (e.g., frame not long enough). |
| * |
| */ |
| otError Init(const uint8_t *aFrame, uint8_t aFrameLength); |
| |
| /** |
| * This method initializes the mesh header from a message object @p aMessage. |
| * |
| * @param[in] aMessage The message object. |
| * |
| * @retval OT_ERROR_NONE Mesh Header initialized successfully. |
| * @retval OT_ERROR_FAILED Mesh header could not be initialized from @ aMessage(e.g., not long enough). |
| * |
| */ |
| otError Init(const Message &aMessage); |
| |
| /** |
| * This method indicates whether or not the header is a Mesh 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. |
| * |
| */ |
| bool IsMeshHeader(void) { return (mDispatchHopsLeft & kDispatchMask) == kDispatch; } |
| |
| /** |
| * This method indicates whether or not the Mesh Header appears to be well-formed. |
| * |
| * @retval TRUE If the header appears to be well-formed. |
| * @retval FALSE If the header does not appear to be well-formed. |
| * |
| */ |
| bool IsValid(void) { return (mDispatchHopsLeft & kSourceShort) && (mDispatchHopsLeft & kDestinationShort); } |
| |
| /** |
| * This method indicates whether or not the header contains Deep Hops Left field. |
| * |
| * @retval TRUE If the header does contain Deep Hops Left field. |
| * @retval FALSE If the header does not contain Deep Hops Left field. |
| * |
| */ |
| bool IsDeepHopsLeftField(void) { return (mDispatchHopsLeft & kHopsLeftMask) == kDeepHopsLeft; } |
| |
| /** |
| * This static method returns the size of the Mesh Header in bytes. |
| * |
| * @returns The size of the Mesh Header in bytes. |
| * |
| */ |
| uint8_t GetHeaderLength(void) { return sizeof(*this) - (IsDeepHopsLeftField() ? 0 : sizeof(mDeepHopsLeft)) ; } |
| |
| /** |
| * This method returns the Hops Left value. |
| * |
| * @returns The Hops Left value. |
| * |
| */ |
| uint8_t GetHopsLeft(void) { return IsDeepHopsLeftField() ? mDeepHopsLeft : mDispatchHopsLeft & kHopsLeftMask; } |
| |
| /** |
| * This method sets the Hops Left value. |
| * |
| * @param[in] aHops The Hops Left value. |
| * |
| */ |
| void SetHopsLeft(uint8_t aHops) { |
| if (aHops < kDeepHopsLeft && !IsDeepHopsLeftField()) { |
| mDispatchHopsLeft = (mDispatchHopsLeft & ~kHopsLeftMask) | aHops; |
| } |
| else { |
| mDispatchHopsLeft = (mDispatchHopsLeft & ~kHopsLeftMask) | kDeepHopsLeft; |
| mDeepHopsLeft = aHops; |
| } |
| } |
| |
| /** |
| * This method returns the Mesh Source address. |
| * |
| * @returns The Mesh Source address. |
| * |
| */ |
| uint16_t GetSource(void) { return HostSwap16(mAddress.mSource); } |
| |
| /** |
| * This method sets the Mesh Source address. |
| * |
| * @param[in] aSource The Mesh Source address. |
| * |
| */ |
| void SetSource(uint16_t aSource) { mAddress.mSource = HostSwap16(aSource); } |
| |
| /** |
| * This method returns the Mesh Destination address. |
| * |
| * @returns The Mesh Destination address. |
| * |
| */ |
| uint16_t GetDestination(void) { return HostSwap16(mAddress.mDestination); } |
| |
| /** |
| * This method sets the Mesh Destination address. |
| * |
| * @param[in] aDestination The Mesh Destination address. |
| * |
| */ |
| void SetDestination(uint16_t aDestination) { mAddress.mDestination = HostSwap16(aDestination); } |
| |
| /** |
| * This method appends Mesh Header to the @p aFrame frame. |
| * |
| * @param[in] aFrame The pointer to the frame. |
| * |
| */ |
| void AppendTo(uint8_t *aFrame) { |
| *aFrame++ = mDispatchHopsLeft; |
| |
| if (IsDeepHopsLeftField()) { |
| *aFrame++ = mDeepHopsLeft; |
| } |
| |
| memcpy(aFrame, &mAddress, sizeof(mAddress)); |
| } |
| |
| private: |
| enum |
| { |
| kDispatch = 2 << 6, |
| kDispatchMask = 3 << 6, |
| kHopsLeftMask = 0x0f, |
| kSourceShort = 1 << 5, |
| kDestinationShort = 1 << 4, |
| kDeepHopsLeft = 0x0f |
| }; |
| |
| uint8_t mDispatchHopsLeft; |
| uint8_t mDeepHopsLeft; |
| struct |
| { |
| uint16_t mSource; |
| uint16_t mDestination; |
| } mAddress OT_TOOL_PACKED_FIELD; |
| } OT_TOOL_PACKED_END; |
| |
| /** |
| * This class implements Fragment Header generation and parsing. |
| * |
| */ |
| OT_TOOL_PACKED_BEGIN |
| class FragmentHeader |
| { |
| public: |
| /** |
| * This method initializes the Fragment Header. |
| * |
| */ |
| void Init(void) { mDispatchSize = HostSwap16(kDispatch); } |
| |
| /** |
| * This method indicates whether or not the header is a Fragment 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. |
| * |
| */ |
| bool IsFragmentHeader(void) { return (HostSwap16(mDispatchSize) & kDispatchMask) == kDispatch; } |
| |
| /** |
| * This method returns the Fragment Header length. |
| * |
| * @returns The Fragment Header length in bytes. |
| * |
| */ |
| uint8_t GetHeaderLength(void) { |
| return (HostSwap16(mDispatchSize) & kOffset) ? sizeof(*this) : sizeof(*this) - sizeof(mOffset); |
| } |
| |
| /** |
| * This method returns the Datagram Size value. |
| * |
| * @returns The Datagram Size value. |
| * |
| */ |
| uint16_t GetDatagramSize(void) { return HostSwap16(mDispatchSize) & kSizeMask; } |
| |
| /** |
| * This method sets the Datagram Size value. |
| * |
| * @param[in] aSize The Datagram Size value. |
| * |
| */ |
| void SetDatagramSize(uint16_t aSize) { |
| mDispatchSize = HostSwap16((HostSwap16(mDispatchSize) & ~kSizeMask) | (aSize & kSizeMask)); |
| } |
| |
| /** |
| * This method returns the Datagram Tag value. |
| * |
| * @returns The Datagram Tag value. |
| * |
| */ |
| uint16_t GetDatagramTag(void) { return HostSwap16(mTag); } |
| |
| /** |
| * This method sets the Datagram Tag value. |
| * |
| * @param[in] aTag The Datagram Tag value. |
| * |
| */ |
| void SetDatagramTag(uint16_t aTag) { mTag = HostSwap16(aTag); } |
| |
| /** |
| * This method returns the Datagram Offset value. |
| * |
| * @returns The Datagram Offset value. |
| * |
| */ |
| uint16_t GetDatagramOffset(void) { return (HostSwap16(mDispatchSize) & kOffset) ? static_cast<uint16_t>(mOffset) * 8 : 0; } |
| |
| /** |
| * This method sets the Datagram Offset value. |
| * |
| * @param[in] aOffset The Datagram Offset value. |
| * |
| */ |
| void SetDatagramOffset(uint16_t aOffset) { |
| if (aOffset == 0) { |
| mDispatchSize = HostSwap16(HostSwap16(mDispatchSize) & ~kOffset); |
| } |
| else { |
| mDispatchSize = HostSwap16(HostSwap16(mDispatchSize) | kOffset); |
| mOffset = (aOffset >> 3) & kOffsetMask; |
| } |
| } |
| |
| private: |
| enum |
| { |
| kDispatch = 3 << 14, |
| kOffset = 1 << 13, |
| kDispatchMask = 0xd800, ///< Accept FRAG1 and FRAGN only. |
| kSizeMask = 0x7ff, |
| kOffsetMask = 0xff, |
| }; |
| |
| uint16_t mDispatchSize; |
| uint16_t mTag; |
| uint8_t mOffset; |
| } OT_TOOL_PACKED_END; |
| |
| /** |
| * @} |
| */ |
| |
| } // namespace Lowpan |
| } // namespace ot |
| |
| #endif // LOWPAN_HPP_ |