mirror of
https://github.com/espressif/openthread.git
synced 2026-08-20 01:19:51 +00:00
[mle] add config and test for discovery request callback (#12284)
Introduces `OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE` to conditionally compile the MLE Discovery Request callback feature. Disabling this feature allows for code size reduction on builds where it is not needed. A new Nexus test (`test_discover_scan.cpp`) is added to directly validate the `otThreadSetDiscoveryRequestCallback()` API behavior. This new test replaces a now-removed CLI-based test which used (`discover reqcallback`). This CLI command was originally added for testing purposes. The CLI command is not helpful as an async event would produce unsolicited output in the CLI. The new direct C++ test is a cleaner approach.
This commit is contained in:
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (575)
|
||||
#define OPENTHREAD_API_VERSION (576)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -998,6 +998,8 @@ typedef void (*otThreadDiscoveryRequestCallback)(const otThreadDiscoveryRequestI
|
||||
/**
|
||||
* Sets a callback to receive MLE Discovery Request data.
|
||||
*
|
||||
* Requires `OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE`.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aCallback A pointer to a function that is called upon receiving an MLE Discovery Request message.
|
||||
* @param[in] aContext A pointer to callback application-specific context.
|
||||
|
||||
+3
-3
@@ -2636,7 +2636,7 @@ template <> otError Interpreter::Process<Cmd("discover")>(Arg aArgs[])
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint32_t scanChannels = 0;
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE
|
||||
/**
|
||||
* @cli discover reqcallback (enable,disable)
|
||||
* @code
|
||||
@@ -2664,7 +2664,7 @@ template <> otError Interpreter::Process<Cmd("discover")>(Arg aArgs[])
|
||||
otThreadSetDiscoveryRequestCallback(GetInstancePtr(), callback, context);
|
||||
ExitNow();
|
||||
}
|
||||
#endif // OPENTHREAD_FTD
|
||||
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE
|
||||
|
||||
if (!aArgs[0].IsEmpty())
|
||||
{
|
||||
@@ -7886,7 +7886,7 @@ void Interpreter::OutputChildTableEntry(uint8_t aIndentSize, const otNetworkDiag
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE
|
||||
void Interpreter::HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo *aInfo, void *aContext)
|
||||
{
|
||||
static_cast<Interpreter *>(aContext)->HandleDiscoveryRequest(*aInfo);
|
||||
|
||||
+1
-1
@@ -297,7 +297,7 @@ private:
|
||||
static void HandleDetachGracefullyResult(void *aContext);
|
||||
void HandleDetachGracefullyResult(void);
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE
|
||||
static void HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo *aInfo, void *aContext);
|
||||
void HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo &aInfo);
|
||||
#endif
|
||||
|
||||
@@ -320,12 +320,14 @@ void otThreadRegisterNeighborTableCallback(otInstance *aInstance, otNeighborTabl
|
||||
AsCoreType(aInstance).Get<NeighborTable>().RegisterCallback(aCallback);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE
|
||||
void otThreadSetDiscoveryRequestCallback(otInstance *aInstance,
|
||||
otThreadDiscoveryRequestCallback aCallback,
|
||||
void *aContext)
|
||||
{
|
||||
AsCoreType(aInstance).Get<Mle::Mle>().SetDiscoveryRequestCallback(aCallback, aContext);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
|
||||
|
||||
@@ -302,6 +302,16 @@
|
||||
#define OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE
|
||||
*
|
||||
* Define as 1 to support `otThreadSetDiscoveryRequestCallback()`. It allows registering a callback to be notified of
|
||||
* received MLE Discovery Requests.
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE
|
||||
#define OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
|
||||
*
|
||||
|
||||
+16
-2
@@ -1092,16 +1092,28 @@ public:
|
||||
*/
|
||||
Error GetMaxChildTimeout(uint32_t &aTimeout) const;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE
|
||||
/**
|
||||
* Callback function pointer invoked reporting a receiving a MLE Discovery Request.
|
||||
*/
|
||||
typedef otThreadDiscoveryRequestCallback DiscoveryRequestCallback;
|
||||
|
||||
/**
|
||||
* Represents info about a received Discovery Request.
|
||||
*/
|
||||
typedef otThreadDiscoveryRequestInfo DiscoveryRequestInfo;
|
||||
|
||||
/**
|
||||
* Sets the callback that is called when processing an MLE Discovery Request message.
|
||||
*
|
||||
* @param[in] aCallback A pointer to a function that is called to deliver MLE Discovery Request data.
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
*/
|
||||
void SetDiscoveryRequestCallback(otThreadDiscoveryRequestCallback aCallback, void *aContext)
|
||||
void SetDiscoveryRequestCallback(DiscoveryRequestCallback aCallback, void *aContext)
|
||||
{
|
||||
mDiscoveryRequestCallback.Set(aCallback, aContext);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Resets the MLE Advertisement Trickle timer interval.
|
||||
@@ -2523,7 +2535,9 @@ private:
|
||||
#if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
|
||||
MeshCoP::SteeringData mSteeringData;
|
||||
#endif
|
||||
Callback<otThreadDiscoveryRequestCallback> mDiscoveryRequestCallback;
|
||||
#if OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE
|
||||
Callback<DiscoveryRequestCallback> mDiscoveryRequestCallback;
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
|
||||
@@ -2749,9 +2749,10 @@ void Mle::HandleDiscoveryRequest(RxInfo &aRxInfo)
|
||||
|
||||
if (parsedDiscoveryRequestTlv)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE
|
||||
if (mDiscoveryRequestCallback.IsSet())
|
||||
{
|
||||
otThreadDiscoveryRequestInfo info;
|
||||
DiscoveryRequestInfo info;
|
||||
|
||||
AsCoreType(&info.mExtAddress).SetFromIid(aRxInfo.mMessageInfo.GetPeerAddr().GetIid());
|
||||
info.mVersion = discoveryRequestTlvValue.GetVersion();
|
||||
@@ -2759,6 +2760,7 @@ void Mle::HandleDiscoveryRequest(RxInfo &aRxInfo)
|
||||
|
||||
mDiscoveryRequestCallback.Invoke(&info);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (discoveryRequestTlvValue.GetJoinerFlag())
|
||||
{
|
||||
|
||||
@@ -116,6 +116,7 @@ endmacro()
|
||||
ot_nexus_test(5_1_1)
|
||||
ot_nexus_test(border_agent)
|
||||
ot_nexus_test(border_agent_tracker)
|
||||
ot_nexus_test(discover_scan)
|
||||
ot_nexus_test(dtls)
|
||||
ot_nexus_test(form_join)
|
||||
ot_nexus_test(full_network_reset)
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
#define OPENTHREAD_CONFIG_MESH_DIAG_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH 1
|
||||
#define OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD 10
|
||||
#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 0
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform/nexus_core.hpp"
|
||||
#include "platform/nexus_node.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Nexus {
|
||||
|
||||
struct DiscoverContext
|
||||
{
|
||||
static constexpr uint16_t kMaxResults = 16;
|
||||
|
||||
void Clear(void)
|
||||
{
|
||||
mDiscoverDone = false;
|
||||
mScanResults.Clear();
|
||||
}
|
||||
|
||||
bool mDiscoverDone;
|
||||
Array<Mle::DiscoverScanner::ScanResult, kMaxResults> mScanResults;
|
||||
};
|
||||
|
||||
struct RequestCallbackContext : public Clearable<RequestCallbackContext>
|
||||
{
|
||||
bool mInvoked;
|
||||
Mle::Mle::DiscoveryRequestInfo mInfo;
|
||||
};
|
||||
|
||||
void HandleDiscoverResult(otActiveScanResult *aResult, void *aContext)
|
||||
{
|
||||
DiscoverContext *context = static_cast<DiscoverContext *>(aContext);
|
||||
|
||||
VerifyOrQuit(aContext != nullptr);
|
||||
|
||||
Log(" HandleDiscoverResult() called%s", aResult == nullptr ? " (done)" : "");
|
||||
|
||||
if (aResult == nullptr)
|
||||
{
|
||||
context->mDiscoverDone = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrQuit(!context->mDiscoverDone);
|
||||
SuccessOrQuit(context->mScanResults.PushBack(*aResult));
|
||||
}
|
||||
}
|
||||
|
||||
void HandleDiscoverRequest(const otThreadDiscoveryRequestInfo *aInfo, void *aContext)
|
||||
{
|
||||
RequestCallbackContext *context = static_cast<RequestCallbackContext *>(aContext);
|
||||
|
||||
VerifyOrQuit(aInfo != nullptr);
|
||||
VerifyOrQuit(aContext != nullptr);
|
||||
|
||||
Log(" HandleDiscoverRequest() called");
|
||||
Log(" ExtAddress: %s", AsCoreType(&aInfo->mExtAddress).ToString().AsCString());
|
||||
Log(" Version: %u", aInfo->mVersion);
|
||||
Log(" IsJoiner: %u", aInfo->mIsJoiner);
|
||||
|
||||
VerifyOrQuit(!context->mInvoked);
|
||||
|
||||
context->mInvoked = true;
|
||||
context->mInfo = *aInfo;
|
||||
}
|
||||
|
||||
void TestDiscoverScanRequestCallback(void)
|
||||
{
|
||||
Core nexus;
|
||||
Node &leader = nexus.CreateNode();
|
||||
Node &scanner = nexus.CreateNode();
|
||||
DiscoverContext resultContext;
|
||||
RequestCallbackContext requestContext;
|
||||
Mle::DiscoverScanner::ScanResult *result;
|
||||
|
||||
Log("------------------------------------------------------------------------------------------------------");
|
||||
Log("TestDiscoverScanRequestCallback");
|
||||
|
||||
nexus.AdvanceTime(0);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Form the network");
|
||||
|
||||
leader.Form();
|
||||
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(leader.Get<Mle::Mle>().IsLeader());
|
||||
|
||||
scanner.Get<ThreadNetif>().Up();
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Register Discovery Request callback on `leader`");
|
||||
|
||||
requestContext.Clear();
|
||||
leader.Get<Mle::Mle>().SetDiscoveryRequestCallback(HandleDiscoverRequest, &requestContext);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Perform discover scan from `scanner`");
|
||||
resultContext.Clear();
|
||||
|
||||
SuccessOrQuit(scanner.Get<Mle::DiscoverScanner>().Discover(Mac::ChannelMask(0), 0xffff, /* aJoiner */ false,
|
||||
/* aFilter */ false, /* aFilterIndexes */ nullptr,
|
||||
HandleDiscoverResult, &resultContext));
|
||||
|
||||
nexus.AdvanceTime(10 * Time::kOneSecondInMsec);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check the Discovery Request callback is invoked correctly");
|
||||
|
||||
VerifyOrQuit(requestContext.mInvoked);
|
||||
VerifyOrQuit(requestContext.mInfo.mVersion == kThreadVersion);
|
||||
VerifyOrQuit(AsCoreType(&requestContext.mInfo.mExtAddress) == scanner.Get<Mac::Mac>().GetExtAddress());
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check the Discovery Result");
|
||||
|
||||
VerifyOrQuit(resultContext.mDiscoverDone);
|
||||
VerifyOrQuit(resultContext.mScanResults.GetLength() == 1);
|
||||
|
||||
result = &resultContext.mScanResults[0];
|
||||
|
||||
VerifyOrQuit(AsCoreType(&result->mExtAddress) == leader.Get<Mac::Mac>().GetExtAddress());
|
||||
VerifyOrQuit(AsCoreType(&result->mExtendedPanId) == leader.Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId());
|
||||
VerifyOrQuit(result->mPanId == leader.Get<Mac::Mac>().GetPanId());
|
||||
VerifyOrQuit(result->mChannel == leader.Get<Mac::Mac>().GetPanChannel());
|
||||
VerifyOrQuit(result->mDiscover);
|
||||
}
|
||||
|
||||
} // namespace Nexus
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::Nexus::TestDiscoverScanRequestCallback();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -114,33 +114,4 @@ if {$::env(THREAD_VERSION) != "1.1" && $::env(OT_NODE_TYPE) == "cli"} {
|
||||
wait_for "" "Done"
|
||||
}
|
||||
|
||||
switch_node 1
|
||||
send "discover reqcallback enable\n"
|
||||
expect_line "Done"
|
||||
|
||||
switch_node 5
|
||||
send "discover\n"
|
||||
expect "Error 13: InvalidState"
|
||||
send "ifconfig up\n"
|
||||
expect_line "Done"
|
||||
send "discover 12\n"
|
||||
|
||||
expect "| Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |"
|
||||
expect "+------------------+------------------+------+------------------+----+-----+-----+"
|
||||
wait_for "" "\\| OpenThread-ch12 +\\| $extpan_1 \\| $pan_1 \\| $extaddr_1 \\| 12 \\| +-?\\d+ \\| +\\d \\|"
|
||||
wait_for "" "Done"
|
||||
|
||||
switch_node 1
|
||||
expect -re {version=\d,joiner=0}
|
||||
|
||||
switch_node 5
|
||||
send "ifconfig up\n"
|
||||
expect_line "Done"
|
||||
send "joiner start 123456\n"
|
||||
set timeout 10
|
||||
expect "NotFound"
|
||||
|
||||
switch_node 1
|
||||
expect -re {version=\d,joiner=1}
|
||||
|
||||
dispose_all
|
||||
|
||||
Reference in New Issue
Block a user