From a222a82e04367a007db167d40d4f3a3a69167124 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 19 Jun 2019 16:41:16 -0700 Subject: [PATCH] [mesh-forwarder] add PrepareDataFrame() (#3952) This commit refactors and updates the existing code to add a generic method `MeshForwarder::PrepareDataFrame()`. This method constructs a MAC data from from a given IPv6 message at the offset set in the message. This method enables link security when message is MLE type and requires fragmentation. --- src/core/thread/mesh_forwarder.cpp | 154 ++++++++++++++++------------- src/core/thread/mesh_forwarder.hpp | 9 +- 2 files changed, 91 insertions(+), 72 deletions(-) diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index ceed0db3f..7f8df838c 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -527,24 +527,15 @@ otError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame) } } - error = SendFragment(*mSendMessage, aFrame); + mMessageNextOffset = + PrepareDataFrame(aFrame, *mSendMessage, mMacSource, mMacDest, mAddMeshHeader, mMeshSource, mMeshDest); - // `SendFragment()` fails with `NotCapable` error if the message is MLE (with - // no link layer security) and also requires fragmentation. - if (error == OT_ERROR_NOT_CAPABLE) + if ((mSendMessage->GetSubType() == Message::kSubTypeMleChildIdRequest) && mSendMessage->IsLinkSecurityEnabled()) { - // Enable security and try again. - mSendMessage->SetLinkSecurityEnabled(true); - - if (mSendMessage->GetSubType() == Message::kSubTypeMleChildIdRequest) - { - otLogNoteMac("Child ID Request requires fragmentation, aborting tx"); - mMessageNextOffset = mSendMessage->GetLength(); - error = OT_ERROR_ABORT; - ExitNow(); - } - - error = SendFragment(*mSendMessage, aFrame); + otLogNoteMac("Child ID Request requires fragmentation, aborting tx"); + mMessageNextOffset = mSendMessage->GetLength(); + error = OT_ERROR_ABORT; + ExitNow(); } assert(aFrame.GetLength() != 7); @@ -610,38 +601,38 @@ exit: return error; } -otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) +// This method constructs a MAC data from from a given IPv6 message. +// +// This method handles generation of MAC header, mesh header (if +// requested), lowpan compression of IPv6 header, lowpan fragmentation +// header (if message requires fragmentation). It uses the message +// offset to construct next fragments. This method enables link security +// when message is MLE type and requires fragmentation. It returns the +// next offset into the message after the prepared frame. +// +uint16_t MeshForwarder::PrepareDataFrame(Mac::Frame & aFrame, + Message & aMessage, + const Mac::Address &aMacSource, + const Mac::Address &aMacDest, + bool aAddMeshHeader, + uint16_t aMeshSource, + uint16_t aMeshDest) { - Mac::Address meshDest, meshSource; - uint16_t fcf; - Lowpan::FragmentHeader *fragmentHeader; - uint8_t * payload; - uint8_t headerLength; - uint16_t payloadLength; - uint16_t fragmentLength; - uint16_t dstpan; - uint8_t secCtl = Mac::Frame::kSecNone; - otError error = OT_ERROR_NONE; -#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC - Mac::HeaderIe ieList[2]; -#endif + uint16_t fcf; + uint8_t *payload; + uint8_t headerLength; + uint16_t payloadLength; + uint16_t fragmentLength; + uint16_t dstpan; + uint8_t secCtl; + uint16_t nextOffset; - if (mAddMeshHeader) - { - meshSource.SetShort(mMeshSource); - meshDest.SetShort(mMeshDest); - } - else - { - meshDest = mMacDest; - meshSource = mMacSource; - } +start: - // initialize MAC header + // Initialize MAC header fcf = Mac::Frame::kFcfFrameData; #if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC - if (aMessage.IsTimeSync()) { fcf |= Mac::Frame::kFcfFrameVersion2015 | Mac::Frame::kFcfIePresent; @@ -652,11 +643,11 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) fcf |= Mac::Frame::kFcfFrameVersion2006; } - fcf |= (mMacDest.IsShort()) ? Mac::Frame::kFcfDstAddrShort : Mac::Frame::kFcfDstAddrExt; - fcf |= (mMacSource.IsShort()) ? Mac::Frame::kFcfSrcAddrShort : Mac::Frame::kFcfSrcAddrExt; + fcf |= (aMacDest.IsShort()) ? Mac::Frame::kFcfDstAddrShort : Mac::Frame::kFcfDstAddrExt; + fcf |= (aMacSource.IsShort()) ? Mac::Frame::kFcfSrcAddrShort : Mac::Frame::kFcfSrcAddrExt; - // all unicast frames request ACK - if (mMacDest.IsExtended() || !mMacDest.IsBroadcast()) + // All unicast frames request ACK + if (aMacDest.IsExtended() || !aMacDest.IsBroadcast()) { fcf |= Mac::Frame::kFcfAckRequest; } @@ -682,6 +673,10 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) secCtl |= Mac::Frame::kSecEncMic32; } + else + { + secCtl = Mac::Frame::kSecNone; + } dstpan = Get().GetPanId(); @@ -723,15 +718,15 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) aFrame.InitMacHeader(fcf, secCtl); aFrame.SetDstPanId(dstpan); aFrame.SetSrcPanId(Get().GetPanId()); - aFrame.SetDstAddr(mMacDest); - aFrame.SetSrcAddr(mMacSource); + aFrame.SetDstAddr(aMacDest); + aFrame.SetSrcAddr(aMacSource); #if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC - if (aMessage.IsTimeSync()) { - Mac::TimeIe *ie; - uint8_t * cur = NULL; + Mac::TimeIe * ie; + uint8_t * cur = NULL; + Mac::HeaderIe ieList[2]; ieList[0].Init(); ieList[0].SetId(Mac::Frame::kHeaderIeVendor); @@ -754,8 +749,8 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) #if OPENTHREAD_FTD - // initialize Mesh header - if (mAddMeshHeader) + // Initialize Mesh header + if (aAddMeshHeader) { Mle::MleRouter & mle = Get(); Lowpan::MeshHeader meshHeader; @@ -769,30 +764,30 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) else { // Calculate the number of predicted hops. - hopsLeft = mle.GetRouteCost(mMeshDest); + hopsLeft = mle.GetRouteCost(aMeshDest); if (hopsLeft != Mle::kMaxRouteCost) { - hopsLeft += mle.GetLinkCost(Mle::Mle::GetRouterId(mle.GetNextHop(mMeshDest))); + hopsLeft += mle.GetLinkCost(Mle::Mle::GetRouterId(mle.GetNextHop(aMeshDest))); } else { // In case there is no route to the destination router (only link). - hopsLeft = mle.GetLinkCost(Mle::Mle::GetRouterId(mMeshDest)); + hopsLeft = mle.GetLinkCost(Mle::Mle::GetRouterId(aMeshDest)); } } // The hopsLft field MUST be incremented by one if the destination RLOC16 // is not that of an active Router. - if (!Mle::Mle::IsActiveRouter(mMeshDest)) + if (!Mle::Mle::IsActiveRouter(aMeshDest)) { hopsLeft += 1; } meshHeader.Init(); meshHeader.SetHopsLeft(hopsLeft + Lowpan::MeshHeader::kAdditionalHopsLeft); - meshHeader.SetSource(mMeshSource); - meshHeader.SetDestination(mMeshDest); + meshHeader.SetSource(aMeshSource); + meshHeader.SetDestination(aMeshDest); meshHeader.AppendTo(payload); payload += meshHeader.GetHeaderLength(); headerLength += meshHeader.GetHeaderLength(); @@ -800,12 +795,25 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) #endif - // copy IPv6 Header + // Compress IPv6 Header if (aMessage.GetOffset() == 0) { Lowpan::BufferWriter buffer(payload, aFrame.GetMaxPayloadLength() - headerLength - Lowpan::FragmentHeader::kInitialHeaderSize); uint8_t hcLength; + Mac::Address meshSource, meshDest; + otError error; + + if (aAddMeshHeader) + { + meshSource.SetShort(aMeshSource); + meshDest.SetShort(aMeshDest); + } + else + { + meshDest = aMacDest; + meshSource = aMacSource; + } error = Get().Compress(aMessage, meshSource, meshDest, buffer); assert(error == OT_ERROR_NONE); @@ -817,16 +825,20 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) if (payloadLength > fragmentLength) { + Lowpan::FragmentHeader *fragmentHeader; + if ((!aMessage.IsLinkSecurityEnabled()) && aMessage.IsSubTypeMle()) { + // Enable security and try again. aMessage.SetOffset(0); - ExitNow(error = OT_ERROR_NOT_CAPABLE); + aMessage.SetLinkSecurityEnabled(true); + goto start; } - // write Fragment header + // Write Fragment header if (aMessage.GetDatagramTag() == 0) { - // avoid using datagram tag value 0, which indicates the tag has not been set + // Avoid using datagram tag value 0, which indicates the tag has not been set if (mFragTag == 0) { mFragTag++; @@ -854,14 +866,16 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) aMessage.Read(aMessage.GetOffset(), payloadLength, payload); aFrame.SetPayloadLength(static_cast(headerLength + payloadLength)); - mMessageNextOffset = aMessage.GetOffset() + payloadLength; + nextOffset = aMessage.GetOffset() + payloadLength; aMessage.SetOffset(0); } else { + Lowpan::FragmentHeader *fragmentHeader; + payloadLength = aMessage.GetLength() - aMessage.GetOffset(); - // write Fragment header + // Write Fragment header fragmentHeader = reinterpret_cast(payload); fragmentHeader->Init(); fragmentHeader->SetDatagramSize(aMessage.GetLength()); @@ -878,14 +892,14 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) payloadLength = fragmentLength; } - // copy IPv6 Payload + // Copy IPv6 Payload aMessage.Read(aMessage.GetOffset(), payloadLength, payload); aFrame.SetPayloadLength(static_cast(headerLength + payloadLength)); - mMessageNextOffset = aMessage.GetOffset() + payloadLength; + nextOffset = aMessage.GetOffset() + payloadLength; } - if (mMessageNextOffset < aMessage.GetLength()) + if (nextOffset < aMessage.GetLength()) { aFrame.SetFramePending(true); #if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC @@ -893,9 +907,7 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) #endif } -exit: - - return error; + return nextOffset; } void MeshForwarder::SendEmptyFrame(Mac::Frame &aFrame, bool aAckRequest) diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index b325e4c35..72f886067 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -385,8 +385,15 @@ private: uint16_t aFrameLength, Lowpan::FragmentHeader &aFragmentHeader); + uint16_t PrepareDataFrame(Mac::Frame & aFrame, + Message & aMessage, + const Mac::Address &aMacSource, + const Mac::Address &aMacDest, + bool aAddMeshHeader = false, + uint16_t aMeshSource = 0xffff, + uint16_t aMeshDest = 0xffff); + void SendMesh(Message &aMessage, Mac::Frame &aFrame); - otError SendFragment(Message &aMessage, Mac::Frame &aFrame); void SendEmptyFrame(Mac::Frame &aFrame, bool aAckRequest); otError UpdateIp6Route(Message &aMessage); otError UpdateIp6RouteFtd(Ip6::Header &ip6Header);