diff --git a/include/openthread/instance.h b/include/openthread/instance.h index dc3f88d35..3f1878291 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -248,6 +248,7 @@ enum 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 126b97e24..6d6908084 100644 --- a/include/openthread/link.h +++ b/include/openthread/link.h @@ -189,7 +189,7 @@ OTAPI uint8_t OTCALL otLinkGetChannel(otInstance *aInstance); * @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 @@ -197,6 +197,30 @@ OTAPI uint8_t OTCALL otLinkGetChannel(otInstance *aInstance); */ 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. * diff --git a/src/core/api/link_api.cpp b/src/core/api/link_api.cpp index e5a1da6f7..7b71caf84 100644 --- a/src/core/api/link_api.cpp +++ b/src/core/api/link_api.cpp @@ -65,6 +65,27 @@ exit: return error; } +uint32_t otLinkGetSupportedChannelMask(otInstance *aInstance) +{ + Instance &instance = *static_cast(aInstance); + + return instance.GetThreadNetif().GetMac().GetSupportedChannelMask().GetMask(); +} + +otError otLinkSetSupportedChannelMask(otInstance *aInstance, uint32_t aChannelMask) +{ + otError error = OT_ERROR_NONE; + Instance &instance = *static_cast(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(aInstance); diff --git a/src/core/common/notifier.cpp b/src/core/common/notifier.cpp index 70ac44ad9..da772e6e7 100644 --- a/src/core/common/notifier.cpp +++ b/src/core/common/notifier.cpp @@ -328,6 +328,10 @@ const char *Notifier::FlagToString(otChangedFlags aFlag) const 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 4e97a64d8..566d7a8ea 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -170,6 +170,7 @@ Mac::Mac(Instance &aInstance) , 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 @@ void Mac::Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanD mScanContext = aContext; mScanDuration = aScanDuration; mScanChannel = ChannelMask::kChannelIteratorFirst; - mScanChannelMask.SetMask((aScanChannels == 0) ? static_cast(kScanChannelsAll) : aScanChannels); + + if (aScanChannels == 0) + { + aScanChannels = OT_RADIO_SUPPORTED_CHANNELS; + } + + mScanChannelMask.SetMask(aScanChannels); + mScanChannelMask.Intersect(mSupportedChannelMask); StartOperation(aScanOperation); } @@ -513,6 +521,7 @@ otError Mac::SetPanChannel(uint8_t aChannel) 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 Mac::SetRadioChannel(uint16_t aAcquisitionId, uint8_t aChannel) 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 @@ exit: 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 54a3a132d..16cb9342c 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -598,7 +598,8 @@ public: * * @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 @@ public: * * @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); @@ -643,6 +646,22 @@ public: */ 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. * @@ -1024,6 +1043,7 @@ private: 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 8c1aae574..f8f875a2b 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -550,6 +550,18 @@ otError Dataset::ApplyConfiguration(Instance &aInstance) const break; } + case Tlv::kChannelMask: + { + const ChannelMask0Entry *mask0Entry = static_cast(cur)->GetMask0Entry(); + + if (mask0Entry != NULL) + { + mac.SetSupportedChannelMask(mask0Entry->GetMask()); + } + + break; + } + case Tlv::kPanId: mac.SetPanId(static_cast(cur)->GetPanId()); break; diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp index 091b0f10a..b3df342b5 100644 --- a/src/core/meshcop/dataset_manager_ftd.cpp +++ b/src/core/meshcop/dataset_manager_ftd.cpp @@ -618,7 +618,7 @@ otError ActiveDataset::GenerateLocal(void) { 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 59540ba5e..55bf24dc1 100644 --- a/src/ncp/changed_props_set.cpp +++ b/src/ncp/changed_props_set.cpp @@ -45,7 +45,7 @@ namespace Ncp { // 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 @@ const ChangedPropsSet::Entry ChangedPropsSet::mSupportedProps[] = { {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 56bd55fad..ce101bf4b 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -183,11 +183,9 @@ NcpBase::NcpBase(Instance *aInstance) , 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 c3af4b004..29541b2c4 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -471,8 +471,7 @@ protected: }; 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 5729c92d2..7b58fcce6 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -651,6 +651,9 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) // MTD (or FTD) Properties (Set Handler) #if OPENTHREAD_MTD || OPENTHREAD_FTD + case SPINEL_PROP_PHY_CHAN_SUPPORTED: + handler = &NcpBase::HandlePropertySet; + break; case SPINEL_PROP_MAC_DATA_POLL_PERIOD: handler = &NcpBase::HandlePropertySet; break; diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 994f040e2..e3fff2c6a 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -225,7 +225,19 @@ template <> otError NcpBase::HandlePropertyGet(void) template <> otError NcpBase::HandlePropertyGet(void) { - return EncodeChannelMask(mSupportedChannelMask); + return EncodeChannelMask(otLinkGetSupportedChannelMask(mInstance)); +} + +template <> otError NcpBase::HandlePropertySet(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(void) @@ -2577,7 +2589,7 @@ exit: template <> otError NcpBase::HandlePropertyGet(void) { - return EncodeChannelMask(mChannelMask); + return EncodeChannelMask(mScanChannelMask); } template <> otError NcpBase::HandlePropertySet(void) @@ -2586,9 +2598,7 @@ template <> otError NcpBase::HandlePropertySet(void) 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 @@ template <> otError NcpBase::HandlePropertySet(void) 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 @@ template <> otError NcpBase::HandlePropertySet(void) // 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 @@ template <> otError NcpBase::HandlePropertySet(void) 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 @@ void NcpBase::ProcessThreadChangedFlags(void) {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);