diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index 8598fb891..04d8ab3a6 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -410,9 +410,7 @@ ThreadError otRemoveExternalRoute(const otIp6Prefix *aPrefix) ThreadError otSendServerData(void) { - Ip6::Address destination; - sThreadNetif->GetMle().GetLeaderAddress(destination); - return sThreadNetif->GetNetworkDataLocal().Register(destination); + return sThreadNetif->GetNetworkDataLocal().SendServerDataNotification(); } ThreadError otAddUnsecurePort(uint16_t aPort) diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 4b8a0d2f8..a00690294 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2314,6 +2314,7 @@ ThreadError MleRouter::RemoveNeighbor(Neighbor &aNeighbor) if (aNeighbor.mState == Neighbor::kStateValid && !IsActiveRouter(aNeighbor.mValid.mRloc16)) { mNetif.SetStateChangedFlags(OT_THREAD_CHILD_REMOVED); + mNetworkData.SendServerDataNotification(aNeighbor.mValid.mRloc16); } break; diff --git a/src/core/thread/network_data.cpp b/src/core/thread/network_data.cpp index f981f215c..680f39672 100644 --- a/src/core/thread/network_data.cpp +++ b/src/core/thread/network_data.cpp @@ -31,17 +31,25 @@ * This file implements common methods for manipulating Thread Network Data. */ +#include #include #include #include +#include +#include #include +#include +#include +#include namespace Thread { namespace NetworkData { -NetworkData::NetworkData(void) +NetworkData::NetworkData(ThreadNetif &aThreadNetif): + mMle(aThreadNetif.GetMle()) { mLength = 0; + mCoapMessageId = 0; } void NetworkData::GetNetworkData(bool aStable, uint8_t *aData, uint8_t &aDataLength) @@ -438,5 +446,89 @@ ThreadError NetworkData::Remove(uint8_t *aStart, uint8_t aLength) return kThreadError_None; } +ThreadError NetworkData::SendServerDataNotification(bool aLocal, uint16_t aRloc16) +{ + ThreadError error = kThreadError_None; + Coap::Header header; + Message *message; + Ip6::MessageInfo messageInfo; + + mSocket.Open(&HandleUdpReceive, this); + + for (size_t i = 0; i < sizeof(mCoapToken); i++) + { + mCoapToken[i] = static_cast(otPlatRandomGet()); + } + + header.Init(); + header.SetVersion(1); + header.SetType(Coap::Header::kTypeConfirmable); + header.SetCode(Coap::Header::kCodePost); + header.SetMessageId(++mCoapMessageId); + header.SetToken(mCoapToken, sizeof(mCoapToken)); + header.AppendUriPathOptions(OPENTHREAD_URI_SERVER_DATA); + header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + header.Finalize(); + + VerifyOrExit((message = Ip6::Udp::NewMessage(0)) != NULL, error = kThreadError_NoBufs); + SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); + + if (aLocal) + { + ThreadTlv tlv; + tlv.SetType(ThreadTlv::kThreadNetworkData); + tlv.SetLength(mLength); + SuccessOrExit(error = message->Append(&tlv, sizeof(tlv))); + SuccessOrExit(error = message->Append(mTlvs, mLength)); + } + + if (aRloc16 != Mac::kShortAddrInvalid) + { + ThreadRloc16Tlv rloc16Tlv; + rloc16Tlv.Init(); + rloc16Tlv.SetRloc16(aRloc16); + SuccessOrExit(error = message->Append(&rloc16Tlv, sizeof(rloc16Tlv))); + } + + memset(&messageInfo, 0, sizeof(messageInfo)); + mMle.GetLeaderAddress(messageInfo.GetPeerAddr()); + messageInfo.mPeerPort = kCoapUdpPort; + SuccessOrExit(error = mSocket.SendTo(*message, messageInfo)); + + otLogInfoNetData("Sent server data notification\n"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + Message::Free(*message); + } + + return error; +} + +void NetworkData::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo) +{ + Local *obj = static_cast(aContext); + obj->HandleUdpReceive(*static_cast(aMessage), *static_cast(aMessageInfo)); +} + +void NetworkData::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + Coap::Header header; + + SuccessOrExit(header.FromMessage(aMessage)); + VerifyOrExit(header.GetType() == Coap::Header::kTypeAcknowledgment && + header.GetCode() == Coap::Header::kCodeChanged && + header.GetMessageId() == mCoapMessageId && + header.GetTokenLength() == sizeof(mCoapToken) && + memcmp(mCoapToken, header.GetToken(), sizeof(mCoapToken)) == 0, ;); + + otLogInfoNetData("Server data notification acknowledged\n"); + +exit: + (void)aMessageInfo; +} + } // namespace NetworkData } // namespace Thread diff --git a/src/core/thread/network_data.hpp b/src/core/thread/network_data.hpp index 6514c5d26..b60965fb2 100644 --- a/src/core/thread/network_data.hpp +++ b/src/core/thread/network_data.hpp @@ -35,7 +35,9 @@ #define NETWORK_DATA_HPP_ #include +#include #include +#include #include namespace Thread { @@ -91,7 +93,7 @@ public: * This constructor initializes the object. * */ - NetworkData(void); + NetworkData(ThreadNetif &aThreadNetif); /** * This method provides a full or stable copy of the Thread Network Data. @@ -248,8 +250,30 @@ protected: */ int8_t PrefixMatch(const uint8_t *a, const uint8_t *b, uint8_t aLength); + /** + * This method sends a Server Data Notification message to the Leader. + * + * @param[in] aLocal TRUE if notifying Leader of local network data, FALSE otherwise. + * @param[in] aRloc16 The old RLOC16 value that was previously registered. + * + * @retval kThreadError_None Successfully enqueued the notification message. + * @retval kThreadError_NoBufs Insufficient message buffers to generate the notification message. + * + */ + ThreadError SendServerDataNotification(bool aLocal, uint16_t aRloc16); + uint8_t mTlvs[kMaxSize]; ///< The Network Data buffer. uint8_t mLength; ///< The number of valid bytes in @var mTlvs. + + Mle::MleRouter &mMle; + +private: + static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo); + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + Ip6::UdpSocket mSocket; + uint8_t mCoapToken[2]; + uint16_t mCoapMessageId; }; } // namespace NetworkData diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index d6c8ecf6d..760b5d79e 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -52,11 +52,11 @@ namespace Thread { namespace NetworkData { Leader::Leader(ThreadNetif &aThreadNetif): + NetworkData(aThreadNetif), mTimer(&HandleTimer, this), mServerData(OPENTHREAD_URI_SERVER_DATA, &HandleServerData, this), mCoapServer(aThreadNetif.GetCoapServer()), - mNetif(aThreadNetif), - mMle(aThreadNetif.GetMle()) + mNetif(aThreadNetif) { Reset(); } @@ -470,21 +470,24 @@ void Leader::HandleServerData(void *aContext, Coap::Header &aHeader, Message &aM void Leader::HandleServerData(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - ThreadNetworkDataTlv threadNetworkDataTlv; - uint8_t tlvsLength; - uint8_t tlvs[kMaxSize]; - uint16_t rloc16; + ThreadNetworkDataTlv networkData; + ThreadRloc16Tlv rloc16; otLogInfoNetData("Received network data registration\n"); - aMessage.Read(aMessage.GetOffset(), sizeof(threadNetworkDataTlv), &threadNetworkDataTlv); - tlvsLength = threadNetworkDataTlv.GetLength(); + if (ThreadTlv::GetTlv(aMessage, ThreadTlv::kRloc16, sizeof(rloc16), rloc16) == kThreadError_None) + { + RemoveBorderRouter(rloc16.GetRloc16()); + } - aMessage.Read(aMessage.GetOffset() + sizeof(threadNetworkDataTlv), tlvsLength, tlvs); - rloc16 = HostSwap16(aMessageInfo.mPeerAddr.mFields.m16[7]); + if (ThreadTlv::GetTlv(aMessage, ThreadTlv::kThreadNetworkData, sizeof(networkData), networkData) == + kThreadError_None) + { + RegisterNetworkData(HostSwap16(aMessageInfo.mPeerAddr.mFields.m16[7]), + networkData.GetTlvs(), networkData.GetLength()); + } SendServerDataResponse(aHeader, aMessageInfo, NULL, 0); - RegisterNetworkData(rloc16, tlvs, tlvsLength); } void Leader::SendServerDataResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, @@ -882,6 +885,22 @@ ThreadError Leader::FreeContext(uint8_t aContextId) return kThreadError_None; } +ThreadError Leader::SendServerDataNotification(uint16_t aRloc16) +{ + ThreadError error = kThreadError_None; + bool rlocIn = false; + bool rlocStable = false; + + RlocLookup(aRloc16, rlocIn, rlocStable, mTlvs, mLength); + + VerifyOrExit(rlocIn, error = kThreadError_NotFound); + + SuccessOrExit(error = NetworkData::SendServerDataNotification(false, aRloc16)); + +exit: + return error; +} + ThreadError Leader::RemoveRloc(uint16_t aRloc16) { NetworkDataTlv *cur = reinterpret_cast(mTlvs); diff --git a/src/core/thread/network_data_leader.hpp b/src/core/thread/network_data_leader.hpp index f92e6ec65..9fa0a8a02 100644 --- a/src/core/thread/network_data_leader.hpp +++ b/src/core/thread/network_data_leader.hpp @@ -208,6 +208,17 @@ public: */ void RemoveBorderRouter(uint16_t aRloc16); + /** + * This method sends a Server Data Notification message to the Leader indicating an invalid RLOC16. + * + * @param[in] aRloc16 The invalid RLOC16 to notify. + * + * @retval kThreadError_None Successfully enqueued the notification message. + * @retval kThreadError_NoBufs Insufficient message buffers to generate the notification message. + * + */ + ThreadError SendServerDataNotification(uint16_t aRloc16); + private: static void HandleServerData(void *aContext, Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); @@ -269,7 +280,6 @@ private: Coap::Server &mCoapServer; ThreadNetif &mNetif; - Mle::MleRouter &mMle; }; /** diff --git a/src/core/thread/network_data_local.cpp b/src/core/thread/network_data_local.cpp index 706e24faf..b9e0b52bd 100644 --- a/src/core/thread/network_data_local.cpp +++ b/src/core/thread/network_data_local.cpp @@ -31,24 +31,20 @@ * This file implements the local Thread Network Data. */ -#include #include #include #include -#include +#include #include #include -#include -#include namespace Thread { namespace NetworkData { Local::Local(ThreadNetif &aThreadNetif): - NetworkData(), - mMle(aThreadNetif.GetMle()) + NetworkData(aThreadNetif), + mOldRloc(Mac::kShortAddrInvalid) { - mCoapMessageId = 0; } ThreadError Local::AddOnMeshPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength, int8_t aPrf, @@ -199,79 +195,25 @@ ThreadError Local::UpdateRloc(BorderRouterTlv &aBorderRouter) return kThreadError_None; } -ThreadError Local::Register(const Ip6::Address &aDestination) +ThreadError Local::SendServerDataNotification(void) { ThreadError error = kThreadError_None; - Coap::Header header; - Message *message; - Ip6::MessageInfo messageInfo; - ThreadNetworkDataTlv threadNetworkDataTlv; + uint16_t rloc = mMle.GetRloc16(); UpdateRloc(); - mSocket.Open(&HandleUdpReceive, this); - for (size_t i = 0; i < sizeof(mCoapToken); i++) + if (mOldRloc == rloc) { - mCoapToken[i] = static_cast(otPlatRandomGet()); + mOldRloc = Mac::kShortAddrInvalid; } - header.Init(); - header.SetVersion(1); - header.SetType(Coap::Header::kTypeConfirmable); - header.SetCode(Coap::Header::kCodePost); - header.SetMessageId(++mCoapMessageId); - header.SetToken(mCoapToken, sizeof(mCoapToken)); - header.AppendUriPathOptions(OPENTHREAD_URI_SERVER_DATA); - header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); - header.Finalize(); - - VerifyOrExit((message = Ip6::Udp::NewMessage(0)) != NULL, error = kThreadError_NoBufs); - SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); - threadNetworkDataTlv.Init(); - threadNetworkDataTlv.SetLength(mLength); - SuccessOrExit(error = message->Append(&threadNetworkDataTlv, sizeof(threadNetworkDataTlv))); - SuccessOrExit(error = message->Append(mTlvs, mLength)); - - memset(&messageInfo, 0, sizeof(messageInfo)); - memcpy(&messageInfo.mPeerAddr, &aDestination, sizeof(messageInfo.mPeerAddr)); - messageInfo.mPeerPort = kCoapUdpPort; - SuccessOrExit(error = mSocket.SendTo(*message, messageInfo)); - - otLogInfoNetData("Sent network data registration\n"); + SuccessOrExit(error = NetworkData::SendServerDataNotification(true, mOldRloc)); + mOldRloc = rloc; exit: - - if (error != kThreadError_None && message != NULL) - { - Message::Free(*message); - } - return error; } -void Local::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo) -{ - Local *obj = reinterpret_cast(aContext); - obj->HandleUdpReceive(*static_cast(aMessage), *static_cast(aMessageInfo)); -} - -void Local::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - Coap::Header header; - - SuccessOrExit(header.FromMessage(aMessage)); - VerifyOrExit(header.GetType() == Coap::Header::kTypeAcknowledgment && - header.GetCode() == Coap::Header::kCodeChanged && - header.GetMessageId() == mCoapMessageId && - header.GetTokenLength() == sizeof(mCoapToken) && - memcmp(mCoapToken, header.GetToken(), sizeof(mCoapToken)) == 0, ;); - - otLogInfoNetData("Network data registration acknowledged\n"); - -exit: - (void)aMessageInfo; -} - } // namespace NetworkData } // namespace Thread diff --git a/src/core/thread/network_data_local.hpp b/src/core/thread/network_data_local.hpp index c61575afc..0eccce10b 100644 --- a/src/core/thread/network_data_local.hpp +++ b/src/core/thread/network_data_local.hpp @@ -34,8 +34,6 @@ #ifndef NETWORK_DATA_LOCAL_HPP_ #define NETWORK_DATA_LOCAL_HPP_ -#include -#include #include namespace Thread { @@ -123,30 +121,21 @@ public: ThreadError RemoveHasRoutePrefix(const uint8_t *aPrefix, uint8_t aPrefixLength); /** - * This method sends a Server Data Registration message to the Leader. + * This method sends a Server Data Notification message to the Leader. * - * @param[in] aDestination The IPv6 destination. - * - * @retval kThreadError_None Successfully enqueued the registration message. - * @retval kThreadError_NoBufs Insufficient message buffers to generate the registration message. + * @retval kThreadError_None Successfully enqueued the notification message. + * @retval kThreadError_NoBufs Insufficient message buffers to generate the notification message. * */ - ThreadError Register(const Ip6::Address &aDestination); + ThreadError SendServerDataNotification(void); private: - static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo); - void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - ThreadError UpdateRloc(void); ThreadError UpdateRloc(PrefixTlv &aPrefix); ThreadError UpdateRloc(HasRouteTlv &aHasRoute); ThreadError UpdateRloc(BorderRouterTlv &aBorderRouter); - Ip6::UdpSocket mSocket; - uint8_t mCoapToken[2]; - uint16_t mCoapMessageId; - - Mle::MleRouter &mMle; + uint16_t mOldRloc; }; } // namespace NetworkData diff --git a/src/core/thread/thread_tlvs.hpp b/src/core/thread/thread_tlvs.hpp index ff0acc305..26d104dea 100644 --- a/src/core/thread/thread_tlvs.hpp +++ b/src/core/thread/thread_tlvs.hpp @@ -487,6 +487,21 @@ public: */ bool IsValid() const { return true; } + /** + * This method returns a pointer to the Network Data TLVs. + * + * @returns A pointer to the Network Data TLVs. + * + */ + uint8_t *GetTlvs(void) { return mTlvs; } + +private: + enum + { + kMaxSize = 255, + }; + + uint8_t mTlvs[kMaxSize]; } OT_TOOL_PACKED_END; } // namespace Thread