[seeker] introduce new otSeeker APIs (#12357)

This commit introduces Seeker APIs in OpenThread. An earlier commit
extracted the discovery and candidate selection logic from the `Joiner`
role into a new, standalone `Seeker` module.

The `Seeker` is responsible for performing MLE Discover Scans to find
nearby Joiner Router candidates. It prioritizes these candidates based
on RSSI and steering data (indicating whether the Joiner is preferred)
and manages the list of candidates for connection attempts.

This separation allows the `Seeker` functionality to be utilized
independently of the full `Joiner` role, enabling the development of
custom joining mechanisms over Thread.

A new configuration option `OPENTHREAD_CONFIG_SEEKER_ENABLE` has been
added to control the presence of `otSeeker` APIs.
This commit is contained in:
Abtin Keshavarzian
2026-02-04 15:54:54 -08:00
committed by GitHub
parent 69c45ce55d
commit 3fec404eff
18 changed files with 351 additions and 34 deletions
+1
View File
@@ -128,6 +128,7 @@
* @brief Includes functions for the Operational Dataset API. * @brief Includes functions for the Operational Dataset API.
* @defgroup api-thread-router Router/Leader * @defgroup api-thread-router Router/Leader
* @brief This module includes functions for Thread Routers and Leaders. * @brief This module includes functions for Thread Routers and Leaders.
* @defgroup api-seeker Seeker
* @defgroup api-server Server * @defgroup api-server Server
* @defgroup api-steering-data Steering Data * @defgroup api-steering-data Steering Data
* *
+1
View File
@@ -252,6 +252,7 @@ ot_option(OT_PLATFORM_NETIF OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE "platform ne
ot_option(OT_PLATFORM_POWER_CALIBRATION OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE "power calibration") ot_option(OT_PLATFORM_POWER_CALIBRATION OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE "power calibration")
ot_option(OT_PLATFORM_UDP OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE "platform UDP") ot_option(OT_PLATFORM_UDP OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE "platform UDP")
ot_option(OT_REFERENCE_DEVICE OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE "test harness reference device") ot_option(OT_REFERENCE_DEVICE OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE "test harness reference device")
ot_option(OT_SEEKER OPENTHREAD_CONFIG_SEEKER_ENABLE "seeker")
ot_option(OT_SERVICE OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE "Network Data service") ot_option(OT_SERVICE OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE "Network Data service")
ot_option(OT_SETTINGS_RAM OPENTHREAD_SETTINGS_RAM "volatile-only storage of settings") ot_option(OT_SETTINGS_RAM OPENTHREAD_SETTINGS_RAM "volatile-only storage of settings")
ot_option(OT_SLAAC OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE "SLAAC address") ot_option(OT_SLAAC OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE "SLAAC address")
+1
View File
@@ -120,6 +120,7 @@ source_set("openthread") {
"radio_stats.h", "radio_stats.h",
"random_crypto.h", "random_crypto.h",
"random_noncrypto.h", "random_noncrypto.h",
"seeker.h",
"server.h", "server.h",
"sntp.h", "sntp.h",
"srp_client.h", "srp_client.h",
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
* *
* @note This number versions both OpenThread platform and user APIs. * @note This number versions both OpenThread platform and user APIs.
*/ */
#define OPENTHREAD_API_VERSION (576) #define OPENTHREAD_API_VERSION (577)
/** /**
* @addtogroup api-instance * @addtogroup api-instance
+192
View File
@@ -0,0 +1,192 @@
/*
* 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
* @brief
* This file implements the Thread Seeker role.
*
* The Seeker is a part of the Thread MeshCoP process. It is responsible for discovering nearby Joiner Router
* candidates, prioritizing them, and iterating through the list to select the best candidate for connection.
* It also operates as a sub-system of the `Joiner`, delegating control to the next layer to enable the
* implementation of alternative and custom joining protocols.
*/
#ifndef OPENTHREAD_SEEKER_H_
#define OPENTHREAD_SEEKER_H_
#include <stdbool.h>
#include <stdint.h>
#include <openthread/error.h>
#include <openthread/instance.h>
#include <openthread/ip6.h>
#include <openthread/link.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup api-seeker
*
* @brief
* This module includes functions for the Thread Seeker role.
*
* @note
* The functions in this module require `OPENTHREAD_CONFIG_SEEKER_ENABLE`.
*
* @{
*/
/**
* Represents a Discover Scan result.
*/
typedef otActiveScanResult otSeekerScanResult;
/**
* Represents a verdict returned from the `otSeekerScanEvaluator` callback when evaluating a Discover Scan result.
*/
typedef enum otSeekerVerdict
{
OT_SEEKER_ACCEPT, ///< The scan result is acceptable.
OT_SEEKER_ACCEPT_PREFERRED, ///< The scan result is acceptable and preferred.
OT_SEEKER_IGNORE, ///< The scan result should be ignored.
} otSeekerVerdict;
/**
* Represents the callback function type used to evaluate a scan result or report the end of a scan.
*
* @param[in] aContext A pointer to the callback context.
* @param[in] aResult A pointer to the scan result to evaluate, or `NULL` to indicate scan completion.
*
* @returns The verdict for the scan result (Accept, AcceptPreferred, or Ignore).
* If @p aResult is `NULL` (scan complete), the return value is ignored.
*/
typedef otSeekerVerdict (*otSeekerScanEvaluator)(void *aContext, const otSeekerScanResult *aResult);
/**
* Starts the Seeker operation.
*
* The Seeker generates and sets a random MAC address for anonymity, then initiates an MLE Discover Scan to find
* Joiner Router candidates.
*
* Found candidates are reported to the @p aScanEvaluator callback. Based on the returned `otSeekerVerdict`, the Seeker
* maintains a prioritized list of candidates for future connection attempts.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aScanEvaluator The callback function to evaluate scan results.
* @param[in] aContext An arbitrary context pointer to use with @p aScanEvaluator.
*
* @retval OT_ERROR_NONE Successfully started the Seeker.
* @retval OT_ERROR_BUSY The Seeker is already active (scanning or connecting).
* @retval OT_ERROR_INVALID_STATE The IPv6 interface is not enabled, or MLE is enabled.
*/
otError otSeekerStart(otInstance *aInstance, otSeekerScanEvaluator aScanEvaluator, void *aContext);
/**
* Stops the Seeker operation.
*
* This function stops any ongoing discovery or connection process, unregisters the unsecure Joiner/Seeker UDP port, and
* clears internal state. If the Seeker is already stopped, this method has no effect.
*
* If the join process succeeds after a call to `otSeekerSetUpNextConnection()`, the caller MUST call this method to
* stop the Seeker and, importantly, unregister the Seeker UDP port as an unsecure port.
*
* @note If `otSeekerSetUpNextConnection()` returns `OT_ERROR_NOT_FOUND` (indicating the candidate list is exhausted),
* the Seeker stops automatically.
*
* @param[in] aInstance The OpenThread instance.
*/
void otSeekerStop(otInstance *aInstance);
/**
* Indicates whether or not the Seeker is running.
*
* @param[in] aInstance The OpenThread instance.
*
* @retval TRUE The Seeker is active and running.
* @retval FALSE The Seeker is stopped.
*/
bool otSeekerIsRunning(otInstance *aInstance);
/**
* Gets the Seeker UDP port (unsecure port).
*
* @param[in] aInstance The OpenThread instance.
*
* @returns The Seeker UDP port.
*/
uint16_t otSeekerGetUdpPort(otInstance *aInstance);
/**
* Sets the Seeker UDP port (unsecure port).
*
* This UDP port can only be changed when the Seeker is not running.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aUdpPort The Seeker UDP port.
*
* @retval OT_ERROR_NONE Successfully set the Joiner/Seeker UDP port.
* @retval OT_ERROR_INVALID_STATE The Seeker is already running.
*/
otError otSeekerSetUdpPort(otInstance *aInstance, uint16_t aUdpPort);
/**
* Selects the next best candidate and prepares the connection.
*
* This function MUST be called after the discovery scan has completed (indicated by the `otSeekerScanEvaluator`
* callback receiving `NULL`). Calling it before scan completion will result in `OT_ERROR_INVALID_STATE`.
*
* This function iterates through the discovered Joiner Router candidates in order of priority. For the selected
* candidate, it configures the radio channel and PAN ID, and populates @p aSockAddr with the candidate's address.
* It also registers the Seeker UDP port `otSeekerGetUdpPort()` as an unsecure port to allow a UDP connection to the
* candidate. The next layer code can start sending UDP messages to the given `otSockAddr` ensuring to use the unsecure
* Seeker UDP port as the source port. These messages are then forwarded by the Joiner Router onward to a
* Commissioner/Enroller connected via a Border Agent/Admitter.
*
* If the list is exhausted, this function returns `OT_ERROR_NOT_FOUND` and automatically calls `otSeekerStop()`,
* which removes the unsecure port and clears internal state.
*
* @param[out] aSockAddr A pointer to a socket address to output the candidate's address.
*
* @retval OT_ERROR_NONE Successfully set up the connection to the next candidate.
* @retval OT_ERROR_NOT_FOUND No more candidates are available (list exhausted).
* @retval OT_ERROR_INVALID_STATE The Seeker is not in a valid state (e.g. scan not yet completed).
*/
otError otSeekerSetUpNextConnection(otInstance *aInstance, otSockAddr *aSockAddr);
/**
* @}
*/
#ifdef __cplusplus
} // end of extern "C"
#endif
#endif // OPENTHREAD_SEEKER_H_
+1
View File
@@ -370,6 +370,7 @@ openthread_core_files = [
"api/radio_stats_api.cpp", "api/radio_stats_api.cpp",
"api/random_crypto_api.cpp", "api/random_crypto_api.cpp",
"api/random_noncrypto_api.cpp", "api/random_noncrypto_api.cpp",
"api/seeker_api.cpp",
"api/server_api.cpp", "api/server_api.cpp",
"api/sntp_api.cpp", "api/sntp_api.cpp",
"api/srp_client_api.cpp", "api/srp_client_api.cpp",
+1
View File
@@ -80,6 +80,7 @@ set(COMMON_SOURCES
api/radio_stats_api.cpp api/radio_stats_api.cpp
api/random_crypto_api.cpp api/random_crypto_api.cpp
api/random_noncrypto_api.cpp api/random_noncrypto_api.cpp
api/seeker_api.cpp
api/server_api.cpp api/server_api.cpp
api/sntp_api.cpp api/sntp_api.cpp
api/srp_client_api.cpp api/srp_client_api.cpp
+63
View File
@@ -0,0 +1,63 @@
/*
* 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 implements the OpenThread Seeker API.
*/
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_SEEKER_ENABLE
#include "instance/instance.hpp"
using namespace ot;
otError otSeekerStart(otInstance *aInstance, otSeekerScanEvaluator aScanEvaluator, void *aContext)
{
return AsCoreType(aInstance).Get<MeshCoP::Seeker>().Start(aScanEvaluator, aContext);
}
void otSeekerStop(otInstance *aInstance) { AsCoreType(aInstance).Get<MeshCoP::Seeker>().Stop(); }
bool otSeekerIsRunning(otInstance *aInstance) { return AsCoreType(aInstance).Get<MeshCoP::Seeker>().IsRunning(); }
uint16_t otSeekerGetUdpPort(otInstance *aInstance) { return AsCoreType(aInstance).Get<MeshCoP::Seeker>().GetUdpPort(); }
otError otSeekerSetUdpPort(otInstance *aInstance, uint16_t aUdpPort)
{
return AsCoreType(aInstance).Get<MeshCoP::Seeker>().SetUdpPort(aUdpPort);
}
otError otSeekerSetUpNextConnection(otInstance *aInstance, otSockAddr *aSockAddr)
{
return AsCoreType(aInstance).Get<MeshCoP::Seeker>().SetUpNextConnection(AsCoreType(aSockAddr));
}
#endif // OPENTHREAD_CONFIG_SEEKER_ENABLE
+14
View File
@@ -73,6 +73,20 @@
#define OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE 0 #define OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE 0
#endif #endif
/**
* @def OPENTHREAD_CONFIG_SEEKER_ENABLE
*
* Define as 1 to enable Seeker functionality and `otSeeker` APIs.
*
* The Seeker is a part of the Thread MeshCoP process. It is responsible for discovering nearby Joiner Router
* candidates, prioritizing them, and iterating through the list to select the best candidate for connection.
* It also operates as a sub-system of the `Joiner`, delegating control to the next layer to enable the
* implementation of alternative and custom joining protocols.
*/
#ifndef OPENTHREAD_CONFIG_SEEKER_ENABLE
#define OPENTHREAD_CONFIG_SEEKER_ENABLE OPENTHREAD_CONFIG_JOINER_ENABLE
#endif
/** /**
* @} * @}
*/ */
+3 -1
View File
@@ -187,8 +187,10 @@ Instance::Instance(void)
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE #if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
, mTmfSecureAgent(*this) , mTmfSecureAgent(*this)
#endif #endif
#if OPENTHREAD_CONFIG_JOINER_ENABLE #if OPENTHREAD_CONFIG_SEEKER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE
, mSeeker(*this) , mSeeker(*this)
#endif
#if OPENTHREAD_CONFIG_JOINER_ENABLE
, mJoiner(*this) , mJoiner(*this)
#endif #endif
#if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE #if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE
+6 -2
View File
@@ -618,8 +618,10 @@ private:
Tmf::SecureAgent mTmfSecureAgent; Tmf::SecureAgent mTmfSecureAgent;
#endif #endif
#if OPENTHREAD_CONFIG_JOINER_ENABLE #if OPENTHREAD_CONFIG_SEEKER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE
MeshCoP::Seeker mSeeker; MeshCoP::Seeker mSeeker;
#endif
#if OPENTHREAD_CONFIG_JOINER_ENABLE
MeshCoP::Joiner mJoiner; MeshCoP::Joiner mJoiner;
#endif #endif
@@ -959,9 +961,11 @@ template <> inline PanIdQueryClient &Instance::Get(void) { return mCommissioner.
template <> inline Dnssd &Instance::Get(void) { return mDnssd; } template <> inline Dnssd &Instance::Get(void) { return mDnssd; }
#endif #endif
#if OPENTHREAD_CONFIG_JOINER_ENABLE #if OPENTHREAD_CONFIG_SEEKER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE
template <> inline MeshCoP::Seeker &Instance::Get(void) { return mSeeker; } template <> inline MeshCoP::Seeker &Instance::Get(void) { return mSeeker; }
#endif
#if OPENTHREAD_CONFIG_JOINER_ENABLE
template <> inline MeshCoP::Joiner &Instance::Get(void) { return mJoiner; } template <> inline MeshCoP::Joiner &Instance::Get(void) { return mJoiner; }
#endif #endif
+1 -1
View File
@@ -132,7 +132,7 @@ Error Joiner::Start(const char *aPskd,
// (free allocated message, stop seeker, close agent, etc). // (free allocated message, stop seeker, close agent, etc).
shouldCleanup = true; shouldCleanup = true;
SuccessOrExit(error = Get<Tmf::SecureAgent>().Bind(Seeker::kUdpPort)); SuccessOrExit(error = Get<Tmf::SecureAgent>().Bind(Get<Seeker>().GetUdpPort()));
Get<Tmf::SecureAgent>().SetConnectCallback(HandleSecureCoapClientConnect, this); Get<Tmf::SecureAgent>().SetConnectCallback(HandleSecureCoapClientConnect, this);
Get<Tmf::SecureAgent>().SetPsk(joinerPskd); Get<Tmf::SecureAgent>().SetPsk(joinerPskd);
+21 -5
View File
@@ -33,7 +33,7 @@
#include "seeker.hpp" #include "seeker.hpp"
#if OPENTHREAD_CONFIG_JOINER_ENABLE #if OPENTHREAD_CONFIG_SEEKER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE
#include "instance/instance.hpp" #include "instance/instance.hpp"
@@ -45,6 +45,7 @@ RegisterLogModule("Seeker");
Seeker::Seeker(Instance &aInstance) Seeker::Seeker(Instance &aInstance)
: InstanceLocator(aInstance) : InstanceLocator(aInstance)
, mState(kStateStopped) , mState(kStateStopped)
, mUdpPort(kDefaultUdpPort)
, mCandidateIndex(0) , mCandidateIndex(0)
{ {
} }
@@ -87,13 +88,28 @@ void Seeker::Stop(void)
case kStateDiscoverDone: case kStateDiscoverDone:
break; break;
case kStateConnecting: case kStateConnecting:
IgnoreError(Get<Ip6::Filter>().RemoveUnsecurePort(kUdpPort)); IgnoreError(Get<Ip6::Filter>().RemoveUnsecurePort(mUdpPort));
break; break;
} }
SetState(kStateStopped); SetState(kStateStopped);
} }
Error Seeker::SetUdpPort(uint16_t aUdpPort)
{
Error error = kErrorNone;
VerifyOrExit(!IsRunning(), error = kErrorInvalidState);
VerifyOrExit(aUdpPort != mUdpPort);
LogInfo("UDP port changed: %u -> %u", mUdpPort, aUdpPort);
mUdpPort = aUdpPort;
exit:
return error;
}
void Seeker::HandleDiscoverResult(ScanResult *aResult, void *aContext) void Seeker::HandleDiscoverResult(ScanResult *aResult, void *aContext)
{ {
static_cast<Seeker *>(aContext)->HandleDiscoverResult(aResult); static_cast<Seeker *>(aContext)->HandleDiscoverResult(aResult);
@@ -228,9 +244,9 @@ Error Seeker::SetUpNextConnection(Ip6::SockAddr &aSockAddr)
Get<Mac::Mac>().SetPanId(candidate->mPanId); Get<Mac::Mac>().SetPanId(candidate->mPanId);
SuccessOrExit(error = Get<Mac::Mac>().SetPanChannel(candidate->mChannel)); SuccessOrExit(error = Get<Mac::Mac>().SetPanChannel(candidate->mChannel));
if (!Get<Ip6::Filter>().IsUnsecurePort(kUdpPort)) if (!Get<Ip6::Filter>().IsUnsecurePort(mUdpPort))
{ {
SuccessOrExit(error = Get<Ip6::Filter>().AddUnsecurePort(kUdpPort)); SuccessOrExit(error = Get<Ip6::Filter>().AddUnsecurePort(mUdpPort));
} }
SetState(kStateConnecting); SetState(kStateConnecting);
@@ -246,4 +262,4 @@ exit:
} // namespace MeshCoP } // namespace MeshCoP
} // namespace ot } // namespace ot
#endif // OPENTHREAD_CONFIG_JOINER_ENABLE #endif // OPENTHREAD_CONFIG_SEEKER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE
+36 -22
View File
@@ -40,8 +40,11 @@
#include "openthread-core-config.h" #include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_JOINER_ENABLE #if OPENTHREAD_CONFIG_SEEKER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE
#include <openthread/seeker.h>
#include "common/as_core_type.hpp"
#include "common/callback.hpp" #include "common/callback.hpp"
#include "common/error.hpp" #include "common/error.hpp"
#include "common/locator.hpp" #include "common/locator.hpp"
@@ -59,30 +62,20 @@ namespace MeshCoP {
class Seeker : public InstanceLocator, private NonCopyable class Seeker : public InstanceLocator, private NonCopyable
{ {
public: public:
static constexpr uint16_t kUdpPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT; ///< The default Joiner UDP port. typedef otSeekerScanResult ScanResult; ///< Discover Scan result.
typedef Mle::DiscoverScanner::ScanResult 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.
* Represents a verdict returned from `ScanEvaluator` when evaluating a Discover Scan result. static constexpr Verdict kAcceptPreferred = OT_SEEKER_ACCEPT_PREFERRED; ///< Scan result is acceptable & preferred.
*/ static constexpr Verdict kIgnore = OT_SEEKER_IGNORE; ///< Scan result should be ignored.
enum Verdict : uint8_t
{
kAccept, ///< The scan result is acceptable.
kAcceptPreferred, ///< The scan result is acceptable and preferred.
kIgnore, ///< The scan result should be ignored.
};
/** /**
* Represents the callback function type used to evaluate a scan result or report the end of a scan. * Represents the callback function type used to evaluate a scan result or report the end of a scan.
* *
* @param[in] aContext A pointer to the callback context. * See `otSeekerScanEvaluator` for more details.
* @param[in] aResult A pointer to the scan result to evaluate, or `nullptr` to indicate scan completion.
*
* @returns The verdict for the scan result (`kAccept`, `kAcceptPreferred`, or `kIgnore`).
* If @p aResult is `nullptr` (scan complete), the return value is ignored.
*/ */
typedef Verdict (*ScanEvaluator)(void *aContext, const ScanResult *aResult); typedef otSeekerScanEvaluator ScanEvaluator;
/** /**
* Initializes the `Seeker` * Initializes the `Seeker`
@@ -131,6 +124,25 @@ public:
*/ */
bool IsRunning(void) const { return GetState() != kStateStopped; } bool IsRunning(void) const { return GetState() != kStateStopped; }
/**
* Gets the Seeker UDP port.
*
* @returns The Seeker UDP port.
*/
uint16_t GetUdpPort(void) const { return mUdpPort; }
/**
* Sets the Seeker UDP port.
*
* This method can only be called when the Seeker is not running.
*
* @param[in] aUdpPort The Seeker UDP port.
*
* @retval kErrorNone Successfully set the Seeker UDP port.
* @retval kErrorInvalidState The Seeker is already running.
*/
Error SetUdpPort(uint16_t aUdpPort);
/** /**
* Selects the next best candidate and prepares the connection. * Selects the next best candidate and prepares the connection.
* *
@@ -139,8 +151,8 @@ public:
* *
* This method iterates through the discovered Joiner Router candidates in order of priority. For the selected * This method iterates through the discovered Joiner Router candidates in order of priority. For the selected
* candidate, it configures the radio channel and PAN ID, and populates @p aSockAddr with the candidate's address. * candidate, it configures the radio channel and PAN ID, and populates @p aSockAddr with the candidate's address.
* It also registers the Joiner UDP port `kUdpPort` as an unsecure port to allow UDP * It also registers the Seeker UDP port (`GetUdpPort()`) as an unsecure port to allow UDP connection to the
* connection to the candidate. * candidate.
* *
* If the list is exhausted, this method returns `kErrorNotFound` and automatically calls `Stop()`, which removes * If the list is exhausted, this method returns `kErrorNotFound` and automatically calls `Stop()`, which removes
* the unsecure port and clears internal state. * the unsecure port and clears internal state.
@@ -154,7 +166,8 @@ public:
Error SetUpNextConnection(Ip6::SockAddr &aSockAddr); Error SetUpNextConnection(Ip6::SockAddr &aSockAddr);
private: private:
static constexpr uint16_t kMaxCandidates = OPENTHREAD_CONFIG_JOINER_MAX_CANDIDATES; static constexpr uint16_t kDefaultUdpPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT;
static constexpr uint16_t kMaxCandidates = OPENTHREAD_CONFIG_JOINER_MAX_CANDIDATES;
enum State : uint8_t enum State : uint8_t
{ {
@@ -183,6 +196,7 @@ private:
static uint8_t CalculatePriority(int8_t aRssi, bool aPreferred); static uint8_t CalculatePriority(int8_t aRssi, bool aPreferred);
State mState; State mState;
uint16_t mUdpPort;
Callback<ScanEvaluator> mScanEvaluator; Callback<ScanEvaluator> mScanEvaluator;
Candidate mCandidates[kMaxCandidates]; Candidate mCandidates[kMaxCandidates];
uint16_t mCandidateIndex; uint16_t mCandidateIndex;
@@ -191,6 +205,6 @@ private:
} // namespace MeshCoP } // namespace MeshCoP
} // namespace ot } // namespace ot
#endif // OPENTHREAD_CONFIG_JOINER_ENABLE #endif // OPENTHREAD_CONFIG_SEEKER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE
#endif // OT_CORE_MESHCOP_SEEKER_HPP_ #endif // OT_CORE_MESHCOP_SEEKER_HPP_
@@ -118,6 +118,7 @@
#define OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 0 #define OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 0
#define OPENTHREAD_CONFIG_RADIO_STATS_ENABLE 0 #define OPENTHREAD_CONFIG_RADIO_STATS_ENABLE 0
#define OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE 1 #define OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE 1
#define OPENTHREAD_CONFIG_SEEKER_ENABLE 1
#define OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE 0 #define OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE 0
#define OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 1 #define OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 1
#define OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE 0 #define OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE 0
@@ -48,6 +48,10 @@
#define OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE 0 #define OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE 0
#define OPENTHREAD_CONFIG_JOINER_ENABLE 0
#define OPENTHREAD_CONFIG_SEEKER_ENABLE 1
#define OPENTHREAD_CONFIG_TREL_MANAGE_DNSSD_ENABLE 1 #define OPENTHREAD_CONFIG_TREL_MANAGE_DNSSD_ENABLE 1
#ifdef __linux__ #ifdef __linux__
@@ -71,6 +71,10 @@
#define OPENTHREAD_CONFIG_MULTICAST_DEFAULT_DNS_VERBOSE_LOGGING_STATE 0 #define OPENTHREAD_CONFIG_MULTICAST_DEFAULT_DNS_VERBOSE_LOGGING_STATE 0
#define OPENTHREAD_CONFIG_JOINER_ENABLE 1
#define OPENTHREAD_CONFIG_SEEKER_ENABLE 1
#define OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX 1 #define OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX 1
#define OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 0 #define OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 0
@@ -95,8 +95,6 @@
#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1 #define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1
#define OPENTHREAD_CONFIG_JOINER_ENABLE 1
#define OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 1 #define OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 1
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE 1 #define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE 1