[mac] update the cached supported channel mask when the region code changes (#9418)

The current code of the `mac.cpp` caches the supported channel mask to
a local variable. But the supported channel mask may be changed after
the country code is changed. This will cause the supported channel
mask used in `mac.cpp` to be inconsistent with the actual supported
channel mask.

This commit adds an API `otLinkSetRegion()` to set the region code and
then update the cached supported channel mask to avoid the channel
mask inconsistencies. The current Thread channel may be not included
in the new supported channel mask. When the Thread stack detects this
case, it detaches the current Thread network gracefully.
This commit is contained in:
Zhanglong Xia
2023-10-24 14:36:57 -07:00
committed by GitHub
parent d26f4e59a2
commit 4275c5826f
9 changed files with 183 additions and 7 deletions
+33
View File
@@ -1182,6 +1182,39 @@ bool otLinkIsCslSupported(otInstance *aInstance);
*/
otError otLinkSendEmptyData(otInstance *aInstance);
/**
* Sets the region code.
*
* The radio region format is the 2-bytes ascii representation of the ISO 3166 alpha-2 code.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aRegionCode The radio region code. The `aRegionCode >> 8` is first ascii char
* and the `aRegionCode & 0xff` is the second ascii char.
*
* @retval OT_ERROR_FAILED Other platform specific errors.
* @retval OT_ERROR_NONE Successfully set region code.
* @retval OT_ERROR_NOT_IMPLEMENTED The feature is not implemented.
*
*/
otError otLinkSetRegion(otInstance *aInstance, uint16_t aRegionCode);
/**
* Get the region code.
*
* The radio region format is the 2-bytes ascii representation of the ISO 3166 alpha-2 code.
* @param[in] aInstance The OpenThread instance structure.
* @param[out] aRegionCode The radio region code. The `aRegionCode >> 8` is first ascii char
* and the `aRegionCode & 0xff` is the second ascii char.
*
* @retval OT_ERROR_INVALID_ARGS @p aRegionCode is nullptr.
* @retval OT_ERROR_FAILED Other platform specific errors.
* @retval OT_ERROR_NONE Successfully got region code.
* @retval OT_ERROR_NOT_IMPLEMENTED The feature is not implemented.
*
*/
otError otLinkGetRegion(otInstance *aInstance, uint16_t *aRegionCode);
/**
* @}
*
+2 -1
View File
@@ -1186,7 +1186,8 @@ otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aCh
* ISO 3166 alpha-2 code.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aRegionCode The radio region.
* @param[in] aRegionCode The radio region code. The `aRegionCode >> 8` is first ascii char
* and the `aRegionCode & 0xff` is the second ascii char.
*
* @retval OT_ERROR_FAILED Other platform specific errors.
* @retval OT_ERROR_NONE Successfully set region code.
+4 -4
View File
@@ -6658,7 +6658,7 @@ exit:
* Done
* @endcode
* @par api_copy
* #otPlatRadioGetRegion
* #otLinkGetRegion
*/
template <> otError Interpreter::Process<Cmd("region")>(Arg aArgs[])
{
@@ -6667,7 +6667,7 @@ template <> otError Interpreter::Process<Cmd("region")>(Arg aArgs[])
if (aArgs[0].IsEmpty())
{
SuccessOrExit(error = otPlatRadioGetRegion(GetInstancePtr(), &regionCode));
SuccessOrExit(error = otLinkGetRegion(GetInstancePtr(), &regionCode));
OutputLine("%c%c", regionCode >> 8, regionCode & 0xff);
}
/**
@@ -6677,7 +6677,7 @@ template <> otError Interpreter::Process<Cmd("region")>(Arg aArgs[])
* Done
* @endcode
* @par api_copy
* #otPlatRadioSetRegion
* #otLinkSetRegion
* @par
* Changing this can affect the transmit power limit.
*/
@@ -6688,7 +6688,7 @@ template <> otError Interpreter::Process<Cmd("region")>(Arg aArgs[])
regionCode = static_cast<uint16_t>(static_cast<uint16_t>(aArgs[0].GetCString()[0]) << 8) +
static_cast<uint16_t>(aArgs[0].GetCString()[1]);
error = otPlatRadioSetRegion(GetInstancePtr(), regionCode);
error = otLinkSetRegion(GetInstancePtr(), regionCode);
}
exit:
+21
View File
@@ -460,3 +460,24 @@ otError otLinkSendEmptyData(otInstance *aInstance)
return AsCoreType(aInstance).Get<MeshForwarder>().SendEmptyMessage();
}
#endif
otError otLinkSetRegion(otInstance *aInstance, uint16_t aRegionCode)
{
return AsCoreType(aInstance).Get<Mac::Mac>().SetRegion(aRegionCode);
}
otError otLinkGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
{
Error error;
if (aRegionCode == nullptr)
{
error = kErrorInvalidArgs;
}
else
{
error = AsCoreType(aInstance).Get<Mac::Mac>().GetRegion(*aRegionCode);
}
return error;
}
+17 -2
View File
@@ -187,7 +187,7 @@ void Mac::Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanD
if (aScanChannels == 0)
{
aScanChannels = GetSupportedChannelMask().GetMask();
aScanChannels = mSupportedChannelMask.GetMask();
}
mScanChannelMask.SetMask(aScanChannels);
@@ -474,7 +474,7 @@ void Mac::SetSupportedChannelMask(const ChannelMask &aMask)
{
ChannelMask newMask = aMask;
newMask.Intersect(ChannelMask(Get<Radio>().GetSupportedChannelMask()));
newMask.Intersect(mSupportedChannelMask);
IgnoreError(Get<Notifier>().Update(mSupportedChannelMask, newMask, kEventSupportedChannelMaskChanged));
}
@@ -2105,6 +2105,21 @@ void Mac::SetPromiscuous(bool aPromiscuous)
UpdateIdleMode();
}
Error Mac::SetRegion(uint16_t aRegionCode)
{
Error error;
ChannelMask oldMask = mSupportedChannelMask;
SuccessOrExit(error = Get<Radio>().SetRegion(aRegionCode));
mSupportedChannelMask.SetMask(Get<Radio>().GetSupportedChannelMask());
IgnoreError(Get<Notifier>().Update(oldMask, mSupportedChannelMask, kEventSupportedChannelMaskChanged));
exit:
return error;
}
Error Mac::GetRegion(uint16_t &aRegionCode) const { return Get<Radio>().GetRegion(aRegionCode); }
#if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
const uint32_t *Mac::GetDirectRetrySuccessHistogram(uint8_t &aNumberOfEntries)
{
+30
View File
@@ -720,6 +720,36 @@ public:
bool IsRadioFilterEnabled(void) const { return mLinks.GetSubMac().IsRadioFilterEnabled(); }
#endif
/**
* Sets the region code.
*
* The radio region format is the 2-bytes ascii representation of the ISO 3166 alpha-2 code.
*
* @param[in] aRegionCode The radio region code. The `aRegionCode >> 8` is first ascii char
* and the `aRegionCode & 0xff` is the second ascii char.
*
* @retval kErrorFailed Other platform specific errors.
* @retval kErrorNone Successfully set region code.
* @retval kErrorNotImplemented The feature is not implemented.
*
*/
Error SetRegion(uint16_t aRegionCode);
/**
* Get the region code.
*
* The radio region format is the 2-bytes ascii representation of the ISO 3166 alpha-2 code.
*
* @param[out] aRegionCode The radio region code. The `aRegionCode >> 8` is first ascii char
* and the `aRegionCode & 0xff` is the second ascii char.
*
* @retval kErrorFailed Other platform specific errors.
* @retval kErrorNone Successfully set region code.
* @retval kErrorNotImplemented The feature is not implemented.
*
*/
Error GetRegion(uint16_t &aRegionCode) const;
private:
static constexpr uint16_t kMaxCcaSampleCount = OPENTHREAD_CONFIG_CCA_FAILURE_RATE_AVERAGING_WINDOW;
+30
View File
@@ -733,6 +733,36 @@ public:
((kChannelMin == aCslChannel) || ((kChannelMin < aCslChannel) && (aCslChannel <= kChannelMax))));
}
/**
* Sets the region code.
*
* The radio region format is the 2-bytes ascii representation of the ISO 3166 alpha-2 code.
*
* @param[in] aRegionCode The radio region code. The `aRegionCode >> 8` is first ascii char
* and the `aRegionCode & 0xff` is the second ascii char.
*
* @retval kErrorFailed Other platform specific errors.
* @retval kErrorNone Successfully set region code.
* @retval kErrorNotImplemented The feature is not implemented.
*
*/
Error SetRegion(uint16_t aRegionCode) { return otPlatRadioSetRegion(GetInstancePtr(), aRegionCode); }
/**
* Get the region code.
*
* The radio region format is the 2-bytes ascii representation of the ISO 3166 alpha-2 code.
*
* @param[out] aRegionCode The radio region code. The `aRegionCode >> 8` is first ascii char
* and the `aRegionCode & 0xff` is the second ascii char.
*
* @retval kErrorFailed Other platform specific errors.
* @retval kErrorNone Successfully set region code.
* @retval kErrorNotImplemented The feature is not implemented.
*
*/
Error GetRegion(uint16_t &aRegionCode) const { return otPlatRadioGetRegion(GetInstancePtr(), &aRegionCode); }
private:
otInstance *GetInstancePtr(void) const { return reinterpret_cast<otInstance *>(&InstanceLocator::GetInstance()); }
+12
View File
@@ -1202,6 +1202,18 @@ void Mle::HandleNotifierEvents(Events aEvents)
}
#endif
if (aEvents.Contains(kEventSupportedChannelMaskChanged))
{
Mac::ChannelMask channelMask = Get<Mac::Mac>().GetSupportedChannelMask();
if (!channelMask.ContainsChannel(Get<Mac::Mac>().GetPanChannel()) && (mRole != kRoleDisabled))
{
LogWarn("Channel %u is not in the supported channel mask %s, detach the network gracefully!",
Get<Mac::Mac>().GetPanChannel(), channelMask.ToString().AsCString());
IgnoreError(DetachGracefully(nullptr, nullptr));
}
}
exit:
return;
}
@@ -61,4 +61,38 @@ send "channel preferred\n"
expect "0x1fff800"
expect_line "Done"
send "region US\n"
expect_line "Done"
send "channel supported\n"
expect "0x7fff800"
expect_line "Done"
send "dataset init new\n"
expect_line "Done"
send "dataset channel 26\n"
expect_line "Done"
send "dataset commit active\n"
expect_line "Done"
attach "leader"
send "channel\n"
expect "26"
expect_line "Done"
send "region WW\n"
expect_line "Done"
wait_for "state" "disabled"
expect_line "Done"
send "channel supported\n"
expect "0x3fff800"
expect_line "Done"
send "channel\n"
expect "26"
expect_line "Done"
dispose_node 1