mirror of
https://github.com/espressif/openthread.git
synced 2026-08-08 19:57:46 +00:00
[mac] add start/stop the MAC according to the state of the netif (#2688)
To ensure proper and expedient shutdown of Openthread when the Interface is brought down, this change provides a mechanism to gracefully stop the MAC layer operations. Scans are stopped by preventing any new channel change. New Transmissions are stopped. Existing transmissions are allowed to complete. Any pending operations are cleared.
This commit is contained in:
@@ -628,6 +628,32 @@ otError otLinkSetPromiscuous(otInstance *aInstance, bool aPromiscuous);
|
||||
*/
|
||||
uint16_t otLinkGetCcaFailureRate(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* This function enables or disables the link layer.
|
||||
*
|
||||
* @note The link layer may only be enabled / disabled when the Thread Interface is disabled.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aEnable true to enable the link layer, or false otherwise.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully enabled / disabled the link layer.
|
||||
* @retval OT_ERROR_INVALID_STATE Could not disable the link layer because
|
||||
* the Thread interface is enabled.
|
||||
*
|
||||
*/
|
||||
otError otLinkSetEnabled(otInstance *aInstance, bool aEnable);
|
||||
|
||||
/**
|
||||
* This function indicates whether or not the link layer is enabled.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @retval true Link layer is enabled.
|
||||
* @retval false Link layer is not enabled.
|
||||
*
|
||||
*/
|
||||
bool otLinkIsEnabled(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -289,6 +289,27 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otLinkSetEnabled(otInstance *aInstance, bool aEnable)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
// cannot disable the link layer if the Thread interface is enabled
|
||||
VerifyOrExit(instance.GetThreadNetif().IsUp() == false, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
error = instance.GetThreadNetif().GetMac().SetEnabled(aEnable);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool otLinkIsEnabled(otInstance *aInstance)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetThreadNetif().GetMac().IsEnabled();
|
||||
}
|
||||
|
||||
const otMacCounters *otLinkGetCounters(otInstance *aInstance)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
@@ -173,6 +173,7 @@ void Instance::Finalize(void)
|
||||
|
||||
IgnoreReturnValue(otThreadSetEnabled(this, false));
|
||||
IgnoreReturnValue(otIp6SetEnabled(this, false));
|
||||
IgnoreReturnValue(otLinkSetEnabled(this, false));
|
||||
|
||||
exit:
|
||||
return;
|
||||
|
||||
+40
-7
@@ -194,6 +194,7 @@ Mac::Mac(Instance &aInstance)
|
||||
, mKeyIdMode2FrameCounter(0)
|
||||
, mCcaSuccessRateTracker()
|
||||
, mCcaSampleCount(0)
|
||||
, mEnabled(true)
|
||||
{
|
||||
GenerateExtAddress(&mExtAddress);
|
||||
|
||||
@@ -212,6 +213,7 @@ otError Mac::ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveSc
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(mEnabled, error = OT_ERROR_INVALID_STATE);
|
||||
VerifyOrExit(!IsActiveScanInProgress() && !IsEnergyScanInProgress(), error = OT_ERROR_BUSY);
|
||||
|
||||
mActiveScanHandler = aHandler;
|
||||
@@ -231,6 +233,7 @@ otError Mac::EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergySc
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(mEnabled, error = OT_ERROR_INVALID_STATE);
|
||||
VerifyOrExit(!IsActiveScanInProgress() && !IsEnergyScanInProgress(), error = OT_ERROR_BUSY);
|
||||
|
||||
mEnergyScanHandler = aHandler;
|
||||
@@ -309,7 +312,14 @@ exit:
|
||||
|
||||
otError Mac::UpdateScanChannel(void)
|
||||
{
|
||||
return mScanChannelMask.GetNextChannel(mScanChannel);
|
||||
otError error;
|
||||
|
||||
VerifyOrExit(mEnabled, error = OT_ERROR_ABORT);
|
||||
|
||||
error = mScanChannelMask.GetNextChannel(mScanChannel);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mac::PerformActiveScan(void)
|
||||
@@ -540,6 +550,7 @@ otError Mac::SendFrameRequest(Sender &aSender)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(mEnabled, error = OT_ERROR_INVALID_STATE);
|
||||
VerifyOrExit(mSendTail != &aSender && aSender.mNext == NULL, error = OT_ERROR_ALREADY);
|
||||
|
||||
if (mSendHead == NULL)
|
||||
@@ -563,6 +574,7 @@ otError Mac::SendOutOfBandFrameRequest(otRadioFrame *aOobFrame)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(mEnabled, error = OT_ERROR_INVALID_STATE);
|
||||
VerifyOrExit(mOobFrame == NULL, error = OT_ERROR_ALREADY);
|
||||
|
||||
mOobFrame = static_cast<Frame *>(aOobFrame);
|
||||
@@ -649,10 +661,21 @@ void Mac::PerformOperation(void)
|
||||
{
|
||||
VerifyOrExit(mOperation == kOperationIdle);
|
||||
|
||||
if (!mEnabled)
|
||||
{
|
||||
mPendingWaitingForData = false;
|
||||
mPendingTransmitOobFrame = false;
|
||||
mPendingActiveScan = false;
|
||||
mPendingEnergyScan = false;
|
||||
mPendingTransmitBeacon = false;
|
||||
mPendingTransmitData = false;
|
||||
mOobFrame = NULL;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// `WaitingForData` should be checked before any other pending
|
||||
// operations since radio should remain in receive mode after
|
||||
// a data poll ack indicating a pending frame from parent.
|
||||
|
||||
if (mPendingWaitingForData)
|
||||
{
|
||||
mPendingWaitingForData = false;
|
||||
@@ -999,6 +1022,8 @@ void Mac::BeginTransmit(void)
|
||||
bool applyTransmitSecurity = true;
|
||||
Frame & sendFrame(*GetOperationFrame());
|
||||
|
||||
VerifyOrExit(mEnabled, error = OT_ERROR_ABORT);
|
||||
|
||||
#if OPENTHREAD_CONFIG_DISABLE_CCA_ON_LAST_ATTEMPT
|
||||
|
||||
// Disable CCA for the last attempt
|
||||
@@ -1225,7 +1250,7 @@ void Mac::HandleTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otEr
|
||||
|
||||
otDumpDebgMac(GetInstance(), "TX ERR", sendFrame.GetHeader(), 16);
|
||||
|
||||
if (!RadioSupportsRetries() && mTransmitAttempts < sendFrame.GetMaxTxAttempts())
|
||||
if (mEnabled && !RadioSupportsRetries() && mTransmitAttempts < sendFrame.GetMaxTxAttempts())
|
||||
{
|
||||
mCounters.mTxRetry++;
|
||||
StartCsmaBackoff();
|
||||
@@ -1301,7 +1326,7 @@ void Mac::HandleTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otEr
|
||||
|
||||
if (sendFrame.IsDataRequestCommand())
|
||||
{
|
||||
if (framePending)
|
||||
if (mEnabled && framePending)
|
||||
{
|
||||
mReceiveTimer.Start(kDataPollTimeout);
|
||||
StartOperation(kOperationWaitingForData);
|
||||
@@ -1684,6 +1709,7 @@ void Mac::HandleReceivedFrame(Frame *aFrame, otError aError)
|
||||
|
||||
VerifyOrExit(error == OT_ERROR_NONE);
|
||||
VerifyOrExit(aFrame != NULL, error = OT_ERROR_NO_FRAME_RECEIVED);
|
||||
VerifyOrExit(mEnabled, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
aFrame->SetSecurityValid(false);
|
||||
|
||||
@@ -1987,11 +2013,11 @@ otError Mac::HandleMacCommand(Frame &aFrame)
|
||||
mCounters.mRxBeaconRequest++;
|
||||
otLogInfoMac(GetInstance(), "Received Beacon Request");
|
||||
|
||||
if (mBeaconsEnabled
|
||||
if (mEnabled && (mBeaconsEnabled
|
||||
#if OPENTHREAD_CONFIG_ENABLE_BEACON_RSP_WHEN_JOINABLE
|
||||
|| IsBeaconJoinable()
|
||||
|| IsBeaconJoinable()
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_BEACON_RSP_WHEN_JOINABLE
|
||||
)
|
||||
))
|
||||
{
|
||||
StartOperation(kOperationTransmitBeacon);
|
||||
}
|
||||
@@ -2045,6 +2071,13 @@ bool Mac::RadioSupportsRetries(void)
|
||||
return (otPlatRadioGetCaps(&GetInstance()) & OT_RADIO_CAPS_TRANSMIT_RETRIES) != 0;
|
||||
}
|
||||
|
||||
otError Mac::SetEnabled(bool aEnable)
|
||||
{
|
||||
mEnabled = aEnable;
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
void Mac::FillMacCountersTlv(NetworkDiagnostic::MacCountersTlv &aMacCounters) const
|
||||
{
|
||||
aMacCounters.SetIfInUnknownProtos(mCounters.mRxOther);
|
||||
|
||||
@@ -786,6 +786,25 @@ public:
|
||||
*/
|
||||
uint16_t GetCcaFailureRate(void) const { return mCcaSuccessRateTracker.GetFailureRate(); }
|
||||
|
||||
/**
|
||||
* This method Starts/Stops the Link layer. It may only be used when the Netif Interface is down
|
||||
*
|
||||
* @param[in] aEnable The requested State for the MAC layer. true - Start, false - Stop.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The operation succeeded or the new State equals the current State.
|
||||
*
|
||||
*/
|
||||
otError SetEnabled(bool aEnable);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the link layer is enabled.
|
||||
*
|
||||
* @retval true Link layer is enabled.
|
||||
* @retval false Link layer is not enabled.
|
||||
*
|
||||
*/
|
||||
bool IsEnabled(void) { return mEnabled; }
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
@@ -924,6 +943,7 @@ private:
|
||||
|
||||
SuccessRateTracker mCcaSuccessRateTracker;
|
||||
uint16_t mCcaSampleCount;
|
||||
bool mEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -111,6 +111,8 @@ otError ThreadNetif::Up(void)
|
||||
{
|
||||
if (!mIsUp)
|
||||
{
|
||||
// Enable the MAC just in case it was disabled while the Interface was down.
|
||||
mMac.SetEnabled(true);
|
||||
GetIp6().AddNetif(*this);
|
||||
mMeshForwarder.Start();
|
||||
mCoap.Start(kCoapUdpPort);
|
||||
|
||||
Reference in New Issue
Block a user