diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 1b5c27ac4..ba3b73c4b 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -73,6 +73,60 @@ Message *Ip6::NewMessage(uint16_t aReserved, const otMessageSettings *aSettings) Message::kTypeIp6, sizeof(Header) + sizeof(HopByHopHeader) + sizeof(OptionMpl) + aReserved, aSettings); } +uint8_t Ip6::DscpToPriority(uint8_t aDscp) +{ + uint8_t priority; + uint8_t cs = aDscp & kDscpCsMask; + + switch (cs) + { + case kDscpCs1: + case kDscpCs2: + priority = Message::kPriorityLow; + break; + + case kDscpCs0: + case kDscpCs3: + priority = Message::kPriorityNormal; + break; + + case kDscpCs4: + case kDscpCs5: + case kDscpCs6: + case kDscpCs7: + priority = Message::kPriorityHigh; + break; + + default: + priority = Message::kPriorityNormal; + break; + } + + return priority; +} + +uint8_t Ip6::PriorityToDscp(uint8_t aPriority) +{ + uint8_t dscp = kDscpCs0; + + switch (aPriority) + { + case Message::kPriorityLow: + dscp = kDscpCs1; + break; + + case Message::kPriorityNormal: + dscp = kDscpCs0; + break; + + case Message::kPriorityHigh: + dscp = kDscpCs4; + break; + } + + return dscp; +} + uint16_t Ip6::UpdateChecksum(uint16_t aChecksum, const Address &aAddress) { return Message::UpdateChecksum(aChecksum, aAddress.mFields.m8, sizeof(aAddress)); @@ -358,6 +412,7 @@ otError Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, IpProto const NetifUnicastAddress *source; header.Init(); + header.SetDscp(PriorityToDscp(aMessage.GetPriority())); header.SetPayloadLength(payloadLength); header.SetNextHeader(aIpProto); header.SetHopLimit(aMessageInfo.mHopLimit ? aMessageInfo.mHopLimit : static_cast(kDefaultHopLimit)); diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp index b5fb27161..9e7b8dd7a 100644 --- a/src/core/net/ip6.hpp +++ b/src/core/net/ip6.hpp @@ -121,6 +121,26 @@ public: */ Message *NewMessage(uint16_t aReserved, const otMessageSettings *aSettings = NULL); + /** + * This method converts the message priority level to IPv6 DSCP value. + * + * @param[in] aPriority The message priority level. + * + * @returns The IPv6 DSCP value. + * + */ + static uint8_t PriorityToDscp(uint8_t aPriority); + + /** + * This method converts the IPv6 DSCP value to message priority level. + * + * @param[in] aDscp The IPv6 DSCP value. + * + * @returns The message priority level. + * + */ + static uint8_t DscpToPriority(uint8_t aDscp); + /** * This constructor initializes the object. * diff --git a/src/core/net/ip6_headers.hpp b/src/core/net/ip6_headers.hpp index 433f3c1eb..b8443391f 100644 --- a/src/core/net/ip6_headers.hpp +++ b/src/core/net/ip6_headers.hpp @@ -101,6 +101,22 @@ enum IpProto kProtoDstOpts = 60, ///< Destination Options for IPv6 }; +/** + * Class Selectors + */ +enum IpDscpCs +{ + kDscpCs0 = 0, ///< Class selector codepoint 0 + kDscpCs1 = 8, ///< Class selector codepoint 8 + kDscpCs2 = 16, ///< Class selector codepoint 16 + kDscpCs3 = 24, ///< Class selector codepoint 24 + kDscpCs4 = 32, ///< Class selector codepoint 32 + kDscpCs5 = 40, ///< Class selector codepoint 40 + kDscpCs6 = 48, ///< Class selector codepoint 48 + kDscpCs7 = 56, ///< Class selector codepoint 56 + kDscpCsMask = 0x38, ///< Class selector mask +}; + enum { kVersionClassFlowSize = 4, ///< Combined size of Version, Class, Flow Label in bytes. @@ -170,6 +186,30 @@ public: */ bool IsVersion6(void) const { return (mVersionClassFlow.m8[0] & kVersionMask) == kVersion6; } + /** + * This method returns the IPv6 DSCP value. + * + * @returns The IPv6 DSCP value. + * + */ + uint8_t GetDscp(void) const + { + return static_cast((HostSwap32(mVersionClassFlow.m32[0]) & kDscpMask) >> kDscpOffset); + } + + /** + * This method sets the IPv6 DSCP value. + * + * @param[in] aDscp The IPv6 DSCP value. + * + */ + void SetDscp(uint8_t aDscp) + { + uint32_t tmp = HostSwap32(mVersionClassFlow.m32[0]); + tmp = (tmp & static_cast(~kDscpMask)) | ((static_cast(aDscp) << kDscpOffset) & kDscpMask); + mVersionClassFlow.m32[0] = HostSwap32(tmp); + } + /** * This method returns the IPv6 Payload Length value. * @@ -287,6 +327,8 @@ private: { kVersion6 = 0x60, kVersionMask = 0xf0, + kDscpOffset = 22, + kDscpMask = 0xfc00000, }; } OT_TOOL_PACKED_END; diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 804b6f510..6398181bf 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -1317,7 +1317,10 @@ void MeshForwarder::HandleFragment(uint8_t * aFrame, if (fragmentHeader.GetDatagramOffset() == 0) { - VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kTypeIp6, 0)) != NULL, + uint8_t priority; + + SuccessOrExit(error = GetFramePriority(aFrame, aFrameLength, aMacSource, aMacDest, priority)); + VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kTypeIp6, 0, priority)) != NULL, error = OT_ERROR_NO_BUFS); message->SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity); message->SetPanId(aLinkInfo.mPanId); @@ -1492,12 +1495,14 @@ void MeshForwarder::HandleLowpanHC(uint8_t * aFrame, otError error = OT_ERROR_NONE; Message * message = NULL; int headerLength; + uint8_t priority; #if OPENTHREAD_FTD UpdateRoutes(aFrame, aFrameLength, aMacSource, aMacDest); #endif - VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kTypeIp6, 0)) != NULL, + SuccessOrExit(error = GetFramePriority(aFrame, aFrameLength, aMacSource, aMacDest, priority)); + VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kTypeIp6, 0, priority)) != NULL, error = OT_ERROR_NO_BUFS); message->SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity); message->SetPanId(aLinkInfo.mPanId); @@ -1552,6 +1557,44 @@ otError MeshForwarder::HandleDatagram(Message & aMessage, return netif.GetIp6().HandleDatagram(aMessage, &netif, netif.GetInterfaceId(), &aLinkInfo, false); } +otError MeshForwarder::GetFramePriority(uint8_t * aFrame, + uint8_t aFrameLength, + const Mac::Address &aMacSource, + const Mac::Address &aMacDest, + uint8_t & aPriority) +{ + otError error = OT_ERROR_NONE; + Ip6::Header ip6Header; + Ip6::UdpHeader udpHeader; + uint8_t headerLength; + bool nextHeaderCompressed; + + SuccessOrExit(error = DecompressIp6Header(aFrame, aFrameLength, aMacSource, aMacDest, ip6Header, headerLength, + nextHeaderCompressed)); + aPriority = GetNetif().GetIp6().DscpToPriority(ip6Header.GetDscp()); + VerifyOrExit(ip6Header.GetNextHeader() == Ip6::kProtoUdp); + + aFrame += headerLength; + aFrameLength -= headerLength; + + if (nextHeaderCompressed) + { + VerifyOrExit(GetNetif().GetLowpan().DecompressUdpHeader(udpHeader, aFrame, aFrameLength) >= 0); + } + else + { + memcpy(&udpHeader, aFrame, sizeof(Ip6::UdpHeader)); + } + + if (udpHeader.GetDestinationPort() == Mle::kUdpPort || udpHeader.GetDestinationPort() == kCoapUdpPort) + { + aPriority = Message::kPriorityNet; + } + +exit: + return error; +} + #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MAC == 1) otError MeshForwarder::ParseIp6UdpTcpHeader(const Message &aMessage, diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 442488952..2f3e98626 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -336,6 +336,12 @@ private: static void ScheduleTransmissionTask(Tasklet &aTasklet); void ScheduleTransmissionTask(void); + otError GetFramePriority(uint8_t * aFrame, + uint8_t aFrameLength, + const Mac::Address &aMacSource, + const Mac::Address &aMacDest, + uint8_t & aPriority); + otError GetDestinationRlocByServiceAloc(uint16_t aServiceAloc, uint16_t &aMeshDest); void LogMessage(MessageAction aAction, const Message &aMessage, const Mac::Address *aAddress, otError aError);