From 5b25a57db7cf65ad24c50e6881a3d35b1e809f53 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 13 Dec 2017 21:50:30 -0800 Subject: [PATCH] [notifier] Notifier class and new OT_CHANGED flags (#2403) This commit contains the following changes: (a) It adds a new class `Notifer` which can be used to register callbacks to be notified of state or configuration changes within OpenThread. This is used both internally (by other core OpenThread classes) or externally by registering `otStateChangedCallback` handlers. (b) This commit also adds a set of new `OT_CHANGED` flag definitions corresponding to fields in the Thread Operational Dataset (e.g., the Thread network channel changes map to `OT_CHANGED_THREAD_CHANNEL`). This ensures that user is notified of changes to Active Operational Dataset. (c) Finally, this commit adds support in `NcpBase` for the newly added `OT_CHANGED` flags by emitting asynchronous spinel property updates corresponding to the changed configuration properties. --- etc/visual-studio/libopenthread.vcxproj | 2 + .../libopenthread.vcxproj.filters | 6 + etc/visual-studio/libopenthread_k.vcxproj | 2 + .../libopenthread_k.vcxproj.filters | 6 + include/openthread/instance.h | 13 +- include/openthread/types.h | 7 + src/core/Makefile.am | 2 + src/core/api/instance_api.cpp | 8 +- src/core/common/instance.cpp | 36 +- src/core/common/instance.hpp | 39 +- src/core/common/locator.cpp | 5 + src/core/common/locator.hpp | 9 + src/core/common/notifier.cpp | 345 ++++++++++++++++++ src/core/common/notifier.hpp | 202 ++++++++++ src/core/meshcop/commissioner.cpp | 4 +- src/core/meshcop/dataset_manager.cpp | 47 ++- src/core/meshcop/joiner.cpp | 4 +- src/core/meshcop/joiner_router.cpp | 12 +- src/core/meshcop/joiner_router.hpp | 9 +- src/core/net/netif.cpp | 97 +---- src/core/net/netif.hpp | 119 ------ src/core/thread/energy_scan_server.cpp | 11 +- src/core/thread/energy_scan_server.hpp | 7 +- src/core/thread/key_manager.cpp | 19 +- src/core/thread/key_manager.hpp | 2 +- src/core/thread/mle.cpp | 28 +- src/core/thread/mle.hpp | 6 +- src/core/thread/mle_router.cpp | 8 +- src/core/thread/network_data_leader.cpp | 6 +- src/core/thread/network_data_leader_ftd.cpp | 12 +- src/ncp/changed_props_set.cpp | 6 + src/ncp/ncp_base.cpp | 2 +- src/ncp/ncp_base.hpp | 2 +- src/ncp/ncp_base_mtd.cpp | 8 +- 34 files changed, 751 insertions(+), 340 deletions(-) create mode 100644 src/core/common/notifier.cpp create mode 100644 src/core/common/notifier.hpp diff --git a/etc/visual-studio/libopenthread.vcxproj b/etc/visual-studio/libopenthread.vcxproj index eb0f75ee2..725d0d277 100644 --- a/etc/visual-studio/libopenthread.vcxproj +++ b/etc/visual-studio/libopenthread.vcxproj @@ -81,6 +81,7 @@ + @@ -160,6 +161,7 @@ + diff --git a/etc/visual-studio/libopenthread.vcxproj.filters b/etc/visual-studio/libopenthread.vcxproj.filters index 1b6526cd5..0d2db8dbd 100644 --- a/etc/visual-studio/libopenthread.vcxproj.filters +++ b/etc/visual-studio/libopenthread.vcxproj.filters @@ -141,6 +141,9 @@ Source Files\common + + Source Files\common + Source Files\common @@ -368,6 +371,9 @@ Header Files\common + + Header Files\common + Header Files\common diff --git a/etc/visual-studio/libopenthread_k.vcxproj b/etc/visual-studio/libopenthread_k.vcxproj index f687a92cf..d8cb5e0cd 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj +++ b/etc/visual-studio/libopenthread_k.vcxproj @@ -90,6 +90,7 @@ + @@ -192,6 +193,7 @@ + diff --git a/etc/visual-studio/libopenthread_k.vcxproj.filters b/etc/visual-studio/libopenthread_k.vcxproj.filters index 816a4bfbe..fa03ea8d8 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj.filters +++ b/etc/visual-studio/libopenthread_k.vcxproj.filters @@ -141,6 +141,9 @@ Source Files\common + + Source Files\common + Source Files\common @@ -368,6 +371,9 @@ Header Files\common + + Header Files\common + Header Files\common diff --git a/include/openthread/instance.h b/include/openthread/instance.h index ac9de8feb..c93a9463b 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -234,22 +234,21 @@ typedef void (OTCALL *otStateChangedCallback)(uint32_t aFlags, void *aContext); * @param[in] aContext A pointer to application-specific context. * * @retval OT_ERROR_NONE Added the callback to the list of callbacks. + * @retval OT_ERROR_ALREADY The callback was already registered. * @retval OT_ERROR_NO_BUFS Could not add the callback due to resource constraints. * */ -OTAPI otError OTCALL otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, - void *aContext); +OTAPI otError OTCALL otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aContext); /** * This function removes a callback to indicate when certain configuration or state changes within OpenThread. * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aCallback A pointer to a function that is called with certain configuration or state changes. - * @param[in] aCallbackContext A pointer to application-specific context. + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aCallback A pointer to a function that is called with certain configuration or state changes. + * @param[in] aContext A pointer to application-specific context. * */ -OTAPI void OTCALL otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback aCallback, - void *aCallbackContext); +OTAPI void OTCALL otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aContext); /** * This method triggers a platform reset. diff --git a/include/openthread/types.h b/include/openthread/types.h index 4878c2b9c..1551e7611 100644 --- a/include/openthread/types.h +++ b/include/openthread/types.h @@ -696,6 +696,13 @@ enum OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED = 1 << 13, ///< Unsubscribed from a IPv6 multicast address OT_CHANGED_COMMISSIONER_STATE = 1 << 14, ///< Commissioner state changed OT_CHANGED_JOINER_STATE = 1 << 15, ///< Joiner state changed + OT_CHANGED_THREAD_CHANNEL = 1 << 16, ///< Thread network channel changed + OT_CHANGED_THREAD_PANID = 1 << 17, ///< Thread network PAN Id changed + OT_CHANGED_THREAD_NETWORK_NAME = 1 << 18, ///< Thread network name changed + OT_CHANGED_THREAD_EXT_PANID = 1 << 19, ///< Thread network extended PAN ID changed + OT_CHANGED_MASTER_KEY = 1 << 20, ///< Master key changed + OT_CHANGED_PSKC = 1 << 21, ///< PSKc changed + OT_CHANGED_SECURITY_POLICY = 1 << 22, ///< Security Policy changed }; /** diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 2c35149c3..0d71dbd58 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -119,6 +119,7 @@ SOURCES_COMMON = \ common/instance.cpp \ common/logging.cpp \ common/locator.cpp \ + common/notifier.cpp \ common/message.cpp \ common/tasklet.cpp \ common/timer.cpp \ @@ -213,6 +214,7 @@ HEADERS_COMMON = \ common/locator.hpp \ common/logging.hpp \ common/message.hpp \ + common/notifier.hpp \ common/owner-locator.hpp \ common/settings.hpp \ common/new.hpp \ diff --git a/src/core/api/instance_api.cpp b/src/core/api/instance_api.cpp index b2f3bf31b..ac4b3ed6a 100644 --- a/src/core/api/instance_api.cpp +++ b/src/core/api/instance_api.cpp @@ -81,18 +81,18 @@ void otInstanceFinalize(otInstance *aInstance) otLogFuncExit(); } -otError otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aCallbackContext) +otError otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aContext) { Instance &instance = *static_cast(aInstance); - return instance.RegisterStateChangedCallback(aCallback, aCallbackContext); + return instance.GetNotifier().RegisterCallback(aCallback, aContext); } -void otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aCallbackContext) +void otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aContext) { Instance &instance = *static_cast(aInstance); - instance.RemoveStateChangedCallback(aCallback, aCallbackContext); + instance.GetNotifier().RemoveCallback(aCallback, aContext); } void otInstanceReset(otInstance *aInstance) diff --git a/src/core/common/instance.cpp b/src/core/common/instance.cpp index edf9c1004..a8685d37d 100644 --- a/src/core/common/instance.cpp +++ b/src/core/common/instance.cpp @@ -55,6 +55,7 @@ Instance::Instance(void) : mActiveScanCallbackContext(NULL), mEnergyScanCallback(NULL), mEnergyScanCallbackContext(NULL), + mNotifier(*this), mTimerMilliScheduler(*this), #if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER mTimerMicroScheduler(*this), @@ -161,36 +162,6 @@ exit: return; } -otError Instance::RegisterStateChangedCallback(otStateChangedCallback aCallback, void *aContext) -{ - otError error = OT_ERROR_NO_BUFS; - - for (size_t i = 0; i < kMaxNetifCallbacks; i++) - { - if (mNetifCallback[i].IsFree()) - { - mNetifCallback[i].Set(aCallback, aContext); - error = mThreadNetif.RegisterCallback(mNetifCallback[i]); - break; - } - } - - return error; -} - -void Instance::RemoveStateChangedCallback(otStateChangedCallback aCallback, void *aContext) -{ - for (size_t i = 0; i < kMaxNetifCallbacks; i++) - { - if (mNetifCallback[i].IsServing(aCallback, aContext)) - { - mThreadNetif.RemoveCallback(mNetifCallback[i]); - mNetifCallback[i].Free(); - break; - } - } -} - void Instance::Reset(void) { otPlatReset(this); @@ -243,6 +214,11 @@ void Instance::InvokeEnergyScanCallback(otEnergyScanResult *aResult) const // Specializations of the `Get()` method. +template<> Notifier &Instance::Get(void) +{ + return GetNotifier(); +} + template<> TaskletScheduler &Instance::Get(void) { return GetTaskletScheduler(); diff --git a/src/core/common/instance.hpp b/src/core/common/instance.hpp index 6b18fd7d9..fd2e8c301 100644 --- a/src/core/common/instance.hpp +++ b/src/core/common/instance.hpp @@ -51,10 +51,10 @@ #include "crypto/heap.hpp" #include "crypto/mbedtls.hpp" #endif +#include "common/notifier.hpp" #include "net/ip6.hpp" #include "thread/thread_netif.hpp" - /** * @addtogroup core-instance * @@ -138,27 +138,6 @@ public: */ void Finalize(void); - /** - * This method registers a callback to indicate when certain configuration or state changes within OpenThread. - * - * @param[in] aCallback A pointer to a function that is called with certain configuration or state changes. - * @param[in] aContext A pointer to application-specific context. - * - * @retval OT_ERROR_NONE Added the callback to the list of callbacks and registered it with OpenThread. - * @retval OT_ERROR_NO_BUFS Could not add the callback due to resource constraints. - * - */ - otError RegisterStateChangedCallback(otStateChangedCallback aCallback, void *aContext); - - /** - * This method removes/unregisters a previously registered "state changed" callback. - * - * @param[in] aCallback A pointer to the callback function pointer. - * @param[in] aCallbackContext A pointer to application-specific context. - * - */ - void RemoveStateChangedCallback(otStateChangedCallback aCallback, void *aCallbackContext); - /** * This method triggers a platform reset. * @@ -241,6 +220,14 @@ public: */ void InvokeEnergyScanCallback(otEnergyScanResult *aResult) const; + /** + * This method returns a reference to the `Notifier` object. + * + * @returns A reference to the `Notifier` object. + * + */ + Notifier &GetNotifier(void) { return mNotifier; } + /** * This method returns a reference to the tasklet scheduler object. * @@ -343,17 +330,13 @@ private: Instance(void); void AfterInit(void); - enum - { - kMaxNetifCallbacks = OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS, - }; - - Ip6::NetifCallback mNetifCallback[kMaxNetifCallbacks]; otHandleActiveScanResult mActiveScanCallback; void *mActiveScanCallbackContext; otHandleEnergyScanResult mEnergyScanCallback; void *mEnergyScanCallbackContext; + Notifier mNotifier; + TaskletScheduler mTaskletScheduler; TimerMilliScheduler mTimerMilliScheduler; diff --git a/src/core/common/locator.cpp b/src/core/common/locator.cpp index 27cb19796..0748c3dcd 100644 --- a/src/core/common/locator.cpp +++ b/src/core/common/locator.cpp @@ -57,4 +57,9 @@ ThreadNetif &InstanceLocator::GetNetif(void) const return GetInstance().GetThreadNetif(); } +Notifier &InstanceLocator::GetNotifier(void) const +{ + return GetInstance().GetNotifier(); +} + } // namespace ot diff --git a/src/core/common/locator.hpp b/src/core/common/locator.hpp index c60892951..32a626520 100644 --- a/src/core/common/locator.hpp +++ b/src/core/common/locator.hpp @@ -42,6 +42,7 @@ namespace ot { class Instance; class ThreadNetif; +class Notifier; namespace Ip6 { class Ip6; } @@ -97,6 +98,14 @@ public: */ ThreadNetif &GetNetif(void) const; + /** + * This method returns a reference to the Notifier. + * + * @returns A reference to the Notifier. + * + */ + Notifier &GetNotifier(void) const; + protected: /** * This constructor initializes the object. diff --git a/src/core/common/notifier.cpp b/src/core/common/notifier.cpp new file mode 100644 index 000000000..31f709d0d --- /dev/null +++ b/src/core/common/notifier.cpp @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2016-2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the Notifier class. + */ + +#define WPP_NAME "notifier.tmh" + +#include "notifier.hpp" + +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "common/owner-locator.hpp" + +namespace ot { + +Notifier::Callback::Callback(Handler aHandler, void *aOwner): + OwnerLocator(aOwner), + mHandler(aHandler), + mNext(this) +{ +} + +Notifier::Notifier(Instance &aInstance): + InstanceLocator(aInstance), + mFlags(0), + mTask(aInstance, &Notifier::HandleStateChanged, this), + mCallbacks(NULL) +{ + for (unsigned int i = 0; i < kMaxExternalHandlers; i++) + { + mExternalCallbacks[i].mHandler = NULL; + mExternalCallbacks[i].mContext = NULL; + } +} + +otError Notifier::RegisterCallback(Callback &aCallback) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(aCallback.mNext == &aCallback, error = OT_ERROR_ALREADY); + + aCallback.mNext = mCallbacks; + mCallbacks = &aCallback; + +exit: + return error; +} + +void Notifier::RemoveCallback(Callback &aCallback) +{ + VerifyOrExit(mCallbacks != NULL); + + if (mCallbacks == &aCallback) + { + mCallbacks = mCallbacks->mNext; + ExitNow(); + } + + for (Callback *callback = mCallbacks; callback->mNext != NULL; callback = callback->mNext) + { + if (callback->mNext == &aCallback) + { + callback->mNext = aCallback.mNext; + ExitNow(); + } + } + +exit: + aCallback.mNext = &aCallback; +} + +otError Notifier::RegisterCallback(otStateChangedCallback aCallback, void *aContext) +{ + otError error = OT_ERROR_NONE; + ExternalCallback *unusedCallback = NULL; + + VerifyOrExit(aCallback != NULL); + + for (unsigned int i = 0; i < kMaxExternalHandlers; i++) + { + ExternalCallback &callback = mExternalCallbacks[i]; + + if (callback.mHandler == NULL) + { + if (unusedCallback == NULL) + { + unusedCallback = &callback; + } + + continue; + } + + VerifyOrExit((callback.mHandler != aCallback) || (callback.mContext != aContext), error = OT_ERROR_ALREADY); + } + + VerifyOrExit(unusedCallback != NULL, error = OT_ERROR_NO_BUFS); + + unusedCallback->mHandler = aCallback; + unusedCallback->mContext = aContext; + +exit: + return error; +} + +void Notifier::RemoveCallback(otStateChangedCallback aCallback, void *aContext) +{ + VerifyOrExit(aCallback != NULL); + + for (unsigned int i = 0; i < kMaxExternalHandlers; i++) + { + ExternalCallback &callback = mExternalCallbacks[i]; + + if ((callback.mHandler == aCallback) && (callback.mContext == aContext)) + { + callback.mHandler = NULL; + callback.mContext = NULL; + } + } + +exit: + return; +} + +void Notifier::SetFlags(uint32_t aFlags) +{ + mFlags |= aFlags; + mTask.Post(); +} + +void Notifier::HandleStateChanged(Tasklet &aTasklet) +{ + aTasklet.GetOwner().HandleStateChanged(); +} + +void Notifier::HandleStateChanged(void) +{ + uint32_t flags = mFlags; + + VerifyOrExit(flags != 0); + + mFlags = 0; + + LogChangedFlags(flags); + + for (Callback *callback = mCallbacks; callback != NULL; callback = callback->mNext) + { + if (callback->mHandler != NULL) + { + callback->mHandler(*callback, flags); + } + } + + for (unsigned int i = 0; i < kMaxExternalHandlers; i++) + { + ExternalCallback &callback = mExternalCallbacks[i]; + + if (callback.mHandler != NULL) + { + callback.mHandler(flags, callback.mContext); + } + } + +exit: + return; +} + +#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1) + +void Notifier::LogChangedFlags(uint32_t aFlags) const +{ + uint32_t flags = aFlags; + char stringBuffer[kFlagsStringBufferSize]; + char *buf = stringBuffer; + int len = sizeof(stringBuffer) - 1; + int charsWritten; + + for (uint8_t bit = 0; bit < 32; bit++) + { + VerifyOrExit(flags != 0); + + if (flags & (1 << bit)) + { + charsWritten = snprintf(buf, static_cast(len), "%s ", FlagToString(1 << bit)); + VerifyOrExit(charsWritten >= 0 && charsWritten < len); + buf += charsWritten; + len -= charsWritten; + + flags ^= (1 << bit); + } + } + +exit: + stringBuffer[sizeof(stringBuffer) - 1] = 0; + otLogInfoMle(GetInstance(), "Notifier: StateChanged (0x%04x) [ %s] ", aFlags, stringBuffer); +} + +const char *Notifier::FlagToString(uint32_t aFlag) const +{ + const char *retval = "(unknown)"; + + switch (aFlag) + { + case OT_CHANGED_IP6_ADDRESS_ADDED: + retval = "Ip6+"; + break; + + case OT_CHANGED_IP6_ADDRESS_REMOVED: + retval = "Ip6-"; + break; + + case OT_CHANGED_THREAD_ROLE: + retval = "Role"; + break; + + case OT_CHANGED_THREAD_LL_ADDR: + retval = "LLAddr"; + break; + + case OT_CHANGED_THREAD_ML_ADDR: + retval = "MLAddr"; + break; + + case OT_CHANGED_THREAD_RLOC_ADDED: + retval = "Rloc+"; + break; + + case OT_CHANGED_THREAD_RLOC_REMOVED: + retval = "Rloc-"; + break; + + case OT_CHANGED_THREAD_PARTITION_ID: + retval = "PartitionId"; + break; + + case OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER: + retval = "KeySeqCntr"; + break; + + case OT_CHANGED_THREAD_NETDATA: + retval = "NetData"; + break; + + case OT_CHANGED_THREAD_CHILD_ADDED: + retval = "Child+"; + break; + + case OT_CHANGED_THREAD_CHILD_REMOVED: + retval = "Child-"; + break; + + case OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED: + retval = "Ip6Mult+"; + break; + + case OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED: + retval = "Ip6Mult-"; + break; + + case OT_CHANGED_COMMISSIONER_STATE: + retval = "CommissionerState"; + break; + + case OT_CHANGED_JOINER_STATE: + retval = "JoinerState"; + break; + + case OT_CHANGED_THREAD_CHANNEL: + retval = "Channel"; + break; + + case OT_CHANGED_THREAD_PANID: + retval = "PanId"; + break; + + case OT_CHANGED_THREAD_NETWORK_NAME: + retval = "NetName"; + break; + + case OT_CHANGED_THREAD_EXT_PANID: + retval = "ExtPanId"; + break; + + case OT_CHANGED_MASTER_KEY: + retval = "MstrKey"; + break; + + case OT_CHANGED_PSKC: + retval = "PSKc"; + break; + + case OT_CHANGED_SECURITY_POLICY: + retval = "SecPolicy"; + break; + + default: + break; + } + + return retval; +} + +#else // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1) + +void Notifier::LogChangedFlags(uint32_t aFlags) const +{ + OT_UNUSED_VARIABLE(aFlags); +} + +const char *Notifier::FlagToString(uint32_t aFlag) const +{ + OT_UNUSED_VARIABLE(aFlag); + return NULL; +} + +#endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1) + +} // namespace ot diff --git a/src/core/common/notifier.hpp b/src/core/common/notifier.hpp new file mode 100644 index 000000000..7c2869b61 --- /dev/null +++ b/src/core/common/notifier.hpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016-2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file defines OpenThread Notifier class. + */ + +#ifndef NOTIFIER_HPP_ +#define NOTIFIER_HPP_ + +#include "openthread-core-config.h" + +#include "utils/wrap_stdint.h" +#include "utils/wrap_stdbool.h" + +#include +#include + +#include "common/locator.hpp" +#include "common/tasklet.hpp" + +namespace ot { + +/** + * @addtogroup core-notifier + * + * @brief + * This module includes definitions for OpenThread Notifier class. + * + * @{ + * + */ + +/** + * This class implements the OpenThread Notifier. + * + * It can be used to register callbacks to be notified of state or configuration changes within OpenThread. + * + */ +class Notifier: public InstanceLocator +{ +public: + + /** + * This class defines a callback instance that can be registered with the `Notifier`. + * + */ + class Callback: public OwnerLocator + { + friend class Notifier; + + public: + /** + * This type defines the function pointer which is called to notify of state or configuration changes. + * + * @param[in] aCallback A reference to callback instance. + * @param[in] aFlags A bit-field indicating specific state that has changed. See `OT_CHANGED_` + * definitions in `types.h`. + * + */ + typedef void (*Handler)(Callback &aCallback, uint32_t aFlags); + + /** + * This constructor initializes a `Callback` instance + * + * @param[in] aHandler A function pointer to the callback handler. + * @param[in] aOwner A pointer to the owner of the `Callback` instance. + * + */ + Callback(Handler aHandler, void *aOwner); + + private: + Handler mHandler; + Callback *mNext; + }; + + /** + * This constructor initializes a `Notifier` instance. + * + * @param[in] aInstance A reference to OpenThread instance. + * + */ + Notifier(Instance &aInstance); + + /** + * This method registers a callback. + * + * @param[in] aCallback A reference to the callback instance. + * + * @retval OT_ERROR_NONE Successfully registered the callback. + * @retval OT_ERROR_ALREADY The callback was already registered. + * + */ + otError RegisterCallback(Callback &aCallback); + + /** + * This method removes a previously registered callback. + * + * @param[in] aCallback A reference to the callback instance. + * + */ + void RemoveCallback(Callback &aCallback); + + /** + * This method registers an `otStateChangedCallback` handler. + * + * @param[in] aCallback A pointer to the handler function that is called to notify of the changes. + * @param[in] aContext A pointer to arbitrary context information. + * + * @retval OT_ERROR_NONE Successfully registered the callback. + * @retval OT_ERROR_ALREADY The callback was already registered. + * @retval OT_ERROR_NO_BUFS Could not add the callback due to resource constraints. + * + */ + otError RegisterCallback(otStateChangedCallback aCallback, void *aContext); + + /** + * This method removes/unregisters a previously registered `otStateChangedCallback` handler. + * + * @param[in] aCallback A pointer to the callback function pointer. + * @param[in] aContex A pointer to arbitrary context information. + * + */ + void RemoveCallback(otStateChangedCallback aCallback, void *aContext); + + /** + * This method schedules notification of changed flags. + * + * The @p aFlags are combined (bitwise-or) with other flags that have not been provided in a callback yet. + * + * @param[in] aFlags A bit-field indicating what configuration or state has changed. + * + */ + void SetFlags(uint32_t aFlags); + + /** + * This method indicates whether or not a state changed callback is pending. + * + * @retval TRUE if a state changed callback is pending, FALSE otherwise. + * + */ + bool IsPending(void) const { return (mFlags != 0); } + +private: + enum + { + kMaxExternalHandlers = OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS, + kFlagsStringBufferSize = 128, + }; + + struct ExternalCallback + { + otStateChangedCallback mHandler; + void *mContext; + }; + + static void HandleStateChanged(Tasklet &aTasklet); + void HandleStateChanged(void); + + void LogChangedFlags(uint32_t aFlags) const; + const char *FlagToString(uint32_t aFlag) const; + + uint32_t mFlags; + Tasklet mTask; + Callback *mCallbacks; + ExternalCallback mExternalCallbacks[kMaxExternalHandlers]; +}; + +/** + * @} + * + */ + +} // namespace ot + +#endif // NOTIFIER_HPP_ diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 25b59590c..8e8e97b4d 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -127,7 +127,7 @@ otError Commissioner::Stop(void) GetNetif().GetCoapSecure().Stop(); mState = OT_COMMISSIONER_STATE_DISABLED; - GetNetif().SetStateChangedFlags(OT_CHANGED_COMMISSIONER_STATE); + GetNotifier().SetFlags(OT_CHANGED_COMMISSIONER_STATE); RemoveCoapResources(); mTransmitAttempts = 0; @@ -677,7 +677,7 @@ exit: } } - GetNetif().SetStateChangedFlags(OT_CHANGED_COMMISSIONER_STATE); + GetNotifier().SetFlags(OT_CHANGED_COMMISSIONER_STATE); otLogFuncExit(); } diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index d444a19b4..12bffe348 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -103,6 +103,7 @@ const Tlv *DatasetManager::GetTlv(Tlv::Type aType) const otError DatasetManager::ApplyConfiguration(void) { ThreadNetif &netif = GetNetif(); + Mac::Mac &mac = netif.GetMac(); otError error = OT_ERROR_NONE; Dataset datasetLocal(mLocal.GetType()); Dataset *dataset; @@ -128,22 +129,49 @@ otError DatasetManager::ApplyConfiguration(void) { case Tlv::kChannel: { - const ChannelTlv *channel = static_cast(cur); - netif.GetMac().SetChannel(static_cast(channel->GetChannel())); + uint8_t channel = static_cast(static_cast(cur)->GetChannel()); + + if (mac.GetChannel() != channel) + { + error = mac.SetChannel(channel); + + if (error != OT_ERROR_NONE) + { + otLogWarnMeshCoP(GetInstance(), + "DatasetManager::ApplyConfiguration() Failed to set channel to %d (%s)", + channel, otThreadErrorToString(error)); + ExitNow(); + } + + GetNotifier().SetFlags(OT_CHANGED_THREAD_CHANNEL); + } + break; } case Tlv::kPanId: { - const PanIdTlv *panid = static_cast(cur); - netif.GetMac().SetPanId(panid->GetPanId()); + uint16_t panid = static_cast(cur)->GetPanId(); + + if (mac.GetPanId() != panid) + { + mac.SetPanId(panid); + GetNotifier().SetFlags(OT_CHANGED_THREAD_PANID); + } + break; } case Tlv::kExtendedPanId: { const ExtendedPanIdTlv *extpanid = static_cast(cur); - netif.GetMac().SetExtendedPanId(extpanid->GetExtendedPanId()); + + if (memcmp(mac.GetExtendedPanId(), extpanid->GetExtendedPanId(), OT_EXT_PAN_ID_SIZE) != 0) + { + mac.SetExtendedPanId(extpanid->GetExtendedPanId()); + GetNotifier().SetFlags(OT_CHANGED_THREAD_EXT_PANID); + } + break; } @@ -153,7 +181,13 @@ otError DatasetManager::ApplyConfiguration(void) otNetworkName networkName; memcpy(networkName.m8, name->GetNetworkName(), name->GetLength()); networkName.m8[name->GetLength()] = '\0'; - netif.GetMac().SetNetworkName(networkName.m8); + + if (strcmp(networkName.m8, mac.GetNetworkName()) != 0) + { + mac.SetNetworkName(networkName.m8); + GetNotifier().SetFlags(OT_CHANGED_THREAD_NETWORK_NAME); + } + break; } @@ -199,6 +233,7 @@ otError DatasetManager::ApplyConfiguration(void) cur = cur->GetNext(); } +exit: return error; } diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index e3bbf2b7a..baec25cec 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -98,7 +98,7 @@ otError Joiner::Start(const char *aPSKd, const char *aProvisioningUrl, VerifyOrExit(mState == OT_JOINER_STATE_IDLE, error = OT_ERROR_BUSY); - GetNetif().SetStateChangedFlags(OT_CHANGED_JOINER_STATE); + GetNotifier().SetFlags(OT_CHANGED_JOINER_STATE); // use extended address based on factory-assigned IEEE EUI-64 GetJoinerId(joinerId); @@ -173,7 +173,7 @@ void Joiner::Complete(otError aError) ThreadNetif &netif = GetNetif(); mState = OT_JOINER_STATE_IDLE; otError error = OT_ERROR_NOT_FOUND; - GetNetif().SetStateChangedFlags(OT_CHANGED_JOINER_STATE); + GetNotifier().SetFlags(OT_CHANGED_JOINER_STATE); netif.GetCoapSecure().Disconnect(); diff --git a/src/core/meshcop/joiner_router.cpp b/src/core/meshcop/joiner_router.cpp index 45dbbe290..8cf8a7c27 100644 --- a/src/core/meshcop/joiner_router.cpp +++ b/src/core/meshcop/joiner_router.cpp @@ -61,22 +61,22 @@ JoinerRouter::JoinerRouter(Instance &aInstance): mSocket(aInstance.GetThreadNetif().GetIp6().GetUdp()), mRelayTransmit(OT_URI_PATH_RELAY_TX, &JoinerRouter::HandleRelayTransmit, this), mTimer(aInstance, &JoinerRouter::HandleTimer, this), + mNotifierCallback(&JoinerRouter::HandleStateChanged, this), mJoinerUdpPort(0), mIsJoinerPortConfigured(false), mExpectJoinEntRsp(false) { mSocket.GetSockName().mPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT; GetNetif().GetCoap().AddResource(mRelayTransmit); - mNetifCallback.Set(HandleNetifStateChanged, this); - GetNetif().RegisterCallback(mNetifCallback); + aInstance.GetNotifier().RegisterCallback(mNotifierCallback); } -void JoinerRouter::HandleNetifStateChanged(uint32_t aFlags, void *aContext) +void JoinerRouter::HandleStateChanged(Notifier::Callback &aCallback, uint32_t aFlags) { - static_cast(aContext)->HandleNetifStateChanged(aFlags); + aCallback.GetOwner().HandleStateChanged(aFlags); } -void JoinerRouter::HandleNetifStateChanged(uint32_t aFlags) +void JoinerRouter::HandleStateChanged(uint32_t aFlags) { ThreadNetif &netif = GetNetif(); @@ -142,7 +142,7 @@ otError JoinerRouter::SetJoinerUdpPort(uint16_t aJoinerUdpPort) otLogFuncEntry(); mJoinerUdpPort = aJoinerUdpPort; mIsJoinerPortConfigured = true; - HandleNetifStateChanged(OT_CHANGED_THREAD_NETDATA); + HandleStateChanged(OT_CHANGED_THREAD_NETDATA); otLogFuncExit(); return OT_ERROR_NONE; } diff --git a/src/core/meshcop/joiner_router.hpp b/src/core/meshcop/joiner_router.hpp index fcbc5c196..a301d4af8 100644 --- a/src/core/meshcop/joiner_router.hpp +++ b/src/core/meshcop/joiner_router.hpp @@ -42,6 +42,7 @@ #include "coap/coap_header.hpp" #include "common/locator.hpp" #include "common/message.hpp" +#include "common/notifier.hpp" #include "common/timer.hpp" #include "mac/mac_frame.hpp" #include "meshcop/meshcop_tlvs.hpp" @@ -89,8 +90,8 @@ private: kDelayJoinEnt = 50, ///< milliseconds }; - static void HandleNetifStateChanged(uint32_t aFlags, void *aContext); - void HandleNetifStateChanged(uint32_t aFlags); + static void HandleStateChanged(Notifier::Callback &aCallback, uint32_t aFlags); + void HandleStateChanged(uint32_t aFlags); static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); @@ -113,14 +114,14 @@ private: otError GetBorderAgentRloc(uint16_t &aRloc); - Ip6::NetifCallback mNetifCallback; - Ip6::UdpSocket mSocket; Coap::Resource mRelayTransmit; TimerMilli mTimer; MessageQueue mDelayedJoinEnts; + Notifier::Callback mNotifierCallback; + uint16_t mJoinerUdpPort; bool mIsJoinerPortConfigured : 1; diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp index 70ec9173f..a51706248 100644 --- a/src/core/net/netif.cpp +++ b/src/core/net/netif.cpp @@ -93,14 +93,11 @@ const otNetifMulticastAddress Netif::kLinkLocalAllRoutersMulticastAddress = Netif::Netif(Instance &aInstance, int8_t aInterfaceId): InstanceLocator(aInstance), - mCallbacks(NULL), mUnicastAddresses(NULL), mMulticastAddresses(NULL), mInterfaceId(aInterfaceId), mMulticastPromiscuous(false), - mStateChangedTask(aInstance, &Netif::HandleStateChangedTask, this), - mNext(NULL), - mStateChangedFlags(0) + mNext(NULL) { for (size_t i = 0; i < sizeof(mExtUnicastAddresses) / sizeof(mExtUnicastAddresses[0]); i++) { @@ -118,54 +115,6 @@ Netif::Netif(Instance &aInstance, int8_t aInterfaceId): const_cast(&kLinkLocalAllNodesMulticastAddress)); } -otError Netif::RegisterCallback(NetifCallback &aCallback) -{ - otError error = OT_ERROR_NONE; - - for (NetifCallback *cur = mCallbacks; cur; cur = cur->mNext) - { - if (cur == &aCallback) - { - ExitNow(error = OT_ERROR_ALREADY); - } - } - - aCallback.mNext = mCallbacks; - mCallbacks = &aCallback; - -exit: - return error; -} - -otError Netif::RemoveCallback(NetifCallback &aCallback) -{ - otError error = OT_ERROR_ALREADY; - NetifCallback *prev = NULL; - - for (NetifCallback *cur = mCallbacks; cur; cur = cur->mNext) - { - if (cur == &aCallback) - { - if (prev) - { - prev->mNext = cur->mNext; - } - else - { - mCallbacks = mCallbacks->mNext; - } - - cur->mNext = NULL; - error = OT_ERROR_NONE; - break; - } - - prev = cur; - } - - return error; -} - bool Netif::IsMulticastSubscribed(const Address &aAddress) const { bool rval = false; @@ -208,7 +157,7 @@ otError Netif::SubscribeAllRoutersMulticast(void) } } - SetStateChangedFlags(OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED); + GetNotifier().SetFlags(OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED); exit: return error; @@ -240,7 +189,7 @@ exit: if (error != OT_ERROR_NOT_FOUND) { - SetStateChangedFlags(OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED); + GetNotifier().SetFlags(OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED); } return error; @@ -261,7 +210,7 @@ otError Netif::SubscribeMulticast(NetifMulticastAddress &aAddress) aAddress.mNext = mMulticastAddresses; mMulticastAddresses = &aAddress; - SetStateChangedFlags(OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED); + GetNotifier().SetFlags(OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED); exit: return error; @@ -294,7 +243,7 @@ exit: if (error != OT_ERROR_NOT_FOUND) { - SetStateChangedFlags(OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED); + GetNotifier().SetFlags(OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED); } return error; @@ -327,7 +276,7 @@ otError Netif::SubscribeExternalMulticast(const Address &aAddress) entry->mAddress = aAddress; entry->mNext = mMulticastAddresses; mMulticastAddresses = entry; - SetStateChangedFlags(OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED); + GetNotifier().SetFlags(OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED); exit: return error; @@ -367,7 +316,7 @@ otError Netif::UnsubscribeExternalMulticast(const Address &aAddress) // To mark the address entry as unused/available, set the `mNext` pointer back to the entry itself. entry->mNext = entry; - SetStateChangedFlags(OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED); + GetNotifier().SetFlags(OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED); exit: return error; @@ -402,7 +351,7 @@ otError Netif::AddUnicastAddress(NetifUnicastAddress &aAddress) aAddress.mNext = mUnicastAddresses; mUnicastAddresses = &aAddress; - SetStateChangedFlags(aAddress.mRloc ? OT_CHANGED_THREAD_RLOC_ADDED : OT_CHANGED_IP6_ADDRESS_ADDED); + GetNotifier().SetFlags(aAddress.mRloc ? OT_CHANGED_THREAD_RLOC_ADDED : OT_CHANGED_IP6_ADDRESS_ADDED); exit: return error; @@ -435,7 +384,8 @@ exit: if (error != OT_ERROR_NOT_FOUND) { - SetStateChangedFlags(aAddress.mRloc ? OT_CHANGED_THREAD_RLOC_REMOVED : OT_CHANGED_IP6_ADDRESS_REMOVED); + GetNotifier().SetFlags(aAddress.mRloc ? + OT_CHANGED_THREAD_RLOC_REMOVED : OT_CHANGED_IP6_ADDRESS_REMOVED); } return error; @@ -478,7 +428,7 @@ otError Netif::AddExternalUnicastAddress(const NetifUnicastAddress &aAddress) entry->mNext = mUnicastAddresses; mUnicastAddresses = entry; - SetStateChangedFlags(OT_CHANGED_IP6_ADDRESS_ADDED); + GetNotifier().SetFlags(OT_CHANGED_IP6_ADDRESS_ADDED); exit: return error; @@ -518,7 +468,7 @@ otError Netif::RemoveExternalUnicastAddress(const Address &aAddress) // To mark the address entry as unused/available, set the `mNext` pointer back to the entry itself. entry->mNext = entry; - SetStateChangedFlags(OT_CHANGED_IP6_ADDRESS_REMOVED); + GetNotifier().SetFlags(OT_CHANGED_IP6_ADDRESS_REMOVED); exit: return error; @@ -554,28 +504,5 @@ exit: return rval; } -void Netif::SetStateChangedFlags(uint32_t aFlags) -{ - mStateChangedFlags |= aFlags; - mStateChangedTask.Post(); -} - -void Netif::HandleStateChangedTask(Tasklet &aTasklet) -{ - aTasklet.GetOwner().HandleStateChangedTask(); -} - -void Netif::HandleStateChangedTask(void) -{ - uint32_t flags = mStateChangedFlags; - - mStateChangedFlags = 0; - - for (NetifCallback *callback = mCallbacks; callback; callback = callback->mNext) - { - callback->Callback(flags); - } -} - } // namespace Ip6 } // namespace ot diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp index 6cfd326d2..b350dc51a 100644 --- a/src/core/net/netif.hpp +++ b/src/core/net/netif.hpp @@ -174,80 +174,6 @@ public: } }; -/** - * This class implements network interface handlers. - * - */ -class NetifCallback -{ - friend class Netif; - -public: - /** - * This constructor initializes the object. - * - */ - NetifCallback(void): - mCallback(NULL), - mContext(NULL), - mNext(NULL) { - } - - /** - * This method sets the callback information. - * - * @param[in] aCallback A pointer to a function that is called when configuration or state changes. - * @param[in] aContext A pointer to arbitrary context information. - * - */ - void Set(otStateChangedCallback aCallback, void *aContext) { - mCallback = aCallback; - mContext = aContext; - } - - /** - * This method tests whether the object is free or in use. - * - * @returns True if the object is free, false otherwise. - * - */ - bool IsFree(void) { return (mCallback == NULL); } - - /** - * This method frees the object. - * - */ - void Free(void) { - mCallback = NULL; - mContext = NULL; - mNext = NULL; - } - - /** - * This method tests whether the object is set to the provided elements. - * - * @param[in] aCallback A pointer to a function that is called when configuration or state changes. - * @param[in] aContext A pointer to arbitrary context information. - * - * @returns True if the object elements equal the input params, false otherwise. - * - */ - bool IsServing(otStateChangedCallback aCallback, void *aContext) { - return (aCallback == mCallback && aContext == mContext); - } - -private: - void Callback(uint32_t aFlags) { - if (mCallback != NULL) { - mCallback(aFlags, mContext); - } - } - - otStateChangedCallback mCallback; - void *mContext; - NetifCallback *mNext; -}; - /** * This class implements an IPv6 network interface. * @@ -458,44 +384,6 @@ public: */ void SetMulticastPromiscuous(bool aEnabled) { mMulticastPromiscuous = aEnabled; } - /** - * This method registers a network interface callback. - * - * @param[in] aCallback A reference to the callback. - * - * @retval OT_ERROR_NONE Successfully registered the callback. - * @retval OT_ERROR_ALREADY The callback was already registered. - */ - otError RegisterCallback(NetifCallback &aCallback); - - /** - * This method removes a network interface callback. - * - * @param[in] aCallback A reference to the callback. - * - * @retval OT_ERROR_NONE Successfully removed the callback. - * @retval OT_ERROR_ALREADY The callback was not in the list. - */ - otError RemoveCallback(NetifCallback &aCallback); - - /** - * This method indicates whether or not a state changed callback is pending. - * - * @retval TRUE if a state changed callback is pending, FALSE otherwise. - * - */ - bool IsStateChangedCallbackPending(void) { return mStateChangedFlags != 0; } - - /** - * This method schedules notification of @p aFlags. - * - * The @p aFlags are combined (bitwise-or) with other flags that have not been provided in a callback yet. - * - * @param[in] aFlags A bit-field indicating what configuration or state has changed. - * - */ - void SetStateChangedFlags(uint32_t aFlags); - /** * This virtual method enqueues an IPv6 messages on this network interface. * @@ -531,19 +419,12 @@ public: uint8_t *aPrefixMatch) = 0; private: - static void HandleStateChangedTask(Tasklet &aTasklet); - void HandleStateChangedTask(void); - - NetifCallback *mCallbacks; NetifUnicastAddress *mUnicastAddresses; NetifMulticastAddress *mMulticastAddresses; int8_t mInterfaceId; bool mMulticastPromiscuous; - Tasklet mStateChangedTask; Netif *mNext; - uint32_t mStateChangedFlags; - NetifUnicastAddress mExtUnicastAddresses[OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS]; NetifMulticastAddress mExtMulticastAddresses[OPENTHREAD_CONFIG_MAX_EXT_MULTICAST_IP_ADDRS]; diff --git a/src/core/thread/energy_scan_server.cpp b/src/core/thread/energy_scan_server.cpp index 7088f62a9..0f5c0e71c 100644 --- a/src/core/thread/energy_scan_server.cpp +++ b/src/core/thread/energy_scan_server.cpp @@ -60,11 +60,10 @@ EnergyScanServer::EnergyScanServer(Instance &aInstance) : mActive(false), mScanResultsLength(0), mTimer(aInstance, &EnergyScanServer::HandleTimer, this), + mNotifierCallback(&EnergyScanServer::HandleStateChanged, this), mEnergyScan(OT_URI_PATH_ENERGY_SCAN, &EnergyScanServer::HandleRequest, this) { - mNetifCallback.Set(&EnergyScanServer::HandleNetifStateChanged, this); - GetNetif().RegisterCallback(mNetifCallback); - + aInstance.GetNotifier().RegisterCallback(mNotifierCallback); GetNetif().GetCoap().AddResource(mEnergyScan); } @@ -226,12 +225,12 @@ exit: return error; } -void EnergyScanServer::HandleNetifStateChanged(uint32_t aFlags, void *aContext) +void EnergyScanServer::HandleStateChanged(Notifier::Callback &aCallback, uint32_t aFlags) { - static_cast(aContext)->HandleNetifStateChanged(aFlags); + aCallback.GetOwner().HandleStateChanged(aFlags); } -void EnergyScanServer::HandleNetifStateChanged(uint32_t aFlags) +void EnergyScanServer::HandleStateChanged(uint32_t aFlags) { if ((aFlags & OT_CHANGED_THREAD_NETDATA) != 0 && !mActive && diff --git a/src/core/thread/energy_scan_server.hpp b/src/core/thread/energy_scan_server.hpp index a87ed5dd1..71e67dc94 100644 --- a/src/core/thread/energy_scan_server.hpp +++ b/src/core/thread/energy_scan_server.hpp @@ -40,6 +40,7 @@ #include "coap/coap.hpp" #include "common/locator.hpp" +#include "common/notifier.hpp" #include "common/timer.hpp" #include "net/ip6_address.hpp" #include "net/udp6.hpp" @@ -82,8 +83,8 @@ private: static void HandleTimer(Timer &aTimer); void HandleTimer(void); - static void HandleNetifStateChanged(uint32_t aFlags, void *aContext); - void HandleNetifStateChanged(uint32_t aFlags); + static void HandleStateChanged(Notifier::Callback &aCallback, uint32_t aFlags); + void HandleStateChanged(uint32_t aFlags); otError SendReport(void); @@ -100,7 +101,7 @@ private: TimerMilli mTimer; - Ip6::NetifCallback mNetifCallback; + Notifier::Callback mNotifierCallback; Coap::Resource mEnergyScan; }; diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index e923b033b..3233e8ea1 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -84,7 +84,11 @@ const uint8_t *KeyManager::GetPSKc(void) const void KeyManager::SetPSKc(const uint8_t *aPSKc) { - memcpy(mPSKc, aPSKc, sizeof(mPSKc)); + if (memcmp(mPSKc, aPSKc, sizeof(mPSKc)) != 0) + { + memcpy(mPSKc, aPSKc, sizeof(mPSKc)); + GetNotifier().SetFlags(OT_CHANGED_PSKC); + } } #endif @@ -132,7 +136,7 @@ otError KeyManager::SetMasterKey(const otMasterKey &aKey) children[i].SetMleFrameCounter(0); } - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER); + GetNotifier().SetFlags(OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER | OT_CHANGED_MASTER_KEY); exit: return error; @@ -185,7 +189,7 @@ void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence) StartKeyRotationTimer(); } - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER); + GetNotifier().SetFlags(OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER); exit: return; @@ -241,6 +245,15 @@ exit: return result; } +void KeyManager::SetSecurityPolicyFlags(uint8_t aSecurityPolicyFlags) +{ + if (mSecurityPolicyFlags != aSecurityPolicyFlags) + { + mSecurityPolicyFlags = aSecurityPolicyFlags; + GetNotifier().SetFlags(OT_CHANGED_SECURITY_POLICY); + } +} + void KeyManager::StartKeyRotationTimer(void) { mHoursSinceKeyRotation = 0; diff --git a/src/core/thread/key_manager.hpp b/src/core/thread/key_manager.hpp index f3e592789..66cd2209c 100644 --- a/src/core/thread/key_manager.hpp +++ b/src/core/thread/key_manager.hpp @@ -323,7 +323,7 @@ public: * @param[in] aSecurityPolicyFlags The Security Policy Flags. * */ - void SetSecurityPolicyFlags(uint8_t aSecurityPolicyFlags) { mSecurityPolicyFlags = aSecurityPolicyFlags; } + void SetSecurityPolicyFlags(uint8_t aSecurityPolicyFlags); private: enum diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index df4448365..bcf517b20 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -103,7 +103,8 @@ Mle::Mle(Instance &aInstance) : #endif mAnnounceChannel(OT_RADIO_CHANNEL_MIN), mPreviousChannel(0), - mPreviousPanId(Mac::kPanIdBroadcast) + mPreviousPanId(Mac::kPanIdBroadcast), + mNotifierCallback(&Mle::HandleStateChanged, this) { uint8_t meshLocalPrefix[8]; size_t i = 0; @@ -199,8 +200,7 @@ Mle::Mle(Instance &aInstance) : // `SetMeshLocalPrefix()` also adds the Mesh-Local EID and subscribes // to the Link- and Realm-Local All Thread Nodes multicast addresses. - mNetifCallback.Set(&Mle::HandleNetifStateChanged, this); - GetNetif().RegisterCallback(mNetifCallback); + aInstance.GetNotifier().RegisterCallback(mNotifierCallback); #if OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH StartParentSearchTimer(); @@ -244,7 +244,7 @@ otError Mle::Start(bool aEnableReattach, bool aAnnounceAttach) VerifyOrExit(netif.IsUp(), error = OT_ERROR_INVALID_STATE); mRole = OT_DEVICE_ROLE_DETACHED; - netif.SetStateChangedFlags(OT_CHANGED_THREAD_ROLE); + GetNotifier().SetFlags(OT_CHANGED_THREAD_ROLE); SetStateDetached(); netif.GetKeyManager().Start(); @@ -582,7 +582,7 @@ otError Mle::SetStateDetached(void) if (mRole != OT_DEVICE_ROLE_DETACHED) { - netif.SetStateChangedFlags(OT_CHANGED_THREAD_ROLE); + GetNotifier().SetFlags(OT_CHANGED_THREAD_ROLE); } if (mRole == OT_DEVICE_ROLE_LEADER) @@ -610,7 +610,7 @@ otError Mle::SetStateChild(uint16_t aRloc16) if (mRole != OT_DEVICE_ROLE_CHILD) { - netif.SetStateChangedFlags(OT_CHANGED_THREAD_ROLE); + GetNotifier().SetFlags(OT_CHANGED_THREAD_ROLE); } if (mRole == OT_DEVICE_ROLE_LEADER) @@ -735,7 +735,7 @@ otError Mle::UpdateLinkLocalAddress(void) mLinkLocal64.GetAddress().SetIid(netif.GetMac().GetExtAddress()); netif.AddUnicastAddress(mLinkLocal64); - netif.SetStateChangedFlags(OT_CHANGED_THREAD_LL_ADDR); + GetNotifier().SetFlags(OT_CHANGED_THREAD_LL_ADDR); return OT_ERROR_NONE; } @@ -802,7 +802,7 @@ otError Mle::SetMeshLocalPrefix(const uint8_t *aMeshLocalPrefix) } // Changing the prefix also causes the mesh local address to be different. - netif.SetStateChangedFlags(OT_CHANGED_THREAD_ML_ADDR); + GetNotifier().SetFlags(OT_CHANGED_THREAD_ML_ADDR); exit: return OT_ERROR_NONE; @@ -854,7 +854,7 @@ void Mle::SetLeaderData(uint32_t aPartitionId, uint8_t aWeighting, uint8_t aLead mLastPartitionId = mLeaderData.GetPartitionId(); mLastPartitionRouterIdSequence = GetNetif().GetMle().GetRouterIdSequence(); mLastPartitionIdTimeout = GetNetif().GetMle().GetNetworkIdTimeout(); - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_PARTITION_ID); + GetNotifier().SetFlags(OT_CHANGED_THREAD_PARTITION_ID); } mLeaderData.SetPartitionId(aPartitionId); @@ -1276,12 +1276,12 @@ exit: return error; } -void Mle::HandleNetifStateChanged(uint32_t aFlags, void *aContext) +void Mle::HandleStateChanged(Notifier::Callback &aCallback, uint32_t aFlags) { - static_cast(aContext)->HandleNetifStateChanged(aFlags); + aCallback.GetOwner().HandleStateChanged(aFlags); } -void Mle::HandleNetifStateChanged(uint32_t aFlags) +void Mle::HandleStateChanged(uint32_t aFlags) { ThreadNetif &netif = GetNetif(); VerifyOrExit(mRole != OT_DEVICE_ROLE_DISABLED); @@ -1297,7 +1297,7 @@ void Mle::HandleNetifStateChanged(uint32_t aFlags) } netif.AddUnicastAddress(mMeshLocal64); - netif.SetStateChangedFlags(OT_CHANGED_THREAD_ML_ADDR); + GetNotifier().SetFlags(OT_CHANGED_THREAD_ML_ADDR); } if (mRole == OT_DEVICE_ROLE_CHILD && (mDeviceMode & ModeTlv::kModeFFD) == 0) @@ -1752,7 +1752,7 @@ void Mle::HandleSendChildUpdateRequest(void) { // a Network Data update can cause a change to the IPv6 address configuration // only send a Child Update Request after we know there are no more pending changes - if (GetNetif().IsStateChangedCallbackPending()) + if (GetNotifier().IsPending()) { mSendChildUpdateRequest.Post(); } diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 31e5af9ad..f4f384982 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1419,8 +1419,8 @@ private: void GenerateNonce(const Mac::ExtAddress &aMacAddr, uint32_t aFrameCounter, uint8_t aSecurityLevel, uint8_t *aNonce); - static void HandleNetifStateChanged(uint32_t aFlags, void *aContext); - void HandleNetifStateChanged(uint32_t aFlags); + static void HandleStateChanged(Notifier::Callback &aCallback, uint32_t aFlags); + void HandleStateChanged(uint32_t aFlags); static void HandleParentRequestTimer(Timer &aTimer); void HandleParentRequestTimer(void); static void HandleDelayedResponseTimer(Timer &aTimer); @@ -1534,7 +1534,7 @@ private: Ip6::NetifMulticastAddress mLinkLocalAllThreadNodes; Ip6::NetifMulticastAddress mRealmLocalAllThreadNodes; - Ip6::NetifCallback mNetifCallback; + Notifier::Callback mNotifierCallback; }; } // namespace Mle diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 0e3681722..e0d9b4e13 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -427,7 +427,7 @@ otError MleRouter::SetStateRouter(uint16_t aRloc16) if (mRole != OT_DEVICE_ROLE_ROUTER) { - netif.SetStateChangedFlags(OT_CHANGED_THREAD_ROLE); + GetNotifier().SetFlags(OT_CHANGED_THREAD_ROLE); } SetRloc16(aRloc16); @@ -466,7 +466,7 @@ otError MleRouter::SetStateLeader(uint16_t aRloc16) if (mRole != OT_DEVICE_ROLE_LEADER) { - netif.SetStateChangedFlags(OT_CHANGED_THREAD_ROLE); + GetNotifier().SetFlags(OT_CHANGED_THREAD_ROLE); } SetRloc16(aRloc16); @@ -4939,11 +4939,11 @@ void MleRouter::SignalChildUpdated(otThreadChildTableEvent aEvent, Child &aChild switch (aEvent) { case OT_THREAD_CHILD_TABLE_EVENT_CHILD_ADDED: - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_CHILD_ADDED); + GetNotifier().SetFlags(OT_CHANGED_THREAD_CHILD_ADDED); break; case OT_THREAD_CHILD_TABLE_EVENT_CHILD_REMOVED: - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_CHILD_REMOVED); + GetNotifier().SetFlags(OT_CHANGED_THREAD_CHILD_REMOVED); break; } } diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index ed229f772..1954d2573 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -68,7 +68,7 @@ void LeaderBase::Reset(void) mVersion = static_cast(otPlatRandomGet()); mStableVersion = static_cast(otPlatRandomGet()); mLength = 0; - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_NETDATA); + GetNotifier().SetFlags(OT_CHANGED_THREAD_NETDATA); } otError LeaderBase::GetContext(const Ip6::Address &aAddress, Lowpan::Context &aContext) @@ -423,7 +423,7 @@ void LeaderBase::SetNetworkData(uint8_t aVersion, uint8_t aStableVersion, bool a otDumpDebgNetData(GetInstance(), "set network data", mTlvs, mLength); - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_NETDATA); + GetNotifier().SetFlags(OT_CHANGED_THREAD_NETDATA); } otError LeaderBase::SetCommissioningData(const uint8_t *aValue, uint8_t aValueLength) @@ -446,7 +446,7 @@ otError LeaderBase::SetCommissioningData(const uint8_t *aValue, uint8_t aValueLe } mVersion++; - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_NETDATA); + GetNotifier().SetFlags(OT_CHANGED_THREAD_NETDATA); exit: return error; diff --git a/src/core/thread/network_data_leader_ftd.cpp b/src/core/thread/network_data_leader_ftd.cpp index a220b7ae7..5ba4297e7 100644 --- a/src/core/thread/network_data_leader_ftd.cpp +++ b/src/core/thread/network_data_leader_ftd.cpp @@ -101,12 +101,10 @@ void Leader::Stop(void) void Leader::IncrementVersion(void) { - ThreadNetif &netif = GetNetif(); - - if (netif.GetMle().GetRole() == OT_DEVICE_ROLE_LEADER) + if (GetNetif().GetMle().GetRole() == OT_DEVICE_ROLE_LEADER) { mVersion++; - netif.SetStateChangedFlags(OT_CHANGED_THREAD_NETDATA); + GetNotifier().SetFlags(OT_CHANGED_THREAD_NETDATA); } } @@ -145,7 +143,7 @@ void Leader::RemoveBorderRouter(uint16_t aRloc16) mStableVersion++; } - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_NETDATA); + GetNotifier().SetFlags(OT_CHANGED_THREAD_NETDATA); exit: return; @@ -771,7 +769,7 @@ otError Leader::RegisterNetworkData(uint16_t aRloc16, uint8_t *aTlvs, uint8_t aT } } - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_NETDATA); + GetNotifier().SetFlags(OT_CHANGED_THREAD_NETDATA); exit: return error; @@ -1177,7 +1175,7 @@ otError Leader::FreeContext(uint8_t aContextId) mContextUsed &= ~(1 << aContextId); mVersion++; mStableVersion++; - GetNetif().SetStateChangedFlags(OT_CHANGED_THREAD_NETDATA); + GetNotifier().SetFlags(OT_CHANGED_THREAD_NETDATA); return OT_ERROR_NONE; } diff --git a/src/ncp/changed_props_set.cpp b/src/ncp/changed_props_set.cpp index 41ad8013d..2b59c0d05 100644 --- a/src/ncp/changed_props_set.cpp +++ b/src/ncp/changed_props_set.cpp @@ -73,6 +73,12 @@ const ChangedPropsSet::Entry ChangedPropsSet::mSupportedProps[] = { SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_JOIN_FAILURE, false }, // 19 { SPINEL_PROP_MAC_SCAN_STATE, SPINEL_STATUS_OK, false }, // 20 { SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, SPINEL_STATUS_OK, true }, // 21 + { SPINEL_PROP_PHY_CHAN, SPINEL_STATUS_OK, true }, // 22 + { SPINEL_PROP_MAC_15_4_PANID, SPINEL_STATUS_OK, true }, // 23 + { SPINEL_PROP_NET_NETWORK_NAME, SPINEL_STATUS_OK, true }, // 24 + { 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 }; uint8_t ChangedPropsSet::GetNumEntries(void) const diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 8e566dcb9..83bb23532 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -577,7 +577,7 @@ NcpBase::NcpBase(Instance *aInstance): #if OPENTHREAD_MTD || OPENTHREAD_FTD otMessageQueueInit(&mMessageQueue); - otSetStateChangedCallback(mInstance, &NcpBase::HandleNetifStateChanged, this); + otSetStateChangedCallback(mInstance, &NcpBase::HandleStateChanged, this); otIp6SetReceiveCallback(mInstance, &NcpBase::HandleDatagramFromStack, this); otIp6SetReceiveFilterEnabled(mInstance, true); otLinkSetPcapCallback(mInstance, &NcpBase::HandleRawFrame, static_cast(this)); diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 92990ad13..cd1bf49c0 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -250,7 +250,7 @@ protected: #endif // OPENTHREAD_ENABLE_RAW_LINK_API #if OPENTHREAD_MTD || OPENTHREAD_FTD - static void HandleNetifStateChanged(uint32_t aFlags, void *aContext); + static void HandleStateChanged(uint32_t aFlags, void *aContext); void ProcessThreadChangedFlags(void); #if OPENTHREAD_FTD diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 265db998a..95a7862af 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -2763,7 +2763,7 @@ exit: // MARK: Property/Status Changed // ---------------------------------------------------------------------------- -void NcpBase::HandleNetifStateChanged(uint32_t aFlags, void *aContext) +void NcpBase::HandleStateChanged(uint32_t aFlags, void *aContext) { NcpBase *ncp = static_cast(aContext); @@ -2791,6 +2791,12 @@ void NcpBase::ProcessThreadChangedFlags(void) { OT_CHANGED_THREAD_CHILD_REMOVED, SPINEL_PROP_THREAD_CHILD_TABLE }, { OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED, SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE }, { OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED, SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE }, + { OT_CHANGED_THREAD_CHANNEL, SPINEL_PROP_PHY_CHAN }, + { OT_CHANGED_THREAD_PANID, SPINEL_PROP_MAC_15_4_PANID }, + { OT_CHANGED_THREAD_NETWORK_NAME, SPINEL_PROP_NET_NETWORK_NAME }, + { OT_CHANGED_THREAD_EXT_PANID, SPINEL_PROP_NET_XPANID }, + { OT_CHANGED_MASTER_KEY, SPINEL_PROP_NET_MASTER_KEY }, + { OT_CHANGED_PSKC, SPINEL_PROP_NET_PSKC }, }; VerifyOrExit(mThreadChangedFlags != 0);