[mac] tracking supported channel mask (#2838)
This commit contains the following changes:
- Adds new logic to `Mac` to track supported channel mask along
get/set methods.
- Adds public OT APIs `otLinkGetSupportedChannelMask()` and
`otLinkSetSupportedChannelMask()` to get/set the channel mask.
- Ensures supported channel mask from `Mac` is included in Dataset
TLVs when a local Dataset is generated.
- Ensures the channel mask at `Mac` gets updated when a new Dataset
configuration is applied.
- Adds `OT_CHANGED` notification for signaling channel mask changes.
- Updates `NcpBase` and `PHY_CHAN_SUPPORTED` spinel property get/set
handlers to adopt the new public APIs.
- Updates `NcpBase` to emit async `PHY_CHAN_SUPPORTED` updated on
OT_CHANGED channel mask notification.
diff --git a/include/openthread/instance.h b/include/openthread/instance.h
index dc3f88d..3f18782 100644
--- a/include/openthread/instance.h
+++ b/include/openthread/instance.h
@@ -248,6 +248,7 @@
OT_CHANGED_PSKC = 1 << 21, ///< PSKc changed
OT_CHANGED_SECURITY_POLICY = 1 << 22, ///< Security Policy changed
OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL = 1 << 23, ///< Channel Manager new pending Thread channel changed
+ OT_CHANGED_SUPPORTED_CHANNEL_MASK = 1 << 24, ///< Supported channel mask changed
};
/**
diff --git a/include/openthread/link.h b/include/openthread/link.h
index 126b97e..6d69080 100644
--- a/include/openthread/link.h
+++ b/include/openthread/link.h
@@ -189,7 +189,7 @@
* @param[in] aChannel The IEEE 802.15.4 channel.
*
* @retval OT_ERROR_NONE Successfully set the channel.
- * @retval OT_ERROR_INVALID_ARGS If @p aChnanel is not in the range [11, 26].
+ * @retval OT_ERROR_INVALID_ARGS If @p aChannel is not in the range [11, 26] or is not in the supported channel mask.
* @retval OT_ERROR_INVALID_STATE Thread protocols are enabled.
*
* @sa otLinkGetChannel
@@ -198,6 +198,30 @@
OTAPI otError OTCALL otLinkSetChannel(otInstance *aInstance, uint8_t aChannel);
/**
+ * Get the supported channel mask.
+ *
+ * @param[in] aInstance A pointer to an OpenThread instance.
+ *
+ * @returns The supported channel mask as `uint32_t` with bit 0 (lsb) mapping to channel 0, bit 1 to channel 1, so on.
+ *
+ */
+uint32_t otLinkGetSupportedChannelMask(otInstance *aInstance);
+
+/**
+ * Set the supported channel mask.
+ *
+ * This function succeeds only when Thread protocols are disabled.
+ *
+ * @param[in] aInstance A pointer to an OpenThread instance.
+ * @param[in] aChannelMask The supported channel mask (bit 0 or lsb mapping to channel 0, and so on).
+ *
+ * @retval OT_ERROR_NONE Successfully set the supported channel mask.
+ * @retval OT_ERROR_INVALID_STATE Thread protocols are enabled.
+ *
+ */
+otError otLinkSetSupportedChannelMask(otInstance *aInstance, uint32_t aChannelMask);
+
+/**
* Get the IEEE 802.15.4 Extended Address.
*
* @param[in] aInstance A pointer to an OpenThread instance.
diff --git a/src/core/api/link_api.cpp b/src/core/api/link_api.cpp
index e5a1da6..7b71caf 100644
--- a/src/core/api/link_api.cpp
+++ b/src/core/api/link_api.cpp
@@ -65,6 +65,27 @@
return error;
}
+uint32_t otLinkGetSupportedChannelMask(otInstance *aInstance)
+{
+ Instance &instance = *static_cast<Instance *>(aInstance);
+
+ return instance.GetThreadNetif().GetMac().GetSupportedChannelMask().GetMask();
+}
+
+otError otLinkSetSupportedChannelMask(otInstance *aInstance, uint32_t aChannelMask)
+{
+ otError error = OT_ERROR_NONE;
+ Instance &instance = *static_cast<Instance *>(aInstance);
+
+ VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
+ error = OT_ERROR_INVALID_STATE);
+
+ instance.GetThreadNetif().GetMac().SetSupportedChannelMask(aChannelMask);
+
+exit:
+ return error;
+}
+
const otExtAddress *otLinkGetExtendedAddress(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
diff --git a/src/core/common/notifier.cpp b/src/core/common/notifier.cpp
index 70ac44a..da772e6 100644
--- a/src/core/common/notifier.cpp
+++ b/src/core/common/notifier.cpp
@@ -328,6 +328,10 @@
retval = "CMNewChan";
break;
+ case OT_CHANGED_SUPPORTED_CHANNEL_MASK:
+ retval = "ChanMask";
+ break;
+
default:
break;
}
diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp
index 4e97a64..566d7a8 100644
--- a/src/core/mac/mac.cpp
+++ b/src/core/mac/mac.cpp
@@ -170,6 +170,7 @@
, mPanChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL)
, mRadioChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL)
, mRadioChannelAcquisitionId(0)
+ , mSupportedChannelMask(OT_RADIO_SUPPORTED_CHANNELS)
, mSendHead(NULL)
, mSendTail(NULL)
, mReceiveHead(NULL)
@@ -249,7 +250,14 @@
mScanContext = aContext;
mScanDuration = aScanDuration;
mScanChannel = ChannelMask::kChannelIteratorFirst;
- mScanChannelMask.SetMask((aScanChannels == 0) ? static_cast<uint32_t>(kScanChannelsAll) : aScanChannels);
+
+ if (aScanChannels == 0)
+ {
+ aScanChannels = OT_RADIO_SUPPORTED_CHANNELS;
+ }
+
+ mScanChannelMask.SetMask(aScanChannels);
+ mScanChannelMask.Intersect(mSupportedChannelMask);
StartOperation(aScanOperation);
}
@@ -513,6 +521,7 @@
otError error = OT_ERROR_NONE;
VerifyOrExit(OT_RADIO_CHANNEL_MIN <= aChannel && aChannel <= OT_RADIO_CHANNEL_MAX, error = OT_ERROR_INVALID_ARGS);
+ VerifyOrExit(mSupportedChannelMask.ContainsChannel(aChannel), error = OT_ERROR_INVALID_ARGS);
VerifyOrExit(mPanChannel != aChannel, GetNotifier().SignalIfFirst(OT_CHANGED_THREAD_CHANNEL));
@@ -536,6 +545,8 @@
otError error = OT_ERROR_NONE;
VerifyOrExit(OT_RADIO_CHANNEL_MIN <= aChannel && aChannel <= OT_RADIO_CHANNEL_MAX, error = OT_ERROR_INVALID_ARGS);
+ VerifyOrExit(mSupportedChannelMask.ContainsChannel(aChannel), error = OT_ERROR_INVALID_ARGS);
+
VerifyOrExit(mRadioChannelAcquisitionId && aAcquisitionId == mRadioChannelAcquisitionId,
error = OT_ERROR_INVALID_STATE);
@@ -577,6 +588,20 @@
return error;
}
+void Mac::SetSupportedChannelMask(const ChannelMask &aMask)
+{
+ ChannelMask newMask = aMask;
+
+ newMask.Intersect(OT_RADIO_SUPPORTED_CHANNELS);
+ VerifyOrExit(newMask != mSupportedChannelMask, GetNotifier().SignalIfFirst(OT_CHANGED_SUPPORTED_CHANNEL_MASK));
+
+ mSupportedChannelMask = newMask;
+ GetNotifier().Signal(OT_CHANGED_SUPPORTED_CHANNEL_MASK);
+
+exit:
+ return;
+}
+
otError Mac::SetNetworkName(const char *aNetworkName)
{
return SetNetworkName(aNetworkName, OT_NETWORK_NAME_MAX_SIZE + 1);
diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp
index 54a3a13..16cb934 100644
--- a/src/core/mac/mac.hpp
+++ b/src/core/mac/mac.hpp
@@ -598,7 +598,8 @@
*
* @param[in] aChannel The IEEE 802.15.4 PAN Channel.
*
- * @retval OT_ERROR_NONE Successfully set the IEEE 802.15.4 PAN Channel.
+ * @retval OT_ERROR_NONE Successfully set the IEEE 802.15.4 PAN Channel.
+ * @retval OT_ERROR_INVALID_ARGS The @p aChannel is not in the supported channel mask.
*
*/
otError SetPanChannel(uint8_t aChannel);
@@ -617,7 +618,9 @@
*
* @param[in] aChannel The IEEE 802.15.4 Radio Channel.
*
- * @retval OT_ERROR_NONE Successfully set the IEEE 802.15.4 Radio Channel.
+ * @retval OT_ERROR_NONE Successfully set the IEEE 802.15.4 Radio Channel.
+ * @retval OT_ERROR_INVALID_ARGS The @p aChannel is not in the supported channel mask.
+ * @retval OT_ERROR_INVALID_STATE The acquisition ID is incorrect.
*
*/
otError SetRadioChannel(uint16_t aAcquisitionId, uint8_t aChannel);
@@ -644,6 +647,22 @@
otError ReleaseRadioChannel(void);
/**
+ * This method returns the supported channel mask.
+ *
+ * @returns The supported channel mask.
+ *
+ */
+ const ChannelMask &GetSupportedChannelMask(void) const { return mSupportedChannelMask; }
+
+ /**
+ * This method sets the supported channel mask
+ *
+ * @param[in] aMask The supported channel mask.
+ *
+ */
+ void SetSupportedChannelMask(const ChannelMask &aMask);
+
+ /**
* This method returns the IEEE 802.15.4 Network Name.
*
* @returns A pointer to the IEEE 802.15.4 Network Name.
@@ -1024,6 +1043,7 @@
uint8_t mPanChannel;
uint8_t mRadioChannel;
uint16_t mRadioChannelAcquisitionId;
+ ChannelMask mSupportedChannelMask;
otNetworkName mNetworkName;
otExtendedPanId mExtendedPanId;
diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp
index 8c1aae5..f8f875a 100644
--- a/src/core/meshcop/dataset.cpp
+++ b/src/core/meshcop/dataset.cpp
@@ -550,6 +550,18 @@
break;
}
+ case Tlv::kChannelMask:
+ {
+ const ChannelMask0Entry *mask0Entry = static_cast<const ChannelMaskTlv *>(cur)->GetMask0Entry();
+
+ if (mask0Entry != NULL)
+ {
+ mac.SetSupportedChannelMask(mask0Entry->GetMask());
+ }
+
+ break;
+ }
+
case Tlv::kPanId:
mac.SetPanId(static_cast<const PanIdTlv *>(cur)->GetPanId());
break;
diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp
index 091b0f1..b3df342 100644
--- a/src/core/meshcop/dataset_manager_ftd.cpp
+++ b/src/core/meshcop/dataset_manager_ftd.cpp
@@ -618,7 +618,7 @@
{
ChannelMask0Tlv tlv;
tlv.Init();
- tlv.SetMask(OT_RADIO_SUPPORTED_CHANNELS);
+ tlv.SetMask(netif.GetMac().GetSupportedChannelMask().GetMask());
dataset.Set(tlv);
}
diff --git a/src/ncp/changed_props_set.cpp b/src/ncp/changed_props_set.cpp
index 59540ba..55bf24d 100644
--- a/src/ncp/changed_props_set.cpp
+++ b/src/ncp/changed_props_set.cpp
@@ -45,7 +45,7 @@
// number of entries in the list is always less than or equal to 32.
//
const ChangedPropsSet::Entry ChangedPropsSet::mSupportedProps[] = {
- // Spinel property Status (if prop is `LAST_STATUS`) IsFilterable?
+ // Spinel property , Status (if prop is `LAST_STATUS`), IsFilterable?
{SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_RESET_UNKNOWN, false}, // 0
{SPINEL_PROP_STREAM_DEBUG, SPINEL_STATUS_OK, true}, // 1
@@ -79,8 +79,9 @@
{SPINEL_PROP_NET_XPANID, SPINEL_STATUS_OK, true}, // 25
{SPINEL_PROP_NET_MASTER_KEY, SPINEL_STATUS_OK, true}, // 26
{SPINEL_PROP_NET_PSKC, SPINEL_STATUS_OK, true}, // 27
+ {SPINEL_PROP_PHY_CHAN_SUPPORTED, SPINEL_STATUS_OK, true}, // 28
#if OPENTHREAD_ENABLE_CHANNEL_MANAGER
- {SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL, SPINEL_STATUS_OK, true}, // 28
+ {SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL, SPINEL_STATUS_OK, true}, // 29
#endif
};
diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp
index 56bd55f..ce101bf 100644
--- a/src/ncp/ncp_base.cpp
+++ b/src/ncp/ncp_base.cpp
@@ -183,11 +183,9 @@
, mDecoder()
, mHostPowerStateInProgress(false)
, mLastStatus(SPINEL_STATUS_OK)
- , mSupportedChannelMask(OT_RADIO_SUPPORTED_CHANNELS)
- , mChannelMask(OT_RADIO_SUPPORTED_CHANNELS)
+ , mScanChannelMask(OT_RADIO_SUPPORTED_CHANNELS)
, mScanPeriod(200)
- , // ms
- mDiscoveryScanJoinerFlag(false)
+ , mDiscoveryScanJoinerFlag(false)
, mDiscoveryScanEnableFiltering(false)
, mDiscoveryScanPanId(0xffff)
, mUpdateChangedPropsTask(*aInstance, &NcpBase::UpdateChangedProps, this)
diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp
index c3af4b0..29541b2 100644
--- a/src/ncp/ncp_base.hpp
+++ b/src/ncp/ncp_base.hpp
@@ -471,8 +471,7 @@
};
spinel_status_t mLastStatus;
- uint32_t mSupportedChannelMask;
- uint32_t mChannelMask;
+ uint32_t mScanChannelMask;
uint16_t mScanPeriod;
bool mDiscoveryScanJoinerFlag;
bool mDiscoveryScanEnableFiltering;
diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp
index 5729c92..7b58fcc 100644
--- a/src/ncp/ncp_base_dispatcher.cpp
+++ b/src/ncp/ncp_base_dispatcher.cpp
@@ -651,6 +651,9 @@
// MTD (or FTD) Properties (Set Handler)
#if OPENTHREAD_MTD || OPENTHREAD_FTD
+ case SPINEL_PROP_PHY_CHAN_SUPPORTED:
+ handler = &NcpBase::HandlePropertySet<SPINEL_PROP_PHY_CHAN_SUPPORTED>;
+ break;
case SPINEL_PROP_MAC_DATA_POLL_PERIOD:
handler = &NcpBase::HandlePropertySet<SPINEL_PROP_MAC_DATA_POLL_PERIOD>;
break;
diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp
index 994f040..e3fff2c 100644
--- a/src/ncp/ncp_base_mtd.cpp
+++ b/src/ncp/ncp_base_mtd.cpp
@@ -225,7 +225,19 @@
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_PHY_CHAN_SUPPORTED>(void)
{
- return EncodeChannelMask(mSupportedChannelMask);
+ return EncodeChannelMask(otLinkGetSupportedChannelMask(mInstance));
+}
+
+template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_PHY_CHAN_SUPPORTED>(void)
+{
+ uint32_t newMask = 0;
+ otError error = OT_ERROR_NONE;
+
+ SuccessOrExit(error = DecodeChannelMask(newMask));
+ error = otLinkSetSupportedChannelMask(mInstance, newMask);
+
+exit:
+ return error;
}
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_PHY_RSSI>(void)
@@ -2577,7 +2589,7 @@
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_SCAN_MASK>(void)
{
- return EncodeChannelMask(mChannelMask);
+ return EncodeChannelMask(mScanChannelMask);
}
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_SCAN_MASK>(void)
@@ -2586,9 +2598,7 @@
otError error = OT_ERROR_NONE;
SuccessOrExit(error = DecodeChannelMask(newMask));
- VerifyOrExit((~mSupportedChannelMask & newMask) == 0, error = OT_ERROR_INVALID_ARGS);
-
- mChannelMask = newMask;
+ mScanChannelMask = newMask;
exit:
return error;
@@ -2662,7 +2672,7 @@
else
#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
{
- error = otLinkActiveScan(mInstance, mChannelMask, mScanPeriod, &HandleActiveScanResult_Jump, this);
+ error = otLinkActiveScan(mInstance, mScanChannelMask, mScanPeriod, &HandleActiveScanResult_Jump, this);
}
SuccessOrExit(error);
@@ -2677,9 +2687,9 @@
// Make sure we aren't already scanning and that we have
// only 1 bit set for the channel mask.
VerifyOrExit(mCurScanChannel == kInvalidScanChannel, error = OT_ERROR_INVALID_STATE);
- VerifyOrExit(HasOnly1BitSet(mChannelMask), error = OT_ERROR_INVALID_ARGS);
+ VerifyOrExit(HasOnly1BitSet(mScanChannelMask), error = OT_ERROR_INVALID_ARGS);
- scanChannel = IndexOfMSB(mChannelMask);
+ scanChannel = IndexOfMSB(mScanChannelMask);
mCurScanChannel = (int8_t)scanChannel;
error = otLinkRawEnergyScan(mInstance, scanChannel, mScanPeriod, LinkRawEnergyScanDone);
@@ -2687,14 +2697,14 @@
else
#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
{
- error = otLinkEnergyScan(mInstance, mChannelMask, mScanPeriod, &HandleEnergyScanResult_Jump, this);
+ error = otLinkEnergyScan(mInstance, mScanChannelMask, mScanPeriod, &HandleEnergyScanResult_Jump, this);
}
SuccessOrExit(error);
break;
case SPINEL_SCAN_STATE_DISCOVER:
- error = otThreadDiscover(mInstance, mChannelMask, mDiscoveryScanPanId, mDiscoveryScanJoinerFlag,
+ error = otThreadDiscover(mInstance, mScanChannelMask, mDiscoveryScanPanId, mDiscoveryScanJoinerFlag,
mDiscoveryScanEnableFiltering, &HandleActiveScanResult_Jump, this);
SuccessOrExit(error);
@@ -2938,6 +2948,7 @@
{OT_CHANGED_MASTER_KEY, SPINEL_PROP_NET_MASTER_KEY},
{OT_CHANGED_PSKC, SPINEL_PROP_NET_PSKC},
{OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL, SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL},
+ {OT_CHANGED_SUPPORTED_CHANNEL_MASK, SPINEL_PROP_PHY_CHAN_SUPPORTED},
};
VerifyOrExit(mThreadChangedFlags != 0);