From dc16c5e69438d091b62ec7cc74b183530ac91b77 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 19 Apr 2018 09:29:18 -0700 Subject: [PATCH] [mle] send a unicast MLE Announce in response to a received Announce (#2669) This commit changes how MLE Announce messages are sent in response to a received MLE Announce. In addition to a multicast MLE Announce message, a unicast MLE Announce is also sent. This behavior can be controlled using `OPENTHREAD_CONFIG_SEND_UNICAST_ANNOUNCE_RESPONSE` config option. By default this is enabled. This commit also changes actions taken after receiving an MLE Announce in `Mle::HandleAnnounce()` to handle the situation where a device may receive multiple MLE Announce messages with same info. No action is taken if the device is detached, and current channel and panid match the values from the received MLE Announce message. --- src/core/openthread-core-default-config.h | 13 ++++++ src/core/thread/mle.cpp | 57 ++++++++++++++++------- src/core/thread/mle.hpp | 1 + 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/core/openthread-core-default-config.h b/src/core/openthread-core-default-config.h index c28fee747..47c539b1b 100644 --- a/src/core/openthread-core-default-config.h +++ b/src/core/openthread-core-default-config.h @@ -1327,6 +1327,19 @@ #define OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD -65 #endif +/** + * @def OPENTHREAD_CONFIG_SEND_UNICAST_ANNOUNCE_RESPONSE + * + * Define as 1 to enable sending of a unicast MLE Announce message in response to a received Announce message from + * a device. + * + * @note The unicast MLE announce message is sent in addition to (and after) the multicast MLE Announce. + * + */ +#ifndef OPENTHREAD_CONFIG_SEND_UNICAST_ANNOUNCE_RESPONSE +#define OPENTHREAD_CONFIG_SEND_UNICAST_ANNOUNCE_RESPONSE 1 +#endif + /** * @def OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE * diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index e8a144bf5..80c4d59de 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1979,13 +1979,23 @@ exit: } otError Mle::SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce) +{ + Ip6::Address destination; + + memset(&destination, 0, sizeof(destination)); + destination.mFields.m16[0] = HostSwap16(0xff02); + destination.mFields.m16[7] = HostSwap16(0x0001); + + return SendAnnounce(aChannel, aOrphanAnnounce, destination); +} + +otError Mle::SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce, const Ip6::Address &aDestination) { ThreadNetif & netif = GetNetif(); otError error = OT_ERROR_NONE; ChannelTlv channel; PanIdTlv panid; ActiveTimestampTlv activeTimestamp; - Ip6::Address destination; Message * message; VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS); @@ -2016,11 +2026,7 @@ otError Mle::SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce) panid.Init(); panid.SetPanId(netif.GetMac().GetPanId()); SuccessOrExit(error = message->Append(&panid, sizeof(panid))); - - memset(&destination, 0, sizeof(destination)); - destination.mFields.m16[0] = HostSwap16(0xff02); - destination.mFields.m16[7] = HostSwap16(0x0001); - SuccessOrExit(error = SendMessage(*message, destination)); + SuccessOrExit(error = SendMessage(*message, aDestination)); otLogInfoMle(GetInstance(), "Send Announce on channel %d", aChannel); @@ -3188,36 +3194,53 @@ otError Mle::HandleAnnounce(const Message &aMessage, const Ip6::MessageInfo &aMe { ThreadNetif & netif = GetNetif(); otError error = OT_ERROR_NONE; - ChannelTlv channel; + ChannelTlv channelTlv; ActiveTimestampTlv timestamp; const MeshCoP::Timestamp *localTimestamp; - PanIdTlv panid; + PanIdTlv panIdTlv; + uint8_t channel; + uint16_t panId; LogMleMessage("Receive Announce", aMessageInfo.GetPeerAddr()); - SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kChannel, sizeof(channel), channel)); - VerifyOrExit(channel.IsValid(), error = OT_ERROR_PARSE); + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kChannel, sizeof(channelTlv), channelTlv)); + VerifyOrExit(channelTlv.IsValid(), error = OT_ERROR_PARSE); + channel = static_cast(channelTlv.GetChannel()); SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kActiveTimestamp, sizeof(timestamp), timestamp)); VerifyOrExit(timestamp.IsValid(), error = OT_ERROR_PARSE); - SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kPanId, sizeof(panid), panid)); - VerifyOrExit(panid.IsValid(), error = OT_ERROR_PARSE); + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kPanId, sizeof(panIdTlv), panIdTlv)); + VerifyOrExit(panIdTlv.IsValid(), error = OT_ERROR_PARSE); + panId = panIdTlv.GetPanId(); localTimestamp = netif.GetActiveDataset().GetTimestamp(); if (localTimestamp == NULL || localTimestamp->Compare(timestamp) > 0) { + uint8_t curChannel = netif.GetMac().GetChannel(); + uint16_t curPanId = netif.GetMac().GetPanId(); + + // No action is required if device is detached, and current + // channel and pan-id match the values from the received MLE + // Announce message. + + VerifyOrExit((mRole != OT_DEVICE_ROLE_DETACHED) || (curChannel != channel) || (curPanId != panId)); + Stop(false); - mPreviousChannel = netif.GetMac().GetChannel(); - mPreviousPanId = netif.GetMac().GetPanId(); - netif.GetMac().SetChannel(static_cast(channel.GetChannel())); - netif.GetMac().SetPanId(panid.GetPanId()); + mPreviousChannel = curChannel; + mPreviousPanId = curPanId; + netif.GetMac().SetChannel(channel); + netif.GetMac().SetPanId(panId); Start(false, true); } else if (localTimestamp->Compare(timestamp) < 0) { - SendAnnounce(static_cast(channel.GetChannel()), false); + SendAnnounce(channel, false); + +#if OPENTHREAD_CONFIG_SEND_UNICAST_ANNOUNCE_RESPONSE + SendAnnounce(channel, false, aMessageInfo.GetPeerAddr()); +#endif } else { diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index cc854d7b6..4a4cb03b2 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1483,6 +1483,7 @@ private: otError SendParentRequest(void); otError SendChildIdRequest(void); void SendOrphanAnnounce(void); + otError SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce, const Ip6::Address &aDestination); bool IsBetterParent(uint16_t aRloc16, uint8_t aLinkQuality, uint8_t aLinkMargin, ConnectivityTlv &aConnectivityTlv); void ResetParentCandidate(void);