mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 07:37:46 +00:00
[p2p] add initial peer-to-peer support (#11494)
This commit implements a minimum P2P which only supports sending/receiving wake-up frames and establishing P2P links between rx-on-when-idle devices.
This commit is contained in:
@@ -159,6 +159,18 @@
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @defgroup api-provisional Provisional
|
||||
* @brief
|
||||
* This module includes the OpenThread provisional APIs. These APIs are not stable and users should use them with
|
||||
* caution.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @defgroup api-provisional-link Link
|
||||
* @defgroup api-provisional-p2p Peer-to-Peer
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
* @defgroup config-nat64 NAT64
|
||||
* @defgroup config-netdata-publisher Network Data Publisher
|
||||
* @defgroup config-network-diagnostic Network Diagnostics
|
||||
* @defgroup config-p2p Peer-to-Peer
|
||||
* @defgroup config-parent-search Parent Search
|
||||
* @defgroup config-ping-sender Ping Sender
|
||||
* @defgroup config-platform Platform Specific Services
|
||||
|
||||
@@ -239,6 +239,7 @@ ot_option(OT_NETDIAG_CLIENT OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE "Network
|
||||
ot_option(OT_NETDIAG_VENDOR_INFO OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE "Allow setting vendor info at runtime")
|
||||
ot_option(OT_OPERATIONAL_DATASET_AUTO_INIT OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT "operational dataset auto init")
|
||||
ot_option(OT_OTNS OPENTHREAD_CONFIG_OTNS_ENABLE "OTNS")
|
||||
ot_option(OT_P2P OPENTHREAD_CONFIG_P2P_ENABLE "peer to peer")
|
||||
ot_option(OT_PING_SENDER OPENTHREAD_CONFIG_PING_SENDER_ENABLE "ping sender" ${OT_APP_CLI})
|
||||
ot_option(OT_PLATFORM_BOOTLOADER_MODE OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE "platform bootloader mode")
|
||||
ot_option(OT_PLATFORM_DNSSD OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE "platform dnssd")
|
||||
|
||||
@@ -111,6 +111,8 @@ source_set("openthread") {
|
||||
"platform/toolchain.h",
|
||||
"platform/trel.h",
|
||||
"platform/udp.h",
|
||||
"provisional/link.h",
|
||||
"provisional/p2p.h",
|
||||
"radio_stats.h",
|
||||
"random_crypto.h",
|
||||
"random_noncrypto.h",
|
||||
|
||||
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (531)
|
||||
#define OPENTHREAD_API_VERSION (532)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 defines the OpenThread provisional IEEE 802.15.4 Link Layer API.
|
||||
*/
|
||||
#ifndef OPENTHREAD_PROVISIONAL_LINK_H_
|
||||
#define OPENTHREAD_PROVISIONAL_LINK_H_
|
||||
|
||||
#include <openthread/link.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/**
|
||||
* @addtogroup api-provisional-link
|
||||
*
|
||||
* @brief
|
||||
* This module includes provisional functions that control link-layer configuration.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents the wake-up identifier.
|
||||
*/
|
||||
typedef uint64_t otWakeupId;
|
||||
|
||||
/**
|
||||
* Represents the wake-up request type.
|
||||
*/
|
||||
typedef enum otWakeupType
|
||||
{
|
||||
OT_WAKEUP_TYPE_EXT_ADDRESS = 0, ///< Wake up the peer by the extended address.
|
||||
OT_WAKEUP_TYPE_IDENTIFIER = 1, ///< Wake up the peer by the wake-up identifier.
|
||||
OT_WAKEUP_TYPE_GROUP_IDENTIFIER = 2, ///< Wake up peers by the group wake-up identifier.
|
||||
} otWakeupType;
|
||||
|
||||
/**
|
||||
* Represents the request to wake up the peer.
|
||||
*/
|
||||
typedef struct otWakeupRequest
|
||||
{
|
||||
union
|
||||
{
|
||||
otWakeupId mWakeupId; ///< Wake-up identifier of the Wake-up Listener.
|
||||
otExtAddress mExtAddress; ///< IEEE 802.15.4 Extended Address of the Wake-up Listener.
|
||||
} mShared;
|
||||
|
||||
otWakeupType mType; ///< Indicates the wake-up request type (`OT_WAKEUP_TYPE_*` enumeration).
|
||||
} otWakeupRequest;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_PROVISIONAL_LINK_H_
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 defines the OpenThread provisional P2P (peer-to-peer) API.
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_PROVISIONAL_P2P_H_
|
||||
#define OPENTHREAD_PROVISIONAL_P2P_H_
|
||||
|
||||
#include <openthread/error.h>
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/provisional/link.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/**
|
||||
* @addtogroup api-provisional-p2p
|
||||
*
|
||||
* @brief
|
||||
* This module includes provisional functions for the Thread P2P link.
|
||||
*
|
||||
* @note
|
||||
* The functions in this module require `OPENTHREAD_CONFIG_P2P_ENABLE=1`.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a request for establishing P2P links.
|
||||
*/
|
||||
typedef struct otP2pRequest
|
||||
{
|
||||
otWakeupRequest mWakeupRequest; ///< Wake-up request.
|
||||
} otP2pRequest;
|
||||
|
||||
/**
|
||||
* Notifies the caller that the P2P link establishment process has ended.
|
||||
*
|
||||
* @param[in] aContext A pointer to the application-specific context.
|
||||
*/
|
||||
typedef void (*otP2pLinkDoneCallback)(void *aContext);
|
||||
|
||||
/**
|
||||
* Attempts to wake up peers and establish P2P links with peers.
|
||||
*
|
||||
* If the @p aP2pRequest indicates a group wake-up, this method establishes multiple P2P links with peers.
|
||||
* Otherwise, it establishes at most one P2P link.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aP2pRequest A pointer to P2P request.
|
||||
* @param[in] aCallback A pointer to the function that is called when the P2P link establishment process ends .
|
||||
* @param[in] aContext A pointer to the callback application-specific context.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started to establish P2P links.
|
||||
* @retval OT_ERROR_BUSY Establishing a P2P link was in progress.
|
||||
* @retval OT_ERROR_INVALID_STATE Device was disabled or not fully configured.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffer space to establish a P2P link.
|
||||
*/
|
||||
otError otP2pWakeupAndLink(otInstance *aInstance,
|
||||
const otP2pRequest *aP2pRequest,
|
||||
otP2pLinkDoneCallback aCallback,
|
||||
void *aContext);
|
||||
|
||||
/**
|
||||
* Defines events of the P2P link.
|
||||
*/
|
||||
typedef enum otP2pEvent
|
||||
{
|
||||
OT_P2P_EVENT_LINKED = 0, ///< The P2P link has been established.
|
||||
OT_P2P_EVENT_UNLINKED = 1, ///< The P2P link has been torn down.
|
||||
} otP2pEvent;
|
||||
|
||||
/**
|
||||
* Callback function pointer to signal events of the P2P link.
|
||||
*
|
||||
* @param[in] aEvent The P2P link event.
|
||||
* @param[in] aExtAddress A pointer to the peer's Extended Address of the P2P link.
|
||||
* @param[in] aContext A pointer to the application-specific context.
|
||||
*/
|
||||
typedef void (*otP2pEventCallback)(otP2pEvent aEvent, const otExtAddress *aExtAddress, void *aContext);
|
||||
|
||||
/**
|
||||
* Sets the callback function to notify event changes of P2P links.
|
||||
*
|
||||
* A subsequent call to this function will replace any previously set callback.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aCallback The callback function pointer.
|
||||
* @param[in] aContext A pointer to the callback application-specific context.
|
||||
*/
|
||||
void otP2pSetEventCallback(otInstance *aInstance, otP2pEventCallback aCallback, void *aContext);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_PROVISIONAL_P2P_H_
|
||||
@@ -135,6 +135,7 @@ build_simulation()
|
||||
options+=("-DOT_LINK_METRICS_INITIATOR=ON")
|
||||
options+=("-DOT_LINK_METRICS_SUBJECT=ON")
|
||||
options+=("-DOT_LINK_METRICS_MANAGER=ON")
|
||||
options+=("-DOT_P2P=ON")
|
||||
options+=("-DOT_WAKEUP_COORDINATOR=ON")
|
||||
options+=("-DOT_WAKEUP_END_DEVICE=ON")
|
||||
fi
|
||||
@@ -194,6 +195,9 @@ build_posix()
|
||||
options+=("-DOT_LINK_METRICS_INITIATOR=ON")
|
||||
options+=("-DOT_LINK_METRICS_SUBJECT=ON")
|
||||
options+=("-DOT_LINK_METRICS_MANAGER=ON")
|
||||
options+=("-DOT_P2P=ON")
|
||||
options+=("-DOT_WAKEUP_COORDINATOR=ON")
|
||||
options+=("-DOT_WAKEUP_END_DEVICE=ON")
|
||||
fi
|
||||
|
||||
if [[ ${FULL_LOGS} == 1 ]]; then
|
||||
@@ -479,10 +483,14 @@ do_expect()
|
||||
test_patterns=(-name 'posix-*.exp' -o -name 'cli-*.exp')
|
||||
if [[ ${THREAD_VERSION} != "1.1" ]]; then
|
||||
test_patterns+=(-o -name 'v1_2-*.exp')
|
||||
test_patterns+=(-o -name 'v1_5-*.exp')
|
||||
fi
|
||||
fi
|
||||
else
|
||||
test_patterns=(-name 'cli-*.exp' -o -name 'simulation-*.exp' -o -name 'cli_non_rcp-*.exp')
|
||||
if [[ ${THREAD_VERSION} != "1.1" ]]; then
|
||||
test_patterns+=(-o -name 'v1_5-*.exp')
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $# != 0 ]]; then
|
||||
|
||||
@@ -89,6 +89,7 @@ Done
|
||||
- [networkname](#networkname)
|
||||
- [networktime](#networktime)
|
||||
- [nexthop](#nexthop)
|
||||
- [p2p](#p2p-link-extaddr-extaddr)
|
||||
- [panid](#panid)
|
||||
- [parent](#parent)
|
||||
- [parentpriority](#parentpriority)
|
||||
@@ -3113,6 +3114,17 @@ nexthop 0x8001
|
||||
Done
|
||||
```
|
||||
|
||||
### p2p link extaddr \<extaddr\>
|
||||
|
||||
Wakes up the peer identified by the extended address and establishes a peer-to-peer link with the peer.
|
||||
|
||||
`OPENTHREAD_CONFIG_P2P_ENABLE` and `OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE` are required.
|
||||
|
||||
```bash
|
||||
> p2p link extaddr dead00beef00cafe
|
||||
Done
|
||||
```
|
||||
|
||||
### panid
|
||||
|
||||
Get the IEEE 802.15.4 PAN ID value.
|
||||
|
||||
@@ -8088,6 +8088,58 @@ exit:
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE && OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
template <> otError Interpreter::Process<Cmd("p2p")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
if (aArgs[0] == "link")
|
||||
{
|
||||
otP2pRequest p2pRequest;
|
||||
|
||||
/**
|
||||
* @cli link
|
||||
* @code
|
||||
* link extaddr dead00beef00cafe
|
||||
* Done
|
||||
* @endcode
|
||||
* @cparam link extaddr @ca{extended-address}
|
||||
* @par
|
||||
* `OPENTHREAD_CONFIG_P2P_ENABLE` and `OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE` are required.
|
||||
* @par
|
||||
* Wakes up the Wake-up Listener identified by the extended address and establishes a peer-to-peer link with the
|
||||
* peer.
|
||||
*/
|
||||
if (aArgs[1] == "extaddr")
|
||||
{
|
||||
SuccessOrExit(error = aArgs[2].ParseAsHexString(p2pRequest.mWakeupRequest.mShared.mExtAddress.m8));
|
||||
p2pRequest.mWakeupRequest.mType = OT_WAKEUP_TYPE_EXT_ADDRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = otP2pWakeupAndLink(GetInstancePtr(), &p2pRequest, HandleP2pLinkedResult, this));
|
||||
error = OT_ERROR_PENDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = OT_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Interpreter::HandleP2pLinkedResult(void *aContext)
|
||||
{
|
||||
static_cast<Interpreter *>(aContext)->HandleP2pLinkedResult();
|
||||
}
|
||||
|
||||
void Interpreter::HandleP2pLinkedResult(void) { OutputResult(OT_ERROR_NONE); }
|
||||
#endif // OPENTHREAD_CONFIG_P2P_ENABLE && OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
template <> otError Interpreter::Process<Cmd("wakeup")>(Arg aArgs[])
|
||||
{
|
||||
@@ -8436,6 +8488,9 @@ otError Interpreter::ProcessCommand(Arg aArgs[])
|
||||
#endif
|
||||
#if OPENTHREAD_FTD
|
||||
CmdEntry("nexthop"),
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE && OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
CmdEntry("p2p"),
|
||||
#endif
|
||||
CmdEntry("panid"),
|
||||
CmdEntry("parent"),
|
||||
|
||||
@@ -310,6 +310,11 @@ private:
|
||||
static void HandleIp6Receive(otMessage *aMessage, void *aContext);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE && OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
static void HandleP2pLinkedResult(void *aContext);
|
||||
void HandleP2pLinkedResult(void);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
static void HandleWakeupResult(otError aError, void *aContext);
|
||||
void HandleWakeupResult(otError aError);
|
||||
|
||||
@@ -345,6 +345,7 @@ openthread_core_files = [
|
||||
"api/netdata_publisher_api.cpp",
|
||||
"api/netdiag_api.cpp",
|
||||
"api/network_time_api.cpp",
|
||||
"api/p2p_api.cpp",
|
||||
"api/ping_sender_api.cpp",
|
||||
"api/radio_stats_api.cpp",
|
||||
"api/random_crypto_api.cpp",
|
||||
@@ -671,6 +672,7 @@ openthread_core_files = [
|
||||
"thread/mle.cpp",
|
||||
"thread/mle.hpp",
|
||||
"thread/mle_ftd.cpp",
|
||||
"thread/mle_p2p.cpp",
|
||||
"thread/mle_tlvs.cpp",
|
||||
"thread/mle_tlvs.hpp",
|
||||
"thread/mle_types.cpp",
|
||||
@@ -705,6 +707,10 @@ openthread_core_files = [
|
||||
"thread/network_diagnostic_tlvs.hpp",
|
||||
"thread/panid_query_server.cpp",
|
||||
"thread/panid_query_server.hpp",
|
||||
"thread/peer.cpp",
|
||||
"thread/peer.hpp",
|
||||
"thread/peer_table.cpp",
|
||||
"thread/peer_table.hpp",
|
||||
"thread/radio_selector.cpp",
|
||||
"thread/radio_selector.hpp",
|
||||
"thread/router.cpp",
|
||||
@@ -845,6 +851,7 @@ source_set("libopenthread_core_config") {
|
||||
"config/netdata_publisher.h",
|
||||
"config/network_diagnostic.h",
|
||||
"config/openthread-core-config-check.h",
|
||||
"config/p2p.h",
|
||||
"config/parent_search.h",
|
||||
"config/ping_sender.h",
|
||||
"config/platform.h",
|
||||
|
||||
@@ -71,6 +71,7 @@ set(COMMON_SOURCES
|
||||
api/netdata_publisher_api.cpp
|
||||
api/netdiag_api.cpp
|
||||
api/network_time_api.cpp
|
||||
api/p2p_api.cpp
|
||||
api/ping_sender_api.cpp
|
||||
api/radio_stats_api.cpp
|
||||
api/random_crypto_api.cpp
|
||||
@@ -230,6 +231,7 @@ set(COMMON_SOURCES
|
||||
thread/message_framer.cpp
|
||||
thread/mle.cpp
|
||||
thread/mle_ftd.cpp
|
||||
thread/mle_p2p.cpp
|
||||
thread/mle_tlvs.cpp
|
||||
thread/mle_types.cpp
|
||||
thread/mlr_manager.cpp
|
||||
@@ -247,6 +249,8 @@ set(COMMON_SOURCES
|
||||
thread/network_diagnostic.cpp
|
||||
thread/network_diagnostic_tlvs.cpp
|
||||
thread/panid_query_server.cpp
|
||||
thread/peer.cpp
|
||||
thread/peer_table.cpp
|
||||
thread/radio_selector.cpp
|
||||
thread/router.cpp
|
||||
thread/router_table.cpp
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 Peer-to-Peer API.
|
||||
*/
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
|
||||
#include "instance/instance.hpp"
|
||||
|
||||
using namespace ot;
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
otError otP2pWakeupAndLink(otInstance *aInstance,
|
||||
const otP2pRequest *aP2pRequest,
|
||||
otP2pLinkDoneCallback aCallback,
|
||||
void *aContext)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Mle::Mle>().P2pWakeupAndLink(AsCoreType(aP2pRequest), aCallback, aContext);
|
||||
}
|
||||
#endif
|
||||
|
||||
void otP2pSetEventCallback(otInstance *aInstance, otP2pEventCallback aCallback, void *aContext)
|
||||
{
|
||||
AsCoreType(aInstance).Get<Mle::Mle>().P2pSetEventCallback(aCallback, aContext);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 compile-time configurations for the peer-to-peer (P2P).
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_P2P_H_
|
||||
#define CONFIG_P2P_H_
|
||||
|
||||
/**
|
||||
* @addtogroup config-p2p
|
||||
*
|
||||
* @brief
|
||||
* This module includes configuration variables for the peer-to-peer (P2P).
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
*
|
||||
* Define to 1 to enable the P2P feature.
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
#define OPENTHREAD_CONFIG_P2P_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_P2P_MAX_PEERS
|
||||
*
|
||||
* The maximum number of P2P peers.
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_P2P_MAX_PEERS
|
||||
#define OPENTHREAD_CONFIG_P2P_MAX_PEERS 10
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // CONFIG_P2P_H_
|
||||
@@ -89,6 +89,24 @@
|
||||
#define OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_WAKEUP_TX_INTERVAL
|
||||
*
|
||||
* The default time interval between (start of) wake-up frame transmissions in microseconds.
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_WAKEUP_TX_INTERVAL
|
||||
#define OPENTHREAD_CONFIG_WAKEUP_TX_INTERVAL 7500
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_WAKEUP_MAX_DURATION
|
||||
*
|
||||
* The default duration of time that wake-up frames are periodically transmitted in milliseconds.
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_WAKEUP_MAX_DURATION
|
||||
#define OPENTHREAD_CONFIG_WAKEUP_MAX_DURATION 1090
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_WED_LISTEN_INTERVAL
|
||||
*
|
||||
|
||||
@@ -788,6 +788,10 @@ template <> inline ChildTable &Instance::Get(void) { return mMle.mChildTable; }
|
||||
template <> inline RouterTable &Instance::Get(void) { return mMle.mRouterTable; }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
template <> inline PeerTable &Instance::Get(void) { return mMle.mP2p.mPeerTable; }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
template <> inline WakeupTxScheduler &Instance::Get(void) { return mMle.mWakeupTxScheduler; }
|
||||
#endif
|
||||
|
||||
+16
-13
@@ -2699,18 +2699,22 @@ Error Mac::HandleWakeupFrame(const RxFrame &aFrame)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
const ConnectionIe *connectionIe;
|
||||
Address srcAddress;
|
||||
WakeupInfo wakeupInfo;
|
||||
uint32_t rvTimeUs;
|
||||
uint64_t rvTimestampUs;
|
||||
uint32_t attachDelayMs;
|
||||
uint64_t radioNowUs;
|
||||
uint8_t retryInterval;
|
||||
uint8_t retryCount;
|
||||
|
||||
VerifyOrExit(mWakeupListenEnabled && aFrame.IsWakeupFrame());
|
||||
connectionIe = aFrame.GetConnectionIe();
|
||||
retryInterval = connectionIe->GetRetryInterval();
|
||||
retryCount = connectionIe->GetRetryCount();
|
||||
VerifyOrExit(retryInterval > 0 && retryCount > 0, error = kErrorInvalidArgs);
|
||||
|
||||
SuccessOrExit(error = aFrame.GetSrcAddr(srcAddress));
|
||||
VerifyOrExit(srcAddress.IsExtended(), error = kErrorDrop);
|
||||
|
||||
wakeupInfo.mExtAddress = srcAddress.GetExtended();
|
||||
connectionIe = aFrame.GetConnectionIe();
|
||||
wakeupInfo.mRetryInterval = connectionIe->GetRetryInterval();
|
||||
wakeupInfo.mRetryCount = connectionIe->GetRetryCount();
|
||||
VerifyOrExit(wakeupInfo.mRetryInterval > 0 && wakeupInfo.mRetryCount > 0, error = kErrorInvalidArgs);
|
||||
|
||||
radioNowUs = otPlatRadioGetNow(&GetInstance());
|
||||
rvTimeUs = aFrame.GetRendezvousTimeIe()->GetRendezvousTime() * kUsPerTenSymbols;
|
||||
@@ -2718,12 +2722,12 @@ Error Mac::HandleWakeupFrame(const RxFrame &aFrame)
|
||||
|
||||
if (rvTimestampUs > radioNowUs + kCslRequestAhead)
|
||||
{
|
||||
attachDelayMs = static_cast<uint32_t>(rvTimestampUs - radioNowUs - kCslRequestAhead);
|
||||
attachDelayMs = attachDelayMs / 1000;
|
||||
wakeupInfo.mAttachDelayMs = static_cast<uint32_t>(rvTimestampUs - radioNowUs - kCslRequestAhead);
|
||||
wakeupInfo.mAttachDelayMs = wakeupInfo.mAttachDelayMs / Time::kOneMsecInUsec;
|
||||
}
|
||||
else
|
||||
{
|
||||
attachDelayMs = 0;
|
||||
wakeupInfo.mAttachDelayMs = 0;
|
||||
}
|
||||
|
||||
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
@@ -2732,15 +2736,14 @@ Error Mac::HandleWakeupFrame(const RxFrame &aFrame)
|
||||
|
||||
IgnoreError(aFrame.GetFrameCounter(frameCounter));
|
||||
LogInfo("Received wake-up frame, fc:%lu, rendezvous:%luus, retries:%u/%u", ToUlong(frameCounter),
|
||||
ToUlong(rvTimeUs), retryCount, retryInterval);
|
||||
ToUlong(rvTimeUs), wakeupInfo.mRetryCount, wakeupInfo.mRetryInterval);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Stop receiving more wake up frames
|
||||
IgnoreError(SetWakeupListenEnabled(false));
|
||||
|
||||
// TODO: start MLE attach process with the WC
|
||||
OT_UNUSED_VARIABLE(attachDelayMs);
|
||||
Get<Mle::Mle>().HandleWakeupFrame(wakeupInfo);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
|
||||
@@ -404,5 +404,24 @@ bool KeyMaterial::operator==(const KeyMaterial &aOther) const
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
void WakeupRequest::SetExtAddress(const ExtAddress &aExtAddress)
|
||||
{
|
||||
SetType(kTypeExtAddress);
|
||||
aExtAddress.CopyTo(mShared.mExtAddress.m8);
|
||||
}
|
||||
|
||||
const ExtAddress &WakeupRequest::GetExtAddress(void) const { return AsCoreType(&mShared.mExtAddress); }
|
||||
|
||||
ExtAddress &WakeupRequest::GetExtAddress(void) { return AsCoreType(&mShared.mExtAddress); }
|
||||
|
||||
void WakeupRequest::SetType(Type aType) { mType = MapEnum(aType); }
|
||||
|
||||
bool WakeupRequest::IsWakeupByExtAddress(void) const { return MapEnum(mType) == kTypeExtAddress; }
|
||||
|
||||
bool WakeupRequest::IsWakeupById(void) const { return MapEnum(mType) == kTypeWakeupId; }
|
||||
|
||||
bool WakeupRequest::IsWakeupByGroupId(void) const { return MapEnum(mType) == kTypeGroupWakeupId; }
|
||||
#endif
|
||||
} // namespace Mac
|
||||
} // namespace ot
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#include <openthread/link.h>
|
||||
#include <openthread/thread.h>
|
||||
#include <openthread/provisional/link.h>
|
||||
|
||||
#include "common/as_core_type.hpp"
|
||||
#include "common/clearable.hpp"
|
||||
@@ -959,6 +960,96 @@ private:
|
||||
uint8_t mUncertainty;
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
/**
|
||||
* Represents a wake-up request.
|
||||
*/
|
||||
class WakeupRequest : public otWakeupRequest
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Represents a wake-up request type.
|
||||
*/
|
||||
enum Type : uint8_t
|
||||
{
|
||||
kTypeExtAddress = OT_WAKEUP_TYPE_EXT_ADDRESS,
|
||||
kTypeWakeupId = OT_WAKEUP_TYPE_IDENTIFIER,
|
||||
kTypeGroupWakeupId = OT_WAKEUP_TYPE_GROUP_IDENTIFIER,
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the wake-up request with an Extended Address.
|
||||
*
|
||||
* The type is also updated to indicate that the wake-up request type is `kTypeExtAddress`.
|
||||
*
|
||||
* @param[in] aExtAddress An Extended Address.
|
||||
*/
|
||||
void SetExtAddress(const ExtAddress &aExtAddress);
|
||||
|
||||
/**
|
||||
* Gets the Extended Address of the wake-up request.
|
||||
*
|
||||
* MUST be used only if the wake-up request type is `kTypeExtAddress`.
|
||||
*
|
||||
* @returns A constant reference to the Extended Address.
|
||||
*/
|
||||
const ExtAddress &GetExtAddress(void) const;
|
||||
|
||||
/**
|
||||
* Gets the Extended Address of the wake-up request.
|
||||
*
|
||||
* MUST be used only if the wake-up request type is `kTypeExtAddress`.
|
||||
*
|
||||
* @returns A reference to the Extended Address.
|
||||
*/
|
||||
ExtAddress &GetExtAddress(void);
|
||||
|
||||
/**
|
||||
* Sets the wake-up request type.
|
||||
*
|
||||
* @param[in] aType The wake-up request type.
|
||||
*/
|
||||
void SetType(Type aType);
|
||||
|
||||
/**
|
||||
* Indicates whether the peer is set to be woken up by the extended address.
|
||||
*
|
||||
* @retval TRUE If the peer is set to be woken up by the extended address.
|
||||
* @retval FALSE If the peer is not not set to be woken up by the extended address.
|
||||
*/
|
||||
bool IsWakeupByExtAddress(void) const;
|
||||
|
||||
/**
|
||||
* Indicates whether the peer is set to be woken up by the wake-up identifier.
|
||||
*
|
||||
* @retval TRUE If the peer is set to be woken up by the wake-up identifier.
|
||||
* @retval FALSE If the peer is not set to be woken up by the wake-up identifier.
|
||||
*/
|
||||
bool IsWakeupById(void) const;
|
||||
|
||||
/**
|
||||
* Indicates whether the peer is set to be woken up by the group wake-up identifier.
|
||||
*
|
||||
* @retval TRUE If the peer is set to be woken up by the group wake-up identifier.
|
||||
* @retval FALSE If the peer is not set to be woken up by the group wake-up identifier.
|
||||
*/
|
||||
bool IsWakeupByGroupId(void) const;
|
||||
};
|
||||
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
/**
|
||||
* Represents the information of the received wake-up frame.
|
||||
*/
|
||||
struct WakeupInfo
|
||||
{
|
||||
ExtAddress mExtAddress; ///< The extended address of the Wake-up Coordinator.
|
||||
uint32_t mAttachDelayMs; ///< The delay before linking to the peer.
|
||||
uint8_t mRetryInterval : 2; ///< The interval of the periodic connection windows.
|
||||
uint8_t mRetryCount : 4; ///< The maximum number of retries the action by the Wake-up Listener.
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@@ -967,6 +1058,10 @@ private:
|
||||
|
||||
DefineCoreType(otExtAddress, Mac::ExtAddress);
|
||||
DefineCoreType(otMacKey, Mac::Key);
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
DefineCoreType(otWakeupRequest, Mac::WakeupRequest);
|
||||
DefineMapEnum(otWakeupType, Mac::WakeupRequest::Type);
|
||||
#endif
|
||||
|
||||
} // namespace ot
|
||||
|
||||
|
||||
@@ -51,19 +51,21 @@ WakeupTxScheduler::WakeupTxScheduler(Instance &aInstance)
|
||||
UpdateFrameRequestAhead();
|
||||
}
|
||||
|
||||
Error WakeupTxScheduler::WakeUp(const Mac::ExtAddress &aWedAddress, uint16_t aIntervalUs, uint16_t aDurationMs)
|
||||
Error WakeupTxScheduler::WakeUp(const Mac::WakeupRequest &aWakeupRequest, uint16_t aIntervalUs, uint16_t aDurationMs)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(!mIsRunning, error = kErrorInvalidState);
|
||||
// TODO: Add support for wake-up identifiers.
|
||||
VerifyOrExit(aWakeupRequest.IsWakeupByExtAddress(), error = kErrorInvalidState);
|
||||
|
||||
mWedAddress = aWedAddress;
|
||||
mTxTimeUs = TimerMicro::GetNow() + mTxRequestAheadTimeUs;
|
||||
mTxEndTimeUs = mTxTimeUs + aDurationMs * Time::kOneMsecInUsec + aIntervalUs;
|
||||
mIntervalUs = aIntervalUs;
|
||||
mIsRunning = true;
|
||||
mWakeupRequest = aWakeupRequest;
|
||||
mTxTimeUs = TimerMicro::GetNow() + mTxRequestAheadTimeUs;
|
||||
mTxEndTimeUs = mTxTimeUs + aDurationMs * Time::kOneMsecInUsec + aIntervalUs;
|
||||
mIntervalUs = aIntervalUs;
|
||||
mIsRunning = true;
|
||||
|
||||
LogInfo("Started wake-up sequence to %s", aWedAddress.ToString().AsCString());
|
||||
LogInfo("Started wake-up sequence to %s", aWakeupRequest.GetExtAddress().ToString().AsCString());
|
||||
|
||||
ScheduleTimer();
|
||||
|
||||
@@ -87,7 +89,7 @@ Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
|
||||
|
||||
VerifyOrExit(mIsRunning);
|
||||
|
||||
target.SetExtended(mWedAddress);
|
||||
target.SetExtended(mWakeupRequest.GetExtAddress());
|
||||
source.SetExtended(Get<Mac::Mac>().GetExtAddress());
|
||||
VerifyOrExit(mTxTimeUs >= nowUs);
|
||||
radioTxDelay = mTxTimeUs - nowUs;
|
||||
|
||||
@@ -60,14 +60,14 @@ public:
|
||||
/**
|
||||
* Initiates the wake-up sequence to a Wake-up End Device.
|
||||
*
|
||||
* @param[in] aWedAddress The extended address of the Wake-up End Device.
|
||||
* @param[in] aIntervalUs An interval between consecutive wake-up frames (in microseconds).
|
||||
* @param[in] aDurationMs Duration of the wake-up sequence (in milliseconds).
|
||||
* @param[in] aWakeupRequest The wake-up request.
|
||||
* @param[in] aIntervalUs An interval between consecutive wake-up frames (in microseconds).
|
||||
* @param[in] aDurationMs Duration of the wake-up sequence (in milliseconds).
|
||||
*
|
||||
* @retval kErrorNone Successfully started the wake-up sequence.
|
||||
* @retval kErrorInvalidState This or another device is currently being woken-up.
|
||||
*/
|
||||
Error WakeUp(const Mac::ExtAddress &aWedAddress, uint16_t aIntervalUs, uint16_t aDurationMs);
|
||||
Error WakeUp(const Mac::WakeupRequest &aWakeupRequest, uint16_t aIntervalUs, uint16_t aDurationMs);
|
||||
|
||||
/**
|
||||
* Returns the connection window used by this device.
|
||||
@@ -99,6 +99,11 @@ public:
|
||||
*/
|
||||
void UpdateFrameRequestAhead(void);
|
||||
|
||||
/**
|
||||
* Returns the wake-up request.
|
||||
*/
|
||||
const Mac::WakeupRequest &GetWakeupRequest(void) const { return mWakeupRequest; }
|
||||
|
||||
private:
|
||||
constexpr static uint8_t kConnectionRetryInterval = OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_CONNECTION_RETRY_INTERVAL;
|
||||
constexpr static uint8_t kConnectionRetryCount = OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_CONNECTION_RETRY_COUNT;
|
||||
@@ -116,13 +121,13 @@ private:
|
||||
|
||||
using WakeupTimer = TimerMicroIn<WakeupTxScheduler, &WakeupTxScheduler::RequestWakeupFrameTransmission>;
|
||||
|
||||
Mac::ExtAddress mWedAddress;
|
||||
TimeMicro mTxTimeUs; // Point in time when the next TX occurs.
|
||||
TimeMicro mTxEndTimeUs; // Point in time when the wake-up sequence is over.
|
||||
uint32_t mTxRequestAheadTimeUs; // How much ahead the TX MAC operation needs to be requested.
|
||||
uint16_t mIntervalUs; // Interval between consecutive wake-up frames.
|
||||
WakeupTimer mTimer;
|
||||
bool mIsRunning;
|
||||
Mac::WakeupRequest mWakeupRequest;
|
||||
TimeMicro mTxTimeUs; // Point in time when the next TX occurs.
|
||||
TimeMicro mTxEndTimeUs; // Point in time when the wake-up sequence is over.
|
||||
uint32_t mTxRequestAheadTimeUs; // How much ahead the TX MAC operation needs to be requested.
|
||||
uint16_t mIntervalUs; // Interval between consecutive wake-up frames.
|
||||
WakeupTimer mTimer;
|
||||
bool mIsRunning;
|
||||
};
|
||||
|
||||
} // namespace ot
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
#include "config/nat64.h"
|
||||
#include "config/netdata_publisher.h"
|
||||
#include "config/network_diagnostic.h"
|
||||
#include "config/p2p.h"
|
||||
#include "config/parent_search.h"
|
||||
#include "config/ping_sender.h"
|
||||
#include "config/platform.h"
|
||||
|
||||
+46
-2
@@ -107,6 +107,9 @@ Mle::Mle(Instance &aInstance)
|
||||
, mChildTable(aInstance)
|
||||
, mRouterTable(aInstance)
|
||||
#endif // OPENTHREAD_FTD
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
, mP2p(aInstance)
|
||||
#endif
|
||||
{
|
||||
mParent.Init(aInstance);
|
||||
|
||||
@@ -1761,6 +1764,24 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
case kCommandP2pLinkRequest:
|
||||
mP2p.HandleP2pLinkRequest(rxInfo);
|
||||
break;
|
||||
|
||||
case kCommandP2pLinkAccept:
|
||||
mP2p.HandleP2pLinkAccept(rxInfo);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
case kCommandP2pLinkAcceptAndRequest:
|
||||
mP2p.HandleP2pLinkAcceptAndRequest(rxInfo);
|
||||
break;
|
||||
#endif
|
||||
#endif // OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
|
||||
default:
|
||||
ExitNow(error = kErrorDrop);
|
||||
}
|
||||
@@ -2869,6 +2890,11 @@ const char *Mle::MessageTypeToString(MessageType aType)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
"Time Sync", // (31) kTypeTimeSync
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
"P2P Link Request", // (32) kTypeP2pLinkRequest
|
||||
"P2P Link Accept and Request", // (33) kTypeP2pLinkAcceptAndRequest
|
||||
"P2P Link Accept", // (34) kTypeP2pLinkAccept
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -2912,6 +2938,11 @@ const char *Mle::MessageTypeToString(MessageType aType)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
ValidateNextEnum(kTypeTimeSync);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
ValidateNextEnum(kTypeP2pLinkRequest);
|
||||
ValidateNextEnum(kTypeP2pLinkAcceptAndRequest);
|
||||
ValidateNextEnum(kTypeP2pLinkAccept);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -3025,13 +3056,15 @@ Error Mle::Wakeup(const Mac::ExtAddress &aWedAddress,
|
||||
WakeupCallback aCallback,
|
||||
void *aCallbackContext)
|
||||
{
|
||||
Error error;
|
||||
Error error = kErrorNone;
|
||||
Mac::WakeupRequest wakeupRequest;
|
||||
|
||||
VerifyOrExit((aIntervalUs > 0) && (aDurationMs > 0), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aIntervalUs < aDurationMs * Time::kOneMsecInUsec, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(mWedAttachState == kWedDetached, error = kErrorInvalidState);
|
||||
|
||||
SuccessOrExit(error = mWakeupTxScheduler.WakeUp(aWedAddress, aIntervalUs, aDurationMs));
|
||||
wakeupRequest.SetExtAddress(aWedAddress);
|
||||
SuccessOrExit(error = mWakeupTxScheduler.WakeUp(wakeupRequest, aIntervalUs, aDurationMs));
|
||||
|
||||
mWedAttachState = kWedAttaching;
|
||||
mWakeupCallback.Set(aCallback, aCallbackContext);
|
||||
@@ -3045,6 +3078,17 @@ exit:
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
void Mle::HandleWakeupFrame(const Mac::WakeupInfo &aWakeupInfo)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aWakeupInfo);
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
mP2p.HandleP2pWakeup(aWakeupInfo);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// TlvList
|
||||
|
||||
|
||||
+126
-2
@@ -37,8 +37,10 @@
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <openthread/thread_ftd.h>
|
||||
#include <openthread/provisional/p2p.h>
|
||||
|
||||
#include "coap/coap_message.hpp"
|
||||
#include "common/as_core_type.hpp"
|
||||
#include "common/callback.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
#include "common/locator.hpp"
|
||||
@@ -67,6 +69,8 @@
|
||||
#include "thread/mle_types.hpp"
|
||||
#include "thread/neighbor_table.hpp"
|
||||
#include "thread/network_data_types.hpp"
|
||||
#include "thread/peer.hpp"
|
||||
#include "thread/peer_table.hpp"
|
||||
#include "thread/router.hpp"
|
||||
#include "thread/router_table.hpp"
|
||||
#include "thread/thread_tlvs.hpp"
|
||||
@@ -130,8 +134,9 @@ class Mle : public InstanceLocator, private NonCopyable
|
||||
|
||||
public:
|
||||
typedef otDetachGracefullyCallback DetachCallback; ///< Callback to signal end of graceful detach.
|
||||
|
||||
typedef otWakeupCallback WakeupCallback; ///< Callback to communicate the result of waking a Wake-up End Device
|
||||
typedef otP2pLinkDoneCallback P2pLinkDoneCallback; ///< Callback to inform the result of establishing P2P links.
|
||||
typedef otP2pEventCallback P2pEventCallback; ///< Callback to signal events of the P2P link.
|
||||
typedef otWakeupCallback WakeupCallback; ///< Callback to communicate the result of waking a Wake-up End Device
|
||||
|
||||
/**
|
||||
* Initializes the MLE object.
|
||||
@@ -1158,6 +1163,49 @@ public:
|
||||
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
/**
|
||||
* Attempts to wake up peers and establish P2P links with peers.
|
||||
*
|
||||
* If the @p aP2pRequest indicates a group identifier, this method establishes multiple P2P links with peers.
|
||||
* Otherwise, it establishes at most one P2P link.
|
||||
*
|
||||
* @param[in] aP2pRequest A constant reference to the P2P request.
|
||||
* @param[in] aCallback A pointer to the function that is called when the P2P link succeeds or fails.
|
||||
* @param[in] aContext A pointer to the callback application-specific context.
|
||||
*
|
||||
* @retval kErrorNone Successfully started to establish P2P links.
|
||||
* @retval kErrorBusy Establishing a P2P link in progress.
|
||||
* @retval kErrorInvalidState Device was disabled or not fully configured.
|
||||
* @retval kErrorNoBufs Insufficient buffer space to establish a P2P link.
|
||||
*/
|
||||
Error P2pWakeupAndLink(const P2pRequest &aP2pRequest, P2pLinkDoneCallback aCallback, void *aContext)
|
||||
{
|
||||
return mP2p.WakeupAndLink(aP2pRequest, aCallback, aContext);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets the callback function to notify event changes of P2P links.
|
||||
*
|
||||
* A subsequent call to this function will replace any previously set callback.
|
||||
*
|
||||
* @param[in] aCallback The callback function pointer.
|
||||
* @param[in] aContext A pointer to the callback application-specific context.
|
||||
*/
|
||||
void P2pSetEventCallback(P2pEventCallback aCallback, void *aContext) { mP2p.SetEventCallback(aCallback, aContext); }
|
||||
#endif // OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
/**
|
||||
* Notifies MLE that a wake-up frame was received successfully.
|
||||
*
|
||||
* @param[in] aWakeupInfo A reference to the wake-up frame information.
|
||||
*/
|
||||
void HandleWakeupFrame(const Mac::WakeupInfo &aWakeupInfo);
|
||||
#endif
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Constants
|
||||
@@ -1420,6 +1468,11 @@ private:
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
kTypeTimeSync,
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
kTypeP2pLinkRequest,
|
||||
kTypeP2pLinkAcceptAndRequest,
|
||||
kTypeP2pLinkAccept,
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -1574,7 +1627,9 @@ private:
|
||||
Mac::ExtAddress mChildExtAddress; // The child extended address.
|
||||
RxChallenge mRxChallenge; // The challenge from the Parent Request.
|
||||
};
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
struct LinkAcceptInfo
|
||||
{
|
||||
Mac::ExtAddress mExtAddress; // The neighbor/router extended address.
|
||||
@@ -1582,7 +1637,9 @@ private:
|
||||
RxChallenge mRxChallenge; // The challenge in Link Request.
|
||||
uint8_t mLinkMargin; // Link margin of the received Link Request.
|
||||
};
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
struct DiscoveryResponseInfo
|
||||
{
|
||||
Mac::PanId mPanId;
|
||||
@@ -2090,6 +2147,69 @@ private:
|
||||
uint8_t mJitter;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
void HandleP2pLinkTimer(void) { mP2p.HandleLinkTimer(); }
|
||||
|
||||
class P2p : public InstanceLocator
|
||||
{
|
||||
friend class ot::Instance;
|
||||
|
||||
public:
|
||||
P2p(Instance &aInstance);
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
Error WakeupAndLink(const P2pRequest &aP2pRequest, P2pLinkDoneCallback aCallback, void *aContext);
|
||||
void HandleP2pLinkRequest(RxInfo &aRxInfo);
|
||||
void HandleP2pLinkAccept(RxInfo &aRxInfo);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
void HandleP2pWakeup(const Mac::WakeupInfo &aWakeupInfo);
|
||||
void HandleP2pLinkAcceptAndRequest(RxInfo &aRxInfo);
|
||||
#endif
|
||||
|
||||
void SetEventCallback(P2pEventCallback aCallback, void *aContext);
|
||||
void HandleLinkTimer(void);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kWakeupMaxDuration = OPENTHREAD_CONFIG_WAKEUP_MAX_DURATION;
|
||||
static constexpr uint16_t kWakeupTxInterval = OPENTHREAD_CONFIG_WAKEUP_TX_INTERVAL;
|
||||
static constexpr uint32_t kEstablishP2pLinkTimeoutUs = 500000;
|
||||
|
||||
enum State : uint8_t
|
||||
{
|
||||
kStateIdle,
|
||||
kStateWakingUp,
|
||||
kStateWaitingLinkAccept,
|
||||
kStateAttachDelay,
|
||||
kStateWaitingLinkAcceptAndRequest,
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
void SendP2pLinkRequest(Peer *aPeer);
|
||||
Error SendP2pLinkAccept(const LinkAcceptInfo &aInfo);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
Error SendP2pLinkAcceptAndRequest(const LinkAcceptInfo &aInfo);
|
||||
#endif
|
||||
|
||||
Error SendP2pLinkAcceptVariant(const LinkAcceptInfo &aInfo, bool aIsLinkAcceptorRequest);
|
||||
void HandleP2pLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType);
|
||||
void SetWakeupListenerEnabled(void);
|
||||
void ClearPeersInLinkRequestState(void);
|
||||
|
||||
using P2pLinkTimer = TimerMicroIn<Mle, &Mle::HandleP2pLinkTimer>;
|
||||
|
||||
State mState;
|
||||
PeerTable mPeerTable;
|
||||
P2pLinkTimer mTimer;
|
||||
Callback<P2pLinkDoneCallback> mLinkedCallback;
|
||||
Callback<P2pEventCallback> mEventCallback;
|
||||
Peer *mPeer;
|
||||
};
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
@@ -2374,6 +2494,10 @@ private:
|
||||
Callback<otThreadDiscoveryRequestCallback> mDiscoveryRequestCallback;
|
||||
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
P2p mP2p;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 functionality required for the Thread peer-to-peer (P2P) link.
|
||||
*/
|
||||
|
||||
#include "mle.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
#if !(OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE)
|
||||
#error "OPENTHREAD_CONFIG_P2P_ENABLE requires OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE or "\
|
||||
"OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE"
|
||||
#endif
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "instance/instance.hpp"
|
||||
#include "openthread/platform/toolchain.h"
|
||||
|
||||
namespace ot {
|
||||
namespace Mle {
|
||||
|
||||
RegisterLogModule("P2p");
|
||||
|
||||
Mle::P2p::P2p(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mState(kStateIdle)
|
||||
, mPeerTable(aInstance)
|
||||
, mTimer(aInstance)
|
||||
, mLinkedCallback()
|
||||
, mEventCallback()
|
||||
, mPeer(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
Error Mle::P2p::WakeupAndLink(const P2pRequest &aP2pRequest, P2pLinkDoneCallback aCallback, void *aContext)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(!Get<Radio>().GetPromiscuous(), error = kErrorInvalidState);
|
||||
VerifyOrExit(Get<ThreadNetif>().IsUp(), error = kErrorInvalidState);
|
||||
VerifyOrExit(!Get<Mle>().IsDisabled(), error = kErrorInvalidState);
|
||||
VerifyOrExit(mState == kStateIdle, error = kErrorBusy);
|
||||
VerifyOrExit(!mPeerTable.IsFull(), error = kErrorNoBufs);
|
||||
|
||||
// TODO: support rx-off-when-idle device later.
|
||||
VerifyOrExit(Get<Mle>().IsRxOnWhenIdle(), error = kErrorInvalidState);
|
||||
|
||||
SuccessOrExit(
|
||||
error = Get<WakeupTxScheduler>().WakeUp(aP2pRequest.GetWakeupRequest(), kWakeupTxInterval, kWakeupMaxDuration));
|
||||
|
||||
mState = kStateWakingUp;
|
||||
mLinkedCallback.Set(aCallback, aContext);
|
||||
mTimer.FireAt(Get<WakeupTxScheduler>().GetTxEndTime() + Get<WakeupTxScheduler>().GetConnectionWindowUs());
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mle::P2p::HandleP2pLinkRequest(RxInfo &aRxInfo)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
LinkAcceptInfo info;
|
||||
DeviceMode mode;
|
||||
Peer *peer;
|
||||
uint16_t version;
|
||||
|
||||
Log(kMessageReceive, kTypeP2pLinkRequest, aRxInfo.mMessageInfo.GetPeerAddr());
|
||||
VerifyOrExit(mState == kStateWakingUp, error = kErrorInvalidState);
|
||||
VerifyOrExit(aRxInfo.mMessageInfo.GetPeerAddr().IsLinkLocalUnicast(), error = kErrorDrop);
|
||||
|
||||
info.mExtAddress.SetFromIid(aRxInfo.mMessageInfo.GetPeerAddr().GetIid());
|
||||
VerifyOrExit(Get<NeighborTable>().FindNeighbor(info.mExtAddress, Neighbor::kInStateAnyExceptInvalid) == nullptr,
|
||||
error = kErrorDrop);
|
||||
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadModeTlv(mode));
|
||||
// TODO: support the rx-off-when-idle device later.
|
||||
VerifyOrExit(mode.IsRxOnWhenIdle(), error = kErrorDrop);
|
||||
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(info.mRxChallenge));
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
|
||||
|
||||
Get<Mle>().ProcessKeySequence(aRxInfo);
|
||||
|
||||
VerifyOrExit((peer = mPeerTable.GetNewPeer()) != nullptr, error = kErrorNoBufs);
|
||||
|
||||
Get<Mle>().InitNeighbor(*peer, aRxInfo);
|
||||
peer->SetDeviceMode(mode);
|
||||
peer->SetVersion(version);
|
||||
peer->SetState(Neighbor::kStateLinkRequest);
|
||||
|
||||
SuccessOrExit(error = SendP2pLinkAcceptAndRequest(info));
|
||||
Get<WakeupTxScheduler>().Stop();
|
||||
|
||||
mState = kStateWaitingLinkAccept;
|
||||
mTimer.Start(kEstablishP2pLinkTimeoutUs);
|
||||
|
||||
exit:
|
||||
LogProcessError(kTypeP2pLinkRequest, error);
|
||||
}
|
||||
|
||||
Error Mle::P2p::SendP2pLinkAcceptAndRequest(const LinkAcceptInfo &aInfo)
|
||||
{
|
||||
return SendP2pLinkAcceptVariant(aInfo, true /* aIsLinkAcceptAndRequest*/);
|
||||
}
|
||||
|
||||
void Mle::P2p::HandleP2pLinkAccept(RxInfo &aRxInfo) { HandleP2pLinkAcceptVariant(aRxInfo, kTypeP2pLinkAccept); }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
void Mle::P2p::HandleP2pWakeup(const Mac::WakeupInfo &aWakeupInfo)
|
||||
{
|
||||
Peer *peer = nullptr;
|
||||
|
||||
VerifyOrExit(mState == kStateIdle);
|
||||
peer = mPeerTable.FindPeer(aWakeupInfo.mExtAddress, Peer::kInStateAnyExceptInvalid);
|
||||
VerifyOrExit(peer == nullptr);
|
||||
|
||||
peer = mPeerTable.GetNewPeer();
|
||||
VerifyOrExit(peer != nullptr);
|
||||
|
||||
peer->GetLinkInfo().Clear();
|
||||
peer->ResetLinkFailures();
|
||||
peer->SetLastHeard(TimerMilli::GetNow());
|
||||
peer->SetExtAddress(aWakeupInfo.mExtAddress);
|
||||
peer->SetState(Neighbor::kStateRestored);
|
||||
|
||||
mPeer = peer;
|
||||
mState = kStateAttachDelay;
|
||||
mTimer.Start(aWakeupInfo.mAttachDelayMs * Time::kOneMsecInUsec);
|
||||
|
||||
exit:
|
||||
if (peer == nullptr)
|
||||
{
|
||||
SetWakeupListenerEnabled();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Mle::P2p::SendP2pLinkRequest(Peer *aPeer)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
TxMessage *message = nullptr;
|
||||
Ip6::Address destination;
|
||||
|
||||
VerifyOrExit(aPeer != nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit((message = Get<Mle>().NewMleMessage(kCommandP2pLinkRequest)) != nullptr, error = kErrorNoBufs);
|
||||
SuccessOrExit(error = message->AppendModeTlv(Get<Mle>().GetDeviceMode()));
|
||||
SuccessOrExit(error = message->AppendVersionTlv());
|
||||
|
||||
aPeer->GenerateChallenge();
|
||||
SuccessOrExit(error = message->AppendChallengeTlv(aPeer->GetChallenge()));
|
||||
|
||||
aPeer->GetLinkLocalIp6Address(destination);
|
||||
SuccessOrExit(error = message->SendTo(destination));
|
||||
aPeer->SetState(Neighbor::kStateLinkRequest);
|
||||
|
||||
mState = kStateWaitingLinkAcceptAndRequest;
|
||||
mTimer.Start(kEstablishP2pLinkTimeoutUs);
|
||||
|
||||
Log(kMessageSend, kTypeP2pLinkRequest, destination);
|
||||
|
||||
exit:
|
||||
if (error != kErrorNone)
|
||||
{
|
||||
if (aPeer != nullptr)
|
||||
{
|
||||
aPeer->SetState(Neighbor::kStateInvalid);
|
||||
}
|
||||
mState = kStateIdle;
|
||||
SetWakeupListenerEnabled();
|
||||
}
|
||||
|
||||
FreeMessageOnError(message, error);
|
||||
}
|
||||
|
||||
void Mle::P2p::HandleP2pLinkAcceptAndRequest(RxInfo &aRxInfo)
|
||||
{
|
||||
HandleP2pLinkAcceptVariant(aRxInfo, kTypeP2pLinkAcceptAndRequest);
|
||||
}
|
||||
|
||||
Error Mle::P2p::SendP2pLinkAccept(const LinkAcceptInfo &aInfo)
|
||||
{
|
||||
return SendP2pLinkAcceptVariant(aInfo, false /* aIsLinkAcceptAndRequest*/);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
|
||||
Error Mle::P2p::SendP2pLinkAcceptVariant(const LinkAcceptInfo &aInfo, bool aIsLinkAcceptAndRequest)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Command command = aIsLinkAcceptAndRequest ? kCommandP2pLinkAcceptAndRequest : kCommandP2pLinkAccept;
|
||||
TxMessage *message = nullptr;
|
||||
Peer *peer = nullptr;
|
||||
Ip6::Address destination;
|
||||
|
||||
VerifyOrExit((message = Get<Mle>().NewMleMessage(command)) != nullptr, error = kErrorNoBufs);
|
||||
if (command == kCommandP2pLinkAcceptAndRequest)
|
||||
{
|
||||
SuccessOrExit(error = message->AppendModeTlv(Get<Mle>().GetDeviceMode()));
|
||||
SuccessOrExit(error = message->AppendVersionTlv());
|
||||
}
|
||||
|
||||
SuccessOrExit(error = message->AppendResponseTlv(aInfo.mRxChallenge));
|
||||
if (command == kCommandP2pLinkAcceptAndRequest)
|
||||
{
|
||||
VerifyOrExit((peer = mPeerTable.FindPeer(aInfo.mExtAddress, Peer::kInStateLinkRequest)) != nullptr,
|
||||
error = kErrorNotFound);
|
||||
|
||||
peer->GenerateChallenge();
|
||||
SuccessOrExit(error = message->AppendChallengeTlv(peer->GetChallenge()));
|
||||
message->SetDirectTransmission();
|
||||
}
|
||||
else
|
||||
{
|
||||
peer = mPeerTable.FindPeer(aInfo.mExtAddress, Peer::kInStateValid);
|
||||
VerifyOrExit(peer != nullptr, error = kErrorNotFound);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = message->AppendLinkMarginTlv(aInfo.mLinkMargin));
|
||||
SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs());
|
||||
|
||||
peer->GetLinkLocalIp6Address(destination);
|
||||
SuccessOrExit(error = message->SendTo(destination));
|
||||
|
||||
if (command == kCommandP2pLinkAccept)
|
||||
{
|
||||
mState = kStateIdle;
|
||||
mTimer.Stop();
|
||||
SetWakeupListenerEnabled();
|
||||
|
||||
LogInfo("P2P link to %s is established", aInfo.mExtAddress.ToString().AsCString());
|
||||
mEventCallback.InvokeIfSet(OT_P2P_EVENT_LINKED, &aInfo.mExtAddress);
|
||||
}
|
||||
|
||||
Log(kMessageSend, (command == kCommandP2pLinkAccept) ? kTypeP2pLinkAccept : kTypeP2pLinkAcceptAndRequest,
|
||||
destination);
|
||||
|
||||
exit:
|
||||
FreeMessageOnError(message, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mle::P2p::HandleP2pLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
DeviceMode mode;
|
||||
uint16_t version;
|
||||
RxChallenge response;
|
||||
uint32_t linkFrameCounter;
|
||||
uint32_t mleFrameCounter;
|
||||
Peer *peer;
|
||||
LinkAcceptInfo info;
|
||||
uint8_t linkMargin;
|
||||
|
||||
Log(kMessageReceive, aMessageType, aRxInfo.mMessageInfo.GetPeerAddr());
|
||||
|
||||
info.mExtAddress.SetFromIid(aRxInfo.mMessageInfo.GetPeerAddr().GetIid());
|
||||
VerifyOrExit((peer = mPeerTable.FindPeer(info.mExtAddress, Peer::kInStateLinkRequest)) != nullptr,
|
||||
error = kErrorNotFound);
|
||||
aRxInfo.mNeighbor = peer;
|
||||
|
||||
if (aMessageType == kTypeP2pLinkAcceptAndRequest)
|
||||
{
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadModeTlv(mode));
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
|
||||
peer->SetDeviceMode(mode);
|
||||
peer->SetVersion(version);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadResponseTlv(response));
|
||||
VerifyOrExit(response == peer->GetChallenge(), error = kErrorSecurity);
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
|
||||
SuccessOrExit(error = Tlv::Find<LinkMarginTlv>(aRxInfo.mMessage, linkMargin));
|
||||
|
||||
Get<Mle>().InitNeighbor(*peer, aRxInfo);
|
||||
|
||||
peer->SetState(Neighbor::kStateValid);
|
||||
peer->GetLinkFrameCounters().SetAll(linkFrameCounter);
|
||||
peer->SetLinkAckFrameCounter(linkFrameCounter);
|
||||
peer->SetMleFrameCounter(mleFrameCounter);
|
||||
peer->SetKeySequence(aRxInfo.mKeySequence);
|
||||
aRxInfo.mClass = RxInfo::kAuthoritativeMessage;
|
||||
|
||||
Get<Mle>().ProcessKeySequence(aRxInfo);
|
||||
|
||||
if (aMessageType == kTypeP2pLinkAcceptAndRequest)
|
||||
{
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(info.mRxChallenge));
|
||||
|
||||
info.mExtAddress = aRxInfo.mNeighbor->GetExtAddress();
|
||||
info.mLinkMargin = Get<Mac::Mac>().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss());
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
SuccessOrExit(error = SendP2pLinkAccept(info));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
LogInfo("P2P link to %s is established", peer->GetExtAddress().ToString().AsCString());
|
||||
|
||||
mEventCallback.InvokeIfSet(OT_P2P_EVENT_LINKED, &peer->GetExtAddress());
|
||||
|
||||
if (!mPeerTable.HasPeers(Peer::kInStateLinkRequest))
|
||||
{
|
||||
// All P2P links have been established.
|
||||
mState = kStateIdle;
|
||||
mTimer.Stop();
|
||||
mLinkedCallback.InvokeAndClearIfSet();
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
LogProcessError(aMessageType, error);
|
||||
}
|
||||
|
||||
void Mle::P2p::HandleLinkTimer(void)
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
case kStateWakingUp:
|
||||
case kStateWaitingLinkAccept:
|
||||
{
|
||||
if (mState == kStateWakingUp)
|
||||
{
|
||||
LogInfo("Connection window closed");
|
||||
}
|
||||
|
||||
mState = kStateIdle;
|
||||
ClearPeersInLinkRequestState();
|
||||
mLinkedCallback.InvokeAndClearIfSet();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
case kStateAttachDelay:
|
||||
SendP2pLinkRequest(mPeer);
|
||||
break;
|
||||
|
||||
case kStateWaitingLinkAcceptAndRequest:
|
||||
LogWarn("Waiting for the P2P link accept and request timeout");
|
||||
|
||||
mState = kStateIdle;
|
||||
ClearPeersInLinkRequestState();
|
||||
SetWakeupListenerEnabled();
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Mle::P2p::SetWakeupListenerEnabled(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
// The wake-up listener is disabled after a wake-up frame is received, here enables the wake-up listener again.
|
||||
IgnoreError(Get<Mac::Mac>().SetWakeupListenEnabled(true));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mle::P2p::ClearPeersInLinkRequestState(void)
|
||||
{
|
||||
for (Peer &peer : mPeerTable.Iterate(Peer::kInStateLinkRequest))
|
||||
{
|
||||
peer.SetState(Neighbor::kStateInvalid);
|
||||
}
|
||||
}
|
||||
|
||||
void Mle::P2p::SetEventCallback(otP2pEventCallback aCallback, void *aContext)
|
||||
{
|
||||
mEventCallback.Set(aCallback, aContext);
|
||||
}
|
||||
|
||||
} // namespace Mle
|
||||
} // namespace ot
|
||||
#endif // OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
@@ -39,6 +39,9 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
#include <openthread/provisional/p2p.h>
|
||||
#endif
|
||||
#include <openthread/thread.h>
|
||||
#if OPENTHREAD_FTD
|
||||
#include <openthread/thread_ftd.h>
|
||||
@@ -132,28 +135,31 @@ enum DeviceRole : uint8_t
|
||||
*/
|
||||
enum Command : uint8_t
|
||||
{
|
||||
kCommandLinkRequest = 0, ///< Link Request command
|
||||
kCommandLinkAccept = 1, ///< Link Accept command
|
||||
kCommandLinkAcceptAndRequest = 2, ///< Link Accept And Request command
|
||||
kCommandLinkReject = 3, ///< Link Reject command
|
||||
kCommandAdvertisement = 4, ///< Advertisement command
|
||||
kCommandUpdate = 5, ///< Update command
|
||||
kCommandUpdateRequest = 6, ///< Update Request command
|
||||
kCommandDataRequest = 7, ///< Data Request command
|
||||
kCommandDataResponse = 8, ///< Data Response command
|
||||
kCommandParentRequest = 9, ///< Parent Request command
|
||||
kCommandParentResponse = 10, ///< Parent Response command
|
||||
kCommandChildIdRequest = 11, ///< Child ID Request command
|
||||
kCommandChildIdResponse = 12, ///< Child ID Response command
|
||||
kCommandChildUpdateRequest = 13, ///< Child Update Request command
|
||||
kCommandChildUpdateResponse = 14, ///< Child Update Response command
|
||||
kCommandAnnounce = 15, ///< Announce command
|
||||
kCommandDiscoveryRequest = 16, ///< Discovery Request command
|
||||
kCommandDiscoveryResponse = 17, ///< Discovery Response command
|
||||
kCommandLinkMetricsManagementRequest = 18, ///< Link Metrics Management Request command
|
||||
kCommandLinkMetricsManagementResponse = 19, ///< Link Metrics Management Response command
|
||||
kCommandLinkProbe = 20, ///< Link Probe command
|
||||
kCommandTimeSync = 99, ///< Time Sync command
|
||||
kCommandLinkRequest = 0, ///< Link Request command
|
||||
kCommandLinkAccept = 1, ///< Link Accept command
|
||||
kCommandLinkAcceptAndRequest = 2, ///< Link Accept And Request command
|
||||
kCommandLinkReject = 3, ///< Link Reject command
|
||||
kCommandAdvertisement = 4, ///< Advertisement command
|
||||
kCommandUpdate = 5, ///< Update command
|
||||
kCommandUpdateRequest = 6, ///< Update Request command
|
||||
kCommandDataRequest = 7, ///< Data Request command
|
||||
kCommandDataResponse = 8, ///< Data Response command
|
||||
kCommandParentRequest = 9, ///< Parent Request command
|
||||
kCommandParentResponse = 10, ///< Parent Response command
|
||||
kCommandChildIdRequest = 11, ///< Child ID Request command
|
||||
kCommandChildIdResponse = 12, ///< Child ID Response command
|
||||
kCommandChildUpdateRequest = 13, ///< Child Update Request command
|
||||
kCommandChildUpdateResponse = 14, ///< Child Update Response command
|
||||
kCommandAnnounce = 15, ///< Announce command
|
||||
kCommandDiscoveryRequest = 16, ///< Discovery Request command
|
||||
kCommandDiscoveryResponse = 17, ///< Discovery Response command
|
||||
kCommandLinkMetricsManagementRequest = 18, ///< Link Metrics Management Request command
|
||||
kCommandLinkMetricsManagementResponse = 19, ///< Link Metrics Management Response command
|
||||
kCommandLinkProbe = 20, ///< Link Probe command
|
||||
kCommandTimeSync = 99, ///< Time Sync command
|
||||
kCommandP2pLinkRequest = 100, ///< P2P Link Request command
|
||||
kCommandP2pLinkAccept = 101, ///< P2P Link Accept command
|
||||
kCommandP2pLinkAcceptAndRequest = 102, ///< P2P Link Accept And Request command
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -838,6 +844,22 @@ inline bool IsChildRloc16(uint16_t aRloc16) { return ChildIdFromRloc16(aRloc16)
|
||||
*/
|
||||
const char *RoleToString(DeviceRole aRole);
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE && OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
/**
|
||||
* Represents a P2P request.
|
||||
*/
|
||||
class P2pRequest : public otP2pRequest
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Gets the wake-up request.
|
||||
*
|
||||
* @returns The wake-up request.
|
||||
*/
|
||||
const Mac::WakeupRequest &GetWakeupRequest(void) const { return AsCoreType(&mWakeupRequest); }
|
||||
};
|
||||
#endif // OPENTHREAD_CONFIG_P2P_ENABLE && OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@@ -850,6 +872,9 @@ DefineMapEnum(otDeviceRole, Mle::DeviceRole);
|
||||
DefineCoreType(otDeviceProperties, Mle::DeviceProperties);
|
||||
DefineMapEnum(otPowerSupply, Mle::DeviceProperties::PowerSupply);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE && OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||
DefineCoreType(otP2pRequest, Mle::P2pRequest);
|
||||
#endif
|
||||
|
||||
} // namespace ot
|
||||
|
||||
|
||||
@@ -164,6 +164,10 @@ bool Neighbor::MatchesFilter(StateFilter aFilter) const
|
||||
matches = !IsStateValidOrRestoring();
|
||||
break;
|
||||
|
||||
case kInStateLinkRequest:
|
||||
matches = IsStateLinkRequest();
|
||||
break;
|
||||
|
||||
case kInStateAny:
|
||||
matches = true;
|
||||
break;
|
||||
|
||||
@@ -108,6 +108,7 @@ public:
|
||||
kInStateAnyExceptInvalid, ///< Accept neighbor in any state except `kStateInvalid`.
|
||||
kInStateAnyExceptValidOrRestoring, ///< Accept neighbor in any state except `IsStateValidOrRestoring()`.
|
||||
kInStateAny, ///< Accept neighbor in any state.
|
||||
kInStateLinkRequest, ///< Accept neighbor only in `State::kStateLinkRequest`.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -90,6 +90,13 @@ Neighbor *NeighborTable::FindNeighbor(const Neighbor::AddressMatcher &aMatcher)
|
||||
neighbor = FindParent(aMatcher);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
if (neighbor == nullptr)
|
||||
{
|
||||
neighbor = FindPeer(aMatcher);
|
||||
}
|
||||
#endif
|
||||
|
||||
return neighbor;
|
||||
}
|
||||
|
||||
@@ -114,6 +121,13 @@ Neighbor *NeighborTable::FindNeighbor(const Mac::Address &aMacAddress, Neighbor:
|
||||
return FindNeighbor(Neighbor::AddressMatcher(aMacAddress, aFilter));
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
Neighbor *NeighborTable::FindPeer(const Neighbor::AddressMatcher &aMatcher)
|
||||
{
|
||||
return Get<PeerTable>().FindPeer(aMatcher);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
Neighbor *NeighborTable::FindChildOrRouter(const Neighbor::AddressMatcher &aMatcher)
|
||||
|
||||
@@ -152,6 +152,10 @@ public:
|
||||
Neighbor *FindNeighbor(const Mac::Address &aMacAddress,
|
||||
Neighbor::StateFilter aFilter = Neighbor::kInStateValidOrRestoring);
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
Neighbor *FindPeer(const Neighbor::AddressMatcher &aMatcher);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 a Thread P2P `Peer`.
|
||||
*/
|
||||
|
||||
#include "peer.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
|
||||
#include "instance/instance.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
void Peer::Clear(void)
|
||||
{
|
||||
Instance &instance = GetInstance();
|
||||
|
||||
ClearAllBytes(*this);
|
||||
Init(instance);
|
||||
}
|
||||
|
||||
void Peer::SetDeviceMode(Mle::DeviceMode aMode)
|
||||
{
|
||||
VerifyOrExit(aMode != GetDeviceMode());
|
||||
|
||||
Neighbor::SetDeviceMode(aMode);
|
||||
|
||||
VerifyOrExit(IsStateValid());
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 a Thread P2P `Peer`.
|
||||
*/
|
||||
|
||||
#ifndef PEER_HPP_
|
||||
#define PEER_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
|
||||
#include "thread/neighbor.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
/**
|
||||
* Represents a P2P Peer.
|
||||
*/
|
||||
class Peer : public CslNeighbor
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes the `Peer` object.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
*/
|
||||
void Init(Instance &aInstance) { Neighbor::Init(aInstance); }
|
||||
|
||||
/**
|
||||
* Clears the peer entry.
|
||||
*/
|
||||
void Clear(void);
|
||||
|
||||
/**
|
||||
* Sets the device mode flags.
|
||||
*
|
||||
* @param[in] aMode The device mode flags.
|
||||
*/
|
||||
void SetDeviceMode(Mle::DeviceMode aMode);
|
||||
|
||||
/**
|
||||
* Gets the link local IPv6 address of the peer.
|
||||
*
|
||||
* @returns The link local IPv6 address of the peer.
|
||||
*/
|
||||
void GetLinkLocalIp6Address(Ip6::Address &aIp6Address) const { aIp6Address.SetToLinkLocalAddress(GetExtAddress()); }
|
||||
|
||||
/**
|
||||
* Generates a new challenge value to use during a child attach.
|
||||
*/
|
||||
void GenerateChallenge(void) { mAttachChallenge.GenerateRandom(); }
|
||||
|
||||
/**
|
||||
* Gets the current challenge value used during attach.
|
||||
*
|
||||
* @returns The current challenge value.
|
||||
*/
|
||||
const Mle::TxChallenge &GetChallenge(void) const { return mAttachChallenge; }
|
||||
|
||||
private:
|
||||
Mle::TxChallenge mAttachChallenge;
|
||||
};
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
|
||||
#endif // PEER_HPP_
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 the Thread Peer table.
|
||||
*/
|
||||
|
||||
#include "peer_table.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
|
||||
#include "instance/instance.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
PeerTable::Iterator::Iterator(Instance &aInstance, Peer::StateFilter aFilter)
|
||||
: InstanceLocator(aInstance)
|
||||
, ItemPtrIterator(nullptr)
|
||||
, mFilter(aFilter)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void PeerTable::Iterator::Reset(void)
|
||||
{
|
||||
mItem = &Get<PeerTable>().mPeers[0];
|
||||
|
||||
if (!mItem->MatchesFilter(mFilter))
|
||||
{
|
||||
Advance();
|
||||
}
|
||||
}
|
||||
|
||||
void PeerTable::Iterator::Advance(void)
|
||||
{
|
||||
VerifyOrExit(mItem != nullptr);
|
||||
|
||||
do
|
||||
{
|
||||
mItem++;
|
||||
VerifyOrExit(mItem < &Get<PeerTable>().mPeers[Get<PeerTable>().kMaxPeers], mItem = nullptr);
|
||||
} while (!mItem->MatchesFilter(mFilter));
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
PeerTable::PeerTable(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
{
|
||||
for (Peer &peer : mPeers)
|
||||
{
|
||||
peer.Init(aInstance);
|
||||
peer.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void PeerTable::Clear(void)
|
||||
{
|
||||
for (Peer &peer : mPeers)
|
||||
{
|
||||
peer.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
Peer *PeerTable::GetNewPeer(void)
|
||||
{
|
||||
Peer *peer = FindPeer(Peer::AddressMatcher(Peer::kInStateInvalid));
|
||||
|
||||
VerifyOrExit(peer != nullptr);
|
||||
peer->Clear();
|
||||
|
||||
exit:
|
||||
return peer;
|
||||
}
|
||||
|
||||
const Peer *PeerTable::FindPeer(const Peer::AddressMatcher &aMatcher) const
|
||||
{
|
||||
const Peer *peer = mPeers;
|
||||
|
||||
for (uint16_t num = kMaxPeers; num != 0; num--, peer++)
|
||||
{
|
||||
if (peer->Matches(aMatcher))
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
peer = nullptr;
|
||||
|
||||
exit:
|
||||
return peer;
|
||||
}
|
||||
|
||||
Peer *PeerTable::FindPeer(const Mac::ExtAddress &aExtAddress, Peer::StateFilter aFilter)
|
||||
{
|
||||
return FindPeer(Peer::AddressMatcher(aExtAddress, aFilter));
|
||||
}
|
||||
|
||||
bool PeerTable::HasPeers(Peer::StateFilter aFilter) const
|
||||
{
|
||||
return (FindPeer(Peer::AddressMatcher(aFilter)) != nullptr);
|
||||
}
|
||||
|
||||
bool PeerTable::IsFull(void) const { return FindPeer(Peer::AddressMatcher(Peer::kInStateInvalid)) == nullptr; }
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 the Thread Peer table.
|
||||
*/
|
||||
|
||||
#ifndef PEER_TABLE_HPP_
|
||||
#define PEER_TABLE_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
|
||||
#include "common/const_cast.hpp"
|
||||
#include "common/iterator_utils.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/non_copyable.hpp"
|
||||
#include "thread/peer.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
/**
|
||||
* Represents the Thread Peer table.
|
||||
*/
|
||||
class PeerTable : public InstanceLocator, private NonCopyable
|
||||
{
|
||||
friend class NeighborTable;
|
||||
class IteratorBuilder;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Represents an iterator for iterating through the peer entries in the peer table.
|
||||
*/
|
||||
class Iterator : public InstanceLocator, public ItemPtrIterator<Peer, Iterator>
|
||||
{
|
||||
friend class ItemPtrIterator<Peer, Iterator>;
|
||||
friend class IteratorBuilder;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initializes an `Iterator` instance.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aFilter A peer state filter.
|
||||
*/
|
||||
Iterator(Instance &aInstance, Peer::StateFilter aFilter);
|
||||
|
||||
/**
|
||||
* Resets the iterator to start over.
|
||||
*/
|
||||
void Reset(void);
|
||||
|
||||
/**
|
||||
* Gets the `Peer` entry to which the iterator is currently pointing.
|
||||
*
|
||||
* @returns A pointer to the `Peer` entry, or `nullptr` if the iterator is done and/or empty.
|
||||
*/
|
||||
Peer *GetPeer(void) { return mItem; }
|
||||
|
||||
private:
|
||||
explicit Iterator(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mFilter(Peer::StateFilter::kInStateValid)
|
||||
{
|
||||
}
|
||||
|
||||
void Advance(void);
|
||||
|
||||
Peer::StateFilter mFilter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a `PeerTable` instance.
|
||||
*
|
||||
* @param[in] aInstance A reference to the OpenThread instance.
|
||||
*/
|
||||
explicit PeerTable(Instance &aInstance);
|
||||
|
||||
/**
|
||||
* Clears the peer table.
|
||||
*/
|
||||
void Clear(void);
|
||||
|
||||
/**
|
||||
* Gets a new/unused `Peer` entry from the peer table.
|
||||
*
|
||||
* @note The returned peer entry will be cleared (`memset` to zero).
|
||||
*
|
||||
* @returns A pointer to a new `Peer` entry, or `nullptr` if all `Peer` entries are in use.
|
||||
*/
|
||||
Peer *GetNewPeer(void);
|
||||
|
||||
/**
|
||||
* Searches the peer table for a `Peer` with a given extended address also matching a given state
|
||||
* filter.
|
||||
*
|
||||
* @param[in] aExtAddress A reference to an extended address.
|
||||
* @param[in] aFilter A peer state filter.
|
||||
*
|
||||
* @returns A pointer to the `Peer` entry if one is found, or `nullptr` otherwise.
|
||||
*/
|
||||
Peer *FindPeer(const Mac::ExtAddress &aExtAddress, Peer::StateFilter aFilter);
|
||||
|
||||
/**
|
||||
* Indicates whether the peer table contains any peer matching a given state filter.
|
||||
*
|
||||
* @param[in] aFilter A peer state filter.
|
||||
*
|
||||
* @returns TRUE if the table contains at least one peer table matching the given filter, FALSE otherwise.
|
||||
*/
|
||||
bool HasPeers(Peer::StateFilter aFilter) const;
|
||||
|
||||
/**
|
||||
* Enables range-based `for` loop iteration over all peer entries in the peer table matching a given
|
||||
* state filter.
|
||||
*
|
||||
* Should be used as follows:
|
||||
*
|
||||
* for (Peer &peer : aPeerTable.Iterate(aFilter)) { ... }
|
||||
*
|
||||
* @param[in] aFilter A peer state filter.
|
||||
*
|
||||
* @returns An IteratorBuilder instance.
|
||||
*/
|
||||
IteratorBuilder Iterate(Peer::StateFilter aFilter) { return IteratorBuilder(GetInstance(), aFilter); }
|
||||
|
||||
/**
|
||||
* Indicates whether the peer table is full.
|
||||
*
|
||||
* @returns TRUE if the table is full, FALSE otherwise.
|
||||
*/
|
||||
bool IsFull(void) const;
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kMaxPeers = OPENTHREAD_CONFIG_P2P_MAX_PEERS;
|
||||
|
||||
class IteratorBuilder : public InstanceLocator
|
||||
{
|
||||
public:
|
||||
IteratorBuilder(Instance &aInstance, Peer::StateFilter aFilter)
|
||||
: InstanceLocator(aInstance)
|
||||
, mFilter(aFilter)
|
||||
{
|
||||
}
|
||||
|
||||
Iterator begin(void) { return Iterator(GetInstance(), mFilter); }
|
||||
Iterator end(void) { return Iterator(GetInstance()); }
|
||||
|
||||
private:
|
||||
Peer::StateFilter mFilter;
|
||||
};
|
||||
|
||||
Peer *FindPeer(const Peer::AddressMatcher &aMatcher) { return AsNonConst(AsConst(this)->FindPeer(aMatcher)); }
|
||||
const Peer *FindPeer(const Peer::AddressMatcher &aMatcher) const;
|
||||
|
||||
Peer mPeers[kMaxPeers];
|
||||
};
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
|
||||
#endif // PEER_TABLE_HPP_
|
||||
Executable
+217
@@ -0,0 +1,217 @@
|
||||
#!/usr/bin/expect -f
|
||||
|
||||
#
|
||||
# Copyright (c) 2025, 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.
|
||||
#
|
||||
|
||||
source "tests/scripts/expect/_common.exp"
|
||||
source "tests/scripts/expect/_multinode.exp"
|
||||
|
||||
set WL1 1
|
||||
set WL2 2
|
||||
set WC1 3
|
||||
set WC2 4
|
||||
set WL1_EXT_ADDRESS "deadbeefcafe0001"
|
||||
set WL2_EXT_ADDRESS "deadbeefcafe0002"
|
||||
set WC1_EXT_ADDRESS "deadbeefcafe0003"
|
||||
set WC2_EXT_ADDRESS "deadbeefcafe0004"
|
||||
|
||||
|
||||
send_user "\n\n>>> Setup WL1\n"
|
||||
spawn_node $WL1
|
||||
|
||||
setup_default_network
|
||||
|
||||
send "mode rdn\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "extaddr $WL1_EXT_ADDRESS\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "wakeup channel 11\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "routerupgradethreshold 0\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "ifconfig up\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "thread start\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "wakeup listen enable\n"
|
||||
expect_line "Done"
|
||||
|
||||
set wl1_link_local_addr [get_ipaddr linklocal]
|
||||
|
||||
|
||||
send_user "\n\n>>> Setup WL2\n"
|
||||
spawn_node $WL2
|
||||
|
||||
setup_default_network
|
||||
|
||||
send "mode rdn\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "extaddr $WL2_EXT_ADDRESS\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "wakeup channel 11\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "routerupgradethreshold 0\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "ifconfig up\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "thread start\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "wakeup listen enable\n"
|
||||
expect_line "Done"
|
||||
|
||||
set wl2_link_local_addr [get_ipaddr linklocal]
|
||||
|
||||
|
||||
send_user "\n\n>>> Setup WC1\n"
|
||||
spawn_node $WC1
|
||||
setup_default_network
|
||||
|
||||
send "mode rdn\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "extaddr $WC1_EXT_ADDRESS\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "wakeup channel 11\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "routerupgradethreshold 0\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "ifconfig up\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "thread start\n"
|
||||
expect_line "Done"
|
||||
|
||||
set wc1_link_local_addr [get_ipaddr linklocal]
|
||||
|
||||
|
||||
send_user "\n\n>>> Setup WC2\n"
|
||||
spawn_node $WC2
|
||||
setup_default_network
|
||||
|
||||
send "mode rdn\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "extaddr $WC2_EXT_ADDRESS\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "wakeup channel 11\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "routerupgradethreshold 0\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "ifconfig up\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "thread start\n"
|
||||
expect_line "Done"
|
||||
|
||||
set wc2_link_local_addr [get_ipaddr linklocal]
|
||||
|
||||
|
||||
send_user "\n\n>>> WC1 establishes a P2P link with WL1\n"
|
||||
switch_node $WC1
|
||||
send "p2p link extaddr $WL1_EXT_ADDRESS\n"
|
||||
expect_line "Done"
|
||||
|
||||
send_user "\n\n>>> WC1 pings WL1\n"
|
||||
send "ping $wl1_link_local_addr 20 5\n"
|
||||
for {set i 1} {$i <= 5} {incr i} {
|
||||
expect "28 bytes from $wl1_link_local_addr: icmp_seq=$i"
|
||||
}
|
||||
|
||||
sleep 1
|
||||
|
||||
|
||||
send_user "\n\n>>> WC1 establishes a P2P link with WL2\n"
|
||||
send "p2p link extaddr $WL2_EXT_ADDRESS\n"
|
||||
expect_line "Done"
|
||||
|
||||
sleep 1
|
||||
|
||||
send_user "\n\n>>> WC1 pings WL2\n"
|
||||
send "ping $wl2_link_local_addr 20 5\n"
|
||||
for {set i 6} {$i <= 10} {incr i} {
|
||||
expect "28 bytes from $wl2_link_local_addr: icmp_seq=$i"
|
||||
}
|
||||
|
||||
|
||||
send_user "\n\n>>> WC2 establishes a P2P link with WL1\n"
|
||||
switch_node $WC2
|
||||
send "p2p link extaddr $WL1_EXT_ADDRESS\n"
|
||||
expect_line "Done"
|
||||
|
||||
sleep 1
|
||||
|
||||
send_user "\n\n>>> WC2 pings WL1\n"
|
||||
send "ping $wl1_link_local_addr 20 5\n"
|
||||
for {set i 1} {$i <= 5} {incr i} {
|
||||
expect "28 bytes from $wl1_link_local_addr: icmp_seq=$i"
|
||||
}
|
||||
|
||||
|
||||
send_user "\n\n>>> WL1 pings WC1\n"
|
||||
switch_node $WL1
|
||||
|
||||
send "ping $wc1_link_local_addr 20 5\n"
|
||||
for {set i 1} {$i <= 5} {incr i} {
|
||||
expect "28 bytes from $wc1_link_local_addr: icmp_seq=$i"
|
||||
}
|
||||
|
||||
|
||||
send_user "\n\n>>> WL1 pings WC2\n"
|
||||
send "ping $wc2_link_local_addr 20 5\n"
|
||||
for {set i 6} {$i <= 10} {incr i} {
|
||||
expect "28 bytes from $wc2_link_local_addr: icmp_seq=$i"
|
||||
}
|
||||
|
||||
|
||||
send_user "\n\n>>> WL2 pings WC1\n"
|
||||
switch_node $WL2
|
||||
|
||||
send "ping $wc1_link_local_addr 20 5\n"
|
||||
for {set i 1} {$i <= 5} {incr i} {
|
||||
expect "28 bytes from $wc1_link_local_addr: icmp_seq=$i"
|
||||
}
|
||||
|
||||
dispose_all
|
||||
@@ -108,6 +108,10 @@ static bool StateMatchesFilter(Child::State aState, Child::StateFilter aFilter)
|
||||
case Child::kInStateAny:
|
||||
rval = true;
|
||||
break;
|
||||
|
||||
case Child::kInStateLinkRequest:
|
||||
rval = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return rval;
|
||||
|
||||
Reference in New Issue
Block a user