diff --git a/Android.mk b/Android.mk index ae4356ca4..6b22e961f 100644 --- a/Android.mk +++ b/Android.mk @@ -241,6 +241,7 @@ LOCAL_SRC_FILES := \ src/core/thread/announce_begin_server.cpp \ src/core/thread/announce_sender.cpp \ src/core/thread/child_table.cpp \ + src/core/thread/discover_scanner.cpp \ src/core/thread/dua_manager.cpp \ src/core/thread/energy_scan_server.cpp \ src/core/thread/indirect_sender.cpp \ diff --git a/BUILD.gn b/BUILD.gn index 6be9e4f57..2002ac094 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -136,6 +136,7 @@ static_library("lib-ot-core") { "src/core/thread/announce_begin_server.cpp", "src/core/thread/announce_sender.cpp", "src/core/thread/child_table.cpp", + "src/core/thread/discover_scanner.cpp", "src/core/thread/dua_manager.cpp", "src/core/thread/energy_scan_server.cpp", "src/core/thread/indirect_sender.cpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2ef88e6cd..0c3afa675 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -172,6 +172,7 @@ set(COMMON_SOURCES thread/announce_begin_server.cpp thread/announce_sender.cpp thread/child_table.cpp + thread/discover_scanner.cpp thread/dua_manager.cpp thread/energy_scan_server.cpp thread/indirect_sender.cpp diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 24818f93e..d462752db 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -214,6 +214,7 @@ SOURCES_COMMON = \ thread/announce_begin_server.cpp \ thread/announce_sender.cpp \ thread/child_table.cpp \ + thread/discover_scanner.cpp \ thread/dua_manager.cpp \ thread/energy_scan_server.cpp \ thread/indirect_sender.cpp \ @@ -423,6 +424,7 @@ HEADERS_COMMON = \ thread/announce_begin_server.hpp \ thread/announce_sender.hpp \ thread/child_table.hpp \ + thread/discover_scanner.hpp \ thread/dua_manager.hpp \ thread/energy_scan_server.hpp \ thread/indirect_sender.hpp \ diff --git a/src/core/api/thread_api.cpp b/src/core/api/thread_api.cpp index 0e1b0fb01..471864b86 100644 --- a/src/core/api/thread_api.cpp +++ b/src/core/api/thread_api.cpp @@ -457,15 +457,15 @@ otError otThreadDiscover(otInstance * aInstance, { Instance &instance = *static_cast(aInstance); - return instance.Get().Discover(static_cast(aScanChannels), aPanId, aJoiner, - aEnableEui64Filtering, aCallback, aCallbackContext); + return instance.Get().Discover(static_cast(aScanChannels), aPanId, aJoiner, + aEnableEui64Filtering, aCallback, aCallbackContext); } bool otThreadIsDiscoverInProgress(otInstance *aInstance) { Instance &instance = *static_cast(aInstance); - return instance.Get().IsDiscoverInProgress(); + return instance.Get().IsInProgress(); } const otIpCounters *otThreadGetIp6Counters(otInstance *aInstance) diff --git a/src/core/common/instance.hpp b/src/core/common/instance.hpp index 8642f81f4..c0de28e3e 100644 --- a/src/core/common/instance.hpp +++ b/src/core/common/instance.hpp @@ -438,6 +438,11 @@ template <> inline Mle::MleRouter &Instance::Get(void) return mThreadNetif.mMleRouter; } +template <> inline Mle::DiscoverScanner &Instance::Get(void) +{ + return mThreadNetif.mDiscoverScanner; +} + #if OPENTHREAD_FTD template <> inline ChildTable &Instance::Get(void) { diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index 79f58a424..7c587dd0a 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -122,9 +122,9 @@ otError Joiner::Start(const char * aPskd, SuccessOrExit(error = PrepareJoinerFinalizeMessage(aProvisioningUrl, aVendorName, aVendorModel, aVendorSwVersion, aVendorData)); - SuccessOrExit(error = Get().Discover(Mac::ChannelMask(0), Get().GetPanId(), - /* aJoiner */ true, /* aEnableFiltering */ true, - HandleDiscoverResult, this)); + SuccessOrExit(error = Get().Discover(Mac::ChannelMask(0), Get().GetPanId(), + /* aJoiner */ true, /* aEnableFiltering */ true, + HandleDiscoverResult, this)); mCallback = aCallback; mContext = aContext; diff --git a/src/core/thread/discover_scanner.cpp b/src/core/thread/discover_scanner.cpp new file mode 100644 index 000000000..a5e91056f --- /dev/null +++ b/src/core/thread/discover_scanner.cpp @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2016-2020, 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 implements MLE Discover Scan process. + */ + +#include "discover_scanner.hpp" + +#include "common/code_utils.hpp" +#include "common/instance.hpp" +#include "common/locator-getters.hpp" +#include "common/logging.hpp" +#include "thread/mesh_forwarder.hpp" +#include "thread/mle.hpp" +#include "thread/mle_router.hpp" + +namespace ot { +namespace Mle { + +DiscoverScanner::DiscoverScanner(Instance &aInstance) + : InstanceLocator(aInstance) + , mHandler(NULL) + , mHandlerContext(NULL) + , mTimer(aInstance, DiscoverScanner::HandleTimer, this) + , mFilterIndexes() + , mScanChannels() + , mState(kStateIdle) + , mScanChannel(0) + , mEnableFiltering(false) + , mShouldRestorePanId(false) +{ +} + +otError DiscoverScanner::Discover(const Mac::ChannelMask &aScanChannels, + uint16_t aPanId, + bool aJoiner, + bool aEnableFiltering, + Handler aCallback, + void * aContext) +{ + otError error = OT_ERROR_NONE; + Message * message = NULL; + Ip6::Address destination; + MeshCoP::DiscoveryRequestTlv discoveryRequest; + + VerifyOrExit(mState == kStateIdle, error = OT_ERROR_BUSY); + + mEnableFiltering = aEnableFiltering; + + if (mEnableFiltering) + { + Mac::ExtAddress extAddress; + + Get().GetIeeeEui64(extAddress); + MeshCoP::ComputeJoinerId(extAddress, extAddress); + + MeshCoP::SteeringData::CalculateHashBitIndexes(extAddress, mFilterIndexes); + } + + mHandler = aCallback; + mHandlerContext = aContext; + mShouldRestorePanId = false; + mScanChannels = Get().GetSupportedChannelMask(); + + if (!aScanChannels.IsEmpty()) + { + mScanChannels.Intersect(aScanChannels); + } + + VerifyOrExit((message = Get().NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS); + message->SetSubType(Message::kSubTypeMleDiscoverRequest); + message->SetPanId(aPanId); + SuccessOrExit(error = Get().AppendHeader(*message, Header::kCommandDiscoveryRequest)); + + // Append MLE Discovery TLV with a single sub-TLV (MeshCoP Discovery Request). + discoveryRequest.Init(); + discoveryRequest.SetVersion(kThreadVersion); + discoveryRequest.SetJoiner(aJoiner); + + SuccessOrExit(error = Tlv::AppendTlv(*message, Tlv::kDiscovery, &discoveryRequest, sizeof(discoveryRequest))); + + destination.SetToLinkLocalAllRoutersMulticast(); + + SuccessOrExit(error = Get().SendMessage(*message, destination)); + + if ((aPanId == Mac::kPanIdBroadcast) && (Get().GetPanId() == Mac::kPanIdBroadcast)) + { + // In case a specific PAN ID of a Thread Network to be + // discovered is not known, Discovery Request messages MUST + // have the Destination PAN ID in the IEEE 802.15.4 MAC + // header set to be the Broadcast PAN ID (0xffff) and the + // Source PAN ID set to a randomly generated value. + + Get().SetPanId(Mac::GenerateRandomPanId()); + mShouldRestorePanId = true; + } + + mScanChannel = Mac::ChannelMask::kChannelIteratorFirst; + mState = (mScanChannels.GetNextChannel(mScanChannel) == OT_ERROR_NONE) ? kStateScanning : kStateScanDone; + + otLogInfoMle("Send Discovery Request (%s)", destination.ToString().AsCString()); + +exit: + + if (error != OT_ERROR_NONE && message != NULL) + { + message->Free(); + } + + return error; +} + +otError DiscoverScanner::PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame) +{ + otError error = OT_ERROR_NONE; + + switch (mState) + { + case kStateIdle: + case kStateScanDone: + // If scan is finished (no more channels to scan), abort the + // Discovery Request frame tx. The handler callback is invoked & + // state is cleared from `HandleDiscoveryRequestFrameTxDone()`. + error = OT_ERROR_ABORT; + break; + + case kStateScanning: + aFrame.SetChannel(mScanChannel); + IgnoreError(Get().SetTemporaryChannel(mScanChannel)); + break; + } + + return error; +} + +void DiscoverScanner::HandleDiscoveryRequestFrameTxDone(Message &aMessage) +{ + switch (mState) + { + case kStateIdle: + break; + + case kStateScanning: + // Mark the Discovery Request message for direct tx to ensure it + // is not dequeued and freed by `MeshForwarder` and is ready for + // the next scan channel. Also pause message tx on `MeshForwarder` + // while listening to receive Discovery Responses. + aMessage.SetDirectTransmission(); + Get().PauseMessageTransmissions(); + mTimer.Start(kDefaultScanDuration); + break; + + case kStateScanDone: + HandleDiscoverComplete(); + break; + } +} + +void DiscoverScanner::HandleDiscoverComplete(void) +{ + switch (mState) + { + case kStateIdle: + break; + + case kStateScanning: + mTimer.Stop(); + Get().ResumeMessageTransmissions(); + + // Fall through + + case kStateScanDone: + Get().ClearTemporaryChannel(); + + if (mShouldRestorePanId) + { + Get().SetPanId(Mac::kPanIdBroadcast); + mShouldRestorePanId = false; + } + + mState = kStateIdle; + + if (mHandler) + { + mHandler(NULL, mHandlerContext); + } + + break; + } +} + +void DiscoverScanner::HandleTimer(Timer &aTimer) +{ + aTimer.GetOwner().HandleTimer(); +} + +void DiscoverScanner::HandleTimer(void) +{ + VerifyOrExit(mState == kStateScanning, OT_NOOP); + + // Move to next scan channel and resume message transmissions on + // `MeshForwarder` so that the queued MLE Discovery Request message + // is prepared again for the next scan channel. If no more channel + // to scan, change the state to `kStateScanDone` which ensures the + // frame tx is aborted from `PrepareDiscoveryRequestFrame()` and + // then wraps up the scan (invoking handler callback). + + if (mScanChannels.GetNextChannel(mScanChannel) != OT_ERROR_NONE) + { + mState = kStateScanDone; + } + + Get().ResumeMessageTransmissions(); + +exit: + return; +} + +void DiscoverScanner::HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const +{ + otError error = OT_ERROR_NONE; + const otThreadLinkInfo * linkInfo = static_cast(aMessageInfo.GetLinkInfo()); + Tlv tlv; + MeshCoP::Tlv meshcopTlv; + MeshCoP::DiscoveryResponseTlv discoveryResponse; + MeshCoP::NetworkNameTlv networkName; + ScanResult result; + uint16_t offset; + uint16_t end; + bool didCheckSteeringData = false; + + otLogInfoMle("Receive Discovery Response (%s)", aMessageInfo.GetPeerAddr().ToString().AsCString()); + + VerifyOrExit(mState == kStateScanning, error = OT_ERROR_DROP); + + // Find MLE Discovery TLV + VerifyOrExit(Tlv::FindTlvOffset(aMessage, Tlv::kDiscovery, offset) == OT_ERROR_NONE, error = OT_ERROR_PARSE); + aMessage.Read(offset, sizeof(tlv), &tlv); + + offset += sizeof(tlv); + end = offset + tlv.GetLength(); + + memset(&result, 0, sizeof(result)); + result.mPanId = linkInfo->mPanId; + result.mChannel = linkInfo->mChannel; + result.mRssi = linkInfo->mRss; + result.mLqi = linkInfo->mLqi; + aMessageInfo.GetPeerAddr().ToExtAddress(*static_cast(&result.mExtAddress)); + + // Process MeshCoP TLVs + while (offset < end) + { + aMessage.Read(offset, sizeof(meshcopTlv), &meshcopTlv); + + switch (meshcopTlv.GetType()) + { + case MeshCoP::Tlv::kDiscoveryResponse: + aMessage.Read(offset, sizeof(discoveryResponse), &discoveryResponse); + VerifyOrExit(discoveryResponse.IsValid(), error = OT_ERROR_PARSE); + result.mVersion = discoveryResponse.GetVersion(); + result.mIsNative = discoveryResponse.IsNativeCommissioner(); + break; + + case MeshCoP::Tlv::kExtendedPanId: + SuccessOrExit(error = Tlv::ReadTlv(aMessage, offset, &result.mExtendedPanId, sizeof(Mac::ExtendedPanId))); + break; + + case MeshCoP::Tlv::kNetworkName: + aMessage.Read(offset, sizeof(networkName), &networkName); + IgnoreError(static_cast(result.mNetworkName).Set(networkName.GetNetworkName())); + break; + + case MeshCoP::Tlv::kSteeringData: + if (meshcopTlv.GetLength() > 0) + { + MeshCoP::SteeringData &steeringData = static_cast(result.mSteeringData); + uint8_t dataLength = MeshCoP::SteeringData::kMaxLength; + + if (meshcopTlv.GetLength() < dataLength) + { + dataLength = meshcopTlv.GetLength(); + } + + steeringData.Init(dataLength); + + SuccessOrExit(error = Tlv::ReadTlv(aMessage, offset, steeringData.GetData(), dataLength)); + + if (mEnableFiltering) + { + VerifyOrExit(steeringData.Contains(mFilterIndexes), OT_NOOP); + } + + didCheckSteeringData = true; + } + break; + + case MeshCoP::Tlv::kJoinerUdpPort: + SuccessOrExit(error = Tlv::ReadUint16Tlv(aMessage, offset, result.mJoinerUdpPort)); + break; + + default: + break; + } + + offset += sizeof(meshcopTlv) + meshcopTlv.GetLength(); + } + + VerifyOrExit(!mEnableFiltering || didCheckSteeringData, OT_NOOP); + + if (mHandler) + { + mHandler(&result, mHandlerContext); + } + +exit: + + if (error != OT_ERROR_NONE) + { + otLogWarnMle("Failed to process Discovery Response: %s", otThreadErrorToString(error)); + } +} + +} // namespace Mle +} // namespace ot diff --git a/src/core/thread/discover_scanner.hpp b/src/core/thread/discover_scanner.hpp new file mode 100644 index 000000000..ca14a1b64 --- /dev/null +++ b/src/core/thread/discover_scanner.hpp @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2016-2020, 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 MLE Discover Scan process. + */ + +#ifndef DISCOVER_SCANNER_HPP_ +#define DISCOVER_SCANNER_HPP_ + +#include "openthread-core-config.h" + +#include "common/locator.hpp" +#include "common/timer.hpp" +#include "mac/channel_mask.hpp" +#include "mac/mac.hpp" +#include "mac/mac_types.hpp" +#include "meshcop/meshcop.hpp" +#include "thread/mle.hpp" + +namespace ot { + +class MeshForwarder; + +namespace Mle { + +/** + * This class implements MLE Discover Scan. + * + */ +class DiscoverScanner : public InstanceLocator +{ + friend class ot::Instance; + friend class ot::MeshForwarder; + friend class Mle; + +public: + enum + { + kDefaultScanDuration = Mac::kScanDurationDefault, ///< Default scan duration (per channel), in milliseconds. + }; + + /** + * This type represents Discover Scan result. + * + */ + typedef otActiveScanResult ScanResult; + + /** + * This type represents the handler function pointer called with any Discover Scan result or when the scan + * completes. + * + * The handler function format is `void (*oHandler)(ScanResult *aResult, void *aContext);`. End of scan is + * indicated by `aResult` pointer being set to NULL. + * + */ + typedef otHandleActiveScanResult Handler; + + /** + * This constructor initializes the object. + * + * @param[in] aInstance A reference to the OpenThread instance. + * + */ + explicit DiscoverScanner(Instance &aInstance); + + /** + * This method starts a Thread Discovery Scan. + * + * @param[in] aScanChannels Channel mask listing channels to scan (if empty, use all supported channels). + * @param[in] aPanId The PAN ID filter (set to Broadcast PAN to disable filter). + * @param[in] aJoiner Value of the Joiner Flag in the Discovery Request TLV. + * @param[in] aEnableFiltering Enable filtering MLE Discovery Responses that don't match our factory EUI64. + * @param[in] aHandler A pointer to a function that is called on receiving an MLE Discovery Response. + * @param[in] aContext A pointer to arbitrary context information. + * + * @retval OT_ERROR_NONE Successfully started a Thread Discovery Scan. + * @retval OT_ERROR_NO_BUFS Could not allocate message for Discovery Request. + * @retval OT_ERROR_BUSY Thread Discovery Scan is already in progress. + * + */ + otError Discover(const Mac::ChannelMask &aScanChannels, + Mac::PanId aPanId, + bool aJoiner, + bool aEnableFiltering, + Handler aHandler, + void * aContext); + + /** + * This method indicates whether or not an MLE Thread Discovery Scan is currently in progress. + * + * @returns true if an MLE Thread Discovery Scan is in progress, false otherwise. + * + */ + bool IsInProgress(void) const { return (mState != kStateIdle); } + +private: + enum State + { + kStateIdle, + kStateScanning, + kStateScanDone, + }; + + // Methods used by `MeshForwarder` + otError PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame); + void HandleDiscoveryRequestFrameTxDone(Message &aMessage); + void Stop(void) { HandleDiscoverComplete(); } + + // Methods used from `Mle` + void HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const; + + void HandleDiscoverComplete(void); + static void HandleTimer(Timer &aTimer); + void HandleTimer(void); + + Handler mHandler; + void * mHandlerContext; + TimerMilli mTimer; + MeshCoP::SteeringData::HashBitIndexes mFilterIndexes; + Mac::ChannelMask mScanChannels; + State mState; + uint8_t mScanChannel; + bool mEnableFiltering : 1; + bool mShouldRestorePanId : 1; +}; + +} // namespace Mle +} // namespace ot + +#endif // DISCOVER_SCANNER_HPP_ diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 7846e6327..df01ebde4 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -57,20 +57,16 @@ namespace ot { MeshForwarder::MeshForwarder(Instance &aInstance) : InstanceLocator(aInstance) - , mDiscoverTimer(aInstance, MeshForwarder::HandleDiscoverTimer, this) , mUpdateTimer(aInstance, MeshForwarder::HandleUpdateTimer, this) , mMessageNextOffset(0) , mSendMessage(NULL) , mMeshSource() , mMeshDest() , mAddMeshHeader(false) + , mEnabled(false) + , mTxPaused(false) , mSendBusy(false) , mScheduleTransmissionTask(aInstance, ScheduleTransmissionTask, this) - , mEnabled(false) - , mScanChannels(0) - , mScanChannel(0) - , mRestorePanId(Mac::kPanIdBroadcast) - , mScanning(false) #if OPENTHREAD_FTD , mIndirectSender(aInstance) #endif @@ -106,11 +102,7 @@ void MeshForwarder::Stop(void) mDataPollSender.StopPolling(); mUpdateTimer.Stop(); - - if (mScanning) - { - HandleDiscoverComplete(); - } + Get().Stop(); while ((message = mSendQueue.GetHead()) != NULL) { @@ -163,6 +155,15 @@ void MeshForwarder::RemoveMessage(Message &aMessage) aMessage.Free(); } +void MeshForwarder::ResumeMessageTransmissions(void) +{ + if (mTxPaused) + { + mTxPaused = false; + mScheduleTransmissionTask.Post(); + } +} + void MeshForwarder::ScheduleTransmissionTask(Tasklet &aTasklet) { aTasklet.GetOwner().ScheduleTransmissionTask(); @@ -170,7 +171,7 @@ void MeshForwarder::ScheduleTransmissionTask(Tasklet &aTasklet) void MeshForwarder::ScheduleTransmissionTask(void) { - VerifyOrExit(!mSendBusy, OT_NOOP); + VerifyOrExit(!mSendBusy && !mTxPaused, OT_NOOP); mSendMessage = GetDirectTransmission(); VerifyOrExit(mSendMessage != NULL, OT_NOOP); @@ -186,27 +187,6 @@ exit: return; } -otError MeshForwarder::PrepareDiscoverRequest(void) -{ - otError error = OT_ERROR_NONE; - - VerifyOrExit(!mScanning, OT_NOOP); - - mScanChannel = Mac::ChannelMask::kChannelIteratorFirst; - mRestorePanId = Get().GetPanId(); - - mScanning = true; - - if (mScanChannels.GetNextChannel(mScanChannel) != OT_ERROR_NONE) - { - HandleDiscoverComplete(); - ExitNow(error = OT_ERROR_DROP); - } - -exit: - return error; -} - Message *MeshForwarder::GetDirectTransmission(void) { Message *curMessage, *nextMessage; @@ -226,12 +206,6 @@ Message *MeshForwarder::GetDirectTransmission(void) { case Message::kTypeIp6: error = UpdateIp6Route(*curMessage); - - if (curMessage->GetSubType() == Message::kSubTypeMleDiscoverRequest) - { - error = PrepareDiscoverRequest(); - } - break; #if OPENTHREAD_FTD @@ -436,18 +410,7 @@ otError MeshForwarder::HandleFrameRequest(Mac::TxFrame &aFrame) case Message::kTypeIp6: if (mSendMessage->GetSubType() == Message::kSubTypeMleDiscoverRequest) { - SuccessOrExit(error = Get().SetTemporaryChannel(mScanChannel)); - - aFrame.SetChannel(mScanChannel); - - // In case a specific PAN ID of a Thread Network to be discovered is not known, Discovery - // Request messages MUST have the Destination PAN ID in the IEEE 802.15.4 MAC header set - // to be the Broadcast PAN ID (0xFFFF) and the Source PAN ID set to a randomly generated - // value. - if (mSendMessage->GetPanId() == Mac::kPanIdBroadcast && Get().GetPanId() == Mac::kPanIdBroadcast) - { - Get().SetPanId(Mac::GenerateRandomPanId()); - } + SuccessOrExit(error = Get().PrepareDiscoveryRequestFrame(aFrame)); } mMessageNextOffset = @@ -887,9 +850,7 @@ void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, otError aError) if (mSendMessage->GetSubType() == Message::kSubTypeMleDiscoverRequest) { - mSendBusy = true; - mDiscoverTimer.Start(static_cast(Mac::kScanDurationDefault)); - ExitNow(); + Get().HandleDiscoveryRequestFrameTxDone(*mSendMessage); } if (!mSendMessage->GetDirectTransmission() && !mSendMessage->IsChildPending()) @@ -920,50 +881,6 @@ exit: } } -void MeshForwarder::SetDiscoverParameters(const Mac::ChannelMask &aScanChannels) -{ - uint32_t mask; - uint32_t supportedMask = Get().GetSupportedChannelMask().GetMask(); - - mask = aScanChannels.IsEmpty() ? supportedMask : aScanChannels.GetMask(); - mScanChannels.SetMask(mask & supportedMask); -} - -void MeshForwarder::HandleDiscoverTimer(Timer &aTimer) -{ - aTimer.GetOwner().HandleDiscoverTimer(); -} - -void MeshForwarder::HandleDiscoverTimer(void) -{ - if (mScanChannels.GetNextChannel(mScanChannel) != OT_ERROR_NONE) - { - mSendQueue.Dequeue(*mSendMessage); - mSendMessage->Free(); - mSendMessage = NULL; - - HandleDiscoverComplete(); - ExitNow(); - } - - mSendMessage->SetDirectTransmission(); - -exit: - mSendBusy = false; - mScheduleTransmissionTask.Post(); -} - -void MeshForwarder::HandleDiscoverComplete(void) -{ - OT_ASSERT(mScanning); - - Get().ClearTemporaryChannel(); - Get().SetPanId(mRestorePanId); - mScanning = false; - Get().HandleDiscoverComplete(); - mDiscoverTimer.Stop(); -} - void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame) { otThreadLinkInfo linkInfo; diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 7e9e9ed70..a2281ac0b 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -50,6 +50,10 @@ namespace ot { +namespace Mle { +class DiscoverScanner; +} + enum { kReassemblyTimeout = OPENTHREAD_CONFIG_6LOWPAN_REASSEMBLY_TIMEOUT, @@ -171,6 +175,7 @@ class MeshForwarder : public InstanceLocator friend class Instance; friend class DataPollSender; friend class IndirectSender; + friend class Mle::DiscoverScanner; public: /** @@ -312,7 +317,6 @@ public: */ const PriorityQueue &GetResolvingQueue(void) const { return mResolvingQueue; } #endif - private: enum { @@ -368,7 +372,6 @@ private: void GetMacDestinationAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr); void GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr); Message *GetDirectTransmission(void); - otError PrepareDiscoverRequest(void); void HandleMesh(uint8_t * aFrame, uint16_t aFrameLength, const Mac::Address & aMacSource, @@ -438,6 +441,9 @@ private: otError GetDestinationRlocByServiceAloc(uint16_t aServiceAloc, uint16_t &aMeshDest); + void PauseMessageTransmissions(void) { mTxPaused = true; } + void ResumeMessageTransmissions(void); + void LogMessage(MessageAction aAction, const Message &aMessage, const Mac::Address *aAddress, otError aError); void LogFrame(const char *aActionText, const Mac::Frame &aFrame, otError aError); void LogFragmentFrameDrop(otError aError, @@ -500,7 +506,6 @@ private: otLogLevel aLogLevel); #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MAC == 1) - TimerMilli mDiscoverTimer; TimerMilli mUpdateTimer; PriorityQueue mSendQueue; @@ -514,17 +519,12 @@ private: Mac::Address mMacDest; uint16_t mMeshSource; uint16_t mMeshDest; - bool mAddMeshHeader; - - bool mSendBusy; + bool mAddMeshHeader : 1; + bool mEnabled : 1; + bool mTxPaused : 1; + bool mSendBusy : 1; Tasklet mScheduleTransmissionTask; - bool mEnabled; - - Mac::ChannelMask mScanChannels; - uint8_t mScanChannel; - uint16_t mRestorePanId; - bool mScanning; otIpCounters mIpCounters; diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 9ad91f781..3779be7f6 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -91,10 +91,6 @@ Mle::Mle(Instance &aInstance) , mReceivedResponseFromParent(false) , mSocket(aInstance.Get()) , mTimeout(kMleEndDeviceTimeout) - , mDiscoverHandler(NULL) - , mDiscoverContext(NULL) - , mDiscoverInProgress(false) - , mDiscoverEnableFiltering(false) #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH , mPreviousParentRloc(Mac::kShortAddrInvalid) #endif @@ -511,73 +507,6 @@ exit: return error; } -otError Mle::Discover(const Mac::ChannelMask &aScanChannels, - uint16_t aPanId, - bool aJoiner, - bool aEnableFiltering, - DiscoverHandler aCallback, - void * aContext) -{ - otError error = OT_ERROR_NONE; - Message * message = NULL; - Ip6::Address destination; - MeshCoP::DiscoveryRequestTlv discoveryRequest; - - VerifyOrExit(!mDiscoverInProgress, error = OT_ERROR_BUSY); - - mDiscoverEnableFiltering = aEnableFiltering; - - if (mDiscoverEnableFiltering) - { - Mac::ExtAddress extAddress; - - Get().GetIeeeEui64(extAddress); - MeshCoP::ComputeJoinerId(extAddress, extAddress); - - MeshCoP::SteeringData::CalculateHashBitIndexes(extAddress, mDiscoverFilterIndexes); - } - - mDiscoverHandler = aCallback; - mDiscoverContext = aContext; - Get().SetDiscoverParameters(aScanChannels); - - VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS); - message->SetSubType(Message::kSubTypeMleDiscoverRequest); - message->SetPanId(aPanId); - SuccessOrExit(error = AppendHeader(*message, Header::kCommandDiscoveryRequest)); - - // Append MLE Discovery TLV with a single sub-TLV (MeshCoP Discovery Request). - discoveryRequest.Init(); - discoveryRequest.SetVersion(kThreadVersion); - discoveryRequest.SetJoiner(aJoiner); - - SuccessOrExit(error = Tlv::AppendTlv(*message, Tlv::kDiscovery, &discoveryRequest, sizeof(discoveryRequest))); - - destination.SetToLinkLocalAllRoutersMulticast(); - - SuccessOrExit(error = SendMessage(*message, destination)); - - mDiscoverInProgress = true; - - LogMleMessage("Send Discovery Request", destination); - -exit: - - if (error != OT_ERROR_NONE && message != NULL) - { - message->Free(); - } - - return error; -} - -void Mle::HandleDiscoverComplete(void) -{ - mDiscoverInProgress = false; - mDiscoverEnableFiltering = false; - mDiscoverHandler(NULL, mDiscoverContext); -} - otError Mle::BecomeDetached(void) { otError error = OT_ERROR_NONE; @@ -2625,7 +2554,7 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn #endif case Header::kCommandDiscoveryResponse: - HandleDiscoveryResponse(aMessage, aMessageInfo); + Get().HandleDiscoveryResponse(aMessage, aMessageInfo); break; default: @@ -3840,107 +3769,6 @@ void Mle::ProcessAnnounce(void) IgnoreError(Start(/* aAnnounceAttach */ true)); } -void Mle::HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - otError error = OT_ERROR_NONE; - const otThreadLinkInfo * linkInfo = static_cast(aMessageInfo.GetLinkInfo()); - Tlv tlv; - MeshCoP::Tlv meshcopTlv; - MeshCoP::DiscoveryResponseTlv discoveryResponse; - MeshCoP::NetworkNameTlv networkName; - otActiveScanResult result; - uint16_t offset; - uint16_t end; - bool didCheckSteeringData = false; - - LogMleMessage("Receive Discovery Response", aMessageInfo.GetPeerAddr()); - - VerifyOrExit(mDiscoverInProgress, error = OT_ERROR_DROP); - - // find MLE Discovery TLV - VerifyOrExit(Tlv::FindTlvOffset(aMessage, Tlv::kDiscovery, offset) == OT_ERROR_NONE, error = OT_ERROR_PARSE); - aMessage.Read(offset, sizeof(tlv), &tlv); - - offset += sizeof(tlv); - end = offset + tlv.GetLength(); - - memset(&result, 0, sizeof(result)); - result.mPanId = linkInfo->mPanId; - result.mChannel = linkInfo->mChannel; - result.mRssi = linkInfo->mRss; - result.mLqi = linkInfo->mLqi; - aMessageInfo.GetPeerAddr().ToExtAddress(*static_cast(&result.mExtAddress)); - - // process MeshCoP TLVs - while (offset < end) - { - aMessage.Read(offset, sizeof(meshcopTlv), &meshcopTlv); - - switch (meshcopTlv.GetType()) - { - case MeshCoP::Tlv::kDiscoveryResponse: - aMessage.Read(offset, sizeof(discoveryResponse), &discoveryResponse); - VerifyOrExit(discoveryResponse.IsValid(), error = OT_ERROR_PARSE); - result.mVersion = discoveryResponse.GetVersion(); - result.mIsNative = discoveryResponse.IsNativeCommissioner(); - break; - - case MeshCoP::Tlv::kExtendedPanId: - SuccessOrExit(error = Tlv::ReadTlv(aMessage, offset, &result.mExtendedPanId, sizeof(Mac::ExtendedPanId))); - break; - - case MeshCoP::Tlv::kNetworkName: - aMessage.Read(offset, sizeof(networkName), &networkName); - IgnoreError(static_cast(result.mNetworkName).Set(networkName.GetNetworkName())); - break; - - case MeshCoP::Tlv::kSteeringData: - if (meshcopTlv.GetLength() > 0) - { - MeshCoP::SteeringData &steeringData = static_cast(result.mSteeringData); - uint8_t dataLength = MeshCoP::SteeringData::kMaxLength; - - if (meshcopTlv.GetLength() < dataLength) - { - dataLength = meshcopTlv.GetLength(); - } - - steeringData.Init(dataLength); - - SuccessOrExit(error = Tlv::ReadTlv(aMessage, offset, steeringData.GetData(), dataLength)); - - if (mDiscoverEnableFiltering) - { - VerifyOrExit(steeringData.Contains(mDiscoverFilterIndexes), OT_NOOP); - } - - didCheckSteeringData = true; - } - break; - - case MeshCoP::Tlv::kJoinerUdpPort: - SuccessOrExit(error = Tlv::ReadUint16Tlv(aMessage, offset, result.mJoinerUdpPort)); - break; - - default: - break; - } - - offset += sizeof(meshcopTlv) + meshcopTlv.GetLength(); - } - - VerifyOrExit(!mDiscoverEnableFiltering || didCheckSteeringData, OT_NOOP); - - mDiscoverHandler(&result, mDiscoverContext); - -exit: - - if (error != OT_ERROR_NONE) - { - otLogWarnMle("Failed to process Discovery Response: %s", otThreadErrorToString(error)); - } -} - Neighbor *Mle::GetNeighbor(uint16_t aAddress) { Neighbor *rval = NULL; diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 8183780a4..850498a9b 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -307,6 +307,8 @@ private: */ class Mle : public InstanceLocator, public Notifier::Receiver { + friend class DiscoverScanner; + public: /** * This constructor initializes the MLE object. @@ -371,51 +373,6 @@ public: */ otError Store(void); - /** - * This function pointer is called on receiving an MLE Discovery Response message. - * - * @param[in] aResult A valid pointer to the Discovery Response information or NULL when the Discovery completes. - * @param[in] aContext A pointer to application-specific context. - * - */ - typedef void (*DiscoverHandler)(otActiveScanResult *aResult, void *aContext); - - /** - * This method initiates a Thread Discovery. - * - * @param[in] aScanChannels A bit vector indicating which channels to scan. - * @param[in] aPanId The PAN ID filter (set to Broadcast PAN to disable filter). - * @param[in] aJoiner Value of the Joiner Flag in the Discovery Request TLV. - * @param[in] aEnableFiltering Enable filtering out MLE discovery responses that don't match our factory - * assigned EUI64. - * @param[in] aHandler A pointer to a function that is called on receiving an MLE Discovery Response. - * @param[in] aContext A pointer to arbitrary context information. - * - * @retval OT_ERROR_NONE Successfully started a Thread Discovery. - * @retval OT_ERROR_BUSY Thread Discovery is already in progress. - * - */ - otError Discover(const Mac::ChannelMask &aScanChannels, - uint16_t aPanId, - bool aJoiner, - bool aEnableFiltering, - DiscoverHandler aCallback, - void * aContext); - - /** - * This method indicates whether or not an MLE Thread Discovery is currently in progress. - * - * @returns true if an MLE Thread Discovery is in progress, false otherwise. - * - */ - bool IsDiscoverInProgress(void) const { return mDiscoverInProgress; } - - /** - * This method is called by the MeshForwarder to indicate that discovery is complete. - * - */ - void HandleDiscoverComplete(void); - /** * This method generates an MLE Announce message. * @@ -1720,7 +1677,6 @@ private: void HandleDataResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const Neighbor *aNeighbor); void HandleParentResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, uint32_t aKeySequence); void HandleAnnounce(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - void HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); otError HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); void ProcessAnnounce(void); bool HasUnregisteredAddress(void); @@ -1788,12 +1744,6 @@ private: Ip6::UdpSocket mSocket; uint32_t mTimeout; - DiscoverHandler mDiscoverHandler; - void * mDiscoverContext; - MeshCoP::SteeringData::HashBitIndexes mDiscoverFilterIndexes; - bool mDiscoverInProgress; - bool mDiscoverEnableFiltering; - #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH uint16_t mPreviousParentRloc; #endif diff --git a/src/core/thread/thread_netif.cpp b/src/core/thread/thread_netif.cpp index 6bf54da64..2965d4d1a 100644 --- a/src/core/thread/thread_netif.cpp +++ b/src/core/thread/thread_netif.cpp @@ -72,6 +72,7 @@ ThreadNetif::ThreadNetif(Instance &aInstance) , mMac(aInstance) , mMeshForwarder(aInstance) , mMleRouter(aInstance) + , mDiscoverScanner(aInstance) #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE , mNetworkDataLocal(aInstance) #endif diff --git a/src/core/thread/thread_netif.hpp b/src/core/thread/thread_netif.hpp index f3a203035..afb42551a 100644 --- a/src/core/thread/thread_netif.hpp +++ b/src/core/thread/thread_netif.hpp @@ -75,6 +75,7 @@ #include "net/sntp_client.hpp" #include "thread/address_resolver.hpp" #include "thread/announce_begin_server.hpp" +#include "thread/discover_scanner.hpp" #include "thread/energy_scan_server.hpp" #include "thread/key_manager.hpp" #include "thread/mesh_forwarder.hpp" @@ -210,6 +211,7 @@ private: Mac::Mac mMac; MeshForwarder mMeshForwarder; Mle::MleRouter mMleRouter; + Mle::DiscoverScanner mDiscoverScanner; #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE NetworkData::Local mNetworkDataLocal; #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE