[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:
Abtin Keshavarzian
2020-12-10 11:46:07 -08:00
committed by Jonathan Hui
parent 48333ce530
commit ffb3fdf9bd
49 changed files with 3948 additions and 413 deletions
+3
View File
@@ -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 \
+1
View File
@@ -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
*
* @}
+3
View File
@@ -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;
/**
+2
View File
@@ -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.
*/
+7
View File
@@ -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",
+3
View File
@@ -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
+7
View File
@@ -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 \
+15 -1
View File
@@ -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)
{
+3
View File
@@ -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
+49 -1
View File
@@ -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
+75
View File
@@ -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_
+22 -11
View File
@@ -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)
+12 -4
View File
@@ -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);
+8
View File
@@ -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;
}
+14
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+38 -7
View File
@@ -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.
+280
View File
@@ -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
+691
View File
@@ -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_
+144
View File
@@ -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
+310
View File
@@ -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
};
/**
* @}
*
+1 -1
View File
@@ -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.
*
+1
View File
@@ -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"
+6 -3
View File
@@ -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
View File
@@ -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_
+97 -21
View File
@@ -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
+64
View File
@@ -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
+106
View File
@@ -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_
+26 -17
View File
@@ -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)
+2 -2
View File
@@ -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);
+5 -5
View File
@@ -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)
+3 -3
View File
@@ -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;
+73 -13
View File
@@ -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)
{
+74 -13
View File
@@ -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;
+168 -47
View File
@@ -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)
{
+26 -5
View File
@@ -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);
+24 -2
View File
@@ -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
View File
@@ -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);
+26 -6
View File
@@ -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
+1 -2
View File
@@ -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);
+378
View File
@@ -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
+200
View File
@@ -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_
+3
View File
@@ -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
+4
View File
@@ -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
+2 -1
View File
@@ -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();
+71 -8
View File
@@ -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
+4 -3
View File
@@ -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");