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);