[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:
pvanhorn
2018-05-01 11:18:34 -07:00
committed by Jonathan Hui
parent 273e6f9ba4
commit e4f5aa89d0
6 changed files with 110 additions and 7 deletions
+26
View File
@@ -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);
/**
* @}
*
+21
View File
@@ -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);
+1
View File
@@ -173,6 +173,7 @@ void Instance::Finalize(void)
IgnoreReturnValue(otThreadSetEnabled(this, false));
IgnoreReturnValue(otIp6SetEnabled(this, false));
IgnoreReturnValue(otLinkSetEnabled(this, false));
exit:
return;
+40 -7
View File
@@ -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);
+20
View File
@@ -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;
};
/**
+2
View File
@@ -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);