mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 15:47:46 +00:00
[radio-selector] adding multi radio link support (#4440)
This commit adds support for multi radio links in OpenThread core. A set of `OPENTHREAD_CONFIG_RADIO_LINK_*` definitions (in header `config/radio_link.h`) determines the supported radio link types. This commit adds a new class `RadioSelector` which selects the radio link for each message transmission. Per neighbor it tracks the supported radio types and a preference value for each type. `RadioSelector` updates the preference value based on the history of rx/tx events with the neighbor, e.g., a successful tx on a radio link increases the preference, whereas a failed tx attempt decreases it. A new class `Mac::Links` is added defining a layer between `Mac` and different radio links (e.g., `SubMac` for 802.15.4 radio type). Broadcast frames are sent in parallel over all radio links. A unicast transmission is sent over a single radio link at a time but on a tx failure it may be retransmitted over other radio links. This commit also adds the concept of deferred ack, allowing radio links report status of ack at a later time through a different callback.
This commit is contained in:
committed by
Jonathan Hui
parent
48333ce530
commit
ffb3fdf9bd
@@ -215,6 +215,7 @@ LOCAL_SRC_FILES := \
|
||||
src/core/mac/mac.cpp \
|
||||
src/core/mac/mac_filter.cpp \
|
||||
src/core/mac/mac_frame.cpp \
|
||||
src/core/mac/mac_links.cpp \
|
||||
src/core/mac/mac_types.cpp \
|
||||
src/core/mac/sub_mac.cpp \
|
||||
src/core/mac/sub_mac_callbacks.cpp \
|
||||
@@ -250,6 +251,7 @@ LOCAL_SRC_FILES := \
|
||||
src/core/radio/radio.cpp \
|
||||
src/core/radio/radio_callbacks.cpp \
|
||||
src/core/radio/radio_platform.cpp \
|
||||
src/core/radio/trel.cpp \
|
||||
src/core/thread/address_resolver.cpp \
|
||||
src/core/thread/announce_begin_server.cpp \
|
||||
src/core/thread/announce_sender.cpp \
|
||||
@@ -278,6 +280,7 @@ LOCAL_SRC_FILES := \
|
||||
src/core/thread/network_data_notifier.cpp \
|
||||
src/core/thread/network_diagnostic.cpp \
|
||||
src/core/thread/panid_query_server.cpp \
|
||||
src/core/thread/radio_selector.cpp \
|
||||
src/core/thread/router_table.cpp \
|
||||
src/core/thread/src_match_controller.cpp \
|
||||
src/core/thread/thread_netif.cpp \
|
||||
|
||||
@@ -158,6 +158,7 @@
|
||||
* @defgroup plat-spi-slave SPI Slave
|
||||
* @defgroup plat-time Time Service
|
||||
* @defgroup plat-toolchain Toolchain
|
||||
* @defgroup plat-trel TREL
|
||||
* @defgroup plat-uart UART
|
||||
*
|
||||
* @}
|
||||
|
||||
@@ -69,6 +69,9 @@ typedef struct otThreadLinkInfo
|
||||
// Applicable/Required only when time sync feature (`OPENTHREAD_CONFIG_TIME_SYNC_ENABLE`) is enabled.
|
||||
uint8_t mTimeSyncSeq; ///< The time sync sequence.
|
||||
int64_t mNetworkTimeOffset; ///< The time offset to the Thread network time, in microseconds.
|
||||
|
||||
// Applicable only when OPENTHREAD_CONFIG_MULTI_RADIO feature is enabled.
|
||||
uint8_t mRadioType; ///< Radio link type.
|
||||
} otThreadLinkInfo;
|
||||
|
||||
/**
|
||||
|
||||
@@ -217,6 +217,8 @@ typedef struct otRadioFrame
|
||||
uint16_t mLength; ///< Length of the PSDU.
|
||||
uint8_t mChannel; ///< Channel used to transmit/receive the frame.
|
||||
|
||||
uint8_t mRadioType; ///< Radio link type - should be ignored by radio driver.
|
||||
|
||||
/**
|
||||
* The union of transmit and receive information for a radio frame.
|
||||
*/
|
||||
|
||||
@@ -423,6 +423,8 @@ openthread_core_files = [
|
||||
"mac/mac_filter.hpp",
|
||||
"mac/mac_frame.cpp",
|
||||
"mac/mac_frame.hpp",
|
||||
"mac/mac_links.cpp",
|
||||
"mac/mac_links.hpp",
|
||||
"mac/mac_types.cpp",
|
||||
"mac/mac_types.hpp",
|
||||
"mac/sub_mac.cpp",
|
||||
@@ -494,6 +496,8 @@ openthread_core_files = [
|
||||
"radio/radio.hpp",
|
||||
"radio/radio_callbacks.cpp",
|
||||
"radio/radio_platform.cpp",
|
||||
"radio/trel.cpp",
|
||||
"radio/trel.hpp",
|
||||
"thread/address_resolver.cpp",
|
||||
"thread/address_resolver.hpp",
|
||||
"thread/announce_begin_server.cpp",
|
||||
@@ -555,6 +559,8 @@ openthread_core_files = [
|
||||
"thread/network_diagnostic_tlvs.hpp",
|
||||
"thread/panid_query_server.cpp",
|
||||
"thread/panid_query_server.hpp",
|
||||
"thread/radio_selector.cpp",
|
||||
"thread/radio_selector.hpp",
|
||||
"thread/router_table.cpp",
|
||||
"thread/router_table.hpp",
|
||||
"thread/src_match_controller.cpp",
|
||||
@@ -657,6 +663,7 @@ source_set("libopenthread_core_config") {
|
||||
"config/openthread-core-default-config.h",
|
||||
"config/parent_search.h",
|
||||
"config/platform.h",
|
||||
"config/radio_link.h",
|
||||
"config/sntp_client.h",
|
||||
"config/time_sync.h",
|
||||
"config/tmf.h",
|
||||
|
||||
@@ -107,6 +107,7 @@ set(COMMON_SOURCES
|
||||
mac/mac.cpp
|
||||
mac/mac_filter.cpp
|
||||
mac/mac_frame.cpp
|
||||
mac/mac_links.cpp
|
||||
mac/mac_types.cpp
|
||||
mac/sub_mac.cpp
|
||||
mac/sub_mac_callbacks.cpp
|
||||
@@ -143,6 +144,7 @@ set(COMMON_SOURCES
|
||||
radio/radio.cpp
|
||||
radio/radio_callbacks.cpp
|
||||
radio/radio_platform.cpp
|
||||
radio/trel.cpp
|
||||
thread/address_resolver.cpp
|
||||
thread/announce_begin_server.cpp
|
||||
thread/announce_sender.cpp
|
||||
@@ -171,6 +173,7 @@ set(COMMON_SOURCES
|
||||
thread/network_data_notifier.cpp
|
||||
thread/network_diagnostic.cpp
|
||||
thread/panid_query_server.cpp
|
||||
thread/radio_selector.cpp
|
||||
thread/router_table.cpp
|
||||
thread/src_match_controller.cpp
|
||||
thread/thread_netif.cpp
|
||||
|
||||
@@ -184,6 +184,7 @@ SOURCES_COMMON = \
|
||||
mac/mac.cpp \
|
||||
mac/mac_filter.cpp \
|
||||
mac/mac_frame.cpp \
|
||||
mac/mac_links.cpp \
|
||||
mac/mac_types.cpp \
|
||||
mac/sub_mac.cpp \
|
||||
mac/sub_mac_callbacks.cpp \
|
||||
@@ -220,6 +221,7 @@ SOURCES_COMMON = \
|
||||
radio/radio.cpp \
|
||||
radio/radio_callbacks.cpp \
|
||||
radio/radio_platform.cpp \
|
||||
radio/trel.cpp \
|
||||
thread/address_resolver.cpp \
|
||||
thread/announce_begin_server.cpp \
|
||||
thread/announce_sender.cpp \
|
||||
@@ -248,6 +250,7 @@ SOURCES_COMMON = \
|
||||
thread/network_data_notifier.cpp \
|
||||
thread/network_diagnostic.cpp \
|
||||
thread/panid_query_server.cpp \
|
||||
thread/radio_selector.cpp \
|
||||
thread/router_table.cpp \
|
||||
thread/src_match_controller.cpp \
|
||||
thread/thread_netif.cpp \
|
||||
@@ -398,6 +401,7 @@ HEADERS_COMMON = \
|
||||
config/openthread-core-default-config.h \
|
||||
config/parent_search.h \
|
||||
config/platform.h \
|
||||
config/radio_link.h \
|
||||
config/sntp_client.h \
|
||||
config/time_sync.h \
|
||||
config/tmf.h \
|
||||
@@ -417,6 +421,7 @@ HEADERS_COMMON = \
|
||||
mac/mac.hpp \
|
||||
mac/mac_filter.hpp \
|
||||
mac/mac_frame.hpp \
|
||||
mac/mac_links.hpp \
|
||||
mac/mac_types.hpp \
|
||||
mac/sub_mac.hpp \
|
||||
meshcop/announce_begin_client.hpp \
|
||||
@@ -452,6 +457,7 @@ HEADERS_COMMON = \
|
||||
net/tcp.hpp \
|
||||
net/udp6.hpp \
|
||||
radio/radio.hpp \
|
||||
radio/trel.hpp \
|
||||
thread/address_resolver.hpp \
|
||||
thread/announce_begin_server.hpp \
|
||||
thread/announce_sender.hpp \
|
||||
@@ -485,6 +491,7 @@ HEADERS_COMMON = \
|
||||
thread/network_diagnostic.hpp \
|
||||
thread/network_diagnostic_tlvs.hpp \
|
||||
thread/panid_query_server.hpp \
|
||||
thread/radio_selector.hpp \
|
||||
thread/router_table.hpp \
|
||||
thread/src_match_controller.hpp \
|
||||
thread/thread_netif.hpp \
|
||||
|
||||
@@ -446,6 +446,13 @@ template <> inline MeshForwarder &Instance::Get(void)
|
||||
return mThreadNetif.mMeshForwarder;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
template <> inline RadioSelector &Instance::Get(void)
|
||||
{
|
||||
return mThreadNetif.mRadioSelector;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <> inline Mle::Mle &Instance::Get(void)
|
||||
{
|
||||
return mThreadNetif.mMleRouter;
|
||||
@@ -500,9 +507,16 @@ template <> inline Mac::Mac &Instance::Get(void)
|
||||
|
||||
template <> inline Mac::SubMac &Instance::Get(void)
|
||||
{
|
||||
return mThreadNetif.mMac.mSubMac;
|
||||
return mThreadNetif.mMac.mLinks.mSubMac;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
template <> inline Trel::Link &Instance::Get(void)
|
||||
{
|
||||
return mThreadNetif.mMac.mLinks.mTrel;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
template <> inline Mac::Filter &Instance::Get(void)
|
||||
{
|
||||
|
||||
@@ -625,6 +625,9 @@ void Message::SetLinkInfo(const ThreadLinkInfo &aLinkInfo)
|
||||
SetTimeSyncSeq(aLinkInfo.mTimeSyncSeq);
|
||||
SetNetworkTimeOffset(aLinkInfo.mNetworkTimeOffset);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
SetRadioType(static_cast<Mac::RadioType>(aLinkInfo.mRadioType));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Message::IsTimeSync(void) const
|
||||
|
||||
@@ -176,8 +176,14 @@ struct MessageMetadata
|
||||
bool mMulticastLoop : 1; ///< Indicates whether or not this multicast message may be looped back.
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
bool mTimeSync : 1; ///< Indicates whether the message is also used for time sync purpose.
|
||||
uint8_t mTimeSyncSeq; ///< The time sync sequence.
|
||||
int64_t mNetworkTimeOffset; ///< The time offset to the Thread network time, in microseconds.
|
||||
uint8_t mTimeSyncSeq; ///< The time sync sequence.
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
uint8_t mRadioType : 2; ///< The radio link type the message was received on, or should be sent on.
|
||||
bool mIsRadioTypeSet : 1; ///< Indicates whether the radio type is set.
|
||||
|
||||
static_assert(Mac::kNumRadioTypes <= (1 << 2), "mRadioType bitfield cannot store all radio type values");
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -1116,6 +1122,48 @@ public:
|
||||
uint8_t GetTimeSyncSeq(void) const { return GetMetadata().mTimeSyncSeq; }
|
||||
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
/**
|
||||
* This method indicates whether the radio type is set.
|
||||
*
|
||||
* @retval TRUE If the radio type is set.
|
||||
* @retval FALSE If the radio type is not set.
|
||||
*
|
||||
*/
|
||||
bool IsRadioTypeSet(void) const { return GetMetadata().mIsRadioTypeSet; }
|
||||
|
||||
/**
|
||||
* This method gets the radio link type the message was received on, or should be sent on.
|
||||
*
|
||||
* This method should be used only when `IsRadioTypeSet()` returns `true`.
|
||||
*
|
||||
* @returns The radio link type of the message.
|
||||
*
|
||||
*/
|
||||
Mac::RadioType GetRadioType(void) const { return static_cast<Mac::RadioType>(GetMetadata().mRadioType); }
|
||||
|
||||
/**
|
||||
* This method sets the radio link type the message was received on, or should be sent on.
|
||||
*
|
||||
* @param[in] aRadioType A radio link type of the message.
|
||||
*
|
||||
*/
|
||||
void SetRadioType(Mac::RadioType aRadioType)
|
||||
{
|
||||
GetMetadata().mIsRadioTypeSet = true;
|
||||
GetMetadata().mRadioType = aRadioType;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method clears any previously set radio type on the message.
|
||||
*
|
||||
* After calling this method, `IsRadioTypeSet()` returns false until radio type is set (`SetRadioType()`).
|
||||
*
|
||||
*/
|
||||
void ClearRadioType(void) { GetMetadata().mIsRadioTypeSet = false; }
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
private:
|
||||
/**
|
||||
* This method returns a pointer to the message pool to which this message belongs
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 radio links.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_RADIO_LINK_H_
|
||||
#define CONFIG_RADIO_LINK_H_
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
*
|
||||
* Set to 1 to enable support for IEEE802.15.4 radio link.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
#define OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
*
|
||||
* Set to 1 to enable support for Thread Radio Encapsulation Link (TREL).
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
#define OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE 0
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
#if !OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE && !OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
#error "No radio link type is enabled - at least one radio link type should be enabled"
|
||||
#endif
|
||||
|
||||
#ifdef OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
#error "OPENTHREAD_CONFIG_MULTI_RADIO should not be defined directly." \
|
||||
"It is derived from CONFIG_RADIO_LINK_<TYPE>_ENABLE options."
|
||||
#endif
|
||||
|
||||
#if (OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE && OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE)
|
||||
#define OPENTHREAD_CONFIG_MULTI_RADIO 1
|
||||
#else
|
||||
#define OPENTHREAD_CONFIG_MULTI_RADIO 0
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_RADIO_LINK_H_
|
||||
@@ -138,6 +138,10 @@ void DataPollHandler::HandleDataPoll(Mac::RxFrame &aFrame)
|
||||
|
||||
child->SetLastHeard(TimerMilli::GetNow());
|
||||
child->ResetLinkFailures();
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
child->SetLastPollRadioType(aFrame.GetRadioType());
|
||||
#endif
|
||||
|
||||
indirectMsgCount = child->GetIndirectMessageCount();
|
||||
|
||||
otLogInfoMac("Rx data poll, src:0x%04x, qed_msgs:%d, rss:%d, ack-fp:%d", child->GetRloc16(), indirectMsgCount,
|
||||
@@ -167,13 +171,20 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
otError DataPollHandler::HandleFrameRequest(Mac::TxFrame &aFrame)
|
||||
Mac::TxFrame *DataPollHandler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Mac::TxFrame *frame = nullptr;
|
||||
|
||||
VerifyOrExit(mIndirectTxChild != nullptr, error = OT_ERROR_ABORT);
|
||||
VerifyOrExit(mIndirectTxChild != nullptr);
|
||||
|
||||
SuccessOrExit(error = mCallbacks.PrepareFrameForChild(aFrame, mFrameContext, *mIndirectTxChild));
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
frame = &aTxFrames.GetTxFrame(mIndirectTxChild->GetLastPollRadioType());
|
||||
#else
|
||||
frame = &aTxFrames.GetTxFrame();
|
||||
#endif
|
||||
|
||||
VerifyOrExit(mCallbacks.PrepareFrameForChild(*frame, mFrameContext, *mIndirectTxChild) == OT_ERROR_NONE,
|
||||
frame = nullptr);
|
||||
|
||||
if (mIndirectTxChild->GetIndirectTxAttempts() > 0)
|
||||
{
|
||||
@@ -181,22 +192,22 @@ otError DataPollHandler::HandleFrameRequest(Mac::TxFrame &aFrame)
|
||||
// child, we ensure to use the same frame counter, key id, and
|
||||
// data sequence number as the previous attempt.
|
||||
|
||||
aFrame.SetIsARetransmission(true);
|
||||
aFrame.SetSequence(mIndirectTxChild->GetIndirectDataSequenceNumber());
|
||||
frame->SetIsARetransmission(true);
|
||||
frame->SetSequence(mIndirectTxChild->GetIndirectDataSequenceNumber());
|
||||
|
||||
if (aFrame.GetSecurityEnabled())
|
||||
if (frame->GetSecurityEnabled())
|
||||
{
|
||||
aFrame.SetFrameCounter(mIndirectTxChild->GetIndirectFrameCounter());
|
||||
aFrame.SetKeyId(mIndirectTxChild->GetIndirectKeyId());
|
||||
frame->SetFrameCounter(mIndirectTxChild->GetIndirectFrameCounter());
|
||||
frame->SetKeyId(mIndirectTxChild->GetIndirectKeyId());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFrame.SetIsARetransmission(false);
|
||||
frame->SetIsARetransmission(false);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
return frame;
|
||||
}
|
||||
|
||||
void DataPollHandler::HandleSentFrame(const Mac::TxFrame &aFrame, otError aError)
|
||||
|
||||
@@ -117,6 +117,11 @@ public:
|
||||
bool IsFrameReplacePending(void) const { return mFrameReplacePending; }
|
||||
void SetFrameReplacePending(bool aReplacePending) { mFrameReplacePending = aReplacePending; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
Mac::RadioType GetLastPollRadioType(void) const { return mLastPollRadioType; }
|
||||
void SetLastPollRadioType(Mac::RadioType aRadioType) { mLastPollRadioType = aRadioType; }
|
||||
#endif
|
||||
|
||||
uint32_t mIndirectFrameCounter; // Frame counter for current indirect frame (used for retx).
|
||||
uint8_t mIndirectKeyId; // Key Id for current indirect frame (used for retx).
|
||||
uint8_t mIndirectDsn; // MAC level Data Sequence Number (DSN) for retx attempts.
|
||||
@@ -124,6 +129,9 @@ public:
|
||||
bool mDataPollPending : 1; // Indicates whether or not a Data Poll was received.
|
||||
bool mFramePurgePending : 1; // Indicates a pending purge request for the current indirect frame.
|
||||
bool mFrameReplacePending : 1; // Indicates a pending replace request for the current indirect frame.
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
Mac::RadioType mLastPollRadioType; // The radio link last data poll frame was received on.
|
||||
#endif
|
||||
|
||||
static_assert(kMaxPollTriggeredTxAttempts < (1 << 5), "mIndirectTxAttempts cannot fit max!");
|
||||
};
|
||||
@@ -163,7 +171,7 @@ public:
|
||||
* @param[out] aContext A reference to a `FrameContext` where the context for the new frame would be placed.
|
||||
* @param[in] aChild The child for which to prepare the frame.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Frame was prepared successfully
|
||||
* @retval OT_ERROR_NONE Frame was prepared successfully.
|
||||
* @retval OT_ERROR_ABORT Indirect transmission to child should be aborted (no frame for the child).
|
||||
*
|
||||
*/
|
||||
@@ -262,9 +270,9 @@ public:
|
||||
|
||||
private:
|
||||
// Callbacks from MAC
|
||||
void HandleDataPoll(Mac::RxFrame &aFrame);
|
||||
otError HandleFrameRequest(Mac::TxFrame &aFrame);
|
||||
void HandleSentFrame(const Mac::TxFrame &aFrame, otError aError);
|
||||
void HandleDataPoll(Mac::RxFrame &aFrame);
|
||||
Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);
|
||||
void HandleSentFrame(const Mac::TxFrame &aFrame, otError aError);
|
||||
|
||||
void HandleSentFrame(const Mac::TxFrame &aFrame, otError aError, Child &aChild);
|
||||
void ProcessPendingPolls(void);
|
||||
|
||||
@@ -135,7 +135,11 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
otError DataPollSender::GetPollDestinationAddress(Mac::Address &aDest, Mac::RadioType &aRadioType) const
|
||||
#else
|
||||
otError DataPollSender::GetPollDestinationAddress(Mac::Address &aDest) const
|
||||
#endif
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
const Neighbor &parent = GetParent();
|
||||
@@ -153,6 +157,10 @@ otError DataPollSender::GetPollDestinationAddress(Mac::Address &aDest) const
|
||||
aDest.SetShort(parent.GetRloc16());
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
aRadioType = Get<RadioSelector>().SelectPollFrameRadio(parent);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -130,6 +130,19 @@ public:
|
||||
*/
|
||||
uint32_t GetExternalPollPeriod(void) const { return mExternalPollPeriod; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
/**
|
||||
* This method gets the destination MAC address for a data poll frame.
|
||||
*
|
||||
* @param[out] aDest Reference to a `MAC::Address` to output the poll destination address (on success).
|
||||
* @param[out] aRadioType Reference to a `Mac::RadioType` to output the link type (on success).
|
||||
*
|
||||
* @retval OT_ERROR_NONE @p aDest and @p aRadioType were updated successfully.
|
||||
* @retval OT_ERROR_ABORT Abort the data poll transmission (not currently attached to any parent).
|
||||
*
|
||||
*/
|
||||
otError GetPollDestinationAddress(Mac::Address &aDest, Mac::RadioType &aRadioType) const;
|
||||
#else
|
||||
/**
|
||||
* This method gets the destination MAC address for a data poll frame.
|
||||
*
|
||||
@@ -140,6 +153,7 @@ public:
|
||||
*
|
||||
*/
|
||||
otError GetPollDestinationAddress(Mac::Address &aDest) const;
|
||||
#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
/**
|
||||
* This method informs the data poll sender of success/error status of a previously requested poll frame
|
||||
|
||||
+318
-121
@@ -114,12 +114,15 @@ Mac::Mac(Instance &aInstance)
|
||||
#endif
|
||||
, mActiveScanHandler(nullptr) // Initialize `mActiveScanHandler` and `mEnergyScanHandler` union
|
||||
, mScanHandlerContext(nullptr)
|
||||
, mSubMac(aInstance)
|
||||
, mLinks(aInstance)
|
||||
, mOperationTask(aInstance, Mac::HandleOperationTask, this)
|
||||
, mTimer(aInstance, Mac::HandleTimer, this)
|
||||
, mOobFrame(nullptr)
|
||||
, mKeyIdMode2FrameCounter(0)
|
||||
, mCcaSampleCount(0)
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
, mTxError(OT_ERROR_NONE)
|
||||
#endif
|
||||
{
|
||||
ExtAddress randomExtAddress;
|
||||
|
||||
@@ -130,7 +133,7 @@ Mac::Mac(Instance &aInstance)
|
||||
mExtendedPanId.Clear();
|
||||
|
||||
SetEnabled(true);
|
||||
IgnoreError(mSubMac.Enable());
|
||||
mLinks.Enable();
|
||||
|
||||
Get<KeyManager>().UpdateKeyMaterial();
|
||||
SetExtendedPanId(static_cast<const ExtendedPanId &>(sExtendedPanidInit));
|
||||
@@ -293,7 +296,7 @@ void Mac::PerformActiveScan(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
mSubMac.SetPanId(mPanId);
|
||||
mLinks.SetPanId(mPanId);
|
||||
FinishOperation();
|
||||
ReportActiveScanResult(nullptr);
|
||||
PerformNextOperation();
|
||||
@@ -330,14 +333,14 @@ void Mac::PerformEnergyScan(void)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
IgnoreError(mSubMac.Receive(mScanChannel));
|
||||
ReportEnergyScanResult(mSubMac.GetRssi());
|
||||
mLinks.Receive(mScanChannel);
|
||||
ReportEnergyScanResult(mLinks.GetRssi());
|
||||
SuccessOrExit(error = UpdateScanChannel());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = mSubMac.EnergyScan(mScanChannel, mScanDuration);
|
||||
error = mLinks.EnergyScan(mScanChannel, mScanDuration);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -407,7 +410,7 @@ void Mac::SetRxOnWhenIdle(bool aRxOnWhenIdle)
|
||||
#endif
|
||||
}
|
||||
|
||||
mSubMac.SetRxOnWhenBackoff(mRxOnWhenIdle || mPromiscuous);
|
||||
mLinks.SetRxOnWhenBackoff(mRxOnWhenIdle || mPromiscuous);
|
||||
UpdateIdleMode();
|
||||
|
||||
exit:
|
||||
@@ -544,7 +547,7 @@ otError Mac::SetDomainName(const NameData &aNameData)
|
||||
void Mac::SetPanId(PanId aPanId)
|
||||
{
|
||||
SuccessOrExit(Get<Notifier>().Update(mPanId, aPanId, kEventThreadPanIdChanged));
|
||||
mSubMac.SetPanId(mPanId);
|
||||
mLinks.SetPanId(mPanId);
|
||||
|
||||
exit:
|
||||
return;
|
||||
@@ -664,16 +667,16 @@ void Mac::UpdateIdleMode(void)
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
if (IsCslEnabled())
|
||||
{
|
||||
IgnoreError(mSubMac.CslSample(mRadioChannel));
|
||||
mLinks.CslSample(mRadioChannel);
|
||||
ExitNow();
|
||||
}
|
||||
#endif
|
||||
IgnoreError(mSubMac.Sleep());
|
||||
mLinks.Sleep();
|
||||
otLogDebgMac("Idle mode: Radio sleeping");
|
||||
}
|
||||
else
|
||||
{
|
||||
IgnoreError(mSubMac.Receive(mRadioChannel));
|
||||
mLinks.Receive(mRadioChannel);
|
||||
otLogDebgMac("Idle mode: Radio receiving on channel %d", mRadioChannel);
|
||||
}
|
||||
|
||||
@@ -877,7 +880,7 @@ void Mac::PerformNextOperation(void)
|
||||
break;
|
||||
|
||||
case kOperationWaitingForData:
|
||||
IgnoreError(mSubMac.Receive(mRadioChannel));
|
||||
mLinks.Receive(mRadioChannel);
|
||||
mTimer.Start(kDataPollTimeout);
|
||||
break;
|
||||
}
|
||||
@@ -892,14 +895,21 @@ void Mac::FinishOperation(void)
|
||||
mOperation = kOperationIdle;
|
||||
}
|
||||
|
||||
otError Mac::PrepareDataRequest(TxFrame &aFrame)
|
||||
TxFrame *Mac::PrepareDataRequest(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
TxFrame *frame = nullptr;
|
||||
Address src, dst;
|
||||
uint16_t fcf;
|
||||
|
||||
SuccessOrExit(error = Get<DataPollSender>().GetPollDestinationAddress(dst));
|
||||
VerifyOrExit(!dst.IsNone(), error = OT_ERROR_ABORT);
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
RadioType radio;
|
||||
|
||||
SuccessOrExit(Get<DataPollSender>().GetPollDestinationAddress(dst, radio));
|
||||
frame = &mLinks.GetTxFrames().GetTxFrame(radio);
|
||||
#else
|
||||
SuccessOrExit(Get<DataPollSender>().GetPollDestinationAddress(dst));
|
||||
frame = &mLinks.GetTxFrames().GetTxFrame();
|
||||
#endif
|
||||
|
||||
fcf = Frame::kFcfFrameMacCmd | Frame::kFcfPanidCompression | Frame::kFcfAckRequest | Frame::kFcfSecurityEnabled;
|
||||
UpdateFrameControlField(nullptr, /* aIsTimeSync */ false, fcf);
|
||||
@@ -915,50 +925,54 @@ otError Mac::PrepareDataRequest(TxFrame &aFrame)
|
||||
src.SetShort(GetShortAddress());
|
||||
}
|
||||
|
||||
aFrame.InitMacHeader(fcf, Frame::kKeyIdMode1 | Frame::kSecEncMic32);
|
||||
frame->InitMacHeader(fcf, Frame::kKeyIdMode1 | Frame::kSecEncMic32);
|
||||
|
||||
if (aFrame.IsDstPanIdPresent())
|
||||
if (frame->IsDstPanIdPresent())
|
||||
{
|
||||
aFrame.SetDstPanId(GetPanId());
|
||||
frame->SetDstPanId(GetPanId());
|
||||
}
|
||||
|
||||
aFrame.SetSrcAddr(src);
|
||||
aFrame.SetDstAddr(dst);
|
||||
frame->SetSrcAddr(src);
|
||||
frame->SetDstAddr(dst);
|
||||
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
|
||||
IgnoreError(AppendHeaderIe(false, aFrame));
|
||||
IgnoreError(AppendHeaderIe(false, *frame));
|
||||
#endif
|
||||
|
||||
IgnoreError(aFrame.SetCommandId(Frame::kMacCmdDataRequest));
|
||||
IgnoreError(frame->SetCommandId(Frame::kMacCmdDataRequest));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
return frame;
|
||||
}
|
||||
|
||||
void Mac::PrepareBeaconRequest(TxFrame &aFrame)
|
||||
TxFrame *Mac::PrepareBeaconRequest(void)
|
||||
{
|
||||
uint16_t fcf = Frame::kFcfFrameMacCmd | Frame::kFcfDstAddrShort | Frame::kFcfSrcAddrNone;
|
||||
TxFrame &frame = mLinks.GetTxFrames().GetBroadcastTxFrame();
|
||||
uint16_t fcf = Frame::kFcfFrameMacCmd | Frame::kFcfDstAddrShort | Frame::kFcfSrcAddrNone;
|
||||
|
||||
aFrame.InitMacHeader(fcf, Frame::kSecNone);
|
||||
aFrame.SetDstPanId(kShortAddrBroadcast);
|
||||
aFrame.SetDstAddr(kShortAddrBroadcast);
|
||||
IgnoreError(aFrame.SetCommandId(Frame::kMacCmdBeaconRequest));
|
||||
frame.InitMacHeader(fcf, Frame::kSecNone);
|
||||
frame.SetDstPanId(kShortAddrBroadcast);
|
||||
frame.SetDstAddr(kShortAddrBroadcast);
|
||||
IgnoreError(frame.SetCommandId(Frame::kMacCmdBeaconRequest));
|
||||
|
||||
otLogInfoMac("Sending Beacon Request");
|
||||
|
||||
return &frame;
|
||||
}
|
||||
|
||||
void Mac::PrepareBeacon(TxFrame &aFrame)
|
||||
TxFrame *Mac::PrepareBeacon(void)
|
||||
{
|
||||
TxFrame & frame = mLinks.GetTxFrames().GetBroadcastTxFrame();
|
||||
uint8_t beaconLength;
|
||||
uint16_t fcf;
|
||||
Beacon * beacon = nullptr;
|
||||
BeaconPayload *beaconPayload = nullptr;
|
||||
|
||||
fcf = Frame::kFcfFrameBeacon | Frame::kFcfDstAddrNone | Frame::kFcfSrcAddrExt;
|
||||
aFrame.InitMacHeader(fcf, Frame::kSecNone);
|
||||
IgnoreError(aFrame.SetSrcPanId(mPanId));
|
||||
aFrame.SetSrcAddr(GetExtAddress());
|
||||
frame.InitMacHeader(fcf, Frame::kSecNone);
|
||||
IgnoreError(frame.SetSrcPanId(mPanId));
|
||||
frame.SetSrcAddr(GetExtAddress());
|
||||
|
||||
beacon = reinterpret_cast<Beacon *>(aFrame.GetPayload());
|
||||
beacon = reinterpret_cast<Beacon *>(frame.GetPayload());
|
||||
beacon->Init();
|
||||
beaconLength = sizeof(*beacon);
|
||||
|
||||
@@ -983,9 +997,11 @@ void Mac::PrepareBeacon(TxFrame &aFrame)
|
||||
beaconLength += sizeof(*beaconPayload);
|
||||
}
|
||||
|
||||
aFrame.SetPayloadLength(beaconLength);
|
||||
frame.SetPayloadLength(beaconLength);
|
||||
|
||||
LogBeacon("Sending", *beaconPayload);
|
||||
|
||||
return &frame;
|
||||
}
|
||||
|
||||
bool Mac::ShouldSendBeacon(void) const
|
||||
@@ -1048,9 +1064,33 @@ void Mac::ProcessTransmitSecurity(TxFrame &aFrame)
|
||||
break;
|
||||
|
||||
case Frame::kKeyIdMode1:
|
||||
// For MAC Key ID Mode 1, the security frame counter update and CCM* is done at SubMac or Radio depending on
|
||||
// `OT_RADIO_CAPS_TRANSMIT_SEC`.
|
||||
|
||||
// For 15.4 radio link, the AES CCM* and frame security counter (under MAC
|
||||
// key ID mode 1) are managed by `SubMac` or `Radio` modules.
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
#if !OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
ExitNow();
|
||||
#else
|
||||
VerifyOrExit(aFrame.GetRadioType() != kRadioTypeIeee802154);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
aFrame.SetAesKey(*mLinks.GetCurrentMacKey(aFrame));
|
||||
extAddress = &GetExtAddress();
|
||||
|
||||
// If the frame is marked as a retransmission, `MeshForwarder` which
|
||||
// prepared the frame should set the frame counter and key id to the
|
||||
// same values used in the earlier transmit attempt. For a new frame (not
|
||||
// a retransmission), we get a new frame counter and key id from the key
|
||||
// manager.
|
||||
|
||||
if (!aFrame.IsARetransmission())
|
||||
{
|
||||
mLinks.SetMacFrameCounter(aFrame);
|
||||
aFrame.SetKeyId((keyManager.GetCurrentKeySequence() & 0x7f) + 1);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case Frame::kKeyIdMode2:
|
||||
@@ -1088,76 +1128,87 @@ exit:
|
||||
|
||||
void Mac::BeginTransmit(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
TxFrame &sendFrame = mSubMac.GetTransmitFrame();
|
||||
TxFrame * frame = nullptr;
|
||||
TxFrames &txFrames = mLinks.GetTxFrames();
|
||||
Address dstAddr;
|
||||
|
||||
VerifyOrExit(IsEnabled(), error = OT_ERROR_ABORT);
|
||||
sendFrame.SetIsARetransmission(false);
|
||||
sendFrame.SetIsSecurityProcessed(false);
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
sendFrame.SetTxDelay(0);
|
||||
sendFrame.SetTxDelayBaseTime(0);
|
||||
txFrames.Clear();
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mTxPendingRadioLinks.Clear();
|
||||
mTxError = OT_ERROR_ABORT;
|
||||
#endif
|
||||
sendFrame.SetCsmaCaEnabled(true); // Set to true by default, only set to `false` for CSL transmission
|
||||
|
||||
VerifyOrExit(IsEnabled());
|
||||
|
||||
switch (mOperation)
|
||||
{
|
||||
case kOperationActiveScan:
|
||||
mSubMac.SetPanId(kPanIdBroadcast);
|
||||
sendFrame.SetChannel(mScanChannel);
|
||||
PrepareBeaconRequest(sendFrame);
|
||||
sendFrame.SetSequence(0);
|
||||
sendFrame.SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
|
||||
sendFrame.SetMaxFrameRetries(mMaxFrameRetriesDirect);
|
||||
mLinks.SetPanId(kPanIdBroadcast);
|
||||
frame = PrepareBeaconRequest();
|
||||
VerifyOrExit(frame != nullptr);
|
||||
frame->SetChannel(mScanChannel);
|
||||
frame->SetSequence(0);
|
||||
frame->SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
|
||||
frame->SetMaxFrameRetries(mMaxFrameRetriesDirect);
|
||||
break;
|
||||
|
||||
case kOperationTransmitBeacon:
|
||||
sendFrame.SetChannel(mRadioChannel);
|
||||
PrepareBeacon(sendFrame);
|
||||
sendFrame.SetSequence(mBeaconSequence++);
|
||||
sendFrame.SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
|
||||
sendFrame.SetMaxFrameRetries(mMaxFrameRetriesDirect);
|
||||
frame = PrepareBeacon();
|
||||
VerifyOrExit(frame != nullptr);
|
||||
frame->SetChannel(mRadioChannel);
|
||||
frame->SetSequence(mBeaconSequence++);
|
||||
frame->SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
|
||||
frame->SetMaxFrameRetries(mMaxFrameRetriesDirect);
|
||||
break;
|
||||
|
||||
case kOperationTransmitPoll:
|
||||
sendFrame.SetChannel(mRadioChannel);
|
||||
SuccessOrExit(error = PrepareDataRequest(sendFrame));
|
||||
sendFrame.SetSequence(mDataSequence++);
|
||||
sendFrame.SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
|
||||
sendFrame.SetMaxFrameRetries(mMaxFrameRetriesDirect);
|
||||
frame = PrepareDataRequest();
|
||||
VerifyOrExit(frame != nullptr);
|
||||
frame->SetChannel(mRadioChannel);
|
||||
frame->SetSequence(mDataSequence++);
|
||||
frame->SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
|
||||
frame->SetMaxFrameRetries(mMaxFrameRetriesDirect);
|
||||
break;
|
||||
|
||||
case kOperationTransmitDataDirect:
|
||||
sendFrame.SetChannel(mRadioChannel);
|
||||
sendFrame.SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
|
||||
sendFrame.SetMaxFrameRetries(mMaxFrameRetriesDirect);
|
||||
SuccessOrExit(error = Get<MeshForwarder>().HandleFrameRequest(sendFrame));
|
||||
sendFrame.SetSequence(mDataSequence++);
|
||||
// Set channel and retry counts on all TxFrames before asking
|
||||
// the next layer (`MeshForwarder`) to prepare the frame. This
|
||||
// allows next layer to possibility change these parameters.
|
||||
txFrames.SetChannel(mRadioChannel);
|
||||
txFrames.SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect);
|
||||
txFrames.SetMaxFrameRetries(mMaxFrameRetriesDirect);
|
||||
frame = Get<MeshForwarder>().HandleFrameRequest(txFrames);
|
||||
VerifyOrExit(frame != nullptr);
|
||||
frame->SetSequence(mDataSequence++);
|
||||
break;
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
case kOperationTransmitDataIndirect:
|
||||
sendFrame.SetChannel(mRadioChannel);
|
||||
sendFrame.SetMaxCsmaBackoffs(kMaxCsmaBackoffsIndirect);
|
||||
sendFrame.SetMaxFrameRetries(mMaxFrameRetriesIndirect);
|
||||
SuccessOrExit(error = Get<DataPollHandler>().HandleFrameRequest(sendFrame));
|
||||
txFrames.SetChannel(mRadioChannel);
|
||||
txFrames.SetMaxCsmaBackoffs(kMaxCsmaBackoffsIndirect);
|
||||
txFrames.SetMaxFrameRetries(mMaxFrameRetriesIndirect);
|
||||
frame = Get<DataPollHandler>().HandleFrameRequest(txFrames);
|
||||
VerifyOrExit(frame != nullptr);
|
||||
|
||||
// If the frame is marked as a retransmission, then data sequence number is already set.
|
||||
if (!sendFrame.IsARetransmission())
|
||||
if (!frame->IsARetransmission())
|
||||
{
|
||||
sendFrame.SetSequence(mDataSequence++);
|
||||
frame->SetSequence(mDataSequence++);
|
||||
}
|
||||
break;
|
||||
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
case kOperationTransmitDataCsl:
|
||||
sendFrame.SetMaxCsmaBackoffs(kMaxCsmaBackoffsCsl);
|
||||
sendFrame.SetMaxFrameRetries(kMaxFrameRetriesCsl);
|
||||
SuccessOrExit(error = Get<CslTxScheduler>().HandleFrameRequest(sendFrame));
|
||||
txFrames.SetMaxCsmaBackoffs(kMaxCsmaBackoffsCsl);
|
||||
txFrames.SetMaxFrameRetries(kMaxFrameRetriesCsl);
|
||||
frame = Get<CslTxScheduler>().HandleFrameRequest(txFrames);
|
||||
VerifyOrExit(frame != nullptr);
|
||||
|
||||
// If the frame is marked as a retransmission, then data sequence number is already set.
|
||||
if (!sendFrame.IsARetransmission())
|
||||
if (!frame->IsARetransmission())
|
||||
{
|
||||
sendFrame.SetSequence(mDataSequence++);
|
||||
frame->SetSequence(mDataSequence++);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1166,8 +1217,9 @@ void Mac::BeginTransmit(void)
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
case kOperationTransmitOutOfBandFrame:
|
||||
sendFrame.CopyFrom(*mOobFrame);
|
||||
sendFrame.SetIsSecurityProcessed(true);
|
||||
frame = &txFrames.GetBroadcastTxFrame();
|
||||
frame->CopyFrom(*mOobFrame);
|
||||
frame->SetIsSecurityProcessed(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1177,47 +1229,94 @@ void Mac::BeginTransmit(void)
|
||||
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
{
|
||||
uint8_t timeIeOffset = GetTimeIeOffset(sendFrame);
|
||||
uint8_t timeIeOffset = GetTimeIeOffset(*frame);
|
||||
|
||||
sendFrame.SetTimeIeOffset(timeIeOffset);
|
||||
frame->SetTimeIeOffset(timeIeOffset);
|
||||
|
||||
if (timeIeOffset != 0)
|
||||
{
|
||||
sendFrame.SetTimeSyncSeq(Get<TimeSync>().GetTimeSyncSeq());
|
||||
sendFrame.SetNetworkTimeOffset(Get<TimeSync>().GetNetworkTimeOffset());
|
||||
frame->SetTimeSyncSeq(Get<TimeSync>().GetTimeSyncSeq());
|
||||
frame->SetNetworkTimeOffset(Get<TimeSync>().GetNetworkTimeOffset());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!sendFrame.IsSecurityProcessed())
|
||||
if (!frame->IsSecurityProcessed())
|
||||
{
|
||||
ProcessTransmitSecurity(sendFrame);
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
// Go through all selected radio link types for this tx and
|
||||
// copy the frame into correct `TxFrame` for each radio type
|
||||
// (if it is not already prepared), then process security for
|
||||
// each radio type separately. This allows radio links to
|
||||
// handle security differently, e.g., with different keys or
|
||||
// link frame counters.
|
||||
|
||||
for (uint8_t index = 0; index < OT_ARRAY_LENGTH(RadioTypes::kAllRadioTypes); index++)
|
||||
{
|
||||
RadioType radio = RadioTypes::kAllRadioTypes[index];
|
||||
|
||||
if (txFrames.GetSelectedRadioTypes().Contains(radio))
|
||||
{
|
||||
TxFrame &txFrame = txFrames.GetTxFrame(radio);
|
||||
|
||||
if (txFrame.IsEmpty())
|
||||
{
|
||||
txFrame.CopyFrom(*frame);
|
||||
}
|
||||
|
||||
ProcessTransmitSecurity(txFrame);
|
||||
}
|
||||
}
|
||||
#else
|
||||
ProcessTransmitSecurity(*frame);
|
||||
#endif
|
||||
}
|
||||
|
||||
mBroadcastTransmitCount = 0;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mTxPendingRadioLinks = txFrames.GetSelectedRadioTypes();
|
||||
|
||||
// If the "required radio type set" is empty,`mTxError` starts as
|
||||
// `OT_ERROR_ABORT`. In this case, successful tx over any radio
|
||||
// link is sufficient for overall tx to be considered successful.
|
||||
// When the "required radio type set" is not empty, `mTxError`
|
||||
// starts as `OT_ERROR_NONE` and we update it if tx over any link
|
||||
// in the required set fails.
|
||||
|
||||
if (!txFrames.GetRequiredRadioTypes().IsEmpty())
|
||||
{
|
||||
mTxError = OT_ERROR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
|
||||
if (!mRxOnWhenIdle && !mPromiscuous)
|
||||
{
|
||||
mShouldDelaySleep = sendFrame.GetFramePending();
|
||||
mShouldDelaySleep = frame->GetFramePending();
|
||||
otLogDebgMac("Delay sleep for pending tx");
|
||||
}
|
||||
#endif
|
||||
|
||||
error = mSubMac.Send();
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mLinks.Send(*frame, mTxPendingRadioLinks);
|
||||
#else
|
||||
mLinks.Send();
|
||||
#endif
|
||||
|
||||
exit:
|
||||
|
||||
if (error != OT_ERROR_NONE)
|
||||
if (frame == nullptr)
|
||||
{
|
||||
// If the sendFrame could not be prepared and the tx is being
|
||||
// If the frame could not be prepared and the tx is being
|
||||
// aborted, we set the frame length to zero to mark it as empty.
|
||||
// The empty frame helps differentiate between an aborted tx due
|
||||
// to OpenThread itself not being able to prepare the frame, versus
|
||||
// the radio platform aborting the tx operation.
|
||||
|
||||
sendFrame.SetLength(0);
|
||||
HandleTransmitDone(sendFrame, nullptr, OT_ERROR_ABORT);
|
||||
frame = &txFrames.GetBroadcastTxFrame();
|
||||
frame->SetLength(0);
|
||||
HandleTransmitDone(*frame, nullptr, OT_ERROR_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1364,7 +1463,12 @@ exit:
|
||||
|
||||
void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, otError aError)
|
||||
{
|
||||
if (!aFrame.IsEmpty())
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
if (!aFrame.IsEmpty()
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
&& (aFrame.GetRadioType() == kRadioTypeIeee802154)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
Address dstAddr;
|
||||
|
||||
@@ -1378,7 +1482,15 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, otError aError
|
||||
|
||||
if (mBroadcastTransmitCount < kTxNumBcast)
|
||||
{
|
||||
IgnoreError(mSubMac.Send());
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
{
|
||||
RadioTypes radioTypes;
|
||||
radioTypes.Add(kRadioTypeIeee802154);
|
||||
mLinks.Send(aFrame, radioTypes);
|
||||
}
|
||||
#else
|
||||
mLinks.Send();
|
||||
#endif
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
@@ -1394,6 +1506,55 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, otError aError
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (!aFrame.IsEmpty())
|
||||
{
|
||||
RadioType radio = aFrame.GetRadioType();
|
||||
RadioTypes requriedRadios = mLinks.GetTxFrames().GetRequiredRadioTypes();
|
||||
|
||||
Get<RadioSelector>().UpdateOnSendDone(aFrame, aError);
|
||||
|
||||
if (requriedRadios.IsEmpty())
|
||||
{
|
||||
// If the "required radio type set" is empty, successful
|
||||
// tx over any radio link is sufficient for overall tx to
|
||||
// be considered successful. In this case `mTxError`
|
||||
// starts as `OT_ERROR_ABORT` and we update it only when
|
||||
// it is not already `OT_ERROR_NONE`.
|
||||
|
||||
if (mTxError != OT_ERROR_NONE)
|
||||
{
|
||||
mTxError = aError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// When the "required radio type set" is not empty we
|
||||
// expect the successful frame tx on all links in this set
|
||||
// to consider the overall tx successful. In this case,
|
||||
// `mTxError` starts as `OT_ERROR_NONE` and we update it
|
||||
// if tx over any link in the set fails.
|
||||
|
||||
if (requriedRadios.Contains(radio) && (aError != OT_ERROR_NONE))
|
||||
{
|
||||
otLogDebgMac("Frame tx failed on required radio link %s with error %s", RadioTypeToString(radio),
|
||||
otThreadErrorToString(aError));
|
||||
|
||||
mTxError = aError;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of radio links on which the frame is sent
|
||||
// and wait for all radio links to finish.
|
||||
mTxPendingRadioLinks.Remove(radio);
|
||||
|
||||
VerifyOrExit(mTxPendingRadioLinks.IsEmpty());
|
||||
|
||||
aError = mTxError;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Determine next action based on current operation.
|
||||
|
||||
@@ -1439,9 +1600,9 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, otError aError
|
||||
mCounters.mTxDirectMaxRetryExpiry++;
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
|
||||
else if (mSubMac.GetTransmitRetries() < OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_DIRECT)
|
||||
else if (mLinks.GetTransmitRetries() < OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_DIRECT)
|
||||
{
|
||||
mRetryHistogram.mTxDirectRetrySuccess[mSubMac.GetTransmitRetries()]++;
|
||||
mRetryHistogram.mTxDirectRetrySuccess[mLinks.GetTransmitRetries()]++;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1478,9 +1639,9 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, otError aError
|
||||
mCounters.mTxIndirectMaxRetryExpiry++;
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
|
||||
else if (mSubMac.GetTransmitRetries() < OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_INDIRECT)
|
||||
else if (mLinks.GetTransmitRetries() < OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_MAX_SIZE_COUNT_INDIRECT)
|
||||
{
|
||||
mRetryHistogram.mTxIndirectRetrySuccess[mSubMac.GetTransmitRetries()]++;
|
||||
mRetryHistogram.mTxIndirectRetrySuccess[mLinks.GetTransmitRetries()]++;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1500,6 +1661,7 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, otError aError
|
||||
|
||||
default:
|
||||
OT_ASSERT(false);
|
||||
OT_UNREACHABLE_CODE(ExitNow()); // Added to suppress "unused label exit" warning (in TREL radio only).
|
||||
OT_UNREACHABLE_CODE(break);
|
||||
}
|
||||
|
||||
@@ -1591,17 +1753,17 @@ otError Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Ne
|
||||
if (keyid == (keyManager.GetCurrentKeySequence() & 0x7f))
|
||||
{
|
||||
keySequence = keyManager.GetCurrentKeySequence();
|
||||
macKey = &mSubMac.GetCurrentMacKey();
|
||||
macKey = mLinks.GetCurrentMacKey(aFrame);
|
||||
}
|
||||
else if (keyid == ((keyManager.GetCurrentKeySequence() - 1) & 0x7f))
|
||||
{
|
||||
keySequence = keyManager.GetCurrentKeySequence() - 1;
|
||||
macKey = &mSubMac.GetPreviousMacKey();
|
||||
macKey = mLinks.GetTemporaryMacKey(aFrame, keySequence);
|
||||
}
|
||||
else if (keyid == ((keyManager.GetCurrentKeySequence() + 1) & 0x7f))
|
||||
{
|
||||
keySequence = keyManager.GetCurrentKeySequence() + 1;
|
||||
macKey = &mSubMac.GetNextMacKey();
|
||||
macKey = mLinks.GetTemporaryMacKey(aFrame, keySequence);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1619,10 +1781,18 @@ otError Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Ne
|
||||
|
||||
if (keySequence == aNeighbor->GetKeySequence())
|
||||
{
|
||||
// If frame counter is one off, then frame is a duplicate.
|
||||
VerifyOrExit((frameCounter + 1) != aNeighbor->GetLinkFrameCounter(), error = OT_ERROR_DUPLICATED);
|
||||
uint32_t neighborFrameCounter;
|
||||
|
||||
VerifyOrExit(frameCounter >= aNeighbor->GetLinkFrameCounter());
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
neighborFrameCounter = aNeighbor->GetLinkFrameCounters().Get(aFrame.GetRadioType());
|
||||
#else
|
||||
neighborFrameCounter = aNeighbor->GetLinkFrameCounters().Get();
|
||||
#endif
|
||||
|
||||
// If frame counter is one off, then frame is a duplicate.
|
||||
VerifyOrExit((frameCounter + 1) != neighborFrameCounter, error = OT_ERROR_DUPLICATED);
|
||||
|
||||
VerifyOrExit(frameCounter >= neighborFrameCounter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1650,11 +1820,21 @@ otError Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Ne
|
||||
aNeighbor->SetMleFrameCounter(0);
|
||||
}
|
||||
|
||||
aNeighbor->SetLinkFrameCounter(frameCounter + 1);
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
if ((frameCounter + 1) > aNeighbor->GetLinkAckFrameCounter())
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
aNeighbor->GetLinkFrameCounters().Set(aFrame.GetRadioType(), frameCounter + 1);
|
||||
#else
|
||||
aNeighbor->GetLinkFrameCounters().Set(frameCounter + 1);
|
||||
#endif
|
||||
|
||||
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) && OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (aFrame.GetRadioType() == kRadioTypeIeee802154)
|
||||
#endif
|
||||
{
|
||||
aNeighbor->SetLinkAckFrameCounter(frameCounter + 1);
|
||||
if ((frameCounter + 1) > aNeighbor->GetLinkAckFrameCounter())
|
||||
{
|
||||
aNeighbor->SetLinkAckFrameCounter(frameCounter + 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1730,15 +1910,15 @@ otError Mac::ProcessEnhAckSecurity(TxFrame &aTxFrame, RxFrame &aAckFrame)
|
||||
|
||||
if (ackKeyId == (keyManager.GetCurrentKeySequence() & 0x7f))
|
||||
{
|
||||
macKey = &mSubMac.GetCurrentMacKey();
|
||||
macKey = &mLinks.GetSubMac().GetCurrentMacKey();
|
||||
}
|
||||
else if (ackKeyId == ((keyManager.GetCurrentKeySequence() - 1) & 0x7f))
|
||||
{
|
||||
macKey = &mSubMac.GetPreviousMacKey();
|
||||
macKey = &mLinks.GetSubMac().GetPreviousMacKey();
|
||||
}
|
||||
else if (ackKeyId == ((keyManager.GetCurrentKeySequence() + 1) & 0x7f))
|
||||
{
|
||||
macKey = &mSubMac.GetNextMacKey();
|
||||
macKey = &mLinks.GetSubMac().GetNextMacKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1952,6 +2132,10 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, otError aError)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
Get<RadioSelector>().UpdateOnReceive(*neighbor, aFrame->GetRadioType(), /* aIsDuplicate */ false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2123,7 +2307,7 @@ void Mac::SetPromiscuous(bool aPromiscuous)
|
||||
mShouldDelaySleep = false;
|
||||
#endif
|
||||
|
||||
mSubMac.SetRxOnWhenBackoff(mRxOnWhenIdle || mPromiscuous);
|
||||
mLinks.SetRxOnWhenBackoff(mRxOnWhenIdle || mPromiscuous);
|
||||
UpdateIdleMode();
|
||||
}
|
||||
|
||||
@@ -2252,11 +2436,24 @@ void Mac::LogFrameRxFailure(const RxFrame *aFrame, otError aError) const
|
||||
|
||||
void Mac::LogFrameTxFailure(const TxFrame &aFrame, otError aError, uint8_t aRetryCount, bool aWillRetx) const
|
||||
{
|
||||
uint8_t maxAttempts = aFrame.GetMaxFrameRetries() + 1;
|
||||
uint8_t curAttempt = aWillRetx ? (aRetryCount + 1) : maxAttempts;
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE && OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (aFrame.GetRadioType() == kRadioTypeIeee802154)
|
||||
#elif OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
if (true)
|
||||
#else
|
||||
if (false)
|
||||
#endif
|
||||
{
|
||||
uint8_t maxAttempts = aFrame.GetMaxFrameRetries() + 1;
|
||||
uint8_t curAttempt = aWillRetx ? (aRetryCount + 1) : maxAttempts;
|
||||
|
||||
otLogInfoMac("Frame tx attempt %d/%d failed, error:%s, %s", curAttempt, maxAttempts, otThreadErrorToString(aError),
|
||||
aFrame.ToInfoString().AsCString());
|
||||
otLogInfoMac("Frame tx attempt %d/%d failed, error:%s, %s", curAttempt, maxAttempts,
|
||||
otThreadErrorToString(aError), aFrame.ToInfoString().AsCString());
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogInfoMac("Frame tx failed, error:%s, %s", otThreadErrorToString(aError), aFrame.ToInfoString().AsCString());
|
||||
}
|
||||
}
|
||||
|
||||
void Mac::LogBeacon(const char *aActionText, const BeaconPayload &aBeaconPayload) const
|
||||
@@ -2305,8 +2502,8 @@ void Mac::SetCslChannel(uint8_t aChannel)
|
||||
{
|
||||
VerifyOrExit(GetCslChannel() != aChannel);
|
||||
|
||||
mSubMac.SetCslChannel(aChannel);
|
||||
mSubMac.SetCslChannelSpecified(aChannel != 0);
|
||||
mLinks.GetSubMac().SetCslChannel(aChannel);
|
||||
mLinks.GetSubMac().SetCslChannelSpecified(aChannel != 0);
|
||||
|
||||
if (IsCslEnabled())
|
||||
{
|
||||
@@ -2318,7 +2515,7 @@ exit:
|
||||
|
||||
void Mac::SetCslPeriod(uint16_t aPeriod)
|
||||
{
|
||||
mSubMac.SetCslPeriod(aPeriod);
|
||||
mLinks.GetSubMac().SetCslPeriod(aPeriod);
|
||||
|
||||
if (IsCslEnabled())
|
||||
{
|
||||
@@ -2333,7 +2530,7 @@ void Mac::SetCslTimeout(uint32_t aTimeout)
|
||||
{
|
||||
VerifyOrExit(GetCslTimeout() != aTimeout);
|
||||
|
||||
mSubMac.SetCslTimeout(aTimeout);
|
||||
mLinks.GetSubMac().SetCslTimeout(aTimeout);
|
||||
|
||||
if (IsCslEnabled())
|
||||
{
|
||||
|
||||
+30
-22
@@ -47,8 +47,10 @@
|
||||
#include "mac/channel_mask.hpp"
|
||||
#include "mac/mac_filter.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
#include "mac/mac_links.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "mac/sub_mac.hpp"
|
||||
#include "radio/trel.hpp"
|
||||
#include "thread/key_manager.hpp"
|
||||
#include "thread/link_quality.hpp"
|
||||
|
||||
@@ -262,7 +264,7 @@ public:
|
||||
* @returns A pointer to the IEEE 802.15.4 Extended Address.
|
||||
*
|
||||
*/
|
||||
const ExtAddress &GetExtAddress(void) const { return mSubMac.GetExtAddress(); }
|
||||
const ExtAddress &GetExtAddress(void) const { return mLinks.GetExtAddress(); }
|
||||
|
||||
/**
|
||||
* This method sets the IEEE 802.15.4 Extended Address.
|
||||
@@ -270,7 +272,7 @@ public:
|
||||
* @param[in] aExtAddress A reference to the IEEE 802.15.4 Extended Address.
|
||||
*
|
||||
*/
|
||||
void SetExtAddress(const ExtAddress &aExtAddress) { mSubMac.SetExtAddress(aExtAddress); }
|
||||
void SetExtAddress(const ExtAddress &aExtAddress) { mLinks.SetExtAddress(aExtAddress); }
|
||||
|
||||
/**
|
||||
* This method returns the IEEE 802.15.4 Short Address.
|
||||
@@ -278,7 +280,7 @@ public:
|
||||
* @returns The IEEE 802.15.4 Short Address.
|
||||
*
|
||||
*/
|
||||
ShortAddress GetShortAddress(void) const { return mSubMac.GetShortAddress(); }
|
||||
ShortAddress GetShortAddress(void) const { return mLinks.GetShortAddress(); }
|
||||
|
||||
/**
|
||||
* This method sets the IEEE 802.15.4 Short Address.
|
||||
@@ -286,7 +288,7 @@ public:
|
||||
* @param[in] aShortAddress The IEEE 802.15.4 Short Address.
|
||||
*
|
||||
*/
|
||||
void SetShortAddress(ShortAddress aShortAddress) { mSubMac.SetShortAddress(aShortAddress); }
|
||||
void SetShortAddress(ShortAddress aShortAddress) { mLinks.SetShortAddress(aShortAddress); }
|
||||
|
||||
/**
|
||||
* This method returns the IEEE 802.15.4 PAN Channel.
|
||||
@@ -573,7 +575,7 @@ public:
|
||||
*/
|
||||
void SetPcapCallback(otLinkPcapCallback aPcapCallback, void *aCallbackContext)
|
||||
{
|
||||
mSubMac.SetPcapCallback(aPcapCallback, aCallbackContext);
|
||||
mLinks.SetPcapCallback(aPcapCallback, aCallbackContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -647,7 +649,7 @@ public:
|
||||
* @returns The noise floor value in dBm.
|
||||
*
|
||||
*/
|
||||
int8_t GetNoiseFloor(void) { return mSubMac.GetNoiseFloor(); }
|
||||
int8_t GetNoiseFloor(void) { return mLinks.GetNoiseFloor(); }
|
||||
|
||||
/**
|
||||
* This method returns the current CCA (Clear Channel Assessment) failure rate.
|
||||
@@ -684,7 +686,7 @@ public:
|
||||
* @returns CSL channel.
|
||||
*
|
||||
*/
|
||||
uint8_t GetCslChannel(void) const { return mSubMac.GetCslChannel(); }
|
||||
uint8_t GetCslChannel(void) const { return mLinks.GetSubMac().GetCslChannel(); }
|
||||
|
||||
/**
|
||||
* This method sets the CSL channel.
|
||||
@@ -700,7 +702,7 @@ public:
|
||||
* @returns If CSL channel has been specified.
|
||||
*
|
||||
*/
|
||||
bool IsCslChannelSpecified(void) const { return mSubMac.IsCslChannelSpecified(); }
|
||||
bool IsCslChannelSpecified(void) const { return mLinks.GetSubMac().IsCslChannelSpecified(); }
|
||||
|
||||
/**
|
||||
* This method gets the CSL period.
|
||||
@@ -708,7 +710,7 @@ public:
|
||||
* @returns CSL period in units of 10 symbols.
|
||||
*
|
||||
*/
|
||||
uint16_t GetCslPeriod(void) const { return mSubMac.GetCslPeriod(); }
|
||||
uint16_t GetCslPeriod(void) const { return mLinks.GetSubMac().GetCslPeriod(); }
|
||||
|
||||
/**
|
||||
* This method sets the CSL period.
|
||||
@@ -724,7 +726,7 @@ public:
|
||||
* @returns CSL timeout in seconds.
|
||||
*
|
||||
*/
|
||||
uint32_t GetCslTimeout(void) const { return mSubMac.GetCslTimeout(); }
|
||||
uint32_t GetCslTimeout(void) const { return mLinks.GetSubMac().GetCslTimeout(); }
|
||||
|
||||
/**
|
||||
* This method sets the CSL timeout.
|
||||
@@ -827,17 +829,18 @@ private:
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
otError ProcessEnhAckSecurity(TxFrame &aTxFrame, RxFrame &aAckFrame);
|
||||
#endif
|
||||
void UpdateIdleMode(void);
|
||||
void StartOperation(Operation aOperation);
|
||||
void FinishOperation(void);
|
||||
void PerformNextOperation(void);
|
||||
otError PrepareDataRequest(TxFrame &aFrame);
|
||||
void PrepareBeaconRequest(TxFrame &aFrame);
|
||||
void PrepareBeacon(TxFrame &aFrame);
|
||||
bool ShouldSendBeacon(void) const;
|
||||
bool IsJoinable(void) const;
|
||||
void BeginTransmit(void);
|
||||
bool HandleMacCommand(RxFrame &aFrame);
|
||||
|
||||
void UpdateIdleMode(void);
|
||||
void StartOperation(Operation aOperation);
|
||||
void FinishOperation(void);
|
||||
void PerformNextOperation(void);
|
||||
TxFrame *PrepareDataRequest(void);
|
||||
TxFrame *PrepareBeaconRequest(void);
|
||||
TxFrame *PrepareBeacon(void);
|
||||
bool ShouldSendBeacon(void) const;
|
||||
bool IsJoinable(void) const;
|
||||
void BeginTransmit(void);
|
||||
bool HandleMacCommand(RxFrame &aFrame);
|
||||
|
||||
static void HandleTimer(Timer &aTimer);
|
||||
void HandleTimer(void);
|
||||
@@ -926,7 +929,7 @@ private:
|
||||
|
||||
void *mScanHandlerContext;
|
||||
|
||||
SubMac mSubMac;
|
||||
Links mLinks;
|
||||
Tasklet mOperationTask;
|
||||
TimerMilli mTimer;
|
||||
TxFrame * mOobFrame;
|
||||
@@ -938,6 +941,11 @@ private:
|
||||
RetryHistogram mRetryHistogram;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
RadioTypes mTxPendingRadioLinks;
|
||||
otError mTxError;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
Filter mFilter;
|
||||
#endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
|
||||
+96
-10
@@ -37,6 +37,7 @@
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "radio/trel.hpp"
|
||||
#if !OPENTHREAD_RADIO || OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE
|
||||
#include "crypto/aes_ccm.hpp"
|
||||
#endif
|
||||
@@ -970,25 +971,106 @@ exit:
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
uint16_t Frame::GetMtu(void) const
|
||||
{
|
||||
uint16_t mtu;
|
||||
|
||||
switch (GetRadioType())
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
case kRadioTypeIeee802154:
|
||||
mtu = OT_RADIO_FRAME_MAX_SIZE;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
case kRadioTypeTrel:
|
||||
mtu = Trel::Link::kMtuSize;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
OT_ASSERT(false);
|
||||
}
|
||||
|
||||
return mtu;
|
||||
}
|
||||
|
||||
uint8_t Frame::GetFcsSize(void) const
|
||||
{
|
||||
uint8_t fcsSize;
|
||||
|
||||
switch (GetRadioType())
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
case kRadioTypeIeee802154:
|
||||
fcsSize = k154FcsSize;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
case kRadioTypeTrel:
|
||||
fcsSize = Trel::Link::kFcsSize;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
OT_ASSERT(false);
|
||||
}
|
||||
|
||||
return fcsSize;
|
||||
}
|
||||
|
||||
#elif OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
uint16_t Frame::GetMtu(void) const
|
||||
{
|
||||
return Trel::Link::kMtuSize;
|
||||
}
|
||||
|
||||
uint8_t Frame::GetFcsSize(void) const
|
||||
{
|
||||
return Trel::Link::kFcsSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
void TxFrame::CopyFrom(const TxFrame &aFromFrame)
|
||||
{
|
||||
uint8_t * psduBuffer = mPsdu;
|
||||
otRadioIeInfo *ieInfoBuffer = mInfo.mTxInfo.mIeInfo;
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
uint8_t radioType = mRadioType;
|
||||
#endif
|
||||
|
||||
memcpy(this, &aFromFrame, sizeof(Frame));
|
||||
|
||||
// Set the original buffer pointers back on the frame
|
||||
// which were overwritten by above `memcpy()`.
|
||||
// Set the original buffer pointers (and link type) back on
|
||||
// the frame (which were overwritten by above `memcpy()`).
|
||||
|
||||
mPsdu = psduBuffer;
|
||||
mInfo.mTxInfo.mIeInfo = ieInfoBuffer;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mRadioType = radioType;
|
||||
#endif
|
||||
|
||||
memcpy(mPsdu, aFromFrame.mPsdu, aFromFrame.mLength);
|
||||
|
||||
// mIeInfo may be null when TIME_SYNC is not enabled.
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
memcpy(mInfo.mTxInfo.mIeInfo, aFromFrame.mInfo.mTxInfo.mIeInfo, sizeof(otRadioIeInfo));
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (mRadioType != aFromFrame.GetRadioType())
|
||||
{
|
||||
// Frames associated with different radio link types can have
|
||||
// different FCS size. We adjust the PSDU length after the
|
||||
// copy to account for this.
|
||||
|
||||
SetLength(aFromFrame.GetPsduLength() - aFromFrame.GetFcsSize() + GetFcsSize());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void TxFrame::ProcessTransmitAesCcm(const ExtAddress &aExtAddress)
|
||||
@@ -1010,7 +1092,7 @@ void TxFrame::ProcessTransmitAesCcm(const ExtAddress &aExtAddress)
|
||||
Crypto::AesCcm::GenerateNonce(aExtAddress, frameCounter, securityLevel, nonce);
|
||||
|
||||
aesCcm.SetKey(GetAesKey());
|
||||
tagLength = GetFooterLength() - Frame::kFcsSize;
|
||||
tagLength = GetFooterLength() - GetFcsSize();
|
||||
|
||||
aesCcm.Init(GetHeaderLength(), GetPayloadLength(), tagLength, nonce, sizeof(nonce));
|
||||
aesCcm.Header(GetHeader(), GetHeaderLength());
|
||||
@@ -1161,12 +1243,12 @@ otError RxFrame::ProcessReceiveAesCcm(const ExtAddress &aExtAddress, const Key &
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
#else
|
||||
otError error = OT_ERROR_SECURITY;
|
||||
uint32_t frameCounter = 0;
|
||||
uint8_t securityLevel;
|
||||
uint8_t nonce[Crypto::AesCcm::kNonceSize];
|
||||
uint8_t tag[kMaxMicSize];
|
||||
uint8_t tagLength;
|
||||
otError error = OT_ERROR_SECURITY;
|
||||
uint32_t frameCounter = 0;
|
||||
uint8_t securityLevel;
|
||||
uint8_t nonce[Crypto::AesCcm::kNonceSize];
|
||||
uint8_t tag[kMaxMicSize];
|
||||
uint8_t tagLength;
|
||||
Crypto::AesCcm aesCcm;
|
||||
|
||||
VerifyOrExit(GetSecurityEnabled(), error = OT_ERROR_NONE);
|
||||
@@ -1177,7 +1259,7 @@ otError RxFrame::ProcessReceiveAesCcm(const ExtAddress &aExtAddress, const Key &
|
||||
Crypto::AesCcm::GenerateNonce(aExtAddress, frameCounter, securityLevel, nonce);
|
||||
|
||||
aesCcm.SetKey(aMacKey);
|
||||
tagLength = GetFooterLength() - Frame::kFcsSize;
|
||||
tagLength = GetFooterLength() - GetFcsSize();
|
||||
|
||||
aesCcm.Init(GetHeaderLength(), GetPayloadLength(), tagLength, nonce, sizeof(nonce));
|
||||
aesCcm.Header(GetHeader(), GetHeaderLength());
|
||||
@@ -1264,6 +1346,10 @@ Frame::InfoString Frame::ToInfoString(void) const
|
||||
dst.ToString().AsCString(), GetSecurityEnabled() ? "yes" : "no",
|
||||
GetAckRequest() ? "yes" : "no"));
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
IgnoreError(string.Append(", radio:%s", RadioTypeToString(GetRadioType())));
|
||||
#endif
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
@@ -261,13 +261,12 @@ class Frame : public otRadioFrame
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kMtu = OT_RADIO_FRAME_MAX_SIZE,
|
||||
kFcfSize = sizeof(uint16_t),
|
||||
kDsnSize = sizeof(uint8_t),
|
||||
kSecurityControlSize = sizeof(uint8_t),
|
||||
kFrameCounterSize = sizeof(uint32_t),
|
||||
kCommandIdSize = sizeof(uint8_t),
|
||||
kFcsSize = sizeof(uint16_t),
|
||||
k154FcsSize = sizeof(uint16_t),
|
||||
|
||||
kFcfFrameBeacon = 0 << 0,
|
||||
kFcfFrameData = 1 << 0,
|
||||
@@ -334,9 +333,9 @@ public:
|
||||
kHeaderIeCsl = 0x1a,
|
||||
kHeaderIeTermination2 = 0x7f,
|
||||
|
||||
kInfoStringSize = 110, ///< Max chars needed for the info string representation (@sa ToInfoString()).
|
||||
kImmAckLength = kFcfSize + kDsnSize + k154FcsSize,
|
||||
|
||||
kImmAckLength = kFcfSize + kDsnSize + kFcsSize,
|
||||
kInfoStringSize = 128, ///< Max chars needed for the info string representation (@sa ToInfoString()).
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -952,13 +951,38 @@ public:
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
/**
|
||||
* This method gets the radio link type of the frame.
|
||||
*
|
||||
* @returns Frame's radio link type.
|
||||
*
|
||||
*/
|
||||
RadioType GetRadioType(void) const { return static_cast<RadioType>(mRadioType); }
|
||||
|
||||
/**
|
||||
* This method sets the radio link type of the frame.
|
||||
*
|
||||
* @param[in] aRadioType A radio link type.
|
||||
*
|
||||
*/
|
||||
void SetRadioType(RadioType aRadioType) { mRadioType = static_cast<uint8_t>(aRadioType); }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method returns the maximum transmission unit size (MTU).
|
||||
*
|
||||
* @returns The maximum transmission unit (MTU).
|
||||
*
|
||||
*/
|
||||
uint16_t GetMtu(void) const { return kMtu; }
|
||||
uint16_t GetMtu(void) const
|
||||
#if !OPENTHREAD_CONFIG_MULTI_RADIO && OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
{
|
||||
return OT_RADIO_FRAME_MAX_SIZE;
|
||||
}
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method returns the FCS size.
|
||||
@@ -966,7 +990,14 @@ public:
|
||||
* @returns This method returns the FCS size.
|
||||
*
|
||||
*/
|
||||
uint16_t GetFcsSize(void) const { return kFcsSize; }
|
||||
uint8_t GetFcsSize(void) const
|
||||
#if !OPENTHREAD_CONFIG_MULTI_RADIO && OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
{
|
||||
return k154FcsSize;
|
||||
}
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method returns information about the frame object as an `InfoString` object.
|
||||
@@ -1213,7 +1244,7 @@ public:
|
||||
void SetAesKey(const Mac::Key &aAesKey) { mInfo.mTxInfo.mAesKey = &aAesKey; }
|
||||
|
||||
/**
|
||||
* This method copies the PSDU and all attributes from another frame.
|
||||
* This method copies the PSDU and all attributes (except for frame link type) from another frame.
|
||||
*
|
||||
* @note This method performs a deep copy meaning the content of PSDU buffer from the given frame is copied into
|
||||
* the PSDU buffer of the current frame.
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 MAC radio links.
|
||||
*/
|
||||
|
||||
#include "mac_links.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator-getters.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Mac {
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// TxFrames
|
||||
|
||||
TxFrames::TxFrames(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
, mTxFrame802154(aInstance.Get<SubMac>().GetTransmitFrame())
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
, mTxFrameTrel(aInstance.Get<Trel::Link>().GetTransmitFrame())
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
, mSelectedRadioTypes()
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
TxFrame &TxFrames::GetTxFrame(RadioType aRadioType)
|
||||
{
|
||||
TxFrame *frame = nullptr;
|
||||
|
||||
switch (aRadioType)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
case kRadioTypeIeee802154:
|
||||
frame = &mTxFrame802154;
|
||||
break;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
case kRadioTypeTrel:
|
||||
frame = &mTxFrameTrel;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
mSelectedRadioTypes.Add(aRadioType);
|
||||
|
||||
return *frame;
|
||||
}
|
||||
|
||||
TxFrame &TxFrames::GetTxFrame(RadioTypes aRadioTypes)
|
||||
{
|
||||
// Return the TxFrame among all set of `aRadioTypes` with the smallest MTU.
|
||||
// Note that this is `TxFrame` to be sent out in parallel over multiple radio
|
||||
// radio links in `aRadioTypes, so we need to make sure that it fits in the
|
||||
// most restricted radio link (with smallest MTU).
|
||||
|
||||
TxFrame *frame = nullptr;
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
if (aRadioTypes.Contains(kRadioTypeIeee802154))
|
||||
{
|
||||
frame = &mTxFrame802154;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
if (aRadioTypes.Contains(kRadioTypeTrel) && ((frame == nullptr) || (frame->GetMtu() > mTxFrameTrel.GetMtu())))
|
||||
{
|
||||
frame = &mTxFrameTrel;
|
||||
}
|
||||
#endif
|
||||
|
||||
mSelectedRadioTypes.Add(aRadioTypes);
|
||||
|
||||
return *frame;
|
||||
}
|
||||
|
||||
TxFrame &TxFrames::GetBroadcastTxFrame(void)
|
||||
{
|
||||
RadioTypes allRadios;
|
||||
|
||||
allRadios.AddAll();
|
||||
return GetTxFrame(allRadios);
|
||||
}
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Links
|
||||
|
||||
Links::Links(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mSubMac(aInstance)
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
, mTrel(aInstance)
|
||||
#endif
|
||||
, mTxFrames(aInstance)
|
||||
#if !OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
, mShortAddress(kShortAddrInvalid)
|
||||
#endif
|
||||
{
|
||||
#if !OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mExtAddress.Clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
void Links::Send(TxFrame &aFrame, RadioTypes aRadioTypes)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
if (aRadioTypes.Contains(kRadioTypeIeee802154) && mTxFrames.mTxFrame802154.IsEmpty())
|
||||
{
|
||||
mTxFrames.mTxFrame802154.CopyFrom(aFrame);
|
||||
}
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
if (aRadioTypes.Contains(kRadioTypeTrel) && mTxFrames.mTxFrameTrel.IsEmpty())
|
||||
{
|
||||
mTxFrames.mTxFrameTrel.CopyFrom(aFrame);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
if (aRadioTypes.Contains(kRadioTypeIeee802154))
|
||||
{
|
||||
otError error = mSubMac.Send();
|
||||
|
||||
OT_ASSERT(error == OT_ERROR_NONE);
|
||||
OT_UNUSED_VARIABLE(error);
|
||||
}
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
if (aRadioTypes.Contains(kRadioTypeTrel))
|
||||
{
|
||||
mTrel.Send();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
const Key *Links::GetCurrentMacKey(const Frame &aFrame) const
|
||||
{
|
||||
// Gets the security MAC key (for Key Mode 1) based on radio link type of `aFrame`.
|
||||
|
||||
const Key *key = nullptr;
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
RadioType radioType = aFrame.GetRadioType();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (radioType == kRadioTypeIeee802154)
|
||||
#endif
|
||||
{
|
||||
ExitNow(key = &Get<SubMac>().GetCurrentMacKey());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (radioType == kRadioTypeTrel)
|
||||
#endif
|
||||
{
|
||||
ExitNow(key = &Get<KeyManager>().GetCurrentTrelMacKey());
|
||||
}
|
||||
#endif
|
||||
|
||||
OT_UNUSED_VARIABLE(aFrame);
|
||||
|
||||
exit:
|
||||
return key;
|
||||
}
|
||||
|
||||
const Key *Links::GetTemporaryMacKey(const Frame &aFrame, uint32_t aKeySequence) const
|
||||
{
|
||||
// Gets the security MAC key (for Key Mode 1) based on radio link
|
||||
// type of `aFrame` and given Key Sequence.
|
||||
|
||||
const Key *key = nullptr;
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
RadioType radioType = aFrame.GetRadioType();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (radioType == kRadioTypeIeee802154)
|
||||
#endif
|
||||
{
|
||||
if (aKeySequence == Get<KeyManager>().GetCurrentKeySequence() - 1)
|
||||
{
|
||||
ExitNow(key = &Get<SubMac>().GetPreviousMacKey());
|
||||
}
|
||||
else if (aKeySequence == Get<KeyManager>().GetCurrentKeySequence() + 1)
|
||||
{
|
||||
ExitNow(key = &Get<SubMac>().GetNextMacKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
OT_ASSERT(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (radioType == kRadioTypeTrel)
|
||||
#endif
|
||||
{
|
||||
ExitNow(key = &Get<KeyManager>().GetTemporaryTrelMacKey(aKeySequence));
|
||||
}
|
||||
#endif
|
||||
|
||||
OT_UNUSED_VARIABLE(aFrame);
|
||||
|
||||
exit:
|
||||
return key;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
void Links::SetMacFrameCounter(TxFrame &aFrame)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
RadioType radioType = aFrame.GetRadioType();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (radioType == kRadioTypeTrel)
|
||||
#endif
|
||||
{
|
||||
aFrame.SetFrameCounter(Get<KeyManager>().GetTrelMacFrameCounter());
|
||||
Get<KeyManager>().IncrementTrelMacFrameCounter();
|
||||
ExitNow();
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
} // namespace Mac
|
||||
} // namespace ot
|
||||
@@ -0,0 +1,691 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 MAC radio links.
|
||||
*/
|
||||
|
||||
#ifndef MAC_LINKS_HPP_
|
||||
#define MAC_LINKS_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/debug.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "mac/sub_mac.hpp"
|
||||
#include "radio/trel.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Mac {
|
||||
|
||||
/**
|
||||
* @addtogroup core-mac
|
||||
*
|
||||
* @brief
|
||||
* This module includes definitions for MAC radio links (multi radio).
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class represents tx frames for different radio link types.
|
||||
*
|
||||
*/
|
||||
class TxFrames : InstanceLocator
|
||||
{
|
||||
friend class Links;
|
||||
|
||||
public:
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
/**
|
||||
* This method gets the `TxFrame` for a given radio link type.
|
||||
*
|
||||
* This method also updates the selected radio types (from `GetSelectedRadioTypes()`) to include the @p aRadioType.
|
||||
*
|
||||
* @param[in] aRadioType A radio link type.
|
||||
*
|
||||
* @returns A reference to the `TxFrame` for the given radio link type.
|
||||
*
|
||||
*/
|
||||
TxFrame &GetTxFrame(RadioType aRadioType);
|
||||
|
||||
/**
|
||||
* This method gets the `TxFrame` with the smallest MTU size among a given set of radio types.
|
||||
*
|
||||
* This method also updates the selected radio types (from `GetSelectedRadioTypes()`) to include the set
|
||||
* @p aRadioTypes.
|
||||
*
|
||||
* @param[in] aRadioTypes A set of radio link types.
|
||||
*
|
||||
* @returns A reference to the `TxFrame` with the smallest MTU size among the set of @p aRadioTypes.
|
||||
*
|
||||
*/
|
||||
TxFrame &GetTxFrame(RadioTypes aRadioTypes);
|
||||
|
||||
/**
|
||||
* This method gets the `TxFrame` for sending a broadcast frame.
|
||||
*
|
||||
* This method also updates the selected radio type (from `GetSelectedRadioTypes()`) to include all radio types
|
||||
* (supported by device).
|
||||
*
|
||||
* The broadcast frame is the `TxFrame` with the smallest MTU size among all radio types.
|
||||
*
|
||||
* @returns A reference to a `TxFrame` for broadcast.
|
||||
*
|
||||
*/
|
||||
TxFrame &GetBroadcastTxFrame(void);
|
||||
|
||||
/**
|
||||
* This method gets the selected radio types.
|
||||
*
|
||||
* This set specifies the radio links the frame should be sent over (in parallel). The set starts a empty after
|
||||
* method `Clear()` is called. It gets updated through calls to methods `GetTxFrame(aType)`,
|
||||
* `GetTxFrame(aRadioTypes)`, or `GetBroadcastTxFrame()`.
|
||||
*
|
||||
* @returns The selected radio types.
|
||||
*
|
||||
*/
|
||||
RadioTypes GetSelectedRadioTypes(void) const { return mSelectedRadioTypes; }
|
||||
|
||||
/**
|
||||
* This method gets the required radio types.
|
||||
*
|
||||
* This set specifies the radio links for which we expect the frame tx to be successful to consider the overall tx
|
||||
* successful. If the set is empty, successful tx over any radio link is sufficient for overall tx to be considered
|
||||
* successful. The required radio type set is expected to be a subset of selected radio types.
|
||||
*
|
||||
* The set starts as empty after `Clear()` call. It can be updated through `SetRequiredRadioTypes()` method
|
||||
*
|
||||
* @returns The required radio types.
|
||||
*
|
||||
*/
|
||||
RadioTypes GetRequiredRadioTypes(void) const { return mRequiredRadioTypes; }
|
||||
|
||||
/**
|
||||
* This method sets the required types.
|
||||
*
|
||||
* Please see `GetRequiredRadioTypes()` for more details on how this set is used during tx.
|
||||
*
|
||||
* @param[in] aRadioTypes A set of radio link types.
|
||||
*
|
||||
*/
|
||||
void SetRequiredRadioTypes(RadioTypes aRadioTypes) { mRequiredRadioTypes = aRadioTypes; }
|
||||
|
||||
#else // #if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
/**
|
||||
* This method gets the tx frame.
|
||||
*
|
||||
* @returns A reference to `TxFrame`.
|
||||
*
|
||||
*/
|
||||
TxFrame &GetTxFrame(void) { return mTxFrame802154; }
|
||||
#elif OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
/**
|
||||
* This method gets the tx frame.
|
||||
*
|
||||
* @returns A reference to `TxFrame`.
|
||||
*
|
||||
*/
|
||||
TxFrame &GetTxFrame(void) { return mTxFrameTrel; }
|
||||
#endif
|
||||
/**
|
||||
* This method gets a tx frame for sending a broadcast frame.
|
||||
*
|
||||
* @returns A reference to a `TxFrame` for broadcast.
|
||||
*
|
||||
*/
|
||||
TxFrame &GetBroadcastTxFrame(void) { return GetTxFrame(); }
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
/**
|
||||
* This method clears all supported radio tx frames (sets the PSDU length to zero and clears flags).
|
||||
*
|
||||
*/
|
||||
void Clear(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mTxFrame802154.SetLength(0);
|
||||
mTxFrame802154.SetIsARetransmission(false);
|
||||
mTxFrame802154.SetIsSecurityProcessed(false);
|
||||
mTxFrame802154.SetCsmaCaEnabled(true); // Set to true by default, only set to `false` for CSL transmission
|
||||
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
mTxFrame802154.SetTxDelay(0);
|
||||
mTxFrame802154.SetTxDelayBaseTime(0);
|
||||
#endif
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTxFrameTrel.SetLength(0);
|
||||
mTxFrameTrel.SetIsARetransmission(false);
|
||||
mTxFrameTrel.SetIsSecurityProcessed(false);
|
||||
mTxFrameTrel.SetCsmaCaEnabled(true);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mSelectedRadioTypes.Clear();
|
||||
mRequiredRadioTypes.Clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the channel on all supported radio tx frames.
|
||||
*
|
||||
* @param[in] aChannel A channel.
|
||||
*
|
||||
*/
|
||||
void SetChannel(uint8_t aChannel)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mTxFrame802154.SetChannel(aChannel);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTxFrameTrel.SetChannel(aChannel);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the Sequence Number value on all supported radio tx frames.
|
||||
*
|
||||
* @param[in] aSequence The Sequence Number value.
|
||||
*
|
||||
*/
|
||||
void SetSequence(uint8_t aSequence)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mTxFrame802154.SetSequence(aSequence);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTxFrameTrel.SetSequence(aSequence);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the maximum number of the CSMA-CA backoffs on all supported radio tx
|
||||
* frames.
|
||||
*
|
||||
* @param[in] aMaxCsmaBackoffs The maximum number of CSMA-CA backoffs.
|
||||
*
|
||||
*/
|
||||
void SetMaxCsmaBackoffs(uint8_t aMaxCsmaBackoffs)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mTxFrame802154.SetMaxCsmaBackoffs(aMaxCsmaBackoffs);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTxFrameTrel.SetMaxCsmaBackoffs(aMaxCsmaBackoffs);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the maximum number of retries allowed after a transmission failure on all supported radio tx
|
||||
* frames.
|
||||
*
|
||||
* @param[in] aMaxFrameRetries The maximum number of retries allowed after a transmission failure.
|
||||
*
|
||||
*/
|
||||
void SetMaxFrameRetries(uint8_t aMaxFrameRetries)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mTxFrame802154.SetMaxFrameRetries(aMaxFrameRetries);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTxFrameTrel.SetMaxFrameRetries(aMaxFrameRetries);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
explicit TxFrames(Instance &aInstance);
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
TxFrame &mTxFrame802154;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
TxFrame &mTxFrameTrel;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
RadioTypes mSelectedRadioTypes;
|
||||
RadioTypes mRequiredRadioTypes;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* This class represents MAC radio links (multi radio).
|
||||
*
|
||||
*/
|
||||
class Links : public InstanceLocator
|
||||
{
|
||||
friend class ot::Instance;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kInvalidRssiValue = SubMac::kInvalidRssiValue, ///< Invalid Received Signal Strength Indicator (RSSI) value.
|
||||
};
|
||||
|
||||
/**
|
||||
* This constructor initializes the `Links` object.
|
||||
*
|
||||
* @param[in] aInstance A reference to the OpenThread instance.
|
||||
*
|
||||
*/
|
||||
explicit Links(Instance &aInstance);
|
||||
|
||||
/**
|
||||
* This method sets the PAN ID.
|
||||
*
|
||||
* @param[in] aPanId The PAN ID.
|
||||
*
|
||||
*/
|
||||
void SetPanId(PanId aPanId)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.SetPanId(aPanId);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTrel.SetPanId(aPanId);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the MAC Short Address.
|
||||
*
|
||||
* @returns The MAC Short Address.
|
||||
*
|
||||
*/
|
||||
ShortAddress GetShortAddress(void) const
|
||||
{
|
||||
return
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.GetShortAddress();
|
||||
#else
|
||||
mShortAddress;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the MAC Short Address.
|
||||
*
|
||||
* @param[in] aShortAddress A MAC Short Address.
|
||||
*
|
||||
*/
|
||||
void SetShortAddress(ShortAddress aShortAddress)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.SetShortAddress(aShortAddress);
|
||||
#else
|
||||
mShortAddress = aShortAddress;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the MAC Extended Address.
|
||||
*
|
||||
* @returns The MAC Extended Address.
|
||||
*
|
||||
*/
|
||||
const ExtAddress &GetExtAddress(void) const
|
||||
{
|
||||
return
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.GetExtAddress();
|
||||
#else
|
||||
mExtAddress;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the MAC Extended Address.
|
||||
*
|
||||
* @param[in] aExtAddress A MAC Extended Address.
|
||||
*
|
||||
*/
|
||||
void SetExtAddress(const ExtAddress &aExtAddress)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.SetExtAddress(aExtAddress);
|
||||
#else
|
||||
mExtAddress = aExtAddress;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method registers a callback to provide received packet capture for IEEE 802.15.4 frames.
|
||||
*
|
||||
* @param[in] aPcapCallback A pointer to a function that is called when receiving an IEEE 802.15.4 link frame
|
||||
* or nullptr to disable the callback.
|
||||
* @param[in] aCallbackContext A pointer to application-specific context.
|
||||
*
|
||||
*/
|
||||
void SetPcapCallback(otLinkPcapCallback aPcapCallback, void *aCallbackContext)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.SetPcapCallback(aPcapCallback, aCallbackContext);
|
||||
#endif
|
||||
OT_UNUSED_VARIABLE(aPcapCallback);
|
||||
OT_UNUSED_VARIABLE(aCallbackContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether radio should stay in Receive or Sleep during CSMA backoff.
|
||||
*
|
||||
* @param[in] aRxOnWhenBackoff TRUE to keep radio in Receive, FALSE to put to Sleep during CSMA backoff.
|
||||
*
|
||||
*/
|
||||
void SetRxOnWhenBackoff(bool aRxOnWhenBackoff)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.SetRxOnWhenBackoff(aRxOnWhenBackoff);
|
||||
#endif
|
||||
OT_UNUSED_VARIABLE(aRxOnWhenBackoff);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method enables all radio links.
|
||||
*
|
||||
*/
|
||||
void Enable(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
IgnoreError(mSubMac.Enable());
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTrel.Enable();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method disables all radio links.
|
||||
*
|
||||
*/
|
||||
void Disable(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
IgnoreError(mSubMac.Disable());
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTrel.Disable();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method transitions all radio links to Sleep.
|
||||
*
|
||||
*/
|
||||
void Sleep(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
IgnoreError(mSubMac.Sleep());
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTrel.Sleep();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
/**
|
||||
* This method transitions all radios link to CSL sample state.
|
||||
*
|
||||
* CSL sample state is only applicable and used for 15.4 radio link. Other link are transitioned to sleep state.
|
||||
*
|
||||
* @param[in] aPanChannel The current phy channel used by the device. This param will only take effect when CSL
|
||||
* channel hasn't been explicitly specified.
|
||||
*/
|
||||
void CslSample(uint8_t aPanChannel)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aPanChannel);
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
IgnoreError(mSubMac.CslSample(aPanChannel));
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTrel.Sleep();
|
||||
#endif
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
|
||||
/**
|
||||
* This method transitions all radio links to Receive.
|
||||
*
|
||||
* @param[in] aChannel The channel to use for receiving.
|
||||
*
|
||||
*/
|
||||
void Receive(uint8_t aChannel)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
IgnoreError(mSubMac.Receive(aChannel));
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTrel.Receive(aChannel);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the radio transmit frames.
|
||||
*
|
||||
* @returns The transmit frames.
|
||||
*
|
||||
*/
|
||||
TxFrames &GetTxFrames(void) { return mTxFrames; }
|
||||
|
||||
#if !OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
/**
|
||||
* This method sends a prepared frame.
|
||||
*
|
||||
* The prepared frame is from `GetTxFrames()`. This method is available only in single radio link mode.
|
||||
*
|
||||
*/
|
||||
void Send(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
{
|
||||
otError error = mSubMac.Send();
|
||||
OT_ASSERT(error == OT_ERROR_NONE);
|
||||
OT_UNUSED_VARIABLE(error);
|
||||
}
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTrel.Send();
|
||||
#endif
|
||||
}
|
||||
|
||||
#else // #if !OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
/**
|
||||
* This method sends prepared frames over a given set of radio links.
|
||||
*
|
||||
* The prepared frame must be from `GetTxFrames()`. This method is available only in multi radio link mode.
|
||||
*
|
||||
* @param[in] aFrame A reference to a prepared frame.
|
||||
* @param[in] aRadioTypes A set of radio types to send on.
|
||||
*
|
||||
*/
|
||||
void Send(TxFrame &aFrame, RadioTypes aRadioTypes);
|
||||
|
||||
#endif // !OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
/**
|
||||
* This method gets the number of transmit retries for the last transmitted frame.
|
||||
*
|
||||
* @returns Number of transmit retries.
|
||||
*
|
||||
*/
|
||||
uint8_t GetTransmitRetries(void) const
|
||||
{
|
||||
return
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.GetTransmitRetries();
|
||||
#else
|
||||
0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the most recent RSSI measurement from radio link.
|
||||
*
|
||||
* @returns The RSSI in dBm when it is valid. `kInvalidRssiValue` when RSSI is invalid.
|
||||
*
|
||||
*/
|
||||
int8_t GetRssi(void) const
|
||||
{
|
||||
return
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.GetRssi();
|
||||
#else
|
||||
kInvalidRssiValue;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method begins energy scan.
|
||||
*
|
||||
* @param[in] aScanChannel The channel to perform the energy scan on.
|
||||
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started scanning the channel.
|
||||
* @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting.
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED Energy scan is not supported by radio link.
|
||||
*
|
||||
*/
|
||||
otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aScanChannel);
|
||||
OT_UNUSED_VARIABLE(aScanDuration);
|
||||
|
||||
return
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.EnergyScan(aScanChannel, aScanDuration);
|
||||
#else
|
||||
OT_ERROR_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the noise floor value (currently use the radio receive sensitivity value).
|
||||
*
|
||||
* @returns The noise floor value in dBm.
|
||||
*
|
||||
*/
|
||||
int8_t GetNoiseFloor(void)
|
||||
{
|
||||
return
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
mSubMac.GetNoiseFloor();
|
||||
#else
|
||||
kDefaultNoiseFloor;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This methods gets a reference to the `SubMac` instance.
|
||||
*
|
||||
* @returns A reference to the `SubMac` instance.
|
||||
*
|
||||
*/
|
||||
SubMac &GetSubMac(void) { return mSubMac; }
|
||||
|
||||
/**
|
||||
* This methods gets a reference to the `SubMac` instance.
|
||||
*
|
||||
* @returns A reference to the `SubMac` instance.
|
||||
*
|
||||
*/
|
||||
const SubMac &GetSubMac(void) const { return mSubMac; }
|
||||
|
||||
/**
|
||||
* This method returns a reference to the current MAC key (for Key Mode 1) for a given Frame.
|
||||
*
|
||||
* @param[in] aFrame The frame for which to get the MAC key.
|
||||
*
|
||||
* @returns A reference to the current MAC key.
|
||||
*
|
||||
*/
|
||||
const Key *GetCurrentMacKey(const Frame &aFrame) const;
|
||||
|
||||
/**
|
||||
* This method returns a reference to the temporary MAC key (for Key Mode 1) for a given Frame based on a given
|
||||
* Key Sequence.
|
||||
*
|
||||
* @param[in] aFrame The frame for which to get the MAC key.
|
||||
* @param[in] aKeySequence The Key Sequence number (MUST be one off (+1 or -1) from current key sequence number).
|
||||
*
|
||||
* @returns A reference to the temporary MAC key.
|
||||
*
|
||||
*/
|
||||
const Key *GetTemporaryMacKey(const Frame &aFrame, uint32_t aKeySequence) const;
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
/**
|
||||
* This method sets the current MAC frame counter value from the value from a `TxFrame`.
|
||||
*
|
||||
* @param[in] TxFrame The `TxFrame` from which to get the counter value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE If successful.
|
||||
* @retval OT_ERROR_INVALID_STATE If the raw link-layer isn't enabled.
|
||||
*
|
||||
*/
|
||||
void SetMacFrameCounter(TxFrame &aFrame);
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kDefaultNoiseFloor = -100,
|
||||
};
|
||||
|
||||
SubMac mSubMac;
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
Trel::Link mTrel;
|
||||
#endif
|
||||
|
||||
// `TxFrames` member definition should be after `mSubMac`, `mTrel`
|
||||
// definitions to allow it to use their methods from its
|
||||
// constructor.
|
||||
TxFrames mTxFrames;
|
||||
|
||||
#if !OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
ShortAddress mShortAddress;
|
||||
ExtAddress mExtAddress;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace Mac
|
||||
} // namespace ot
|
||||
|
||||
#endif // MAC_LINKS_HPP_
|
||||
@@ -180,5 +180,149 @@ exit:
|
||||
}
|
||||
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
const RadioType RadioTypes::kAllRadioTypes[kNumRadioTypes] = {
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
kRadioTypeIeee802154,
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
kRadioTypeTrel,
|
||||
#endif
|
||||
};
|
||||
|
||||
void RadioTypes::AddAll(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
Add(kRadioTypeIeee802154);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
Add(kRadioTypeTrel);
|
||||
#endif
|
||||
}
|
||||
|
||||
RadioTypes::InfoString RadioTypes::ToString(void) const
|
||||
{
|
||||
InfoString string("{");
|
||||
bool addComma = false;
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
if (Contains(kRadioTypeIeee802154))
|
||||
{
|
||||
IgnoreError(string.Append("%s%s", addComma ? ", " : " ", RadioTypeToString(kRadioTypeIeee802154)));
|
||||
addComma = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
if (Contains(kRadioTypeTrel))
|
||||
{
|
||||
IgnoreError(string.Append("%s%s", addComma ? ", " : " ", RadioTypeToString(kRadioTypeTrel)));
|
||||
addComma = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
OT_UNUSED_VARIABLE(addComma);
|
||||
|
||||
IgnoreError(string.Append(" }"));
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
const char *RadioTypeToString(RadioType aRadioType)
|
||||
{
|
||||
const char *str = "unknown";
|
||||
|
||||
switch (aRadioType)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
case kRadioTypeIeee802154:
|
||||
str = "15.4";
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
case kRadioTypeTrel:
|
||||
str = "trel";
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
uint32_t LinkFrameCounters::Get(RadioType aRadioType) const
|
||||
{
|
||||
uint32_t counter = 0;
|
||||
|
||||
switch (aRadioType)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
case kRadioTypeIeee802154:
|
||||
counter = m154Counter;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
case kRadioTypeTrel:
|
||||
counter = mTrelCounter;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
void LinkFrameCounters::Set(RadioType aRadioType, uint32_t aCounter)
|
||||
{
|
||||
switch (aRadioType)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
case kRadioTypeIeee802154:
|
||||
m154Counter = aCounter;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
case kRadioTypeTrel:
|
||||
mTrelCounter = aCounter;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
uint32_t LinkFrameCounters::GetMaximum(void) const
|
||||
{
|
||||
uint32_t counter = 0;
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
if (counter < m154Counter)
|
||||
{
|
||||
counter = m154Counter;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
if (counter < mTrelCounter)
|
||||
{
|
||||
counter = mTrelCounter;
|
||||
}
|
||||
#endif
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
void LinkFrameCounters::SetAll(uint32_t aCounter)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
m154Counter = aCounter;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTrelCounter = aCounter;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Mac
|
||||
} // namespace ot
|
||||
|
||||
@@ -635,6 +635,316 @@ private:
|
||||
};
|
||||
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
/**
|
||||
* This enumeration defines the radio link types.
|
||||
*
|
||||
*/
|
||||
enum RadioType
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
kRadioTypeIeee802154, ///< IEEE 802.15.4 (2.4GHz) link type.
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
kRadioTypeTrel, ///< Thread Radio Encapsulation link type.
|
||||
#endif
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
/**
|
||||
* This constant specifies the number of supported radio link types.
|
||||
*
|
||||
*/
|
||||
kNumRadioTypes = (((OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE) ? 1 : 0) +
|
||||
((OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE) ? 1 : 0)),
|
||||
};
|
||||
|
||||
/**
|
||||
* This class represents a set of radio links.
|
||||
*
|
||||
*/
|
||||
class RadioTypes
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kInfoStringSize = 32, ///< Max chars for the info string (`ToString()`).
|
||||
};
|
||||
|
||||
/**
|
||||
* This type defines the fixed-length `String` object returned from `ToString()`.
|
||||
*
|
||||
*/
|
||||
typedef String<kInfoStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* This static class variable defines an array containing all supported radio link types.
|
||||
*
|
||||
*/
|
||||
static const RadioType kAllRadioTypes[kNumRadioTypes];
|
||||
|
||||
/**
|
||||
* This constructor initializes a `RadioTypes` object as empty set
|
||||
*
|
||||
*/
|
||||
RadioTypes(void)
|
||||
: mBitMask(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor initializes a `RadioTypes` object with a given bit-mask.
|
||||
*
|
||||
* @param[in] aMask A bit-mask representing the radio types (the first bit corresponds to radio type 0, and so on)
|
||||
*
|
||||
*/
|
||||
RadioTypes(uint8_t aMask)
|
||||
: mBitMask(aMask)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This method clears the set.
|
||||
*
|
||||
*/
|
||||
void Clear(void) { mBitMask = 0; }
|
||||
|
||||
/**
|
||||
* This method indicates whether the set is empty or not
|
||||
*
|
||||
* @returns TRUE if the set is empty, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsEmpty(void) const { return (mBitMask == 0); }
|
||||
|
||||
/**
|
||||
* This method indicates whether the set contains only a single radio type.
|
||||
*
|
||||
* @returns TRUE if the set contains a single radio type, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool ContainsSingleRadio(void) const { return !IsEmpty() && ((mBitMask & (mBitMask - 1)) == 0); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the set contains a given radio type.
|
||||
*
|
||||
* @param[in] aType A radio link type.
|
||||
*
|
||||
* @returns TRUE if the set contains @p aType, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool Contains(RadioType aType) const { return ((mBitMask & BitFlag(aType)) != 0); }
|
||||
|
||||
/**
|
||||
* This method adds a radio type to the set.
|
||||
*
|
||||
* @param[in] aType A radio link type.
|
||||
*
|
||||
*/
|
||||
void Add(RadioType aType) { mBitMask |= BitFlag(aType); }
|
||||
|
||||
/**
|
||||
* This method adds another radio types set to the current one.
|
||||
*
|
||||
* @param[in] aTypes A radio link type set to add.
|
||||
*
|
||||
*/
|
||||
void Add(RadioTypes aTypes) { mBitMask |= aTypes.mBitMask; }
|
||||
|
||||
/**
|
||||
* This method adds all radio types supported by device to the set.
|
||||
*
|
||||
*/
|
||||
void AddAll(void);
|
||||
|
||||
/**
|
||||
* This method removes a given radio type from the set.
|
||||
*
|
||||
* @param[in] aType A radio link type.
|
||||
*
|
||||
*/
|
||||
void Remove(RadioType aType) { mBitMask &= ~BitFlag(aType); }
|
||||
|
||||
/**
|
||||
* This method gets the radio type set as a bitmask.
|
||||
*
|
||||
* The first bit in the mask corresponds to first radio type (radio type with value zero), and so on.
|
||||
*
|
||||
* @returns A bitmask representing the set of radio types.
|
||||
*
|
||||
*/
|
||||
uint8_t GetAsBitMask(void) const { return mBitMask; }
|
||||
|
||||
/**
|
||||
* This method overloads operator `-` to return a new set which is the set difference between current set and
|
||||
* a given set.
|
||||
*
|
||||
* @param[in] aOther Another radio type set.
|
||||
*
|
||||
* @returns A new set which is set difference between current one and @p aOther.
|
||||
*
|
||||
*/
|
||||
RadioTypes operator-(const RadioTypes &aOther) const { return RadioTypes(mBitMask & ~aOther.mBitMask); }
|
||||
|
||||
/**
|
||||
* This method converts the radio set to human-readable string.
|
||||
*
|
||||
* @return A string representation of the set of radio types.
|
||||
*
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
private:
|
||||
static uint8_t BitFlag(RadioType aType) { return static_cast<uint8_t>(1U << static_cast<uint8_t>(aType)); }
|
||||
|
||||
uint8_t mBitMask;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function converts a link type to a string
|
||||
*
|
||||
* @param[in] aRadioType A link type value.
|
||||
*
|
||||
* @returns A string representation of the link type.
|
||||
*
|
||||
*/
|
||||
const char *RadioTypeToString(RadioType aRadioType);
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
/**
|
||||
* This class represents Link Frame Counters for all supported radio links.
|
||||
*
|
||||
*/
|
||||
class LinkFrameCounters
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method resets all counters (set them all to zero).
|
||||
*
|
||||
*/
|
||||
void Reset(void) { SetAll(0); }
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
/**
|
||||
* This method gets the link Frame Counter for a given radio link.
|
||||
*
|
||||
* @param[in] aRadioType A radio link type.
|
||||
*
|
||||
* @returns The Link Frame Counter for radio link @p aRadioType.
|
||||
*
|
||||
*/
|
||||
uint32_t Get(RadioType aRadioType) const;
|
||||
|
||||
/**
|
||||
* This method sets the Link Frame Counter for a given radio link.
|
||||
*
|
||||
* @param[in] aRadioType A radio link type.
|
||||
* @param[in] aCounter The new counter value.
|
||||
*
|
||||
*/
|
||||
void Set(RadioType aRadioType, uint32_t aCounter);
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* This method gets the Link Frame Counter value.
|
||||
*
|
||||
* @return The Link Frame Counter value.
|
||||
*
|
||||
*/
|
||||
uint32_t Get(void) const
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
{
|
||||
return m154Counter;
|
||||
}
|
||||
#elif OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
{
|
||||
return mTrelCounter;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method sets the Link Frame Counter for a given radio link.
|
||||
*
|
||||
* @param[in] aCounter The new counter value.
|
||||
*
|
||||
*/
|
||||
void Set(uint32_t aCounter)
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
{
|
||||
m154Counter = aCounter;
|
||||
}
|
||||
#elif OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
{
|
||||
mTrelCounter = aCounter;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
/**
|
||||
* This method gets the Link Frame Counter for 802.15.4 radio link.
|
||||
*
|
||||
* @returns The Link Frame Counter for 802.15.4 radio link.
|
||||
*
|
||||
*/
|
||||
uint32_t Get154(void) const { return m154Counter; }
|
||||
|
||||
/**
|
||||
* This method sets the Link Frame Counter for 802.15.4 radio link.
|
||||
*
|
||||
* @param[in] aCounter The new counter value.
|
||||
*
|
||||
*/
|
||||
void Set154(uint32_t aCounter) { m154Counter = aCounter; }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
/**
|
||||
* This method gets the Link Frame Counter for TREL radio link.
|
||||
*
|
||||
* @returns The Link Frame Counter for TREL radio link.
|
||||
*
|
||||
*/
|
||||
uint32_t GetTrel(void) const { return mTrelCounter; }
|
||||
|
||||
/**
|
||||
* This method increments the Link Frame Counter for TREL radio link.
|
||||
*
|
||||
*/
|
||||
void IncrementTrel(void) { mTrelCounter++; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method gets the maximum Link Frame Counter among all supported radio links.
|
||||
*
|
||||
* @return The maximum Link frame Counter among all supported radio links.
|
||||
*
|
||||
*/
|
||||
uint32_t GetMaximum(void) const;
|
||||
|
||||
/**
|
||||
* This method sets the Link Frame Counter value for all radio links.
|
||||
*
|
||||
* @param[in] aCounter The Link Frame Counter value.
|
||||
*
|
||||
*/
|
||||
void SetAll(uint32_t aCounter);
|
||||
|
||||
private:
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
uint32_t m154Counter;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
uint32_t mTrelCounter;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -339,7 +339,7 @@ public:
|
||||
otError Send(void);
|
||||
|
||||
/**
|
||||
* This method gets the number of transmit retries of last transmit packet.
|
||||
* This method gets the number of transmit retries of last transmitted frame.
|
||||
*
|
||||
* @returns Number of transmit retries.
|
||||
*
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
#include "config/mle.h"
|
||||
#include "config/parent_search.h"
|
||||
#include "config/platform.h"
|
||||
#include "config/radio_link.h"
|
||||
#include "config/sntp_client.h"
|
||||
#include "config/time_sync.h"
|
||||
#include "config/tmf.h"
|
||||
|
||||
@@ -33,9 +33,11 @@
|
||||
|
||||
namespace ot {
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
|
||||
void Radio::SetExtendedAddress(const Mac::ExtAddress &aExtAddress)
|
||||
{
|
||||
otPlatRadioSetExtendedAddress(GetInstance(), &aExtAddress);
|
||||
otPlatRadioSetExtendedAddress(GetInstancePtr(), &aExtAddress);
|
||||
|
||||
#if (OPENTHREAD_MTD || OPENTHREAD_FTD) && OPENTHREAD_CONFIG_OTNS_ENABLE
|
||||
Get<Utils::Otns>().EmitExtendedAddress(aExtAddress);
|
||||
@@ -44,7 +46,7 @@ void Radio::SetExtendedAddress(const Mac::ExtAddress &aExtAddress)
|
||||
|
||||
void Radio::SetShortAddress(Mac::ShortAddress aShortAddress)
|
||||
{
|
||||
otPlatRadioSetShortAddress(GetInstance(), aShortAddress);
|
||||
otPlatRadioSetShortAddress(GetInstancePtr(), aShortAddress);
|
||||
|
||||
#if (OPENTHREAD_MTD || OPENTHREAD_FTD) && OPENTHREAD_CONFIG_OTNS_ENABLE
|
||||
Get<Utils::Otns>().EmitShortAddress(aShortAddress);
|
||||
@@ -57,7 +59,8 @@ otError Radio::Transmit(Mac::TxFrame &aFrame)
|
||||
Get<Utils::Otns>().EmitTransmit(aFrame);
|
||||
#endif
|
||||
|
||||
return otPlatRadioTransmit(GetInstance(), &aFrame);
|
||||
return otPlatRadioTransmit(GetInstancePtr(), &aFrame);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
|
||||
} // namespace ot
|
||||
|
||||
+375
-78
@@ -201,29 +201,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the radio capabilities.
|
||||
*
|
||||
* @returns The radio capability bit vector (see `OT_RADIO_CAP_*` definitions).
|
||||
*
|
||||
*/
|
||||
otRadioCaps GetCaps(void) { return otPlatRadioGetCaps(GetInstance()); }
|
||||
|
||||
/**
|
||||
* This method gets the radio version string.
|
||||
*
|
||||
* @returns A pointer to the OpenThread radio version.
|
||||
*
|
||||
*/
|
||||
const char *GetVersionString(void) { return otPlatRadioGetVersionString(GetInstance()); }
|
||||
|
||||
/**
|
||||
* This method gets the radio receive sensitivity value.
|
||||
*
|
||||
* @returns The radio receive sensitivity value in dBm.
|
||||
*
|
||||
*/
|
||||
int8_t GetReceiveSensitivity(void) { return otPlatRadioGetReceiveSensitivity(GetInstance()); }
|
||||
const char *GetVersionString(void);
|
||||
|
||||
/**
|
||||
* This method gets the factory-assigned IEEE EUI-64 for the device.
|
||||
@@ -231,7 +215,23 @@ public:
|
||||
* @param[out] aIeeeEui64 A reference to `Mac::ExtAddress` to place the factory-assigned IEEE EUI-64.
|
||||
*
|
||||
*/
|
||||
void GetIeeeEui64(Mac::ExtAddress &aIeeeEui64) { otPlatRadioGetIeeeEui64(GetInstance(), aIeeeEui64.m8); }
|
||||
void GetIeeeEui64(Mac::ExtAddress &aIeeeEui64);
|
||||
|
||||
/**
|
||||
* This method gets the radio capabilities.
|
||||
*
|
||||
* @returns The radio capability bit vector (see `OT_RADIO_CAP_*` definitions).
|
||||
*
|
||||
*/
|
||||
otRadioCaps GetCaps(void);
|
||||
|
||||
/**
|
||||
* This method gets the radio receive sensitivity value.
|
||||
*
|
||||
* @returns The radio receive sensitivity value in dBm.
|
||||
*
|
||||
*/
|
||||
int8_t GetReceiveSensitivity(void);
|
||||
|
||||
/**
|
||||
* This method sets the PAN ID for address filtering.
|
||||
@@ -239,7 +239,7 @@ public:
|
||||
* @param[in] aPanId The IEEE 802.15.4 PAN ID.
|
||||
*
|
||||
*/
|
||||
void SetPanId(Mac::PanId aPanId) { otPlatRadioSetPanId(GetInstance(), aPanId); }
|
||||
void SetPanId(Mac::PanId aPanId);
|
||||
|
||||
/**
|
||||
* This method sets the Extended Address for address filtering.
|
||||
@@ -271,10 +271,7 @@ public:
|
||||
uint8_t aKeyId,
|
||||
const Mac::Key &aPrevKey,
|
||||
const Mac::Key &aCurrKey,
|
||||
const Mac::Key &aNextKey)
|
||||
{
|
||||
otPlatRadioSetMacKey(GetInstance(), aKeyIdMode, aKeyId, &aPrevKey, &aCurrKey, &aNextKey);
|
||||
}
|
||||
const Mac::Key &aNextKey);
|
||||
|
||||
/**
|
||||
* This method sets the current MAC Frame Counter value.
|
||||
@@ -284,7 +281,7 @@ public:
|
||||
*/
|
||||
void SetMacFrameCounter(uint32_t aMacFrameCounter)
|
||||
{
|
||||
otPlatRadioSetMacFrameCounter(GetInstance(), aMacFrameCounter);
|
||||
otPlatRadioSetMacFrameCounter(GetInstancePtr(), aMacFrameCounter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,7 +293,7 @@ public:
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED Transmit power configuration via dBm is not implemented.
|
||||
*
|
||||
*/
|
||||
otError GetTransmitPower(int8_t &aPower) { return otPlatRadioGetTransmitPower(GetInstance(), &aPower); }
|
||||
otError GetTransmitPower(int8_t &aPower);
|
||||
|
||||
/**
|
||||
* This method sets the radio's transmit power in dBm.
|
||||
@@ -307,7 +304,7 @@ public:
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED Transmit power configuration via dBm is not implemented.
|
||||
*
|
||||
*/
|
||||
otError SetTransmitPower(int8_t aPower) { return otPlatRadioSetTransmitPower(GetInstance(), aPower); }
|
||||
otError SetTransmitPower(int8_t aPower);
|
||||
|
||||
/**
|
||||
* This method gets the radio's CCA ED threshold in dBm.
|
||||
@@ -318,10 +315,7 @@ public:
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED CCA ED threshold configuration via dBm is not implemented.
|
||||
*
|
||||
*/
|
||||
otError GetCcaEnergyDetectThreshold(int8_t &aThreshold)
|
||||
{
|
||||
return otPlatRadioGetCcaEnergyDetectThreshold(GetInstance(), &aThreshold);
|
||||
}
|
||||
otError GetCcaEnergyDetectThreshold(int8_t &aThreshold);
|
||||
|
||||
/**
|
||||
* This method sets the radio's CCA ED threshold in dBm.
|
||||
@@ -332,10 +326,7 @@ public:
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED CCA ED threshold configuration via dBm is not implemented.
|
||||
*
|
||||
*/
|
||||
otError SetCcaEnergyDetectThreshold(int8_t aThreshold)
|
||||
{
|
||||
return otPlatRadioSetCcaEnergyDetectThreshold(GetInstance(), aThreshold);
|
||||
}
|
||||
otError SetCcaEnergyDetectThreshold(int8_t aThreshold);
|
||||
|
||||
/**
|
||||
* This method gets the status of promiscuous mode.
|
||||
@@ -344,7 +335,7 @@ public:
|
||||
* @retval FALSE Promiscuous mode is disabled.
|
||||
*
|
||||
*/
|
||||
bool GetPromiscuous(void) { return otPlatRadioGetPromiscuous(GetInstance()); }
|
||||
bool GetPromiscuous(void);
|
||||
|
||||
/**
|
||||
* This method enables or disables promiscuous mode.
|
||||
@@ -352,7 +343,7 @@ public:
|
||||
* @param[in] aEnable TRUE to enable or FALSE to disable promiscuous mode.
|
||||
*
|
||||
*/
|
||||
void SetPromiscuous(bool aEnable) { otPlatRadioSetPromiscuous(GetInstance(), aEnable); }
|
||||
void SetPromiscuous(bool aEnable);
|
||||
|
||||
/**
|
||||
* This method returns the current state of the radio.
|
||||
@@ -364,7 +355,7 @@ public:
|
||||
* @return Current state of the radio.
|
||||
*
|
||||
*/
|
||||
otRadioState GetState(void) { return otPlatRadioGetState(GetInstance()); }
|
||||
otRadioState GetState(void);
|
||||
|
||||
/**
|
||||
* This method enables the radio.
|
||||
@@ -373,7 +364,7 @@ public:
|
||||
* @retval OT_ERROR_FAILED The radio could not be enabled.
|
||||
*
|
||||
*/
|
||||
otError Enable(void) { return otPlatRadioEnable(GetInstance()); }
|
||||
otError Enable(void);
|
||||
|
||||
/**
|
||||
* This method disables the radio.
|
||||
@@ -382,7 +373,7 @@ public:
|
||||
* @retval OT_ERROR_INVALID_STATE The radio was not in sleep state.
|
||||
*
|
||||
*/
|
||||
otError Disable(void) { return otPlatRadioDisable(GetInstance()); }
|
||||
otError Disable(void);
|
||||
|
||||
/**
|
||||
* This method indicates whether radio is enabled or not.
|
||||
@@ -390,7 +381,7 @@ public:
|
||||
* @returns TRUE if the radio is enabled, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsEnabled(void) { return otPlatRadioIsEnabled(GetInstance()); }
|
||||
bool IsEnabled(void);
|
||||
|
||||
/**
|
||||
* This method transitions the radio from Receive to Sleep (turn off the radio).
|
||||
@@ -400,7 +391,7 @@ public:
|
||||
* @retval OT_ERROR_INVALID_STATE The radio was disabled.
|
||||
*
|
||||
*/
|
||||
otError Sleep(void) { return otPlatRadioSleep(GetInstance()); }
|
||||
otError Sleep(void);
|
||||
|
||||
/**
|
||||
* This method transitions the radio from Sleep to Receive (turn on the radio).
|
||||
@@ -411,7 +402,7 @@ public:
|
||||
* @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting.
|
||||
*
|
||||
*/
|
||||
otError Receive(uint8_t aChannel) { return otPlatRadioReceive(GetInstance(), aChannel); }
|
||||
otError Receive(uint8_t aChannel);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
/**
|
||||
@@ -420,7 +411,7 @@ public:
|
||||
* @param[in] aCslSampleTime The CSL sample time.
|
||||
*
|
||||
*/
|
||||
void UpdateCslSampleTime(uint32_t aCslSampleTime) { otPlatRadioUpdateCslSampleTime(GetInstance(), aCslSampleTime); }
|
||||
void UpdateCslSampleTime(uint32_t aCslSampleTime);
|
||||
|
||||
/** This method enables CSL sampling in radio.
|
||||
*
|
||||
@@ -433,10 +424,7 @@ public:
|
||||
* @retval OT_ERROR_NONE Successfully enabled or disabled CSL.
|
||||
*
|
||||
*/
|
||||
otError EnableCsl(uint32_t aCslPeriod, const otExtAddress *aExtAddr)
|
||||
{
|
||||
return otPlatRadioEnableCsl(GetInstance(), aCslPeriod, aExtAddr);
|
||||
}
|
||||
otError EnableCsl(uint32_t aCslPeriod, const otExtAddress *aExtAddr);
|
||||
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
|
||||
/**
|
||||
@@ -447,10 +435,7 @@ public:
|
||||
* @returns A reference to the transmit frame buffer.
|
||||
*
|
||||
*/
|
||||
Mac::TxFrame &GetTransmitBuffer(void)
|
||||
{
|
||||
return *static_cast<Mac::TxFrame *>(otPlatRadioGetTransmitBuffer(GetInstance()));
|
||||
}
|
||||
Mac::TxFrame &GetTransmitBuffer(void);
|
||||
|
||||
/**
|
||||
* This method starts the transmit sequence on the radio.
|
||||
@@ -472,7 +457,7 @@ public:
|
||||
* @returns The RSSI in dBm when it is valid. 127 when RSSI is invalid.
|
||||
*
|
||||
*/
|
||||
int8_t GetRssi(void) { return otPlatRadioGetRssi(GetInstance()); }
|
||||
int8_t GetRssi(void);
|
||||
|
||||
/**
|
||||
* This method begins the energy scan sequence on the radio.
|
||||
@@ -486,10 +471,7 @@ public:
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED The radio doesn't support energy scanning.
|
||||
*
|
||||
*/
|
||||
otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration)
|
||||
{
|
||||
return otPlatRadioEnergyScan(GetInstance(), aScanChannel, aScanDuration);
|
||||
}
|
||||
otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration);
|
||||
|
||||
/**
|
||||
* This method enables/disables source address match feature.
|
||||
@@ -508,7 +490,7 @@ public:
|
||||
* @param[in] aEnable Enable/disable source address match feature.
|
||||
*
|
||||
*/
|
||||
void EnableSrcMatch(bool aEnable) { return otPlatRadioEnableSrcMatch(GetInstance(), aEnable); }
|
||||
void EnableSrcMatch(bool aEnable);
|
||||
|
||||
/**
|
||||
* This method adds a short address to the source address match table.
|
||||
@@ -519,10 +501,7 @@ public:
|
||||
* @retval OT_ERROR_NO_BUFS No available entry in the source match table.
|
||||
*
|
||||
*/
|
||||
otError AddSrcMatchShortEntry(Mac::ShortAddress aShortAddress)
|
||||
{
|
||||
return otPlatRadioAddSrcMatchShortEntry(GetInstance(), aShortAddress);
|
||||
}
|
||||
otError AddSrcMatchShortEntry(Mac::ShortAddress aShortAddress);
|
||||
|
||||
/**
|
||||
* This method adds an extended address to the source address match table.
|
||||
@@ -533,10 +512,7 @@ public:
|
||||
* @retval OT_ERROR_NO_BUFS No available entry in the source match table.
|
||||
*
|
||||
*/
|
||||
otError AddSrcMatchExtEntry(const Mac::ExtAddress &aExtAddress)
|
||||
{
|
||||
return otPlatRadioAddSrcMatchExtEntry(GetInstance(), &aExtAddress);
|
||||
}
|
||||
otError AddSrcMatchExtEntry(const Mac::ExtAddress &aExtAddress);
|
||||
|
||||
/**
|
||||
* This method removes a short address from the source address match table.
|
||||
@@ -547,10 +523,7 @@ public:
|
||||
* @retval OT_ERROR_NO_ADDRESS The short address is not in source address match table.
|
||||
*
|
||||
*/
|
||||
otError ClearSrcMatchShortEntry(Mac::ShortAddress aShortAddress)
|
||||
{
|
||||
return otPlatRadioClearSrcMatchShortEntry(GetInstance(), aShortAddress);
|
||||
}
|
||||
otError ClearSrcMatchShortEntry(Mac::ShortAddress aShortAddress);
|
||||
|
||||
/**
|
||||
* This method removes an extended address from the source address match table.
|
||||
@@ -561,22 +534,19 @@ public:
|
||||
* @retval OT_ERROR_NO_ADDRESS The extended address is not in source address match table.
|
||||
*
|
||||
*/
|
||||
otError ClearSrcMatchExtEntry(const Mac::ExtAddress &aExtAddress)
|
||||
{
|
||||
return otPlatRadioClearSrcMatchExtEntry(GetInstance(), &aExtAddress);
|
||||
}
|
||||
otError ClearSrcMatchExtEntry(const Mac::ExtAddress &aExtAddress);
|
||||
|
||||
/**
|
||||
* This method clears all short addresses from the source address match table.
|
||||
*
|
||||
*/
|
||||
void ClearSrcMatchShortEntries(void) { otPlatRadioClearSrcMatchShortEntries(GetInstance()); }
|
||||
void ClearSrcMatchShortEntries(void);
|
||||
|
||||
/**
|
||||
* This method clears all the extended/long addresses from source address match table.
|
||||
*
|
||||
*/
|
||||
void ClearSrcMatchExtEntries(void) { otPlatRadioClearSrcMatchExtEntries(GetInstance()); }
|
||||
void ClearSrcMatchExtEntries(void);
|
||||
|
||||
/**
|
||||
* This method gets the radio supported channel mask that the device is allowed to be on.
|
||||
@@ -584,7 +554,7 @@ public:
|
||||
* @returns The radio supported channel mask.
|
||||
*
|
||||
*/
|
||||
uint32_t GetSupportedChannelMask(void) { return otPlatRadioGetSupportedChannelMask(GetInstance()); }
|
||||
uint32_t GetSupportedChannelMask(void);
|
||||
|
||||
/**
|
||||
* This method gets the radio preferred channel mask that the device prefers to form on.
|
||||
@@ -592,7 +562,7 @@ public:
|
||||
* @returns The radio preferred channel mask.
|
||||
*
|
||||
*/
|
||||
uint32_t GetPreferredChannelMask(void) { return otPlatRadioGetPreferredChannelMask(GetInstance()); }
|
||||
uint32_t GetPreferredChannelMask(void);
|
||||
|
||||
/**
|
||||
* This method checks if a given channel is valid as a CSL channel.
|
||||
@@ -607,11 +577,338 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
otInstance *GetInstance(void) { return reinterpret_cast<otInstance *>(&InstanceLocator::GetInstance()); }
|
||||
otInstance *GetInstancePtr(void) { return reinterpret_cast<otInstance *>(&InstanceLocator::GetInstance()); }
|
||||
|
||||
Callbacks mCallbacks;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Radio APIs that are always mapped to the same `otPlatRadio` function (independent of the link type)
|
||||
|
||||
inline const char *Radio::GetVersionString(void)
|
||||
{
|
||||
return otPlatRadioGetVersionString(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline void Radio::GetIeeeEui64(Mac::ExtAddress &aIeeeEui64)
|
||||
{
|
||||
otPlatRadioGetIeeeEui64(GetInstancePtr(), aIeeeEui64.m8);
|
||||
}
|
||||
|
||||
inline uint32_t Radio::GetSupportedChannelMask(void)
|
||||
{
|
||||
return otPlatRadioGetSupportedChannelMask(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline uint32_t Radio::GetPreferredChannelMask(void)
|
||||
{
|
||||
return otPlatRadioGetPreferredChannelMask(GetInstancePtr());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// If IEEE 802.15.4 is among supported radio links, provide inline
|
||||
// mapping of `Radio` method to related `otPlatRadio` functions.
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
|
||||
inline otRadioCaps Radio::GetCaps(void)
|
||||
{
|
||||
return otPlatRadioGetCaps(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline int8_t Radio::GetReceiveSensitivity(void)
|
||||
{
|
||||
return otPlatRadioGetReceiveSensitivity(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline void Radio::SetPanId(Mac::PanId aPanId)
|
||||
{
|
||||
otPlatRadioSetPanId(GetInstancePtr(), aPanId);
|
||||
}
|
||||
|
||||
inline void Radio::SetMacKey(uint8_t aKeyIdMode,
|
||||
uint8_t aKeyId,
|
||||
const Mac::Key &aPrevKey,
|
||||
const Mac::Key &aCurrKey,
|
||||
const Mac::Key &aNextKey)
|
||||
{
|
||||
otPlatRadioSetMacKey(GetInstancePtr(), aKeyIdMode, aKeyId, &aPrevKey, &aCurrKey, &aNextKey);
|
||||
}
|
||||
|
||||
inline otError Radio::GetTransmitPower(int8_t &aPower)
|
||||
{
|
||||
return otPlatRadioGetTransmitPower(GetInstancePtr(), &aPower);
|
||||
}
|
||||
|
||||
inline otError Radio::SetTransmitPower(int8_t aPower)
|
||||
{
|
||||
return otPlatRadioSetTransmitPower(GetInstancePtr(), aPower);
|
||||
}
|
||||
|
||||
inline otError Radio::GetCcaEnergyDetectThreshold(int8_t &aThreshold)
|
||||
{
|
||||
return otPlatRadioGetCcaEnergyDetectThreshold(GetInstancePtr(), &aThreshold);
|
||||
}
|
||||
|
||||
inline otError Radio::SetCcaEnergyDetectThreshold(int8_t aThreshold)
|
||||
{
|
||||
return otPlatRadioSetCcaEnergyDetectThreshold(GetInstancePtr(), aThreshold);
|
||||
}
|
||||
|
||||
inline bool Radio::GetPromiscuous(void)
|
||||
{
|
||||
return otPlatRadioGetPromiscuous(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline void Radio::SetPromiscuous(bool aEnable)
|
||||
{
|
||||
otPlatRadioSetPromiscuous(GetInstancePtr(), aEnable);
|
||||
}
|
||||
|
||||
inline otRadioState Radio::GetState(void)
|
||||
{
|
||||
return otPlatRadioGetState(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline otError Radio::Enable(void)
|
||||
{
|
||||
return otPlatRadioEnable(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline otError Radio::Disable(void)
|
||||
{
|
||||
return otPlatRadioDisable(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline bool Radio::IsEnabled(void)
|
||||
{
|
||||
return otPlatRadioIsEnabled(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline otError Radio::Sleep(void)
|
||||
{
|
||||
return otPlatRadioSleep(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline otError Radio::Receive(uint8_t aChannel)
|
||||
{
|
||||
return otPlatRadioReceive(GetInstancePtr(), aChannel);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
inline void Radio::UpdateCslSampleTime(uint32_t aCslSampleTime)
|
||||
{
|
||||
otPlatRadioUpdateCslSampleTime(GetInstancePtr(), aCslSampleTime);
|
||||
}
|
||||
|
||||
inline otError Radio::EnableCsl(uint32_t aCslPeriod, const otExtAddress *aExtAddr)
|
||||
{
|
||||
return otPlatRadioEnableCsl(GetInstancePtr(), aCslPeriod, aExtAddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline Mac::TxFrame &Radio::GetTransmitBuffer(void)
|
||||
{
|
||||
return *static_cast<Mac::TxFrame *>(otPlatRadioGetTransmitBuffer(GetInstancePtr()));
|
||||
}
|
||||
|
||||
inline int8_t Radio::GetRssi(void)
|
||||
{
|
||||
return otPlatRadioGetRssi(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline otError Radio::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration)
|
||||
{
|
||||
return otPlatRadioEnergyScan(GetInstancePtr(), aScanChannel, aScanDuration);
|
||||
}
|
||||
|
||||
inline void Radio::EnableSrcMatch(bool aEnable)
|
||||
{
|
||||
otPlatRadioEnableSrcMatch(GetInstancePtr(), aEnable);
|
||||
}
|
||||
|
||||
inline otError Radio::AddSrcMatchShortEntry(Mac::ShortAddress aShortAddress)
|
||||
{
|
||||
return otPlatRadioAddSrcMatchShortEntry(GetInstancePtr(), aShortAddress);
|
||||
}
|
||||
|
||||
inline otError Radio::AddSrcMatchExtEntry(const Mac::ExtAddress &aExtAddress)
|
||||
{
|
||||
return otPlatRadioAddSrcMatchExtEntry(GetInstancePtr(), &aExtAddress);
|
||||
}
|
||||
|
||||
inline otError Radio::ClearSrcMatchShortEntry(Mac::ShortAddress aShortAddress)
|
||||
{
|
||||
return otPlatRadioClearSrcMatchShortEntry(GetInstancePtr(), aShortAddress);
|
||||
}
|
||||
|
||||
inline otError Radio::ClearSrcMatchExtEntry(const Mac::ExtAddress &aExtAddress)
|
||||
{
|
||||
return otPlatRadioClearSrcMatchExtEntry(GetInstancePtr(), &aExtAddress);
|
||||
}
|
||||
|
||||
inline void Radio::ClearSrcMatchShortEntries(void)
|
||||
{
|
||||
otPlatRadioClearSrcMatchShortEntries(GetInstancePtr());
|
||||
}
|
||||
|
||||
inline void Radio::ClearSrcMatchExtEntries(void)
|
||||
{
|
||||
otPlatRadioClearSrcMatchExtEntries(GetInstancePtr());
|
||||
}
|
||||
|
||||
#else //----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
inline otRadioCaps Radio::GetCaps(void)
|
||||
{
|
||||
return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_TRANSMIT_RETRIES;
|
||||
}
|
||||
|
||||
inline int8_t Radio::GetReceiveSensitivity(void)
|
||||
{
|
||||
return -110;
|
||||
}
|
||||
|
||||
inline void Radio::SetPanId(Mac::PanId)
|
||||
{
|
||||
}
|
||||
|
||||
inline void Radio::SetExtendedAddress(const Mac::ExtAddress &)
|
||||
{
|
||||
}
|
||||
|
||||
inline void Radio::SetShortAddress(Mac::ShortAddress)
|
||||
{
|
||||
}
|
||||
|
||||
inline void Radio::SetMacKey(uint8_t, uint8_t, const Mac::Key &, const Mac::Key &, const Mac::Key &)
|
||||
{
|
||||
}
|
||||
|
||||
inline otError Radio::GetTransmitPower(int8_t &)
|
||||
{
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
inline otError Radio::SetTransmitPower(int8_t)
|
||||
{
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
inline otError Radio::GetCcaEnergyDetectThreshold(int8_t &)
|
||||
{
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
inline otError Radio::SetCcaEnergyDetectThreshold(int8_t)
|
||||
{
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
inline bool Radio::GetPromiscuous(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void Radio::SetPromiscuous(bool)
|
||||
{
|
||||
}
|
||||
|
||||
inline otRadioState Radio::GetState(void)
|
||||
{
|
||||
return OT_RADIO_STATE_DISABLED;
|
||||
}
|
||||
|
||||
inline otError Radio::Enable(void)
|
||||
{
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
inline otError Radio::Disable(void)
|
||||
{
|
||||
return OT_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
inline bool Radio::IsEnabled(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
inline otError Radio::Sleep(void)
|
||||
{
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
inline otError Radio::Receive(uint8_t)
|
||||
{
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
inline void Radio::UpdateCslSampleTime(uint32_t)
|
||||
{
|
||||
}
|
||||
|
||||
inline otError Radio::EnableCsl(uint32_t, const otExtAddress *)
|
||||
{
|
||||
return OT_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline Mac::TxFrame &Radio::GetTransmitBuffer(void)
|
||||
{
|
||||
return *static_cast<Mac::TxFrame *>(otPlatRadioGetTransmitBuffer(GetInstancePtr()));
|
||||
}
|
||||
|
||||
inline otError Radio::Transmit(Mac::TxFrame &)
|
||||
{
|
||||
return OT_ERROR_ABORT;
|
||||
}
|
||||
|
||||
inline int8_t Radio::GetRssi(void)
|
||||
{
|
||||
return OT_RADIO_RSSI_INVALID;
|
||||
}
|
||||
|
||||
inline otError Radio::EnergyScan(uint8_t, uint16_t)
|
||||
{
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
inline void Radio::EnableSrcMatch(bool)
|
||||
{
|
||||
}
|
||||
|
||||
inline otError Radio::AddSrcMatchShortEntry(Mac::ShortAddress)
|
||||
{
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
inline otError Radio::AddSrcMatchExtEntry(const Mac::ExtAddress &)
|
||||
{
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
inline otError Radio::ClearSrcMatchShortEntry(Mac::ShortAddress)
|
||||
{
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
inline otError Radio::ClearSrcMatchExtEntry(const Mac::ExtAddress &)
|
||||
{
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
inline void Radio::ClearSrcMatchShortEntries(void)
|
||||
{
|
||||
}
|
||||
|
||||
inline void Radio::ClearSrcMatchExtEntries(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // RADIO_HPP_
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "radio/radio.hpp"
|
||||
|
||||
@@ -41,63 +42,138 @@ using namespace ot;
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// otPlatRadio callbacks
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
|
||||
extern "C" void otPlatRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
|
||||
{
|
||||
Instance *instance = static_cast<Instance *>(aInstance);
|
||||
Instance & instance = *static_cast<Instance *>(aInstance);
|
||||
Mac::RxFrame *rxFrame = static_cast<Mac::RxFrame *>(aFrame);
|
||||
|
||||
if (instance->IsInitialized())
|
||||
VerifyOrExit(instance.IsInitialized());
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (rxFrame != nullptr)
|
||||
{
|
||||
instance->Get<Radio::Callbacks>().HandleReceiveDone(static_cast<Mac::RxFrame *>(aFrame), aError);
|
||||
rxFrame->SetRadioType(Mac::kRadioTypeIeee802154);
|
||||
}
|
||||
#endif
|
||||
|
||||
instance.Get<Radio::Callbacks>().HandleReceiveDone(rxFrame, aError);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" void otPlatRadioTxStarted(otInstance *aInstance, otRadioFrame *aFrame)
|
||||
{
|
||||
Instance *instance = static_cast<Instance *>(aInstance);
|
||||
Instance & instance = *static_cast<Instance *>(aInstance);
|
||||
Mac::TxFrame &txFrame = *static_cast<Mac::TxFrame *>(aFrame);
|
||||
|
||||
if (instance->IsInitialized())
|
||||
{
|
||||
instance->Get<Radio::Callbacks>().HandleTransmitStarted(*static_cast<Mac::TxFrame *>(aFrame));
|
||||
}
|
||||
VerifyOrExit(instance.IsInitialized());
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
txFrame.SetRadioType(Mac::kRadioTypeIeee802154);
|
||||
#endif
|
||||
|
||||
instance.Get<Radio::Callbacks>().HandleTransmitStarted(txFrame);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" void otPlatRadioTxDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
|
||||
{
|
||||
Instance *instance = static_cast<Instance *>(aInstance);
|
||||
Instance & instance = *static_cast<Instance *>(aInstance);
|
||||
Mac::TxFrame &txFrame = *static_cast<Mac::TxFrame *>(aFrame);
|
||||
Mac::RxFrame *ackFrame = static_cast<Mac::RxFrame *>(aAckFrame);
|
||||
|
||||
if (instance->IsInitialized())
|
||||
VerifyOrExit(instance.IsInitialized());
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (ackFrame != nullptr)
|
||||
{
|
||||
instance->Get<Radio::Callbacks>().HandleTransmitDone(*static_cast<Mac::TxFrame *>(aFrame),
|
||||
static_cast<Mac::RxFrame *>(aAckFrame), aError);
|
||||
ackFrame->SetRadioType(Mac::kRadioTypeIeee802154);
|
||||
}
|
||||
|
||||
txFrame.SetRadioType(Mac::kRadioTypeIeee802154);
|
||||
#endif
|
||||
|
||||
instance.Get<Radio::Callbacks>().HandleTransmitDone(txFrame, ackFrame, aError);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi)
|
||||
{
|
||||
Instance *instance = static_cast<Instance *>(aInstance);
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
if (instance->IsInitialized())
|
||||
{
|
||||
instance->Get<Radio::Callbacks>().HandleEnergyScanDone(aEnergyScanMaxRssi);
|
||||
}
|
||||
VerifyOrExit(instance.IsInitialized());
|
||||
instance.Get<Radio::Callbacks>().HandleEnergyScanDone(aEnergyScanMaxRssi);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
extern "C" void otPlatDiagRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
|
||||
{
|
||||
Instance *instance = static_cast<Instance *>(aInstance);
|
||||
Instance & instance = *static_cast<Instance *>(aInstance);
|
||||
Mac::RxFrame *rxFrame = static_cast<Mac::RxFrame *>(aFrame);
|
||||
|
||||
instance->Get<Radio::Callbacks>().HandleDiagsReceiveDone(static_cast<Mac::RxFrame *>(aFrame), aError);
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (rxFrame != nullptr)
|
||||
{
|
||||
rxFrame->SetRadioType(Mac::kRadioTypeIeee802154);
|
||||
}
|
||||
#endif
|
||||
|
||||
instance.Get<Radio::Callbacks>().HandleDiagsReceiveDone(rxFrame, aError);
|
||||
}
|
||||
|
||||
extern "C" void otPlatDiagRadioTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
|
||||
{
|
||||
Instance *instance = static_cast<Instance *>(aInstance);
|
||||
Instance & instance = *static_cast<Instance *>(aInstance);
|
||||
Mac::TxFrame &txFrame = *static_cast<Mac::TxFrame *>(aFrame);
|
||||
|
||||
instance->Get<Radio::Callbacks>().HandleDiagsTransmitDone(*static_cast<Mac::TxFrame *>(aFrame), aError);
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
txFrame.SetRadioType(Mac::kRadioTypeIeee802154);
|
||||
#endif
|
||||
|
||||
instance.Get<Radio::Callbacks>().HandleDiagsTransmitDone(txFrame, aError);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
|
||||
extern "C" void otPlatRadioReceiveDone(otInstance *, otRadioFrame *, otError)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void otPlatRadioTxStarted(otInstance *, otRadioFrame *)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void otPlatRadioTxDone(otInstance *, otRadioFrame *, otRadioFrame *, otError)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void otPlatRadioEnergyScanDone(otInstance *, int8_t)
|
||||
{
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
extern "C" void otPlatDiagRadioReceiveDone(otInstance *, otRadioFrame *, otError)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void otPlatDiagRadioTransmitDone(otInstance *, otRadioFrame *, otError)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // // #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Default/weak implementation of radio platform APIs
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 Thread Radio Encapsulation Link (TREL).
|
||||
*/
|
||||
|
||||
#include "trel.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator-getters.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
Link::Link(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
{
|
||||
memset(&mTxFrame, 0, sizeof(mTxFrame));
|
||||
mTxFrame.mPsdu = &mFrameBuffer[kHeaderSize];
|
||||
mTxFrame.SetLength(0);
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mTxFrame.SetRadioType(Mac::kRadioTypeTrel);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Link::Send(void)
|
||||
{
|
||||
Get<Mac::Mac>().RecordFrameTransmitStatus(mTxFrame, NULL, OT_ERROR_ABORT, 0, false);
|
||||
Get<Mac::Mac>().HandleTransmitDone(mTxFrame, NULL, OT_ERROR_ABORT);
|
||||
}
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 Thread Radio Encapsulation Link (TREL).
|
||||
*/
|
||||
|
||||
#ifndef TREL_HPP_
|
||||
#define TREL_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/locator.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
/**
|
||||
* @addtogroup core-trel
|
||||
*
|
||||
* @brief
|
||||
* This module includes definitions for Thread Radio Encapsulation Link (TREL)
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class represents a Thread Radio Encapsulation Link (TREL).
|
||||
*
|
||||
*/
|
||||
class Link : public InstanceLocator
|
||||
{
|
||||
friend class Instance;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kMtuSize = 1600,
|
||||
kFcsSize = 0,
|
||||
};
|
||||
|
||||
explicit Link(Instance &aInstance);
|
||||
|
||||
void SetPanId(Mac::PanId) {}
|
||||
|
||||
void Enable(void) {}
|
||||
void Disable(void) {}
|
||||
|
||||
void Sleep(void) {}
|
||||
void Receive(uint8_t) {}
|
||||
void Send(void);
|
||||
|
||||
Mac::TxFrame &GetTransmitFrame(void) { return mTxFrame; }
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kHeaderSize = 10,
|
||||
};
|
||||
|
||||
Mac::TxFrame mTxFrame;
|
||||
uint8_t mFrameBuffer[kHeaderSize + kMtuSize];
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
#endif // TREL_HPP_
|
||||
@@ -165,16 +165,25 @@ uint32_t CslTxScheduler::GetNextCslTransmissionDelay(const Child &aChild,
|
||||
return static_cast<uint32_t>(nextTxWindow - aRadioNow - mCslFrameRequestAheadUs);
|
||||
}
|
||||
|
||||
otError CslTxScheduler::HandleFrameRequest(Mac::TxFrame &aFrame)
|
||||
Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Mac::TxFrame *frame = nullptr;
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
uint32_t txDelay;
|
||||
|
||||
VerifyOrExit(mCslTxChild != nullptr, error = OT_ERROR_ABORT);
|
||||
VerifyOrExit(mCslTxChild != nullptr);
|
||||
|
||||
SuccessOrExit(error = mCallbacks.PrepareFrameForChild(aFrame, mFrameContext, *mCslTxChild));
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
frame = &aTxFrames.GetTxFrame(kRadioTypeIeee802154);
|
||||
#else
|
||||
frame = &aTxFrames.GetTxFrame();
|
||||
#endif
|
||||
|
||||
VerifyOrExit(mCallbacks.PrepareFrameForChild(*frame, mFrameContext, *mCslTxChild) == OT_ERROR_NONE,
|
||||
frame = nullptr);
|
||||
mCslTxMessage = mCslTxChild->GetIndirectMessage();
|
||||
VerifyOrExit(mCslTxMessage != nullptr, error = OT_ERROR_ABORT);
|
||||
VerifyOrExit(mCslTxMessage != nullptr, frame = nullptr);
|
||||
|
||||
if (mCslTxChild->GetIndirectTxAttempts() > 0 || mCslTxChild->GetCslTxAttempts() > 0)
|
||||
{
|
||||
@@ -182,31 +191,31 @@ otError CslTxScheduler::HandleFrameRequest(Mac::TxFrame &aFrame)
|
||||
// child, we ensure to use the same frame counter, key id, and
|
||||
// data sequence number as the previous attempt.
|
||||
|
||||
aFrame.SetIsARetransmission(true);
|
||||
aFrame.SetSequence(mCslTxChild->GetIndirectDataSequenceNumber());
|
||||
frame->SetIsARetransmission(true);
|
||||
frame->SetSequence(mCslTxChild->GetIndirectDataSequenceNumber());
|
||||
|
||||
if (aFrame.GetSecurityEnabled())
|
||||
if (frame->GetSecurityEnabled())
|
||||
{
|
||||
aFrame.SetFrameCounter(mCslTxChild->GetIndirectFrameCounter());
|
||||
aFrame.SetKeyId(mCslTxChild->GetIndirectKeyId());
|
||||
frame->SetFrameCounter(mCslTxChild->GetIndirectFrameCounter());
|
||||
frame->SetKeyId(mCslTxChild->GetIndirectKeyId());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFrame.SetIsARetransmission(false);
|
||||
frame->SetIsARetransmission(false);
|
||||
}
|
||||
|
||||
aFrame.SetChannel(mCslTxChild->GetCslChannel() == 0 ? Get<Mac::Mac>().GetPanChannel()
|
||||
frame->SetChannel(mCslTxChild->GetCslChannel() == 0 ? Get<Mac::Mac>().GetPanChannel()
|
||||
: mCslTxChild->GetCslChannel());
|
||||
|
||||
GetNextCslTransmissionDelay(*mCslTxChild, otPlatRadioGetNow(&GetInstance()), txDelay);
|
||||
aFrame.SetTxDelay(txDelay);
|
||||
aFrame.SetTxDelayBaseTime(
|
||||
frame->SetTxDelay(txDelay);
|
||||
frame->SetTxDelayBaseTime(
|
||||
static_cast<uint32_t>(mCslTxChild->GetLastRxTimestamp())); // Only LSB part of the time is required.
|
||||
aFrame.SetCsmaCaEnabled(false);
|
||||
frame->SetCsmaCaEnabled(false);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
#endif // OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
return frame;
|
||||
}
|
||||
|
||||
void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, otError aError)
|
||||
|
||||
@@ -196,8 +196,8 @@ private:
|
||||
uint32_t GetNextCslTransmissionDelay(const Child &aChild, uint64_t aRadioNow, uint32_t &aDelayFromLastRx) const;
|
||||
|
||||
// Callbacks from `Mac`
|
||||
otError HandleFrameRequest(Mac::TxFrame &aFrame);
|
||||
void HandleSentFrame(const Mac::TxFrame &aFrame, otError aError);
|
||||
Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);
|
||||
void HandleSentFrame(const Mac::TxFrame &aFrame, otError aError);
|
||||
|
||||
void HandleSentFrame(const Mac::TxFrame &aFrame, otError aError, Child &aChild);
|
||||
|
||||
|
||||
@@ -177,9 +177,9 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError DiscoverScanner::PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame)
|
||||
Mac::TxFrame *DiscoverScanner::PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Mac::TxFrame *frame = &aFrame;
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
@@ -188,16 +188,16 @@ otError DiscoverScanner::PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame)
|
||||
// If scan is finished (no more channels to scan), abort the
|
||||
// Discovery Request frame tx. The handler callback is invoked &
|
||||
// state is cleared from `HandleDiscoveryRequestFrameTxDone()`.
|
||||
error = OT_ERROR_ABORT;
|
||||
frame = nullptr;
|
||||
break;
|
||||
|
||||
case kStateScanning:
|
||||
aFrame.SetChannel(mScanChannel);
|
||||
frame->SetChannel(mScanChannel);
|
||||
IgnoreError(Get<Mac::Mac>().SetTemporaryChannel(mScanChannel));
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
return frame;
|
||||
}
|
||||
|
||||
void DiscoverScanner::HandleDiscoveryRequestFrameTxDone(Message &aMessage)
|
||||
|
||||
@@ -162,9 +162,9 @@ private:
|
||||
};
|
||||
|
||||
// Methods used by `MeshForwarder`
|
||||
otError PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame);
|
||||
void HandleDiscoveryRequestFrameTxDone(Message &aMessage);
|
||||
void Stop(void) { HandleDiscoverComplete(); }
|
||||
Mac::TxFrame *PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame);
|
||||
void HandleDiscoveryRequestFrameTxDone(Message &aMessage);
|
||||
void Stop(void) { HandleDiscoverComplete(); }
|
||||
|
||||
// Methods used from `Mle`
|
||||
void HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator-getters.hpp"
|
||||
#include "common/timer.hpp"
|
||||
#include "crypto/hkdf_sha256.hpp"
|
||||
#include "thread/mle_router.hpp"
|
||||
#include "thread/thread_netif.hpp"
|
||||
|
||||
@@ -66,6 +67,14 @@ const otMasterKey KeyManager::kDefaultMasterKey = {{
|
||||
0xff,
|
||||
}};
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
const uint8_t KeyManager::kHkdfExtractSaltString[] = {'T', 'h', 'r', 'e', 'a', 'd', 'S', 'e', 'q', 'u', 'e', 'n',
|
||||
'c', 'e', 'M', 'a', 's', 't', 'e', 'r', 'K', 'e', 'y'};
|
||||
|
||||
const uint8_t KeyManager::kTrelInfoString[] = {'T', 'h', 'r', 'e', 'a', 'd', 'O', 'v', 'e',
|
||||
'r', 'I', 'n', 'f', 'r', 'a', 'K', 'e', 'y'};
|
||||
#endif
|
||||
|
||||
KeyManager::KeyManager(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mKeySequence(0)
|
||||
@@ -81,6 +90,7 @@ KeyManager::KeyManager(Instance &aInstance)
|
||||
, mSecurityPolicyFlags(kDefaultSecurityPolicyFlags)
|
||||
, mIsPskcSet(false)
|
||||
{
|
||||
mMacFrameCounters.Reset();
|
||||
mMasterKey = static_cast<const MasterKey &>(kDefaultMasterKey);
|
||||
mPskc.Clear();
|
||||
}
|
||||
@@ -117,7 +127,7 @@ otError KeyManager::SetMasterKey(const MasterKey &aKey)
|
||||
// reset parent frame counters
|
||||
parent = &Get<Mle::MleRouter>().GetParent();
|
||||
parent->SetKeySequence(0);
|
||||
parent->SetLinkFrameCounter(0);
|
||||
parent->GetLinkFrameCounters().Reset();
|
||||
parent->SetLinkAckFrameCounter(0);
|
||||
parent->SetMleFrameCounter(0);
|
||||
|
||||
@@ -126,7 +136,7 @@ otError KeyManager::SetMasterKey(const MasterKey &aKey)
|
||||
for (Router &router : Get<RouterTable>().Iterate())
|
||||
{
|
||||
router.SetKeySequence(0);
|
||||
router.SetLinkFrameCounter(0);
|
||||
router.GetLinkFrameCounters().Reset();
|
||||
router.SetLinkAckFrameCounter(0);
|
||||
router.SetMleFrameCounter(0);
|
||||
}
|
||||
@@ -135,7 +145,7 @@ otError KeyManager::SetMasterKey(const MasterKey &aKey)
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
|
||||
{
|
||||
child.SetKeySequence(0);
|
||||
child.SetLinkFrameCounter(0);
|
||||
child.GetLinkFrameCounters().Reset();
|
||||
child.SetLinkAckFrameCounter(0);
|
||||
child.SetMleFrameCounter(0);
|
||||
}
|
||||
@@ -159,20 +169,42 @@ void KeyManager::ComputeKeys(uint32_t aKeySequence, HashKeys &aHashKeys)
|
||||
hmac.Finish(aHashKeys.mHash);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
void KeyManager::ComputeTrelKey(uint32_t aKeySequence, Mac::Key &aTrelKey)
|
||||
{
|
||||
Crypto::HkdfSha256 hkdf;
|
||||
uint8_t salt[sizeof(uint32_t) + sizeof(kHkdfExtractSaltString)];
|
||||
|
||||
Encoding::BigEndian::WriteUint32(aKeySequence, salt);
|
||||
memcpy(salt + sizeof(uint32_t), kHkdfExtractSaltString, sizeof(kHkdfExtractSaltString));
|
||||
|
||||
hkdf.Extract(salt, sizeof(salt), mMasterKey.m8, sizeof(MasterKey));
|
||||
hkdf.Expand(kTrelInfoString, sizeof(kTrelInfoString), aTrelKey.m8, sizeof(Mac::Key));
|
||||
}
|
||||
#endif
|
||||
|
||||
void KeyManager::UpdateKeyMaterial(void)
|
||||
{
|
||||
HashKeys prev;
|
||||
HashKeys cur;
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
HashKeys prev;
|
||||
HashKeys next;
|
||||
#endif
|
||||
|
||||
ComputeKeys(mKeySequence - 1, prev);
|
||||
ComputeKeys(mKeySequence, cur);
|
||||
ComputeKeys(mKeySequence + 1, next);
|
||||
|
||||
mMleKey = cur.mKeys.mMleKey;
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
ComputeKeys(mKeySequence - 1, prev);
|
||||
ComputeKeys(mKeySequence + 1, next);
|
||||
|
||||
Get<Mac::SubMac>().SetMacKey(Mac::Frame::kKeyIdMode1, (mKeySequence & 0x7f) + 1, prev.mKeys.mMacKey,
|
||||
cur.mKeys.mMacKey, next.mKeys.mMacKey);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
ComputeTrelKey(mKeySequence, mTrelKey);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence)
|
||||
@@ -194,7 +226,7 @@ void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence)
|
||||
mKeySequence = aKeySequence;
|
||||
UpdateKeyMaterial();
|
||||
|
||||
SetMacFrameCounter(0);
|
||||
mMacFrameCounters.Reset();
|
||||
mMleFrameCounter = 0;
|
||||
|
||||
Get<Notifier>().Signal(kEventThreadKeySeqCounterChanged);
|
||||
@@ -213,23 +245,51 @@ const Mle::Key &KeyManager::GetTemporaryMleKey(uint32_t aKeySequence)
|
||||
return mTemporaryMleKey;
|
||||
}
|
||||
|
||||
uint32_t KeyManager::GetMacFrameCounter(void) const
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
const Mac::Key &KeyManager::GetTemporaryTrelMacKey(uint32_t aKeySequence)
|
||||
{
|
||||
return Get<Mac::SubMac>().GetFrameCounter();
|
||||
}
|
||||
ComputeTrelKey(aKeySequence, mTemporaryTrelKey);
|
||||
|
||||
void KeyManager::SetMacFrameCounter(uint32_t aMacFrameCounter)
|
||||
return mTemporaryTrelKey;
|
||||
}
|
||||
#endif
|
||||
|
||||
void KeyManager::SetAllMacFrameCounters(uint32_t aMacFrameCounter)
|
||||
{
|
||||
mMacFrameCounters.SetAll(aMacFrameCounter);
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
Get<Mac::SubMac>().SetFrameCounter(aMacFrameCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
void KeyManager::MacFrameCounterUpdated(uint32_t aMacFrameCounter)
|
||||
{
|
||||
if (aMacFrameCounter >= mStoredMacFrameCounter)
|
||||
mMacFrameCounters.Set154(aMacFrameCounter);
|
||||
|
||||
if (mMacFrameCounters.Get154() >= mStoredMacFrameCounter)
|
||||
{
|
||||
IgnoreError(Get<Mle::MleRouter>().Store());
|
||||
}
|
||||
}
|
||||
#else
|
||||
void KeyManager::MacFrameCounterUpdated(uint32_t)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
void KeyManager::IncrementTrelMacFrameCounter(void)
|
||||
{
|
||||
mMacFrameCounters.IncrementTrel();
|
||||
|
||||
if (mMacFrameCounters.GetTrel() >= mStoredMacFrameCounter)
|
||||
{
|
||||
IgnoreError(Get<Mle::MleRouter>().Store());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void KeyManager::IncrementMleFrameCounter(void)
|
||||
{
|
||||
|
||||
@@ -209,39 +209,85 @@ public:
|
||||
*/
|
||||
void SetCurrentKeySequence(uint32_t aKeySequence);
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
/**
|
||||
* This method returns a pointer to the current MLE key.
|
||||
* This method returns the current MAC key for TREL radio link.
|
||||
*
|
||||
* @returns A pointer to the current MLE key.
|
||||
* @returns The current TREL MAC key.
|
||||
*
|
||||
*/
|
||||
const Mac::Key &GetCurrentTrelMacKey(void) const { return mTrelKey; }
|
||||
|
||||
/**
|
||||
* This method returns a temporary MAC key for TREL radio link computed from the given key sequence.
|
||||
*
|
||||
* @param[in] aKeySequence The key sequence value.
|
||||
*
|
||||
* @returns The temporary TREL MAC key.
|
||||
*
|
||||
*/
|
||||
const Mac::Key &GetTemporaryTrelMacKey(uint32_t aKeySequence);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method returns the current MLE key.
|
||||
*
|
||||
* @returns The current MLE key.
|
||||
*
|
||||
*/
|
||||
const Mle::Key &GetCurrentMleKey(void) const { return mMleKey; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to a temporary MLE key computed from the given key sequence.
|
||||
* This method returns a temporary MLE key computed from the given key sequence.
|
||||
*
|
||||
* @param[in] aKeySequence The key sequence value.
|
||||
*
|
||||
* @returns A pointer to the temporary MLE key.
|
||||
* @returns The temporary MLE key.
|
||||
*
|
||||
*/
|
||||
const Mle::Key &GetTemporaryMleKey(uint32_t aKeySequence);
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
/**
|
||||
* This method returns the current MAC Frame Counter value.
|
||||
* This method returns the current MAC Frame Counter value for 15.4 radio link.
|
||||
*
|
||||
* @returns The current MAC Frame Counter value.
|
||||
*
|
||||
*/
|
||||
uint32_t GetMacFrameCounter(void) const;
|
||||
uint32_t Get154MacFrameCounter(void) const { return mMacFrameCounters.Get154(); }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
/**
|
||||
* This method returns the current MAC Frame Counter value for TREL radio link.
|
||||
*
|
||||
* @returns The current MAC Frame Counter value for TREL radio link.
|
||||
*
|
||||
*/
|
||||
uint32_t GetTrelMacFrameCounter(void) const { return mMacFrameCounters.GetTrel(); }
|
||||
|
||||
/**
|
||||
* This method sets the current MAC Frame Counter value.
|
||||
* This method increments the current MAC Frame Counter value for TREL radio link.
|
||||
*
|
||||
*/
|
||||
void IncrementTrelMacFrameCounter(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method gets the maximum MAC Frame Counter among all supported radio links.
|
||||
*
|
||||
* @return The maximum MAC frame Counter among all supported radio links.
|
||||
*
|
||||
*/
|
||||
uint32_t GetMaximumMacFrameCounter(void) const { return mMacFrameCounters.GetMaximum(); }
|
||||
|
||||
/**
|
||||
* This method sets the current MAC Frame Counter value for all radio links.
|
||||
*
|
||||
* @param[in] aMacFrameCounter The MAC Frame Counter value.
|
||||
*
|
||||
*/
|
||||
void SetMacFrameCounter(uint32_t aMacFrameCounter);
|
||||
void SetAllMacFrameCounters(uint32_t aMacFrameCounter);
|
||||
|
||||
/**
|
||||
* This method sets the MAC Frame Counter value which is stored in non-volatile memory.
|
||||
@@ -447,9 +493,9 @@ public:
|
||||
void UpdateKeyMaterial(void);
|
||||
|
||||
/**
|
||||
* This method handles MAC frame counter change.
|
||||
* This method handles MAC frame counter change (callback from `SubMac` for 15.4 security frame change)
|
||||
*
|
||||
* @param[in] aMacFrameCounter The MAC frame counter value.
|
||||
* @param[in] aMacFrameCounter The 15.4 link MAC frame counter value.
|
||||
*
|
||||
*/
|
||||
void MacFrameCounterUpdated(uint32_t aMacFrameCounter);
|
||||
@@ -477,6 +523,10 @@ private:
|
||||
|
||||
void ComputeKeys(uint32_t aKeySequence, HashKeys &aHashKeys);
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
void ComputeTrelKey(uint32_t aKeySequence, Mac::Key &aTrelKey);
|
||||
#endif
|
||||
|
||||
void StartKeyRotationTimer(void);
|
||||
static void HandleKeyRotationTimer(Timer &aTimer);
|
||||
void HandleKeyRotationTimer(void);
|
||||
@@ -484,15 +534,26 @@ private:
|
||||
static const uint8_t kThreadString[];
|
||||
static const otMasterKey kDefaultMasterKey;
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
static const uint8_t kHkdfExtractSaltString[];
|
||||
static const uint8_t kTrelInfoString[];
|
||||
#endif
|
||||
|
||||
MasterKey mMasterKey;
|
||||
|
||||
uint32_t mKeySequence;
|
||||
Mle::Key mMleKey;
|
||||
Mle::Key mTemporaryMleKey;
|
||||
|
||||
uint32_t mMleFrameCounter;
|
||||
uint32_t mStoredMacFrameCounter;
|
||||
uint32_t mStoredMleFrameCounter;
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
Mac::Key mTrelKey;
|
||||
Mac::Key mTemporaryTrelKey;
|
||||
#endif
|
||||
|
||||
Mac::LinkFrameCounters mMacFrameCounters;
|
||||
uint32_t mMleFrameCounter;
|
||||
uint32_t mStoredMacFrameCounter;
|
||||
uint32_t mStoredMleFrameCounter;
|
||||
|
||||
uint32_t mHoursSinceKeyRotation;
|
||||
uint32_t mKeyRotationTime;
|
||||
|
||||
@@ -74,6 +74,9 @@ void ThreadLinkInfo::SetFrom(const Mac::RxFrame &aFrame)
|
||||
mTimeSyncSeq = aFrame.ReadTimeSyncSeq();
|
||||
}
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mRadioType = static_cast<uint8_t>(aFrame.GetRadioType());
|
||||
#endif
|
||||
}
|
||||
|
||||
MeshForwarder::MeshForwarder(Instance &aInstance)
|
||||
@@ -462,12 +465,29 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError MeshForwarder::HandleFrameRequest(Mac::TxFrame &aFrame)
|
||||
Mac::TxFrame *MeshForwarder::HandleFrameRequest(Mac::TxFrames &aTxFrames)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Mac::TxFrame *frame = nullptr;
|
||||
bool addFragHeader = false;
|
||||
|
||||
VerifyOrExit(mEnabled, error = OT_ERROR_ABORT);
|
||||
VerifyOrExit(mSendMessage != nullptr, error = OT_ERROR_ABORT);
|
||||
VerifyOrExit(mEnabled && (mSendMessage != nullptr));
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
frame = &Get<RadioSelector>().SelectRadio(*mSendMessage, mMacDest, aTxFrames);
|
||||
|
||||
// If multi-radio link is supported, when sending frame with link
|
||||
// security enabled, Fragment Header is always included (even if
|
||||
// the message is small and does not require 6LoWPAN fragmentation).
|
||||
// This allows the Fragment Header's tag to be used to detect and
|
||||
// suppress duplicate received frames over different radio links.
|
||||
|
||||
if (mSendMessage->IsLinkSecurityEnabled())
|
||||
{
|
||||
addFragHeader = true;
|
||||
}
|
||||
#else
|
||||
frame = &aTxFrames.GetTxFrame();
|
||||
#endif
|
||||
|
||||
mSendBusy = true;
|
||||
|
||||
@@ -476,7 +496,8 @@ otError MeshForwarder::HandleFrameRequest(Mac::TxFrame &aFrame)
|
||||
case Message::kTypeIp6:
|
||||
if (mSendMessage->GetSubType() == Message::kSubTypeMleDiscoverRequest)
|
||||
{
|
||||
SuccessOrExit(error = Get<Mle::DiscoverScanner>().PrepareDiscoveryRequestFrame(aFrame));
|
||||
frame = Get<Mle::DiscoverScanner>().PrepareDiscoveryRequestFrame(*frame);
|
||||
VerifyOrExit(frame != nullptr);
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
if (Get<Mac::Mac>().IsCslEnabled() && mSendMessage->IsSubTypeMle())
|
||||
@@ -484,18 +505,17 @@ otError MeshForwarder::HandleFrameRequest(Mac::TxFrame &aFrame)
|
||||
mSendMessage->SetLinkSecurityEnabled(true);
|
||||
}
|
||||
#endif
|
||||
mMessageNextOffset =
|
||||
PrepareDataFrame(aFrame, *mSendMessage, mMacSource, mMacDest, mAddMeshHeader, mMeshSource, mMeshDest);
|
||||
mMessageNextOffset = PrepareDataFrame(*frame, *mSendMessage, mMacSource, mMacDest, mAddMeshHeader, mMeshSource,
|
||||
mMeshDest, addFragHeader);
|
||||
|
||||
if ((mSendMessage->GetSubType() == Message::kSubTypeMleChildIdRequest) && mSendMessage->IsLinkSecurityEnabled())
|
||||
{
|
||||
otLogNoteMac("Child ID Request requires fragmentation, aborting tx");
|
||||
mMessageNextOffset = mSendMessage->GetLength();
|
||||
error = OT_ERROR_ABORT;
|
||||
ExitNow();
|
||||
ExitNow(frame = nullptr);
|
||||
}
|
||||
|
||||
OT_ASSERT(aFrame.GetLength() != 7);
|
||||
OT_ASSERT(frame->GetLength() != 7);
|
||||
break;
|
||||
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
@@ -504,7 +524,7 @@ otError MeshForwarder::HandleFrameRequest(Mac::TxFrame &aFrame)
|
||||
Mac::Address macDestAddr;
|
||||
|
||||
macDestAddr.SetShort(Get<Mle::MleRouter>().GetParent().GetRloc16());
|
||||
PrepareEmptyFrame(aFrame, macDestAddr, /* aAckRequest */ true);
|
||||
PrepareEmptyFrame(*frame, macDestAddr, /* aAckRequest */ true);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@@ -512,7 +532,7 @@ otError MeshForwarder::HandleFrameRequest(Mac::TxFrame &aFrame)
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
case Message::kType6lowpan:
|
||||
SendMesh(*mSendMessage, aFrame);
|
||||
SendMesh(*mSendMessage, *frame);
|
||||
break;
|
||||
|
||||
case Message::kTypeSupervision:
|
||||
@@ -527,24 +547,25 @@ otError MeshForwarder::HandleFrameRequest(Mac::TxFrame &aFrame)
|
||||
|
||||
default:
|
||||
mMessageNextOffset = mSendMessage->GetLength();
|
||||
error = OT_ERROR_ABORT;
|
||||
ExitNow();
|
||||
ExitNow(frame = nullptr);
|
||||
}
|
||||
|
||||
aFrame.SetIsARetransmission(false);
|
||||
frame->SetIsARetransmission(false);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
return frame;
|
||||
}
|
||||
|
||||
// This method constructs a MAC data from from a given IPv6 message.
|
||||
//
|
||||
// This method handles generation of MAC header, mesh header (if
|
||||
// requested), lowpan compression of IPv6 header, lowpan fragmentation
|
||||
// header (if message requires fragmentation). It uses the message
|
||||
// offset to construct next fragments. This method enables link security
|
||||
// when message is MLE type and requires fragmentation. It returns the
|
||||
// next offset into the message after the prepared frame.
|
||||
// header (if message requires fragmentation or if it is explicitly
|
||||
// requested by setting `aAddFragHeader` to `true`) It uses the
|
||||
// message offset to construct next fragments. This method enables
|
||||
// link security when message is MLE type and requires fragmentation.
|
||||
// It returns the next offset into the message after the prepared
|
||||
// frame.
|
||||
//
|
||||
uint16_t MeshForwarder::PrepareDataFrame(Mac::TxFrame & aFrame,
|
||||
Message & aMessage,
|
||||
@@ -552,7 +573,8 @@ uint16_t MeshForwarder::PrepareDataFrame(Mac::TxFrame & aFrame,
|
||||
const Mac::Address &aMacDest,
|
||||
bool aAddMeshHeader,
|
||||
uint16_t aMeshSource,
|
||||
uint16_t aMeshDest)
|
||||
uint16_t aMeshDest,
|
||||
bool aAddFragHeader)
|
||||
{
|
||||
uint16_t fcf;
|
||||
uint8_t *payload;
|
||||
@@ -723,7 +745,7 @@ start:
|
||||
payloadLength = aMessage.GetLength() - aMessage.GetOffset();
|
||||
fragmentLength = aFrame.GetMaxPayloadLength() - headerLength;
|
||||
|
||||
if (payloadLength > fragmentLength)
|
||||
if ((payloadLength > fragmentLength) || aAddFragHeader)
|
||||
{
|
||||
Lowpan::FragmentHeader fragmentHeader;
|
||||
|
||||
@@ -754,7 +776,13 @@ start:
|
||||
|
||||
payload += Lowpan::FragmentHeader::kFirstFragmentHeaderSize;
|
||||
headerLength += Lowpan::FragmentHeader::kFirstFragmentHeaderSize;
|
||||
payloadLength = (aFrame.GetMaxPayloadLength() - headerLength) & ~0x7;
|
||||
|
||||
fragmentLength = aFrame.GetMaxPayloadLength() - headerLength;
|
||||
|
||||
if (payloadLength > fragmentLength)
|
||||
{
|
||||
payloadLength = fragmentLength & ~0x7;
|
||||
}
|
||||
}
|
||||
|
||||
payload += hcLength;
|
||||
@@ -817,25 +845,70 @@ Neighbor *MeshForwarder::UpdateNeighborOnSentFrame(Mac::TxFrame &aFrame, otError
|
||||
|
||||
VerifyOrExit(aFrame.GetAckRequest());
|
||||
|
||||
if (aError == OT_ERROR_NONE)
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
// TREL radio link uses deferred ack model. We ignore
|
||||
// `SendDone` event from `Mac` layer with success status and
|
||||
// wait for deferred ack callback instead.
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (aFrame.GetRadioType() == Mac::kRadioTypeTrel)
|
||||
#endif
|
||||
{
|
||||
neighbor->ResetLinkFailures();
|
||||
VerifyOrExit(aError != OT_ERROR_NONE);
|
||||
}
|
||||
else if (aError == OT_ERROR_NO_ACK)
|
||||
{
|
||||
neighbor->IncrementLinkFailures();
|
||||
VerifyOrExit(Mle::Mle::IsActiveRouter(neighbor->GetRloc16()));
|
||||
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
if (neighbor->GetLinkFailures() >= Mle::kFailedRouterTransmissions)
|
||||
{
|
||||
Get<Mle::MleRouter>().RemoveRouterLink(*static_cast<Router *>(neighbor));
|
||||
}
|
||||
}
|
||||
UpdateNeighborLinkFailures(*neighbor, aError, /* aAllowNeighborRemove */ true);
|
||||
|
||||
exit:
|
||||
return neighbor;
|
||||
}
|
||||
|
||||
void MeshForwarder::UpdateNeighborLinkFailures(Neighbor &aNeighbor, otError aError, bool aAllowNeighborRemove)
|
||||
{
|
||||
// Update neighbor `LinkFailures` counter on ack error.
|
||||
|
||||
if (aError == OT_ERROR_NONE)
|
||||
{
|
||||
aNeighbor.ResetLinkFailures();
|
||||
}
|
||||
else if (aError == OT_ERROR_NO_ACK)
|
||||
{
|
||||
aNeighbor.IncrementLinkFailures();
|
||||
|
||||
if (aAllowNeighborRemove && (Mle::Mle::IsActiveRouter(aNeighbor.GetRloc16())) &&
|
||||
(aNeighbor.GetLinkFailures() >= Mle::kFailedRouterTransmissions))
|
||||
{
|
||||
Get<Mle::MleRouter>().RemoveRouterLink(static_cast<Router &>(aNeighbor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
void MeshForwarder::HandleDeferredAck(Neighbor &aNeighbor, otError aError)
|
||||
{
|
||||
bool allowNeighborRemove = true;
|
||||
|
||||
VerifyOrExit(mEnabled);
|
||||
|
||||
if (aError == OT_ERROR_NO_ACK)
|
||||
{
|
||||
otLogInfoMac("Deferred ack timeout on trel for neighbor %s rloc16:0x%04x",
|
||||
aNeighbor.GetExtAddress().ToString().AsCString(), aNeighbor.GetRloc16());
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
// In multi radio mode, `RadioSelector` will update the neighbor's
|
||||
// link failure counter and removes the neighbor if required.
|
||||
Get<RadioSelector>().UpdateOnDeferredAck(aNeighbor, aError, allowNeighborRemove);
|
||||
#else
|
||||
UpdateNeighborLinkFailures(aNeighbor, aError, allowNeighborRemove);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, otError aError)
|
||||
{
|
||||
Neighbor * neighbor = nullptr;
|
||||
@@ -854,10 +927,19 @@ void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, otError aError)
|
||||
neighbor = UpdateNeighborOnSentFrame(aFrame, aError, macDest);
|
||||
}
|
||||
|
||||
UpdateSendMessage(aError, macDest, neighbor);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MeshForwarder::UpdateSendMessage(otError aFrameTxError, Mac::Address &aMacDest, Neighbor *aNeighbor)
|
||||
{
|
||||
VerifyOrExit(mSendMessage != nullptr);
|
||||
|
||||
OT_ASSERT(mSendMessage->GetDirectTransmission());
|
||||
|
||||
if (aError != OT_ERROR_NONE)
|
||||
if (aFrameTxError != OT_ERROR_NONE)
|
||||
{
|
||||
// If the transmission of any fragment frame fails,
|
||||
// the overall message transmission is considered
|
||||
@@ -880,14 +962,14 @@ void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, otError aError)
|
||||
}
|
||||
else
|
||||
{
|
||||
otError txError = aError;
|
||||
otError txError = aFrameTxError;
|
||||
|
||||
mSendMessage->ClearDirectTransmission();
|
||||
mSendMessage->SetOffset(0);
|
||||
|
||||
if (neighbor != nullptr)
|
||||
if (aNeighbor != nullptr)
|
||||
{
|
||||
neighbor->GetLinkInfo().AddMessageTxStatus(mSendMessage->GetTxSuccess());
|
||||
aNeighbor->GetLinkInfo().AddMessageTxStatus(mSendMessage->GetTxSuccess());
|
||||
}
|
||||
|
||||
#if !OPENTHREAD_CONFIG_DROP_MESSAGE_ON_FRAGMENT_TX_FAILURE
|
||||
@@ -896,7 +978,7 @@ void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, otError aError)
|
||||
// disabled, all fragment frames of a larger message are
|
||||
// sent even if the transmission of an earlier fragment fail.
|
||||
// Note that `GetTxSuccess() tracks the tx success of the
|
||||
// entire message, while `aError` represents the error
|
||||
// entire message, while `aFrameTxError` represents the error
|
||||
// status of the last fragment frame transmission.
|
||||
|
||||
if (!mSendMessage->GetTxSuccess() && (txError == OT_ERROR_NONE))
|
||||
@@ -905,7 +987,7 @@ void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, otError aError)
|
||||
}
|
||||
#endif
|
||||
|
||||
LogMessage(kMessageTransmit, *mSendMessage, &macDest, txError);
|
||||
LogMessage(kMessageTransmit, *mSendMessage, &aMacDest, txError);
|
||||
|
||||
if (mSendMessage->GetType() == Message::kTypeIp6)
|
||||
{
|
||||
@@ -946,11 +1028,7 @@ void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, otError aError)
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (mEnabled)
|
||||
{
|
||||
mScheduleTransmissionTask.Post();
|
||||
}
|
||||
mScheduleTransmissionTask.Post();
|
||||
}
|
||||
|
||||
void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
|
||||
@@ -1032,6 +1110,41 @@ void MeshForwarder::HandleFragment(const uint8_t * aFrame,
|
||||
aFrame += fragmentHeaderLength;
|
||||
aFrameLength -= fragmentHeaderLength;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
if (aLinkInfo.mLinkSecurity)
|
||||
{
|
||||
Neighbor *neighbor = Get<NeighborTable>().FindNeighbor(aMacSource, Neighbor::kInStateAnyExceptInvalid);
|
||||
|
||||
if (neighbor != nullptr)
|
||||
{
|
||||
uint16_t tag = fragmentHeader.GetDatagramTag();
|
||||
|
||||
if (neighbor->IsLastRxFragmentTagSet())
|
||||
{
|
||||
VerifyOrExit(!neighbor->IsLastRxFragmentTagAfter(tag), error = OT_ERROR_DUPLICATED);
|
||||
|
||||
if (neighbor->GetLastRxFragmentTag() == tag)
|
||||
{
|
||||
VerifyOrExit(fragmentHeader.GetDatagramOffset() != 0, error = OT_ERROR_DUPLICATED);
|
||||
|
||||
// Duplication suppression for a "next fragment" is handled
|
||||
// by the code below where the the datagram offset is
|
||||
// checked against the offset of the corresponding message
|
||||
// (same datagram tag and size) in Reassembly List. Note
|
||||
// that if there is no matching message in the Reassembly
|
||||
// List (e.g., in case the message is already fully
|
||||
// assembled) the received "next fragment" frame would be
|
||||
// dropped.
|
||||
}
|
||||
}
|
||||
|
||||
neighbor->SetLastRxFragmentTag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
if (fragmentHeader.GetDatagramOffset() == 0)
|
||||
{
|
||||
uint16_t datagramSize = fragmentHeader.GetDatagramSize();
|
||||
@@ -1509,19 +1622,27 @@ void MeshForwarder::LogIp6Message(MessageAction aAction,
|
||||
uint16_t sourcePort;
|
||||
uint16_t destPort;
|
||||
bool shouldLogRss;
|
||||
bool shouldLogRadio = false;
|
||||
const char *radioString = "";
|
||||
|
||||
SuccessOrExit(ParseIp6UdpTcpHeader(aMessage, ip6Header, checksum, sourcePort, destPort));
|
||||
|
||||
shouldLogRss = (aAction == kMessageReceive) || (aAction == kMessageReassemblyDrop);
|
||||
|
||||
otLogMac(aLogLevel, "%s IPv6 %s msg, len:%d, chksum:%04x%s%s, sec:%s%s%s, prio:%s%s%s",
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
shouldLogRadio = true;
|
||||
radioString = aMessage.IsRadioTypeSet() ? RadioTypeToString(aMessage.GetRadioType()) : "all";
|
||||
#endif
|
||||
|
||||
otLogMac(aLogLevel, "%s IPv6 %s msg, len:%d, chksum:%04x%s%s, sec:%s%s%s, prio:%s%s%s%s%s",
|
||||
MessageActionToString(aAction, aError), Ip6::Ip6::IpProtoToString(ip6Header.GetNextHeader()),
|
||||
aMessage.GetLength(), checksum,
|
||||
(aMacAddress == nullptr) ? "" : ((aAction == kMessageReceive) ? ", from:" : ", to:"),
|
||||
(aMacAddress == nullptr) ? "" : aMacAddress->ToString().AsCString(),
|
||||
aMessage.IsLinkSecurityEnabled() ? "yes" : "no", (aError == OT_ERROR_NONE) ? "" : ", error:",
|
||||
(aError == OT_ERROR_NONE) ? "" : otThreadErrorToString(aError), MessagePriorityToString(aMessage),
|
||||
shouldLogRss ? ", rss:" : "", shouldLogRss ? aMessage.GetRssAverager().ToString().AsCString() : "");
|
||||
shouldLogRss ? ", rss:" : "", shouldLogRss ? aMessage.GetRssAverager().ToString().AsCString() : "",
|
||||
shouldLogRadio ? ", radio:" : "", radioString);
|
||||
|
||||
if (aAction != kMessagePrepareIndirect)
|
||||
{
|
||||
|
||||
@@ -306,6 +306,24 @@ public:
|
||||
*/
|
||||
const PriorityQueue &GetResolvingQueue(void) const { return mResolvingQueue; }
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
/**
|
||||
* This method handles a deferred ack.
|
||||
*
|
||||
* Some radio links can use deferred ack logic, where a tx request always report `HandleSentFrame()` quickly. The
|
||||
* link layer would wait for the ack and report it at a later time using this method.
|
||||
*
|
||||
* The link layer is expected to call `HandleDeferredAck()` (with success or failure status) for every tx request
|
||||
* on the radio link.
|
||||
*
|
||||
* @param[in] aNeighbor The neighbor for which the deferred ack status is being reported.
|
||||
* @param[in] aTxError The deferred ack error status: `OT_ERROR_NONE` to indicate a deferred ack was received,
|
||||
* `OT_ERROR_NO_ACK` to indicate an ack timeout.
|
||||
*
|
||||
*/
|
||||
void HandleDeferredAck(Neighbor &aNeighbor, otError aTxError);
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum : uint8_t
|
||||
{
|
||||
@@ -415,7 +433,8 @@ private:
|
||||
const Mac::Address &aMacDest,
|
||||
bool aAddMeshHeader = false,
|
||||
uint16_t aMeshSource = 0xffff,
|
||||
uint16_t aMeshDest = 0xffff);
|
||||
uint16_t aMeshDest = 0xffff,
|
||||
bool aAddFragHeader = false);
|
||||
void PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address &aMacDest, bool aAckRequest);
|
||||
|
||||
void SendMesh(Message &aMessage, Mac::TxFrame &aFrame);
|
||||
@@ -433,10 +452,12 @@ private:
|
||||
void RemoveMessage(Message &aMessage);
|
||||
void HandleDiscoverComplete(void);
|
||||
|
||||
void HandleReceivedFrame(Mac::RxFrame &aFrame);
|
||||
otError HandleFrameRequest(Mac::TxFrame &aFrame);
|
||||
Neighbor *UpdateNeighborOnSentFrame(Mac::TxFrame &aFrame, otError aError, const Mac::Address &aMacDest);
|
||||
void HandleSentFrame(Mac::TxFrame &aFrame, otError aError);
|
||||
void HandleReceivedFrame(Mac::RxFrame &aFrame);
|
||||
Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);
|
||||
Neighbor * UpdateNeighborOnSentFrame(Mac::TxFrame &aFrame, otError aError, const Mac::Address &aMacDest);
|
||||
void UpdateNeighborLinkFailures(Neighbor &aNeighbor, otError aError, bool aAllowNeighborRemove);
|
||||
void HandleSentFrame(Mac::TxFrame &aFrame, otError aError);
|
||||
void UpdateSendMessage(otError aFrameTxError, Mac::Address &aMacDest, Neighbor *aNeighbor);
|
||||
|
||||
void HandleTimeTick(void);
|
||||
static void ScheduleTransmissionTask(Tasklet &aTasklet);
|
||||
|
||||
@@ -671,8 +671,22 @@ void MeshForwarder::HandleMesh(uint8_t * aFrame,
|
||||
message->WriteBytes(offset, aFrame, aFrameLength);
|
||||
message->SetLinkInfo(aLinkInfo);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
// We set the received radio type on the message in order for it
|
||||
// to be logged correctly from LogMessage().
|
||||
message->SetRadioType(static_cast<Mac::RadioType>(aLinkInfo.mRadioType));
|
||||
#endif
|
||||
|
||||
LogMessage(kMessageReceive, *message, &aMacSource, OT_ERROR_NONE);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
// Since the message will be forwarded, we clear the radio
|
||||
// type on the message to allow the radio type for tx to be
|
||||
// selected later (based on the radios supported by the next
|
||||
// hop).
|
||||
message->ClearRadioType();
|
||||
#endif
|
||||
|
||||
IgnoreError(SendMessage(*message));
|
||||
}
|
||||
|
||||
@@ -990,6 +1004,8 @@ otError MeshForwarder::LogMeshFragmentHeader(MessageAction aAction,
|
||||
Lowpan::MeshHeader meshHeader;
|
||||
Lowpan::FragmentHeader fragmentHeader;
|
||||
uint16_t headerLength;
|
||||
bool shouldLogRadio = false;
|
||||
const char * radioString = "";
|
||||
|
||||
SuccessOrExit(meshHeader.ParseFrom(aMessage, headerLength));
|
||||
|
||||
@@ -1006,15 +1022,21 @@ otError MeshForwarder::LogMeshFragmentHeader(MessageAction aAction,
|
||||
|
||||
shouldLogRss = (aAction == kMessageReceive) || (aAction == kMessageReassemblyDrop);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
shouldLogRadio = true;
|
||||
radioString = aMessage.IsRadioTypeSet() ? RadioTypeToString(aMessage.GetRadioType()) : "all";
|
||||
#endif
|
||||
|
||||
otLogMac(
|
||||
aLogLevel, "%s mesh frame, len:%d%s%s, msrc:%s, mdst:%s, hops:%d, frag:%s, sec:%s%s%s%s%s",
|
||||
aLogLevel, "%s mesh frame, len:%d%s%s, msrc:%s, mdst:%s, hops:%d, frag:%s, sec:%s%s%s%s%s%s%s",
|
||||
MessageActionToString(aAction, aError), aMessage.GetLength(),
|
||||
(aMacAddress == nullptr) ? "" : ((aAction == kMessageReceive) ? ", from:" : ", to:"),
|
||||
(aMacAddress == nullptr) ? "" : aMacAddress->ToString().AsCString(), aMeshSource.ToString().AsCString(),
|
||||
aMeshDest.ToString().AsCString(), meshHeader.GetHopsLeft() + ((aAction == kMessageReceive) ? 1 : 0),
|
||||
hasFragmentHeader ? "yes" : "no", aMessage.IsLinkSecurityEnabled() ? "yes" : "no",
|
||||
(aError == OT_ERROR_NONE) ? "" : ", error:", (aError == OT_ERROR_NONE) ? "" : otThreadErrorToString(aError),
|
||||
shouldLogRss ? ", rss:" : "", shouldLogRss ? aMessage.GetRssAverager().ToString().AsCString() : "");
|
||||
shouldLogRss ? ", rss:" : "", shouldLogRss ? aMessage.GetRssAverager().ToString().AsCString() : "",
|
||||
shouldLogRadio ? ", radio:" : "", radioString);
|
||||
|
||||
if (hasFragmentHeader)
|
||||
{
|
||||
|
||||
+77
-6
@@ -330,7 +330,7 @@ otError Mle::Restore(void)
|
||||
|
||||
Get<KeyManager>().SetCurrentKeySequence(networkInfo.GetKeySequence());
|
||||
Get<KeyManager>().SetMleFrameCounter(networkInfo.GetMleFrameCounter());
|
||||
Get<KeyManager>().SetMacFrameCounter(networkInfo.GetMacFrameCounter());
|
||||
Get<KeyManager>().SetAllMacFrameCounters(networkInfo.GetMacFrameCounter());
|
||||
mDeviceMode.Set(networkInfo.GetDeviceMode());
|
||||
|
||||
// force re-attach when version mismatch.
|
||||
@@ -449,7 +449,7 @@ otError Mle::Store(void)
|
||||
networkInfo.SetKeySequence(Get<KeyManager>().GetCurrentKeySequence());
|
||||
networkInfo.SetMleFrameCounter(Get<KeyManager>().GetMleFrameCounter() +
|
||||
OPENTHREAD_CONFIG_STORE_FRAME_COUNTER_AHEAD);
|
||||
networkInfo.SetMacFrameCounter(Get<KeyManager>().GetMacFrameCounter() +
|
||||
networkInfo.SetMacFrameCounter(Get<KeyManager>().GetMaximumMacFrameCounter() +
|
||||
OPENTHREAD_CONFIG_STORE_FRAME_COUNTER_AHEAD);
|
||||
networkInfo.SetDeviceMode(mDeviceMode.Get());
|
||||
|
||||
@@ -1080,7 +1080,20 @@ otError Mle::ReadResponse(const Message &aMessage, Challenge &aResponse)
|
||||
|
||||
otError Mle::AppendLinkFrameCounter(Message &aMessage)
|
||||
{
|
||||
return Tlv::Append<LinkFrameCounterTlv>(aMessage, Get<KeyManager>().GetMacFrameCounter());
|
||||
uint32_t counter;
|
||||
|
||||
// When including Link-layer Frame Counter TLV in an MLE message
|
||||
// the value is set to the maximum MAC frame counter on all
|
||||
// supported radio links. All radio links must also start using
|
||||
// the same counter value as the value included in the TLV.
|
||||
|
||||
counter = Get<KeyManager>().GetMaximumMacFrameCounter();
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
Get<KeyManager>().SetAllMacFrameCounters(counter);
|
||||
#endif
|
||||
|
||||
return Tlv::Append<LinkFrameCounterTlv>(aMessage, counter);
|
||||
}
|
||||
|
||||
otError Mle::AppendMleFrameCounter(Message &aMessage)
|
||||
@@ -2688,19 +2701,49 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
|
||||
{
|
||||
if (keySequence == neighbor->GetKeySequence())
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
// Only when counter is exactly one off, we allow it to be
|
||||
// used for updating radio link info (by `RadioSelector`)
|
||||
// before message is dropped as a duplicate. This handles
|
||||
// the common case where a broadcast MLE message (such as
|
||||
// Link Advertisement) is received over multiple radio
|
||||
// links.
|
||||
|
||||
if ((frameCounter + 1) == neighbor->GetMleFrameCounter())
|
||||
{
|
||||
OT_ASSERT(aMessage.IsRadioTypeSet());
|
||||
Get<RadioSelector>().UpdateOnReceive(*neighbor, aMessage.GetRadioType(), /* IsDuplicate */ true);
|
||||
|
||||
// We intentionally exit without setting the error to
|
||||
// skip logging "Failed to process UDP" at the exit
|
||||
// label. Note that in multi-radio mode, receiving
|
||||
// duplicate MLE message (with one-off counter) would
|
||||
// be common and ok for broadcast MLE messages (e.g.
|
||||
// MLE Link Advertisements).
|
||||
ExitNow();
|
||||
}
|
||||
#endif
|
||||
VerifyOrExit(frameCounter >= neighbor->GetMleFrameCounter(), error = OT_ERROR_DUPLICATED);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(keySequence > neighbor->GetKeySequence(), error = OT_ERROR_DUPLICATED);
|
||||
neighbor->SetKeySequence(keySequence);
|
||||
neighbor->SetLinkFrameCounter(0);
|
||||
neighbor->GetLinkFrameCounters().Reset();
|
||||
neighbor->SetLinkAckFrameCounter(0);
|
||||
}
|
||||
|
||||
neighbor->SetMleFrameCounter(frameCounter + 1);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (neighbor != nullptr)
|
||||
{
|
||||
OT_ASSERT(aMessage.IsRadioTypeSet());
|
||||
Get<RadioSelector>().UpdateOnReceive(*neighbor, aMessage.GetRadioType(), /* IsDuplicate */ false);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case kCommandAdvertisement:
|
||||
@@ -2801,6 +2844,27 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
|
||||
ExitNow(error = OT_ERROR_DROP);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
// If we could not find a neighbor matching the MAC address of the
|
||||
// received MLE messages, or if the neighbor is now invalid, we
|
||||
// check again after the message is handled with a relaxed neighbor
|
||||
// state filer. The processing of the received MLE message may
|
||||
// create a new neighbor or change the neighbor table (e.g.,
|
||||
// receiving a "Parent Request" from a new child, or processing a
|
||||
// "Link Request" from a previous child which is being promoted to a
|
||||
// router).
|
||||
|
||||
if ((neighbor == nullptr) || neighbor->IsStateInvalid())
|
||||
{
|
||||
neighbor = Get<NeighborTable>().FindNeighbor(extAddr, Neighbor::kInStateAnyExceptInvalid);
|
||||
|
||||
if (neighbor != nullptr)
|
||||
{
|
||||
Get<RadioSelector>().UpdateOnReceive(*neighbor, aMessage.GetRadioType(), /* aIsDuplicate */ false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
LogProcessError(kTypeGenericUdp, error);
|
||||
}
|
||||
@@ -3326,7 +3390,7 @@ void Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInfo &
|
||||
|
||||
mParentCandidate.SetExtAddress(extAddress);
|
||||
mParentCandidate.SetRloc16(sourceAddress);
|
||||
mParentCandidate.SetLinkFrameCounter(linkFrameCounter);
|
||||
mParentCandidate.GetLinkFrameCounters().SetAll(linkFrameCounter);
|
||||
mParentCandidate.SetLinkAckFrameCounter(linkFrameCounter);
|
||||
mParentCandidate.SetMleFrameCounter(mleFrameCounter);
|
||||
mParentCandidate.SetVersion(static_cast<uint8_t>(version));
|
||||
@@ -3559,6 +3623,13 @@ void Mle::HandleChildUpdateRequest(const Message &aMessage, const Ip6::MessageIn
|
||||
ExitNow(error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (aNeighbor != nullptr)
|
||||
{
|
||||
aNeighbor->ClearLastRxFragmentTag();
|
||||
}
|
||||
#endif
|
||||
|
||||
SuccessOrExit(error = SendChildUpdateResponse(tlvs, numTlvs, challenge));
|
||||
|
||||
exit:
|
||||
@@ -3612,7 +3683,7 @@ void Mle::HandleChildUpdateResponse(const Message & aMessage,
|
||||
case kRoleDetached:
|
||||
SuccessOrExit(error = ReadFrameCounters(aMessage, linkFrameCounter, mleFrameCounter));
|
||||
|
||||
mParent.SetLinkFrameCounter(linkFrameCounter);
|
||||
mParent.GetLinkFrameCounters().SetAll(linkFrameCounter);
|
||||
mParent.SetLinkAckFrameCounter(linkFrameCounter);
|
||||
mParent.SetMleFrameCounter(mleFrameCounter);
|
||||
|
||||
|
||||
@@ -654,6 +654,13 @@ void MleRouter::HandleLinkRequest(const Message &aMessage, const Ip6::MessageInf
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
if (neighbor != nullptr)
|
||||
{
|
||||
neighbor->ClearLastRxFragmentTag();
|
||||
}
|
||||
#endif
|
||||
|
||||
SuccessOrExit(error = SendLinkAccept(aMessageInfo, neighbor, requestedTlvs, challenge));
|
||||
|
||||
exit:
|
||||
@@ -934,7 +941,7 @@ otError MleRouter::HandleLinkAccept(const Message & aMessage,
|
||||
aMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
|
||||
router->SetExtAddress(extAddr);
|
||||
router->SetRloc16(sourceAddress);
|
||||
router->SetLinkFrameCounter(linkFrameCounter);
|
||||
router->GetLinkFrameCounters().SetAll(linkFrameCounter);
|
||||
router->SetLinkAckFrameCounter(linkFrameCounter);
|
||||
router->SetMleFrameCounter(mleFrameCounter);
|
||||
router->SetLastHeard(TimerMilli::GetNow());
|
||||
@@ -2248,7 +2255,7 @@ void MleRouter::HandleChildIdRequest(const Message & aMessage,
|
||||
}
|
||||
|
||||
child->SetLastHeard(TimerMilli::GetNow());
|
||||
child->SetLinkFrameCounter(linkFrameCounter);
|
||||
child->GetLinkFrameCounters().SetAll(linkFrameCounter);
|
||||
child->SetLinkAckFrameCounter(linkFrameCounter);
|
||||
child->SetMleFrameCounter(mleFrameCounter);
|
||||
child->SetKeySequence(aKeySequence);
|
||||
@@ -2256,6 +2263,9 @@ void MleRouter::HandleChildIdRequest(const Message & aMessage,
|
||||
child->SetVersion(static_cast<uint8_t>(version));
|
||||
child->GetLinkInfo().AddRss(aMessageInfo.GetThreadLinkInfo()->GetRss());
|
||||
child->SetTimeout(timeout);
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
child->ClearLastRxFragmentTag();
|
||||
#endif
|
||||
|
||||
if (mode.IsFullNetworkData())
|
||||
{
|
||||
@@ -2497,6 +2507,10 @@ void MleRouter::HandleChildUpdateRequest(const Message & aMessage,
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
child->ClearLastRxFragmentTag();
|
||||
#endif
|
||||
|
||||
SendChildUpdateResponse(child, aMessageInfo, tlvs, tlvslength, challenge);
|
||||
|
||||
exit:
|
||||
@@ -2578,7 +2592,7 @@ void MleRouter::HandleChildUpdateResponse(const Message & aMessage,
|
||||
switch (Tlv::Find<LinkFrameCounterTlv>(aMessage, linkFrameCounter))
|
||||
{
|
||||
case OT_ERROR_NONE:
|
||||
child->SetLinkFrameCounter(linkFrameCounter);
|
||||
child->GetLinkFrameCounters().SetAll(linkFrameCounter);
|
||||
child->SetLinkAckFrameCounter(linkFrameCounter);
|
||||
break;
|
||||
case OT_ERROR_NOT_FOUND:
|
||||
@@ -2857,13 +2871,13 @@ void MleRouter::HandleDiscoveryRequest(const Message &aMessage, const Ip6::Messa
|
||||
}
|
||||
}
|
||||
|
||||
error = SendDiscoveryResponse(aMessageInfo.GetPeerAddr(), aMessage.GetPanId());
|
||||
error = SendDiscoveryResponse(aMessageInfo.GetPeerAddr(), aMessage);
|
||||
|
||||
exit:
|
||||
LogProcessError(kTypeDiscoveryRequest, error);
|
||||
}
|
||||
|
||||
otError MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, uint16_t aPanId)
|
||||
otError MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const Message &aDiscoverRequestMessage)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Message * message;
|
||||
@@ -2875,7 +2889,13 @@ otError MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, uint1
|
||||
|
||||
VerifyOrExit((message = NewMleMessage()) != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
message->SetSubType(Message::kSubTypeMleDiscoverResponse);
|
||||
message->SetPanId(aPanId);
|
||||
message->SetPanId(aDiscoverRequestMessage.GetPanId());
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
// Send the MLE Discovery Response message on same radio link
|
||||
// from which the "MLE Discover Request" message was received.
|
||||
message->SetRadioType(aDiscoverRequestMessage.GetRadioType());
|
||||
#endif
|
||||
|
||||
SuccessOrExit(error = AppendHeader(*message, kCommandDiscoveryResponse));
|
||||
|
||||
// Discovery TLV
|
||||
|
||||
@@ -623,8 +623,7 @@ private:
|
||||
uint8_t aTlvsLength,
|
||||
uint16_t aDelay,
|
||||
const Message * aRequestMessage = nullptr);
|
||||
otError SendDiscoveryResponse(const Ip6::Address &aDestination, uint16_t aPanId);
|
||||
|
||||
otError SendDiscoveryResponse(const Ip6::Address &aDestination, const Message &aDiscoverRequestMessage);
|
||||
void SetStateRouter(uint16_t aRloc16);
|
||||
void SetStateLeader(uint16_t aRloc16);
|
||||
void StopLeader(void);
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes implementation of radio selector (for multi radio links).
|
||||
*/
|
||||
|
||||
#include "radio_selector.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator-getters.hpp"
|
||||
#include "common/logging.hpp"
|
||||
#include "common/random.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
namespace ot {
|
||||
|
||||
// This array defines the order in which different radio link types are
|
||||
// selected for message tx (direct message).
|
||||
const Mac::RadioType RadioSelector::sRadioSelectionOrder[Mac::kNumRadioTypes] = {
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
Mac::kRadioTypeTrel,
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
Mac::kRadioTypeIeee802154,
|
||||
#endif
|
||||
};
|
||||
|
||||
RadioSelector::RadioSelector(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
{
|
||||
}
|
||||
|
||||
otLogLevel RadioSelector::UpdatePreference(Neighbor &aNeighbor, Mac::RadioType aRadioType, int16_t aDifference)
|
||||
{
|
||||
uint8_t old = aNeighbor.GetRadioPreference(aRadioType);
|
||||
int16_t preferecne = static_cast<int16_t>(old);
|
||||
|
||||
preferecne += aDifference;
|
||||
|
||||
if (preferecne > kMaxPreference)
|
||||
{
|
||||
preferecne = kMaxPreference;
|
||||
}
|
||||
|
||||
if (preferecne < kMinPreference)
|
||||
{
|
||||
preferecne = kMinPreference;
|
||||
}
|
||||
|
||||
aNeighbor.SetRadioPreference(aRadioType, static_cast<uint8_t>(preferecne));
|
||||
|
||||
// We check whether the update to the preference value caused it
|
||||
// to cross the threshold `kHighPreference`. Based on this we
|
||||
// return a suggested log level. If there is cross, suggest info
|
||||
// log level, otherwise debug log level.
|
||||
|
||||
return ((old >= kHighPreference) != (preferecne >= kHighPreference)) ? OT_LOG_LEVEL_INFO : OT_LOG_LEVEL_DEBG;
|
||||
}
|
||||
|
||||
void RadioSelector::UpdateOnReceive(Neighbor &aNeighbor, Mac::RadioType aRadioType, bool aIsDuplicate)
|
||||
{
|
||||
otLogLevel logLevel = OT_LOG_LEVEL_INFO;
|
||||
|
||||
if (aNeighbor.GetSupportedRadioTypes().Contains(aRadioType))
|
||||
{
|
||||
logLevel = UpdatePreference(aNeighbor, aRadioType,
|
||||
aIsDuplicate ? kPreferenceChangeOnRxDuplicate : kPreferenceChangeOnRx);
|
||||
|
||||
Log(logLevel, aIsDuplicate ? "UpdateOnDupRx" : "UpdateOnRx", aRadioType, aNeighbor);
|
||||
}
|
||||
else
|
||||
{
|
||||
aNeighbor.AddSupportedRadioType(aRadioType);
|
||||
aNeighbor.SetRadioPreference(aRadioType, kInitPreference);
|
||||
|
||||
Log(logLevel, "NewRadio(OnRx)", aRadioType, aNeighbor);
|
||||
}
|
||||
}
|
||||
|
||||
void RadioSelector::UpdateOnSendDone(Mac::TxFrame &aFrame, otError aTxError)
|
||||
{
|
||||
otLogLevel logLevel = OT_LOG_LEVEL_INFO;
|
||||
Mac::RadioType radioType = aFrame.GetRadioType();
|
||||
Mac::Address macDest;
|
||||
Neighbor * neighbor;
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
if (radioType == Mac::kRadioTypeTrel)
|
||||
{
|
||||
// TREL radio link uses deferred ack model. We ignore
|
||||
// `SendDone` event from `Mac` layer with success status and
|
||||
// wait for deferred ack callback.
|
||||
VerifyOrExit(aTxError != OT_ERROR_NONE);
|
||||
}
|
||||
#endif
|
||||
|
||||
VerifyOrExit(aFrame.GetAckRequest());
|
||||
|
||||
IgnoreError(aFrame.GetDstAddr(macDest));
|
||||
neighbor = Get<NeighborTable>().FindNeighbor(macDest, Neighbor::kInStateAnyExceptInvalid);
|
||||
VerifyOrExit(neighbor != nullptr);
|
||||
|
||||
if (neighbor->GetSupportedRadioTypes().Contains(radioType))
|
||||
{
|
||||
logLevel =
|
||||
UpdatePreference(*neighbor, radioType,
|
||||
(aTxError == OT_ERROR_NONE) ? kPreferenceChangeOnTxSuccess : kPreferenceChangeOnTxError);
|
||||
|
||||
Log(logLevel, (aTxError == OT_ERROR_NONE) ? "UpdateOnTxSucc" : "UpdateOnTxErr", radioType, *neighbor);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(aTxError == OT_ERROR_NONE);
|
||||
neighbor->AddSupportedRadioType(radioType);
|
||||
neighbor->SetRadioPreference(radioType, kInitPreference);
|
||||
|
||||
Log(logLevel, "NewRadio(OnTx)", radioType, *neighbor);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
void RadioSelector::UpdateOnDeferredAck(Neighbor &aNeighbor, otError aTxError, bool &aAllowNeighborRemove)
|
||||
{
|
||||
otLogLevel logLevel = OT_LOG_LEVEL_INFO;
|
||||
|
||||
aAllowNeighborRemove = true;
|
||||
|
||||
if (aNeighbor.GetSupportedRadioTypes().Contains(Mac::kRadioTypeTrel))
|
||||
{
|
||||
logLevel = UpdatePreference(aNeighbor, Mac::kRadioTypeTrel,
|
||||
(aTxError == OT_ERROR_NONE) ? kPreferenceChangeOnDeferredAckSuccess
|
||||
: kPreferenceChangeOnDeferredAckTimeout);
|
||||
|
||||
Log(logLevel, (aTxError == OT_ERROR_NONE) ? "UpdateOnDefAckSucc" : "UpdateOnDefAckFail", Mac::kRadioTypeTrel,
|
||||
aNeighbor);
|
||||
|
||||
// In case of deferred ack timeout, we check if the neighbor
|
||||
// has any other radio link (with high preference) for future
|
||||
// tx. If it it does, we set `aAllowNeighborRemove` to `false`
|
||||
// to ensure neighbor is not removed yet.
|
||||
|
||||
VerifyOrExit(aTxError != OT_ERROR_NONE);
|
||||
|
||||
for (Mac::RadioType radio : sRadioSelectionOrder)
|
||||
{
|
||||
if ((radio != Mac::kRadioTypeTrel) && aNeighbor.GetSupportedRadioTypes().Contains(radio) &&
|
||||
aNeighbor.GetRadioPreference(radio) >= kHighPreference)
|
||||
{
|
||||
aAllowNeighborRemove = false;
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(aTxError == OT_ERROR_NONE);
|
||||
aNeighbor.AddSupportedRadioType(Mac::kRadioTypeTrel);
|
||||
aNeighbor.SetRadioPreference(Mac::kRadioTypeTrel, kInitPreference);
|
||||
|
||||
Log(logLevel, "NewRadio(OnDefAckSucc)", Mac::kRadioTypeTrel, aNeighbor);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
Mac::RadioType RadioSelector::Select(Mac::RadioTypes aRadioOptions, const Neighbor &aNeighbor)
|
||||
{
|
||||
Mac::RadioType selectedRadio = sRadioSelectionOrder[0];
|
||||
uint8_t selectedPreference = 0;
|
||||
bool found = false;
|
||||
|
||||
// Select the first radio links with preference higher than
|
||||
// threshold `kHighPreference`. The radio links are checked in the
|
||||
// order defined by the `sRadioSelectionOrder` array. If no radio
|
||||
// link has preference higher then threshold, select the one with
|
||||
// highest preference.
|
||||
|
||||
for (Mac::RadioType radio : sRadioSelectionOrder)
|
||||
{
|
||||
if (aRadioOptions.Contains(radio))
|
||||
{
|
||||
uint8_t preference = aNeighbor.GetRadioPreference(radio);
|
||||
|
||||
if (preference >= kHighPreference)
|
||||
{
|
||||
selectedRadio = radio;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found || (selectedPreference < preference))
|
||||
{
|
||||
found = true;
|
||||
selectedRadio = radio;
|
||||
selectedPreference = preference;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectedRadio;
|
||||
}
|
||||
|
||||
Mac::TxFrame &RadioSelector::SelectRadio(Message &aMessage, const Mac::Address &aMacDest, Mac::TxFrames &aTxFrames)
|
||||
{
|
||||
Neighbor * neighbor;
|
||||
Mac::RadioType selectedRadio;
|
||||
Mac::RadioTypes selections;
|
||||
|
||||
if (aMacDest.IsBroadcast() || aMacDest.IsNone())
|
||||
{
|
||||
aMessage.ClearRadioType();
|
||||
ExitNow(selections.AddAll());
|
||||
}
|
||||
|
||||
// If the radio type is already set when message was created we
|
||||
// use the selected radio type. (e.g., MLE Discovery Response
|
||||
// selects the radio link from which MLE Discovery Request is
|
||||
// received.
|
||||
|
||||
if (aMessage.IsRadioTypeSet())
|
||||
{
|
||||
ExitNow(selections.Add(aMessage.GetRadioType()));
|
||||
}
|
||||
|
||||
neighbor = Get<NeighborTable>().FindNeighbor(aMacDest, Neighbor::kInStateAnyExceptInvalid);
|
||||
|
||||
if ((neighbor == nullptr) || neighbor->GetSupportedRadioTypes().IsEmpty())
|
||||
{
|
||||
// If we do not have a corresponding neighbor or do not yet
|
||||
// know the supported radio types, we try sending on all radio
|
||||
// links in parallel. As an example, such a situation can
|
||||
// happen when recovering a non-sleepy child (sending MLE
|
||||
// Child Update Request to it) after device itself was reset.
|
||||
|
||||
aMessage.ClearRadioType();
|
||||
ExitNow(selections.AddAll());
|
||||
}
|
||||
|
||||
selectedRadio = Select(neighbor->GetSupportedRadioTypes(), *neighbor);
|
||||
selections.Add(selectedRadio);
|
||||
|
||||
Log(OT_LOG_LEVEL_DEBG, "SelectRadio", selectedRadio, *neighbor);
|
||||
|
||||
aMessage.SetRadioType(selectedRadio);
|
||||
|
||||
// We (probabilistically) decide whether to probe on another radio
|
||||
// link for the current frame tx. When probing we allow the same
|
||||
// frame to be sent in parallel over multiple radio links but only
|
||||
// care about the tx outcome (ack status) on the main selected
|
||||
// radio link. This is done by setting the "required radio types"
|
||||
// (`SetRequiredRadioTypes()`) to match the main selection on
|
||||
// `aTxFrames`. We allow probe on TREL radio link if it is not
|
||||
// currently usable (thus not selected) but is/was supported by
|
||||
// the neighbor (i.e., we did rx/tx on TREL link from/to this
|
||||
// neighbor in the past). The probe process helps detect whether
|
||||
// the TREL link is usable again allowing us to switch over
|
||||
// faster.
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
if (!selections.Contains(Mac::kRadioTypeTrel) && neighbor->GetSupportedRadioTypes().Contains(Mac::kRadioTypeTrel) &&
|
||||
(Random::NonCrypto::GetUint8InRange(0, 100) < kTrelProbeProbability))
|
||||
{
|
||||
aTxFrames.SetRequiredRadioTypes(selections);
|
||||
selections.Add(Mac::kRadioTypeTrel);
|
||||
|
||||
Log(OT_LOG_LEVEL_DEBG, "Probe", Mac::kRadioTypeTrel, *neighbor);
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return aTxFrames.GetTxFrame(selections);
|
||||
}
|
||||
|
||||
Mac::RadioType RadioSelector::SelectPollFrameRadio(const Neighbor &aParent)
|
||||
{
|
||||
// This array defines the order in which different radio link types
|
||||
// are selected for data poll frame tx.
|
||||
static const Mac::RadioType selectionOrder[Mac::kNumRadioTypes] = {
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
|
||||
Mac::kRadioTypeIeee802154,
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
Mac::kRadioTypeTrel,
|
||||
#endif
|
||||
};
|
||||
|
||||
Mac::RadioType selection = selectionOrder[0];
|
||||
|
||||
for (Mac::RadioType radio : selectionOrder)
|
||||
{
|
||||
if (aParent.GetSupportedRadioTypes().Contains(radio))
|
||||
{
|
||||
selection = radio;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
|
||||
#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
|
||||
|
||||
void RadioSelector::Log(otLogLevel aLogLevel,
|
||||
const char * aActionText,
|
||||
Mac::RadioType aRadioType,
|
||||
const Neighbor &aNeighbor)
|
||||
{
|
||||
String<kRadioPreferenceStringSize> preferenceString;
|
||||
bool isFirstEntry = true;
|
||||
|
||||
VerifyOrExit(otLoggingGetLevel() >= aLogLevel);
|
||||
|
||||
for (Mac::RadioType radio : sRadioSelectionOrder)
|
||||
{
|
||||
if (aNeighbor.GetSupportedRadioTypes().Contains(radio))
|
||||
{
|
||||
IgnoreError(preferenceString.Append("%s%s:%d", isFirstEntry ? "" : " ", RadioTypeToString(radio),
|
||||
aNeighbor.GetRadioPreference(radio)));
|
||||
isFirstEntry = false;
|
||||
}
|
||||
}
|
||||
|
||||
otLogMac(aLogLevel, "RadioSelector: %s %s - neighbor:[%s rloc16:0x%04x radio-pref:{%s} state:%s]", aActionText,
|
||||
RadioTypeToString(aRadioType), aNeighbor.GetExtAddress().ToString().AsCString(), aNeighbor.GetRloc16(),
|
||||
preferenceString.AsCString(), Neighbor::StateToString(aNeighbor.GetState()));
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#else // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
|
||||
|
||||
void RadioSelector::Log(otLogLevel, const char *, Mac::RadioType, const Neighbor &)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 radio selector (for multi radio links).
|
||||
*/
|
||||
|
||||
#ifndef RADIO_SELECTOR_HPP_
|
||||
#define RADIO_SELECTOR_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/locator.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
#include "mac/mac_links.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
namespace ot {
|
||||
|
||||
/**
|
||||
* @addtogroup core-radio-selector
|
||||
*
|
||||
* @brief
|
||||
* This module includes definition for radio selector (for multi radio links).
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
class Neighbor;
|
||||
|
||||
class RadioSelector : InstanceLocator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This class defines all the neighbor info required for multi radio link and radio selection.
|
||||
*
|
||||
* `Neighbor` class publicly inherits from this class.
|
||||
*
|
||||
*/
|
||||
class NeighborInfo
|
||||
{
|
||||
friend class RadioSelector;
|
||||
|
||||
/**
|
||||
* This method returns the supported radio types by the neighbor.
|
||||
*
|
||||
* @returns The supported radio types set.
|
||||
*
|
||||
*/
|
||||
Mac::RadioTypes GetSupportedRadioTypes(void) const { return mSupportedRadioTypes; }
|
||||
|
||||
private:
|
||||
void AddSupportedRadioType(Mac::RadioType aType) { mSupportedRadioTypes.Add(aType); }
|
||||
void RemoveSupportedRadioType(Mac::RadioType aType) { mSupportedRadioTypes.Remove(aType); }
|
||||
void ClearSupportedRadioType(void) { mSupportedRadioTypes.Clear(); }
|
||||
|
||||
uint8_t GetRadioPreference(Mac::RadioType aType) const { return mRadioPreference[aType]; }
|
||||
void SetRadioPreference(Mac::RadioType aType, uint8_t aValue) { mRadioPreference[aType] = aValue; }
|
||||
|
||||
Mac::RadioTypes mSupportedRadioTypes;
|
||||
uint8_t mRadioPreference[Mac::kNumRadioTypes];
|
||||
};
|
||||
|
||||
/**
|
||||
* This constructor initializes the RadioSelector object.
|
||||
*
|
||||
* @param[in] aInstance A reference to the OpenThread instance.
|
||||
*
|
||||
*/
|
||||
RadioSelector(Instance &aInstance);
|
||||
|
||||
/**
|
||||
* This method updates the neighbor info (for multi radio support) on a received frame event.
|
||||
*
|
||||
* This method notifies `RadioSelector` of a received secure frame/message on a radio link type for neighbor. If
|
||||
* the frame/message happens to be received earlier on another radio link, the `aIsDuplicate` is set to `true`.
|
||||
* A duplicate frame/message should have passed the security check (i.e., tag/MIC should be valid).
|
||||
*
|
||||
* @param[in] aNeighbor The neighbor for which a frame/message was received.
|
||||
* @param[in] aRadioType The radio link type on which the frame/message was received.
|
||||
* @param[in] aIsDuplicate Indicates whether the received frame/message is a duplicate or not.
|
||||
*
|
||||
*/
|
||||
void UpdateOnReceive(Neighbor &aNeighbor, Mac::RadioType aRadioType, bool aIsDuplicate);
|
||||
|
||||
/**
|
||||
* This method updates the neighbor info (for multi radio support) on a send done event.
|
||||
*
|
||||
* This method notifies `RadioSelector` the status of frame transmission on a radio link type. The radio link
|
||||
* type is provided by the `aFrame` itself.
|
||||
*
|
||||
* @param[in] aFrame A transmitted frame.
|
||||
* @param[in] aTxError The transmission error.
|
||||
*
|
||||
*/
|
||||
void UpdateOnSendDone(Mac::TxFrame &aFrame, otError aTxError);
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
/**
|
||||
* This method updates the neighbor info (for multi radio support) on a deferred ack event.
|
||||
*
|
||||
* The deferred ack model is used by TREL radio link.
|
||||
*
|
||||
* @param[in] aNeighbor The neighbor from which ack was expected
|
||||
* @param[in] aError The deferred ack status (`OT_ERROR_NONE` indicates ack was received).
|
||||
* @param[out] aAllowNeighborRemove Boolean variable to output whether the neighbor is allowed to be removed.
|
||||
*
|
||||
*/
|
||||
void UpdateOnDeferredAck(Neighbor &aNeighbor, otError aTxError, bool &aAllowNeighborRemove);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method selects the radio link type for sending a data poll frame to a given parent neighbor.
|
||||
*
|
||||
* @param[in] aParent The parent to which the data poll frame will be sent.
|
||||
*
|
||||
* @returns The radio type on which the data poll frame should be sent.
|
||||
*
|
||||
*/
|
||||
Mac::RadioType SelectPollFrameRadio(const Neighbor &aParent);
|
||||
|
||||
/**
|
||||
* This method selects the radio link for sending a given message to a specified MAC destination.
|
||||
*
|
||||
* The `aMessage` will be updated to store the selected radio type (please see `Message::GetRadioType()`).
|
||||
* The `aTxFrames` will also be updated to indicate which radio links are to be used.
|
||||
*
|
||||
* @param[inout] aMessage The message to send.
|
||||
* @param[in] aDest The MAC destination address.
|
||||
* @param[inout] aTxFrames The set of TxFrames for all radio links.
|
||||
*
|
||||
* @returns A reference to `mTxFrame` to use when preparing the frame for tx.
|
||||
*
|
||||
*/
|
||||
Mac::TxFrame &SelectRadio(Message &aMessage, const Mac::Address &aDest, Mac::TxFrames &aTxFrames);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kPreferenceChangeOnTxError = -35, // Preference change on a tx error on a radio link.
|
||||
kPreferenceChangeOnTxSuccess = 25, // Preference change on tx success on a radio link.
|
||||
kPreferenceChangeOnDeferredAckSuccess = 25, // Preference change on deferred ack success.
|
||||
kPreferenceChangeOnDeferredAckTimeout = -100, // Preference change on deferred ack timeout.
|
||||
kPreferenceChangeOnRx = 15, // Preference change on new (secure) frame/msg rx on a radio link.
|
||||
kPreferenceChangeOnRxDuplicate = 15, // Preference change on new (secure) duplicate frame/msg rx.
|
||||
kMinPreference = 0, // Minimum preference value.
|
||||
kMaxPreference = 255, // Maximum preference value.
|
||||
kInitPreference = 200, // Initial preference value
|
||||
kHighPreference = 220, // High preference.
|
||||
kTrelProbeProbability = 25, // Probability percentage to probe on TREL link
|
||||
kRadioPreferenceStringSize = 75,
|
||||
};
|
||||
|
||||
otLogLevel UpdatePreference(Neighbor &aNeighbor, Mac::RadioType aRadioType, int16_t aDifference);
|
||||
Mac::RadioType Select(Mac::RadioTypes aRadioOptions, const Neighbor &aNeighbor);
|
||||
void Log(otLogLevel aLogLevel, const char *aActionText, Mac::RadioType aType, const Neighbor &aNeighbor);
|
||||
|
||||
static const Mac::RadioType sRadioSelectionOrder[Mac::kNumRadioTypes];
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
#endif // RADIO_SELECTOR_HPP_
|
||||
@@ -73,6 +73,9 @@ ThreadNetif::ThreadNetif(Instance &aInstance)
|
||||
, mMeshForwarder(aInstance)
|
||||
, mMleRouter(aInstance)
|
||||
, mDiscoverScanner(aInstance)
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
, mRadioSelector(aInstance)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||
, mNetworkDataLocal(aInstance)
|
||||
#endif
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
#include "thread/network_data_notifier.hpp"
|
||||
#include "thread/network_diagnostic.hpp"
|
||||
#include "thread/panid_query_server.hpp"
|
||||
#include "thread/radio_selector.hpp"
|
||||
#include "thread/time_sync_service.hpp"
|
||||
#include "utils/child_supervision.hpp"
|
||||
|
||||
@@ -208,6 +209,9 @@ private:
|
||||
MeshForwarder mMeshForwarder;
|
||||
Mle::MleRouter mMleRouter;
|
||||
Mle::DiscoverScanner mDiscoverScanner;
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
RadioSelector mRadioSelector;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||
NetworkData::Local mNetworkDataLocal;
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||
|
||||
@@ -66,10 +66,11 @@ exit:
|
||||
void Neighbor::Info::SetFrom(const Neighbor &aNeighbor)
|
||||
{
|
||||
Clear();
|
||||
|
||||
mExtAddress = aNeighbor.GetExtAddress();
|
||||
mAge = Time::MsecToSec(TimerMilli::GetNow() - aNeighbor.GetLastHeard());
|
||||
mRloc16 = aNeighbor.GetRloc16();
|
||||
mLinkFrameCounter = aNeighbor.GetLinkFrameCounter();
|
||||
mLinkFrameCounter = aNeighbor.GetLinkFrameCounters().GetMaximum();
|
||||
mMleFrameCounter = aNeighbor.GetMleFrameCounter();
|
||||
mLinkQualityIn = aNeighbor.GetLinkInfo().GetLinkQuality();
|
||||
mAverageRssi = aNeighbor.GetLinkInfo().GetAverageRss();
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "thread/link_quality.hpp"
|
||||
#include "thread/mle_tlvs.hpp"
|
||||
#include "thread/mle_types.hpp"
|
||||
#include "thread/radio_selector.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
@@ -64,6 +65,10 @@ class LinkMetricsSeriesInfo; ///< Forward declaration for including each other w
|
||||
*
|
||||
*/
|
||||
class Neighbor : public InstanceLocatorInit
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
,
|
||||
public RadioSelector::NeighborInfo
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -406,20 +411,20 @@ public:
|
||||
void SetLastHeard(TimeMilli aLastHeard) { mLastHeard = aLastHeard; }
|
||||
|
||||
/**
|
||||
* This method gets the link frame counter value.
|
||||
* This method gets the link frame counters.
|
||||
*
|
||||
* @returns The link frame counter value.
|
||||
* @returns A reference to `Mac::LinkFrameCounters` containing link frame counter for all supported radio links.
|
||||
*
|
||||
*/
|
||||
uint32_t GetLinkFrameCounter(void) const { return mValidPending.mValid.mLinkFrameCounter; }
|
||||
Mac::LinkFrameCounters &GetLinkFrameCounters(void) { return mValidPending.mValid.mLinkFrameCounters; }
|
||||
|
||||
/**
|
||||
* This method sets the link frame counter value.
|
||||
* This method gets the link frame counters.
|
||||
*
|
||||
* @param[in] aFrameCounter The link frame counter value.
|
||||
* @returns A reference to `Mac::LinkFrameCounters` containing link frame counter for all supported radio links.
|
||||
*
|
||||
*/
|
||||
void SetLinkFrameCounter(uint32_t aFrameCounter) { mValidPending.mValid.mLinkFrameCounter = aFrameCounter; }
|
||||
const Mac::LinkFrameCounters &GetLinkFrameCounters(void) const { return mValidPending.mValid.mLinkFrameCounters; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
/**
|
||||
@@ -486,6 +491,60 @@ public:
|
||||
*/
|
||||
void SetRloc16(uint16_t aRloc16) { mRloc16 = aRloc16; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
/**
|
||||
* This method clears the last received fragment tag.
|
||||
*
|
||||
* The last received fragment tag is used for detect duplicate frames (receievd over different radios) when
|
||||
* multi-radio feature is enabled.
|
||||
*
|
||||
*/
|
||||
void ClearLastRxFragmentTag(void) { mLastRxFragmentTag = 0; }
|
||||
|
||||
/**
|
||||
* This method gets the last received fragment tag.
|
||||
*
|
||||
* This method MUST be used only when the tag is set (and not cleared). Otherwise its behavior is undefined.
|
||||
*
|
||||
* @returns The last received fragment tag.
|
||||
*
|
||||
*/
|
||||
uint16_t GetLastRxFragmentTag(void) const { return mLastRxFragmentTag; }
|
||||
|
||||
/**
|
||||
* This method set the last received fragment tag.
|
||||
*
|
||||
* @param[in] aTag The new tag value.
|
||||
*
|
||||
*/
|
||||
void SetLastRxFragmentTag(uint16_t aTag) { mLastRxFragmentTag = (aTag == 0) ? 0xffff : aTag; }
|
||||
|
||||
/**
|
||||
* This method indicates whether the last received fragment tag is set or not.
|
||||
*
|
||||
* @returns TRUE if the last received fragment tag is set, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsLastRxFragmentTagSet(void) const { return (mLastRxFragmentTag != 0); }
|
||||
|
||||
/**
|
||||
* This method indicates whether the last received fragment tag is strictly after a given tag value.
|
||||
*
|
||||
* This method MUST be used only when the tag is set (and not cleared). Otherwise its behavior is undefined.
|
||||
*
|
||||
* The tag value compassion follows the Serial Number Arithmetic logic from RFC-1982. It is semantically equivalent
|
||||
* to `LastRxFragementTag > aTag`.
|
||||
*
|
||||
* @param[in] aTag A tag value to compare against.
|
||||
*
|
||||
* @returns TRUE if the current last rx fragment tag is strictly after @p aTag, FALSE if they are equal or it is
|
||||
* before @p aTag.
|
||||
*
|
||||
*/
|
||||
bool IsLastRxFragmentTagAfter(uint16_t aTag) const { return ((aTag - mLastRxFragmentTag) & (1U << 15)) != 0; }
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
|
||||
/**
|
||||
* This method indicates whether or not it is a valid Thread 1.1 neighbor.
|
||||
*
|
||||
@@ -672,8 +731,8 @@ private:
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t mLinkFrameCounter; ///< The Link Frame Counter
|
||||
uint32_t mMleFrameCounter; ///< The MLE Frame Counter
|
||||
Mac::LinkFrameCounters mLinkFrameCounters; ///< The Link Frame Counters
|
||||
uint32_t mMleFrameCounter; ///< The MLE Frame Counter
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
uint32_t mLinkAckFrameCounter; ///< The Link Ack Frame Counter
|
||||
#endif
|
||||
@@ -684,6 +743,10 @@ private:
|
||||
} mPending;
|
||||
} mValidPending;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
uint16_t mLastRxFragmentTag; ///< Last received fragment tag
|
||||
#endif
|
||||
|
||||
uint32_t mKeySequence; ///< Current key sequence
|
||||
uint16_t mRloc16; ///< The RLOC16
|
||||
uint8_t mState : 4; ///< The link state
|
||||
|
||||
@@ -272,11 +272,12 @@ void TestMacHeader(void)
|
||||
|
||||
for (const auto &test : tests)
|
||||
{
|
||||
uint8_t psdu[Mac::Frame::kMtu];
|
||||
uint8_t psdu[OT_RADIO_FRAME_MAX_SIZE];
|
||||
Mac::TxFrame frame;
|
||||
|
||||
frame.mPsdu = psdu;
|
||||
frame.mLength = 0;
|
||||
frame.mPsdu = psdu;
|
||||
frame.mLength = 0;
|
||||
frame.mRadioType = 0;
|
||||
|
||||
frame.InitMacHeader(test.fcf, test.secCtl);
|
||||
VerifyOrQuit(frame.GetHeaderLength() == test.headerLength, "MacHeader test failed");
|
||||
|
||||
Reference in New Issue
Block a user