diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index 625277715..1a94941e2 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -541,6 +541,8 @@ openthread_core_files = [ "mac/mac_links.hpp", "mac/mac_types.cpp", "mac/mac_types.hpp", + "mac/scan_result.cpp", + "mac/scan_result.hpp", "mac/sub_mac.cpp", "mac/sub_mac.hpp", "mac/sub_mac_callbacks.cpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f9c6b1a3e..57d015ef0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -158,6 +158,7 @@ set(COMMON_SOURCES mac/mac_header_ie.cpp mac/mac_links.cpp mac/mac_types.cpp + mac/scan_result.cpp mac/sub_mac.cpp mac/sub_mac_callbacks.cpp mac/sub_mac_csl_receiver.cpp diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index b2c379866..d99c71160 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -93,8 +93,7 @@ Mac::Mac(Instance &aInstance) , mWakeupListenInterval(kDefaultWedListenInterval) , mWakeupListenDuration(kDefaultWedListenDuration) #endif - , mActiveScanHandler(nullptr) // Initialize `mActiveScanHandler` and `mEnergyScanHandler` union - , mScanHandlerContext(nullptr) + , mActiveScanCallback() , mLinks(aInstance) , mOperationTask(aInstance) , mTimer(aInstance) @@ -141,15 +140,14 @@ void Mac::SetEnabled(bool aEnable) } } -Error Mac::ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext) +Error Mac::ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ScanResult::Handler aHandler, void *aContext) { Error error = kErrorNone; VerifyOrExit(IsEnabled(), error = kErrorInvalidState); VerifyOrExit(!IsActiveScanInProgress() && !IsEnergyScanInProgress(), error = kErrorBusy); - mActiveScanHandler = aHandler; - mScanHandlerContext = aContext; + mActiveScanCallback.Set(aHandler, aContext); if (aScanDuration == 0) { @@ -169,8 +167,7 @@ Error Mac::EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergyScan VerifyOrExit(IsEnabled(), error = kErrorInvalidState); VerifyOrExit(!IsActiveScanInProgress() && !IsEnergyScanInProgress(), error = kErrorBusy); - mEnergyScanHandler = aHandler; - mScanHandlerContext = aContext; + mEnergyScanCallback.Set(aHandler, aContext); Scan(kOperationEnergyScan, aScanChannels, aScanDuration); @@ -225,57 +222,6 @@ bool Mac::IsInTransmitState(void) const return retval; } -Error Mac::ConvertBeaconToActiveScanResult(const RxFrame *aBeaconFrame, ActiveScanResult &aResult) -{ - Error error = kErrorNone; - Address address; -#if OPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE - const BeaconPayload *beaconPayload = nullptr; - const Beacon *beacon = nullptr; - uint16_t payloadLength; -#endif - - ClearAllBytes(aResult); - - VerifyOrExit(aBeaconFrame != nullptr, error = kErrorInvalidArgs); - - VerifyOrExit(aBeaconFrame->GetType() == Frame::kTypeBeacon, error = kErrorParse); - SuccessOrExit(error = aBeaconFrame->GetSrcAddr(address)); - VerifyOrExit(address.IsExtended(), error = kErrorParse); - aResult.mExtAddress = address.GetExtended(); - - if (kErrorNone != aBeaconFrame->GetSrcPanId(aResult.mPanId)) - { - IgnoreError(aBeaconFrame->GetDstPanId(aResult.mPanId)); - } - - aResult.mChannel = aBeaconFrame->GetChannel(); - aResult.mRssi = aBeaconFrame->GetRssi(); - aResult.mLqi = aBeaconFrame->GetLqi(); - -#if OPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE - payloadLength = aBeaconFrame->GetPayloadLength(); - - beacon = reinterpret_cast(aBeaconFrame->GetPayload()); - beaconPayload = reinterpret_cast(beacon->GetPayload()); - - if ((payloadLength >= (sizeof(*beacon) + sizeof(*beaconPayload))) && beacon->IsValid() && beaconPayload->IsValid()) - { - aResult.mVersion = beaconPayload->GetProtocolVersion(); - aResult.mIsJoinable = beaconPayload->IsJoiningPermitted(); - aResult.mIsNative = beaconPayload->IsNative(); - IgnoreError(AsCoreType(&aResult.mNetworkName).Set(beaconPayload->GetNetworkName())); - VerifyOrExit(IsValidUtf8String(aResult.mNetworkName.m8), error = kErrorParse); - aResult.mExtendedPanId = beaconPayload->GetExtendedPanId(); - } -#endif - - LogBeacon("Received"); - -exit: - return error; -} - Error Mac::UpdateScanChannel(void) { Error error; @@ -308,18 +254,20 @@ void Mac::PerformActiveScan(void) void Mac::ReportActiveScanResult(const RxFrame *aBeaconFrame) { - VerifyOrExit(mActiveScanHandler != nullptr); + VerifyOrExit(mActiveScanCallback.IsSet()); if (aBeaconFrame == nullptr) { - mActiveScanHandler(nullptr, mScanHandlerContext); + mActiveScanCallback.Invoke(nullptr); } else { - ActiveScanResult result; + ScanResult result; - SuccessOrExit(ConvertBeaconToActiveScanResult(aBeaconFrame, result)); - mActiveScanHandler(&result, mScanHandlerContext); + SuccessOrExit(result.PopulateFromBeacon(aBeaconFrame)); + LogBeacon("Received"); + + mActiveScanCallback.Invoke(&result); } exit: @@ -356,10 +304,7 @@ exit: { FinishOperation(); - if (mEnergyScanHandler != nullptr) - { - mEnergyScanHandler(nullptr, mScanHandlerContext); - } + mEnergyScanCallback.InvokeIfSet(nullptr); PerformNextOperation(); } @@ -369,12 +314,12 @@ void Mac::ReportEnergyScanResult(int8_t aRssi) { EnergyScanResult result; - VerifyOrExit((mEnergyScanHandler != nullptr) && (aRssi != Radio::kInvalidRssi)); + VerifyOrExit(mEnergyScanCallback.IsSet() && (aRssi != Radio::kInvalidRssi)); result.mChannel = mScanChannel; result.mMaxRssi = aRssi; - mEnergyScanHandler(&result, mScanHandlerContext); + mEnergyScanCallback.Invoke(&result); exit: return; diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 7d7ca9083..aac98e4e6 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -51,6 +51,7 @@ #include "mac/mac_frame.hpp" #include "mac/mac_links.hpp" #include "mac/mac_types.hpp" +#include "mac/scan_result.hpp" #include "mac/sub_mac.hpp" #include "radio/trel_link.hpp" #include "thread/key_manager.hpp" @@ -98,16 +99,6 @@ constexpr uint16_t kMinCslIePeriod = OPENTHREAD_CONFIG_MAC_CSL_MIN_PERIOD; constexpr uint32_t kDefaultWedListenInterval = OPENTHREAD_CONFIG_WED_LISTEN_INTERVAL; constexpr uint32_t kDefaultWedListenDuration = OPENTHREAD_CONFIG_WED_LISTEN_DURATION; -/** - * Defines the function pointer called on receiving an IEEE 802.15.4 Beacon during an Active Scan. - */ -typedef otHandleActiveScanResult ActiveScanHandler; - -/** - * Defines an Active Scan result. - */ -typedef otActiveScanResult ActiveScanResult; - /** * Defines the function pointer which is called during an Energy Scan when the scan result for a channel is * ready or when the scan completes. @@ -151,7 +142,7 @@ public: * @retval kErrorNone Successfully scheduled the Active Scan request. * @retval kErrorBusy Could not schedule the scan (a scan is ongoing or scheduled). */ - Error ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext); + Error ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ScanResult::Handler aHandler, void *aContext); /** * Starts an IEEE 802.15.4 Energy Scan. @@ -847,7 +838,6 @@ private: Error UpdateScanChannel(void); void PerformActiveScan(void); void ReportActiveScanResult(const RxFrame *aBeaconFrame); - Error ConvertBeaconToActiveScanResult(const RxFrame *aBeaconFrame, ActiveScanResult &aResult); void PerformEnergyScan(void); void ReportEnergyScanResult(int8_t aRssi); @@ -926,12 +916,10 @@ private: #endif union { - ActiveScanHandler mActiveScanHandler; - EnergyScanHandler mEnergyScanHandler; + ScanResult::ScanCallback mActiveScanCallback; + Callback mEnergyScanCallback; }; - void *mScanHandlerContext; - Links mLinks; OperationTask mOperationTask; MacTimer mTimer; diff --git a/src/core/mac/scan_result.cpp b/src/core/mac/scan_result.cpp new file mode 100644 index 000000000..961ad730f --- /dev/null +++ b/src/core/mac/scan_result.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2026, 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 implementation of methods in `ScanResult`. + */ + +#include "scan_result.hpp" + +namespace ot { + +Error ScanResult::PopulateFromBeacon(const Mac::RxFrame *aBeaconFrame) +{ + Error error = kErrorNone; + Mac::Address address; + + Clear(); + + VerifyOrExit(aBeaconFrame != nullptr, error = kErrorInvalidArgs); + + VerifyOrExit(aBeaconFrame->GetType() == Mac::Frame::kTypeBeacon, error = kErrorParse); + + SuccessOrExit(error = aBeaconFrame->GetSrcAddr(address)); + VerifyOrExit(address.IsExtended(), error = kErrorParse); + mExtAddress = address.GetExtended(); + + if (aBeaconFrame->GetSrcPanId(mPanId) != kErrorNone) + { + IgnoreError(aBeaconFrame->GetDstPanId(mPanId)); + } + + mChannel = aBeaconFrame->GetChannel(); + mRssi = aBeaconFrame->GetRssi(); + mLqi = aBeaconFrame->GetLqi(); + +#if OPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE + { + const Mac::Beacon *beacon; + const Mac::BeaconPayload *beaconPayload; + + VerifyOrExit(aBeaconFrame->GetPayloadLength() >= sizeof(Mac::Beacon) + sizeof(Mac::BeaconPayload)); + + beacon = reinterpret_cast(aBeaconFrame->GetPayload()); + VerifyOrExit(beacon->IsValid()); + + beaconPayload = reinterpret_cast(beacon->GetPayload()); + VerifyOrExit(beaconPayload->IsValid()); + + mVersion = beaconPayload->GetProtocolVersion(); + mIsJoinable = beaconPayload->IsJoiningPermitted(); + mIsNative = beaconPayload->IsNative(); + mExtendedPanId = beaconPayload->GetExtendedPanId(); + + IgnoreError(AsCoreType(&mNetworkName).Set(beaconPayload->GetNetworkName())); + VerifyOrExit(IsValidUtf8String(mNetworkName.m8), error = kErrorParse); + } +#endif + +exit: + return error; +} + +} // namespace ot diff --git a/src/core/mac/scan_result.hpp b/src/core/mac/scan_result.hpp new file mode 100644 index 000000000..e7487613f --- /dev/null +++ b/src/core/mac/scan_result.hpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2026, 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 scan result (discover scan or MAC active scan). + */ + +#ifndef OT_CORE_MAC_SCAN_RESULT_HPP_ +#define OT_CORE_MAC_SCAN_RESULT_HPP_ + +#include "openthread-core-config.h" + +#include + +#include "common/as_core_type.hpp" +#include "common/callback.hpp" +#include "common/clearable.hpp" +#include "common/error.hpp" +#include "mac/mac_frame.hpp" +#include "mac/mac_types.hpp" +#include "meshcop/extended_panid.hpp" +#include "meshcop/network_name.hpp" +#include "meshcop/steering_data.hpp" + +namespace ot { + +namespace Mac { +class Mac; +} + +namespace Mle { +class DiscoverScanner; +} + +/** + * Represents a discover or active scan result. + */ +class ScanResult : public otActiveScanResult, public Clearable +{ + friend class ot::Mac::Mac; + friend class ot::Mle::DiscoverScanner; + +public: + /** + * Represents the function pointer callback to notify scan result. + */ + typedef otHandleActiveScanResult Handler; + + /** + * Gets the IEEE 802.15.4 Extended Address. + * + * @returns A constant reference to the IEEE 802.15.4 Extended Address. + */ + const Mac::ExtAddress &GetExtAddress(void) const { return AsCoreType(&mExtAddress); } + + /** + * Gets the Thread Network Name. + * + * @returns A constant reference to the Thread Network Name. + */ + const MeshCoP::NetworkName &GetNetworkName(void) const { return AsCoreType(&mNetworkName); } + + /** + * Gets the Thread Extended PAN ID. + * + * @returns A constant reference to the Thread Extended PAN ID. + */ + const MeshCoP::ExtendedPanId &GetExtendedPanId(void) const { return AsCoreType(&mExtendedPanId); } + + /** + * Gets the Steering Data. + * + * @returns A constant reference to the Steering Data. + */ + const MeshCoP::SteeringData &GetSteeringData(void) const { return AsCoreType(&mSteeringData); } + + /** + * Gets the IEEE 802.15.4 PAN ID. + * + * @returns The IEEE 802.15.4 PAN ID. + */ + Mac::PanId GetPanId(void) const { return mPanId; } + + /** + * Gets the Joiner UDP Port. + * + * @returns The Joiner UDP Port. + */ + uint16_t GetJoinerUdpPort(void) const { return mJoinerUdpPort; } + + /** + * Gets the IEEE 802.15.4 Channel. + * + * @returns The IEEE 802.15.4 Channel. + */ + uint8_t GetChannel(void) const { return mChannel; } + + /** + * Gets the RSSI (dBm). + * + * @returns The RSSI. + */ + int8_t GetRssi(void) const { return mRssi; } + + /** + * Gets the LQI. + * + * @returns The LQI. + */ + uint8_t GetLqi(void) const { return mLqi; } + + /** + * Gets the Version. + * + * @returns The Version. + */ + uint8_t GetVersion(void) const { return mVersion; } + + /** + * Indicates whether the Native Commissioner flag is set. + * + * @retval TRUE If the Native Commissioner flag is set. + * @retval FALSE If the Native Commissioner flag is not set. + */ + bool IsNative(void) const { return mIsNative; } + + /** + * Indicates whether the result is from MLE Discovery. + * + * @retval TRUE If the result is from MLE Discovery. + * @retval FALSE If the result is not from MLE Discovery. + */ + bool IsDiscover(void) const { return mDiscover; } + + /** + * Indicates whether the Joining Permitted flag is set. + * + * @retval TRUE If the Joining Permitted flag is set. + * @retval FALSE If the Joining Permitted flag is not set. + */ + bool IsJoinable(void) const { return mIsJoinable; } + +private: + typedef Callback ScanCallback; + + Error PopulateFromBeacon(const Mac::RxFrame *aBeaconFrame); +}; + +/** + * Declares a Scan handler method in a given class `Type`. + * + * This macro simplifies the definition of scan handler callback. It defines a `static` handler method which can be + * used as a `Handler `callback function pointer. The `static` handler acts as a wrapper, casting the `aContext` + * pointer back to a `Type` object and invoking its member method with the same `MethodName`. + * + * The `Type` class MUST implement the following member method which will be invoked by the `static` handler: + * + * void MethodName(const ScanResult *aScanResult); + * + * @param[in] Type The class `Type` in which scan result handler is declared. + * @param[in] MethodName The handler method name. + */ +#define DeclareScanResultHandlerIn(Type, MethodName) \ + static void MethodName(otActiveScanResult *aScanResult, void *aContext) \ + { \ + static_cast(aContext)->MethodName(AsCoreTypePtr(aScanResult)); \ + } \ + \ + void MethodName(const ScanResult *aScanResult) + +DefineCoreType(otActiveScanResult, ScanResult); + +} // namespace ot + +#endif // OT_CORE_MAC_SCAN_RESULT_HPP_ diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index 6d22fad01..f049ba5ca 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -202,15 +202,14 @@ exit: return; } -Seeker::Verdict Joiner::EvaluateScanResult(void *aContext, const Seeker::ScanResult *aResult) +Seeker::Verdict Joiner::EvaluateScanResult(void *aContext, const otSeekerScanResult *aResult) { - return static_cast(aContext)->EvaluateScanResult(aResult); + return static_cast(aContext)->EvaluateScanResult(AsCoreTypePtr(aResult)); } -Seeker::Verdict Joiner::EvaluateScanResult(const Seeker::ScanResult *aResult) +Seeker::Verdict Joiner::EvaluateScanResult(const ScanResult *aResult) { - Seeker::Verdict verdict = Seeker::kIgnore; - const SteeringData *steeringData; + Seeker::Verdict verdict = Seeker::kIgnore; if (aResult == nullptr) { @@ -218,13 +217,11 @@ Seeker::Verdict Joiner::EvaluateScanResult(const Seeker::ScanResult *aResult) ExitNow(); } - steeringData = AsCoreTypePtr(&aResult->mSteeringData); - // We prefer networks with an exact match of Joiner ID or // Discerner in the Steering Data compared to ones that allow all // Joiners. - if (steeringData->PermitsAllJoiners()) + if (aResult->GetSteeringData().PermitsAllJoiners()) { verdict = Seeker::kAccept; ExitNow(); @@ -232,11 +229,11 @@ Seeker::Verdict Joiner::EvaluateScanResult(const Seeker::ScanResult *aResult) if (!mDiscerner.IsEmpty()) { - VerifyOrExit(steeringData->Contains(mDiscerner)); + VerifyOrExit(aResult->GetSteeringData().Contains(mDiscerner)); } else { - VerifyOrExit(steeringData->Contains(mId)); + VerifyOrExit(aResult->GetSteeringData().Contains(mId)); } verdict = Seeker::kAcceptPreferred; diff --git a/src/core/meshcop/joiner.hpp b/src/core/meshcop/joiner.hpp index 11535182a..60804d155 100644 --- a/src/core/meshcop/joiner.hpp +++ b/src/core/meshcop/joiner.hpp @@ -195,8 +195,8 @@ private: void FreeJoinerFinalizeMessage(void); void SendJoinerFinalize(void); void SendJoinerEntrustResponse(const Coap::Msg &aMsg); - static Seeker::Verdict EvaluateScanResult(void *aContext, const Seeker::ScanResult *aResult); - Seeker::Verdict EvaluateScanResult(const Seeker::ScanResult *aResult); + static Seeker::Verdict EvaluateScanResult(void *aContext, const otSeekerScanResult *aResult); + Seeker::Verdict EvaluateScanResult(const ScanResult *aResult); void HandleScanCompleted(void); static void HandleSecureCoapClientConnect(Dtls::Session::ConnectEvent aEvent, void *aContext); void HandleSecureCoapClientConnect(Dtls::Session::ConnectEvent aEvent); diff --git a/src/core/meshcop/seeker.cpp b/src/core/meshcop/seeker.cpp index faebe86e6..559bde9f2 100644 --- a/src/core/meshcop/seeker.cpp +++ b/src/core/meshcop/seeker.cpp @@ -110,12 +110,7 @@ exit: return error; } -void Seeker::HandleDiscoverResult(ScanResult *aResult, void *aContext) -{ - static_cast(aContext)->HandleDiscoverResult(aResult); -} - -void Seeker::HandleDiscoverResult(ScanResult *aResult) +void Seeker::HandleDiscoverResult(const ScanResult *aResult) { bool preferred = false; @@ -128,8 +123,8 @@ void Seeker::HandleDiscoverResult(ScanResult *aResult) ExitNow(); } - VerifyOrExit(aResult->mJoinerUdpPort > 0); - VerifyOrExit(AsCoreType(&aResult->mSteeringData).IsValid()); + VerifyOrExit(aResult->GetJoinerUdpPort() > 0); + VerifyOrExit(aResult->GetSteeringData().IsValid()); switch (mScanEvaluator.Invoke(aResult)) { @@ -152,20 +147,19 @@ exit: void Seeker::SaveCandidate(const ScanResult &aResult, bool aPreferred) { - Error error = kErrorNone; - const MeshCoP::ExtendedPanId &extPanId = AsCoreType(&aResult.mExtendedPanId); - bool shouldPushAsNew = false; - CandidateEntry entry; + Error error = kErrorNone; + bool shouldPushAsNew = false; + CandidateEntry entry; entry.MarkAsEmpty(); - if (mCandidates.FindMatching(entry, extPanId, AsCoreType(&aResult.mExtAddress)) == kErrorNone) + if (mCandidates.FindMatching(entry, aResult.GetExtendedPanId(), aResult.GetExtAddress()) == kErrorNone) { entry.Log(Candidate::kReplace); } else { - uint16_t count = CountAndSelectLeastFavoredCandidateFor(extPanId, entry); + uint16_t count = CountAndSelectLeastFavoredCandidateFor(aResult.GetExtendedPanId(), entry); if ((count == kMaxCandidatesPerNetwork) || ((count > 0) && mCandidates.IsFull())) { @@ -412,12 +406,12 @@ exit: void Seeker::Candidate::SetFrom(const ScanResult &aResult, bool aPreferred) { - mExtPanId = AsCoreType(&aResult.mExtendedPanId); - mExtAddr = AsCoreType(&aResult.mExtAddress); - mPanId = aResult.mPanId; - mJoinerUdpPort = aResult.mJoinerUdpPort; - mChannel = aResult.mChannel; - mRssi = aResult.mRssi; + mExtPanId = aResult.GetExtendedPanId(); + mExtAddr = aResult.GetExtAddress(); + mPanId = aResult.GetPanId(); + mJoinerUdpPort = aResult.GetJoinerUdpPort(); + mChannel = aResult.GetChannel(); + mRssi = aResult.GetRssi(); mPreferred = aPreferred; mConnAttempted = false; } @@ -429,7 +423,7 @@ bool Seeker::Candidate::IsFavoredOver(const Candidate &aOther) const bool Seeker::Candidate::IsFavoredOver(const ScanResult &aResult, bool aPreferred) const { - return IsFavoredOver(aResult.mRssi, aPreferred); + return IsFavoredOver(aResult.GetRssi(), aPreferred); } bool Seeker::Candidate::IsFavoredOver(int8_t aRssi, bool aPreferred) const diff --git a/src/core/meshcop/seeker.hpp b/src/core/meshcop/seeker.hpp index c4a0754b5..70abcb70d 100644 --- a/src/core/meshcop/seeker.hpp +++ b/src/core/meshcop/seeker.hpp @@ -70,8 +70,6 @@ class Seeker : public InstanceLocator, private NonCopyable friend class ot::UnitTester; public: - typedef otSeekerScanResult ScanResult; ///< Discover Scan result. - typedef otSeekerVerdict Verdict; ///< A verdict returned from `ScanEvaluator` evaluating a Discover Scan result. static constexpr Verdict kAccept = OT_SEEKER_ACCEPT; ///< Scan result is acceptable. @@ -229,17 +227,17 @@ private: void ReplaceWithIfFavored(const CandidateEntry &aEntry); }; - State GetState(void) const { return mState; } - void SetState(State aState) { mState = aState; } - static void HandleDiscoverResult(ScanResult *aResult, void *aContext); - void HandleDiscoverResult(ScanResult *aResult); - void SaveCandidate(const ScanResult &aResult, bool aPreferred); - Error EvictCandidate(CandidateEntry &aEntry); - Error SelectNextCandidate(CandidateEntry &aEntry); - uint16_t CountAndSelectLeastFavoredCandidateFor(const MeshCoP::ExtendedPanId &aExtPanId, - CandidateEntry &aEntry) const; + State GetState(void) const { return mState; } + void SetState(State aState) { mState = aState; } + void SaveCandidate(const ScanResult &aResult, bool aPreferred); + Error EvictCandidate(CandidateEntry &aEntry); + Error SelectNextCandidate(CandidateEntry &aEntry); + uint16_t CountAndSelectLeastFavoredCandidateFor(const MeshCoP::ExtendedPanId &aExtPanId, + CandidateEntry &aEntry) const; Error SelectMostFavoredCandidateFor(const MeshCoP::ExtendedPanId &aExtPanId, CandidateEntry &aFavoredEntry) const; + DeclareScanResultHandlerIn(Seeker, HandleDiscoverResult); + State mState; uint16_t mUdpPort; Callback mScanEvaluator; diff --git a/src/core/thread/discover_scanner.cpp b/src/core/thread/discover_scanner.cpp index 56d108080..77f06e12a 100644 --- a/src/core/thread/discover_scanner.cpp +++ b/src/core/thread/discover_scanner.cpp @@ -58,7 +58,7 @@ Error DiscoverScanner::Discover(const Mac::ChannelMask &aScanChannels, bool aJoiner, bool aEnableFiltering, const FilterIndexes *aFilterIndexes, - Handler aCallback, + ScanResult::Handler aHandler, void *aContext) { Error error = kErrorNone; @@ -88,7 +88,7 @@ Error DiscoverScanner::Discover(const Mac::ChannelMask &aScanChannels, } } - mCallback.Set(aCallback, aContext); + mCallback.Set(aHandler, aContext); mShouldRestorePanId = false; mScanChannels = Get().GetSupportedChannelMask(); @@ -332,7 +332,7 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const aRxInfo.mMessage.SetOffset(offsetRange.GetOffset()); IgnoreError(aRxInfo.mMessage.SetLength(offsetRange.GetEndOffset())); - ClearAllBytes(result); + result.Clear(); result.mDiscover = true; result.mPanId = aRxInfo.mMessage.GetPanId(); result.mChannel = aRxInfo.mMessage.GetChannel(); diff --git a/src/core/thread/discover_scanner.hpp b/src/core/thread/discover_scanner.hpp index 43cf017e8..2860d2d9a 100644 --- a/src/core/thread/discover_scanner.hpp +++ b/src/core/thread/discover_scanner.hpp @@ -44,6 +44,7 @@ #include "mac/channel_mask.hpp" #include "mac/mac.hpp" #include "mac/mac_types.hpp" +#include "mac/scan_result.hpp" #include "meshcop/meshcop.hpp" #include "thread/mle.hpp" @@ -68,20 +69,6 @@ public: */ static constexpr uint32_t kDefaultScanDuration = Mac::kScanDurationDefault; - /** - * Represents Discover Scan result. - */ - typedef otActiveScanResult ScanResult; - - /** - * 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 `nullptr`. - */ - typedef otHandleActiveScanResult Handler; - /** * Represents the filter indexes, i.e., hash bit index values for the bloom filter (calculated from a * Joiner ID). @@ -109,7 +96,7 @@ public: * @param[in] aFilterIndexes A pointer to `FilterIndexes` to use for filtering (when enabled). * If set to `nullptr`, filter indexes are derived from hash of factory-assigned * EUI64. - * @param[in] aCallback A pointer to a function that is called on receiving an MLE Discovery Response. + * @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 kErrorNone Successfully started a Thread Discovery Scan. @@ -122,7 +109,7 @@ public: bool aJoiner, bool aEnableFiltering, const FilterIndexes *aFilterIndexes, - Handler aCallback, + ScanResult::Handler aHandler, void *aContext); /** @@ -176,15 +163,15 @@ private: using ScanTimer = TimerMilliIn; using ScanDoneTask = TaskletIn; - Callback mCallback; - ScanDoneTask mScanDoneTask; - ScanTimer mTimer; - FilterIndexes mFilterIndexes; - Mac::ChannelMask mScanChannels; - State mState; - uint8_t mScanChannel; - bool mEnableFiltering : 1; - bool mShouldRestorePanId : 1; + ScanResult::ScanCallback mCallback; + ScanDoneTask mScanDoneTask; + ScanTimer mTimer; + FilterIndexes mFilterIndexes; + Mac::ChannelMask mScanChannels; + State mState; + uint8_t mScanChannel; + bool mEnableFiltering : 1; + bool mShouldRestorePanId : 1; #if OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE uint8_t mAdvDataLength; uint8_t mAdvData[kMaxAdvDataLength]; diff --git a/src/core/thread/panid_query_server.cpp b/src/core/thread/panid_query_server.cpp index 074351f6f..18e540611 100644 --- a/src/core/thread/panid_query_server.cpp +++ b/src/core/thread/panid_query_server.cpp @@ -72,12 +72,7 @@ exit: return; } -void PanIdQueryServer::HandleScanResult(Mac::ActiveScanResult *aScanResult, void *aContext) -{ - static_cast(aContext)->HandleScanResult(aScanResult); -} - -void PanIdQueryServer::HandleScanResult(Mac::ActiveScanResult *aScanResult) +void PanIdQueryServer::HandleScanResult(const ScanResult *aScanResult) { if (aScanResult != nullptr) { diff --git a/src/core/thread/panid_query_server.hpp b/src/core/thread/panid_query_server.hpp index a04be70b2..2f9e76ff1 100644 --- a/src/core/thread/panid_query_server.hpp +++ b/src/core/thread/panid_query_server.hpp @@ -64,13 +64,11 @@ private: template void HandleTmf(Coap::Msg &aMsg); - static void HandleScanResult(Mac::ActiveScanResult *aScanResult, void *aContext); - void HandleScanResult(Mac::ActiveScanResult *aScanResult); - - void HandleTimer(void); + DeclareScanResultHandlerIn(PanIdQueryServer, HandleScanResult); static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); + void HandleTimer(void); void SendConflict(void); using DelayTimer = TimerMilliIn; diff --git a/tests/nexus/test_discover_scan.cpp b/tests/nexus/test_discover_scan.cpp index 6a003aae7..4a5496cf9 100644 --- a/tests/nexus/test_discover_scan.cpp +++ b/tests/nexus/test_discover_scan.cpp @@ -46,8 +46,8 @@ struct DiscoverContext mScanResults.Clear(); } - bool mDiscoverDone; - Array mScanResults; + bool mDiscoverDone; + Array mScanResults; }; struct RequestCallbackContext : public Clearable @@ -59,19 +59,20 @@ struct RequestCallbackContext : public Clearable void HandleDiscoverResult(otActiveScanResult *aResult, void *aContext) { DiscoverContext *context = static_cast(aContext); + ScanResult *result = AsCoreTypePtr(aResult); VerifyOrQuit(aContext != nullptr); - Log(" HandleDiscoverResult() called%s", aResult == nullptr ? " (done)" : ""); + Log(" HandleDiscoverResult() called%s", result == nullptr ? " (done)" : ""); - if (aResult == nullptr) + if (result == nullptr) { context->mDiscoverDone = true; } else { VerifyOrQuit(!context->mDiscoverDone); - SuccessOrQuit(context->mScanResults.PushBack(*aResult)); + SuccessOrQuit(context->mScanResults.PushBack(*result)); } } @@ -95,12 +96,12 @@ void HandleDiscoverRequest(const otThreadDiscoveryRequestInfo *aInfo, void *aCon void TestDiscoverScanRequestCallback(void) { - Core nexus; - Node &leader = nexus.CreateNode(); - Node &scanner = nexus.CreateNode(); - DiscoverContext resultContext; - RequestCallbackContext requestContext; - Mle::DiscoverScanner::ScanResult *result; + Core nexus; + Node &leader = nexus.CreateNode(); + Node &scanner = nexus.CreateNode(); + DiscoverContext resultContext; + RequestCallbackContext requestContext; + ScanResult *result; Log("------------------------------------------------------------------------------------------------------"); Log("TestDiscoverScanRequestCallback"); @@ -148,11 +149,11 @@ void TestDiscoverScanRequestCallback(void) result = &resultContext.mScanResults[0]; - VerifyOrQuit(AsCoreType(&result->mExtAddress) == leader.Get().GetExtAddress()); - VerifyOrQuit(AsCoreType(&result->mExtendedPanId) == leader.Get().GetExtPanId()); - VerifyOrQuit(result->mPanId == leader.Get().GetPanId()); - VerifyOrQuit(result->mChannel == leader.Get().GetPanChannel()); - VerifyOrQuit(result->mDiscover); + VerifyOrQuit(result->GetExtAddress() == leader.Get().GetExtAddress()); + VerifyOrQuit(result->GetExtendedPanId() == leader.Get().GetExtPanId()); + VerifyOrQuit(result->GetPanId() == leader.Get().GetPanId()); + VerifyOrQuit(result->GetChannel() == leader.Get().GetPanChannel()); + VerifyOrQuit(result->IsDiscover()); } } // namespace Nexus diff --git a/tests/unit/test_seeker.cpp b/tests/unit/test_seeker.cpp index 8dd2d1629..e08b9d17e 100644 --- a/tests/unit/test_seeker.cpp +++ b/tests/unit/test_seeker.cpp @@ -39,7 +39,6 @@ class UnitTester { public: using Seeker = MeshCoP::Seeker; - using ScanResult = MeshCoP::Seeker::ScanResult; using CandidateEntry = MeshCoP::Seeker::CandidateEntry; static void CreateScanResult(ScanResult &aResult, uint64_t aExtPanId, uint64_t aExtAddr, int8_t aRssi)