From a7e34a6f17085a5d7a9bdc4a1c78eb9f66658e65 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Wed, 15 Jun 2016 12:17:05 -0700 Subject: [PATCH] Add notifications on configuration and state changes from OpenThread. (#146) Example state changes that will cause a notification: - IPv6 address added/removed - Device state (offline, detached, attached) - Device role (disabled, detached, child, router, leader) - Partition ID - Key Sequence - Child added/removed --- include/openthread-types.h | 18 ++++++++++ include/openthread.h | 18 ++++++++++ src/core/mac/mac.cpp | 6 ++++ src/core/mac/mac.hpp | 1 + src/core/net/netif.cpp | 42 +++++++++++++++-------- src/core/net/netif.hpp | 61 ++++++++++++++++++--------------- src/core/openthread.cpp | 8 +++++ src/core/thread/key_manager.cpp | 1 + src/core/thread/mle.cpp | 48 +++++++++++++++++++++----- src/core/thread/mle.hpp | 16 +++++++-- src/core/thread/mle_router.cpp | 30 ++++++++++++---- src/ncp/ncp_base.cpp | 10 +++--- src/ncp/ncp_base.hpp | 4 +-- 13 files changed, 196 insertions(+), 67 deletions(-) diff --git a/include/openthread-types.h b/include/openthread-types.h index 0f2f5af66..8b67da23d 100644 --- a/include/openthread-types.h +++ b/include/openthread-types.h @@ -206,6 +206,24 @@ typedef struct otLinkModeConfig uint8_t mNetworkData : 1; } otLinkModeConfig; +/** + * This enumeration represents flags that indicate what configuration or state has changed within OpenThread. + * + */ +enum +{ + OT_IP6_ADDRESS_ADDED = 1 << 0, ///< IPv6 address was added + OT_IP6_ADDRESS_REMOVED = 1 << 1, ///< IPv6 address was removed + + OT_NET_STATE = 1 << 2, ///< Device state (offline, detached, attached) changed + OT_NET_ROLE = 1 << 3, ///< Device role (disabled, detached, child, router, leader) changed + OT_NET_PARTITION_ID = 1 << 4, ///< Partition ID changed + OT_NET_KEY_SEQUENCE = 1 << 5, ///< Thread Key Sequence changed + + OT_THREAD_CHILD_ADDED = 1 << 6, ///< Child was added + OT_THREAD_CHILD_REMOVED = 1 << 7 ///< Child was removed +}; + /** * @} */ diff --git a/include/openthread.h b/include/openthread.h index d2ec91682..fc6dcc3de 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -457,6 +457,24 @@ ThreadError otAddUnicastAddress(otNetifAddress *aAddress); */ ThreadError otRemoveUnicastAddress(otNetifAddress *aAddress); +/** + * This function pointer is called to notify certain configuration or state changes within OpenThread. + * + * @param[in] aFlags A bit-field indicating specific state that has changed. + * @param[in] aContext A pointer to application-specific context. + * + */ +typedef void (*otStateChangedCallback)(uint32_t aFlags, void *aContext); + +/** + * This function 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. + * + */ +void otSetStateChangedCallback(otStateChangedCallback aCallback, void *aContext); + /** * @} */ diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 9000ce108..6883827a1 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -73,6 +73,7 @@ Mac::Mac(ThreadNetif &aThreadNetif): mReceiveTimer(&HandleReceiveTimer, this), mKeyManager(aThreadNetif.GetKeyManager()), mMle(aThreadNetif.GetMle()), + mNetif(aThreadNetif), mWhitelist() { sMac = this; @@ -611,6 +612,11 @@ void Mac::SentFrame(bool aAcked) if ((neighbor = mMle.GetNeighbor(destination)) != NULL) { + if (neighbor->mState == Neighbor::kStateValid && mMle.GetChildId(neighbor->mValid.mRloc16) != 0) + { + mNetif.SetStateChangedFlags(OT_THREAD_CHILD_REMOVED); + } + neighbor->mState = Neighbor::kStateInvalid; } } diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 2bf43e498..effd13886 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -455,6 +455,7 @@ private: KeyManager &mKeyManager; Mle::MleRouter &mMle; + ThreadNetif &mNetif; ExtAddress mExtAddress; ShortAddress mShortAddress; diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp index 0cf2161a6..8f82c500e 100644 --- a/src/core/net/netif.cpp +++ b/src/core/net/netif.cpp @@ -43,30 +43,32 @@ Netif *Netif::sNetifListHead = NULL; int Netif::sNextInterfaceId = 1; Netif::Netif() : - mUnicastChangedTask(&HandleUnicastChangedTask, this) + mStateChangedTask(&HandleStateChangedTask, this) { - mHandlers = NULL; + mCallbacks = NULL; mUnicastAddresses = NULL; mMulticastAddresses = NULL; mInterfaceId = -1; mAllRoutersSubscribed = false; mNext = NULL; + + mStateChangedFlags = 0; } -ThreadError Netif::RegisterHandler(NetifHandler &aHandler) +ThreadError Netif::RegisterCallback(NetifCallback &aCallback) { ThreadError error = kThreadError_None; - for (NetifHandler *cur = mHandlers; cur; cur = cur->mNext) + for (NetifCallback *cur = mCallbacks; cur; cur = cur->mNext) { - if (cur == &aHandler) + if (cur == &aCallback) { ExitNow(error = kThreadError_Busy); } } - aHandler.mNext = mHandlers; - mHandlers = &aHandler; + aCallback.mNext = mCallbacks; + mCallbacks = &aCallback; exit: return error; @@ -283,7 +285,7 @@ ThreadError Netif::AddUnicastAddress(NetifUnicastAddress &aAddress) if (!aAddress.GetAddress().IsRoutingLocator()) { - mUnicastChangedTask.Post(); + SetStateChangedFlags(OT_IP6_ADDRESS_ADDED); } exit: @@ -317,7 +319,7 @@ exit: if (!aAddress.GetAddress().IsRoutingLocator()) { - mUnicastChangedTask.Post(); + SetStateChangedFlags(OT_IP6_ADDRESS_REMOVED); } return error; @@ -451,17 +453,27 @@ exit: return rval; } -void Netif::HandleUnicastChangedTask(void *aContext) +void Netif::SetStateChangedFlags(uint32_t aFlags) { - Netif *obj = reinterpret_cast(aContext); - obj->HandleUnicastChangedTask(); + mStateChangedFlags |= aFlags; + mStateChangedTask.Post(); } -void Netif::HandleUnicastChangedTask() +void Netif::HandleStateChangedTask(void *aContext) { - for (NetifHandler *handler = mHandlers; handler; handler = handler->mNext) + Netif *obj = reinterpret_cast(aContext); + obj->HandleStateChangedTask(); +} + +void Netif::HandleStateChangedTask(void) +{ + uint32_t flags = mStateChangedFlags; + + mStateChangedFlags = 0; + + for (NetifCallback *callback = mCallbacks; callback; callback = callback->mNext) { - handler->HandleUnicastAddressesChanged(); + callback->Callback(flags); } } diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp index cfe4bf665..6be96fe8c 100644 --- a/src/core/net/netif.hpp +++ b/src/core/net/netif.hpp @@ -157,38 +157,33 @@ private: * This class implements network interface handlers. * */ -class NetifHandler +class NetifCallback { friend class Netif; public: /** - * This function pointer is called when the set of assigned unicast addresses change. + * This method sets the callback information. * - * @param[in] aContext A pointer to arbitrary context 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. * */ - typedef void (*UnicastAddressesChangedHandler)(void *aContext); - - /** - * This constructor initializes the network interface handlers. - * - * @param[in] aHandler A pointer to a function that is called when the set of assigned unicast addresses - * change. - * @param[in] aContext A pointer to arbitrary context information. - * - */ - NetifHandler(UnicastAddressesChangedHandler aHandler, void *aContext) { - mUnicastHandler = aHandler; + void Set(otStateChangedCallback aCallback, void *aContext) { + mCallback = aCallback; mContext = aContext; } private: - void HandleUnicastAddressesChanged(void) { mUnicastHandler(mContext); } + void Callback(uint32_t aFlags) { + if (mCallback != NULL) { + mCallback(aFlags, mContext); + } + } - UnicastAddressesChangedHandler mUnicastHandler; + otStateChangedCallback mCallback; void *mContext; - NetifHandler *mNext; + NetifCallback *mNext; }; /** @@ -313,14 +308,24 @@ public: ThreadError UnsubscribeMulticast(const NetifMulticastAddress &aAddress); /** - * This method registers a network interface handler. + * This method registers a network interface callback. * - * @param[in] aHandler A reference to the handler. + * @param[in] aCallback A reference to the callback. * - * @retval kThreadError_None Successfully registered the handler. - * @retval kThreadError_Busy The handler was already registered. + * @retval kThreadError_None Successfully registered the callback. + * @retval kThreadError_Busy The callback was already registered. */ - ThreadError RegisterHandler(NetifHandler &aHandler); + ThreadError RegisterCallback(NetifCallback &aCallback); + + /** + * 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. @@ -424,17 +429,19 @@ public: static int GetOnLinkNetif(const Address &aAddress); private: - static void HandleUnicastChangedTask(void *aContext); - void HandleUnicastChangedTask(void); + static void HandleStateChangedTask(void *aContext); + void HandleStateChangedTask(void); - NetifHandler *mHandlers; + NetifCallback *mCallbacks; NetifUnicastAddress *mUnicastAddresses; NetifMulticastAddress *mMulticastAddresses; int mInterfaceId; bool mAllRoutersSubscribed; - Tasklet mUnicastChangedTask; + Tasklet mStateChangedTask; Netif *mNext; + uint32_t mStateChangedFlags; + static Netif *sNetifListHead; static int sNextInterfaceId; }; diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index bf61fdb2f..45d4a1128 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -49,6 +49,8 @@ namespace Thread { // of of the features in the NCP. ThreadNetif *sThreadNetif; +static Ip6::NetifCallback sNetifCallback; + #ifdef __cplusplus extern "C" { #endif @@ -545,6 +547,12 @@ ThreadError otRemoveUnicastAddress(otNetifAddress *address) return sThreadNetif->RemoveUnicastAddress(*static_cast(address)); } +void otSetStateChangedCallback(otStateChangedCallback aCallback, void *aContext) +{ + sNetifCallback.Set(aCallback, aContext); + sThreadNetif->RegisterCallback(sNetifCallback); +} + ThreadError otEnable(void) { ThreadError error = kThreadError_None; diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index 68aafb81f..202ba60c5 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -96,6 +96,7 @@ ThreadError KeyManager::ComputeKey(uint32_t aKeySequence, uint8_t *aKey) uint32_t KeyManager::GetCurrentKeySequence() const { + mNetif.SetStateChangedFlags(OT_NET_KEY_SEQUENCE); return mCurrentKeySequence; } diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 731edd534..205665715 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -59,8 +59,7 @@ Mle::Mle(ThreadNetif &aThreadNetif) : mMesh(aThreadNetif.GetMeshForwarder()), mMleRouter(aThreadNetif.GetMle()), mNetworkData(aThreadNetif.GetNetworkDataLeader()), - mParentRequestTimer(&HandleParentRequestTimer, this), - mNetifHandler(&HandleUnicastAddressesChanged, this) + mParentRequestTimer(&HandleParentRequestTimer, this) { mDeviceState = kDeviceStateDisabled; mDeviceMode = ModeTlv::kModeRxOnWhenIdle | ModeTlv::kModeSecureDataRequest | ModeTlv::kModeFFD | @@ -135,7 +134,8 @@ Mle::Mle(ThreadNetif &aThreadNetif) : mRealmLocalAllThreadNodes.GetAddress().m16[7] = HostSwap16(0x0001); mNetif.SubscribeMulticast(mRealmLocalAllThreadNodes); - mNetif.RegisterHandler(mNetifHandler); + mNetifCallback.Set(&HandleNetifStateChanged, this); + mNetif.RegisterCallback(mNetifCallback); } ThreadError Mle::Start(void) @@ -229,6 +229,11 @@ DeviceState Mle::GetDeviceState(void) const ThreadError Mle::SetStateDetached(void) { + if (mDeviceState != kDeviceStateDetached) + { + mNetif.SetStateChangedFlags(OT_NET_STATE | OT_NET_ROLE); + } + mAddressResolver.Clear(); mDeviceState = kDeviceStateDetached; mParentRequestState = kParentIdle; @@ -241,6 +246,16 @@ ThreadError Mle::SetStateDetached(void) ThreadError Mle::SetStateChild(uint16_t aRloc16) { + if (mDeviceState == kDeviceStateDetached) + { + mNetif.SetStateChangedFlags(OT_NET_STATE); + } + + if (mDeviceState != kDeviceStateChild) + { + mNetif.SetStateChangedFlags(OT_NET_ROLE); + } + SetRloc16(aRloc16); mDeviceState = kDeviceStateChild; mParentRequestState = kParentIdle; @@ -403,6 +418,18 @@ uint8_t Mle::GetLeaderId(void) const return mLeaderData.GetLeaderRouterId(); } +void Mle::SetLeaderData(uint32_t aPartitionId, uint8_t aWeighting, uint8_t aLeaderRouterId) +{ + if (mLeaderData.GetPartitionId() != aPartitionId) + { + mNetif.SetStateChangedFlags(OT_NET_PARTITION_ID); + } + + mLeaderData.SetPartitionId(aPartitionId); + mLeaderData.SetWeighting(aWeighting); + mLeaderData.SetLeaderRouterId(aLeaderRouterId); +} + const Ip6::Address *Mle::GetMeshLocal16(void) const { return &mMeshLocal16.GetAddress(); @@ -695,14 +722,16 @@ exit: return error; } -void Mle::HandleUnicastAddressesChanged(void *aContext) +void Mle::HandleNetifStateChanged(uint32_t aFlags, void *aContext) { Mle *obj = reinterpret_cast(aContext); - obj->HandleUnicastAddressesChanged(); + obj->HandleNetifStateChanged(aFlags); } -void Mle::HandleUnicastAddressesChanged(void) +void Mle::HandleNetifStateChanged(uint32_t aFlags) { + VerifyOrExit((aFlags & (OT_IP6_ADDRESS_ADDED | OT_IP6_ADDRESS_REMOVED)) != 0, ;); + if (!mNetif.IsUnicastAddress(mMeshLocal64.GetAddress())) { // Mesh Local EID was removed, choose a new one and add it back @@ -723,6 +752,9 @@ void Mle::HandleUnicastAddressesChanged(void) default: break; } + +exit: + return; } void Mle::HandleParentRequestTimer(void *aContext) @@ -1667,9 +1699,7 @@ ThreadError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::Messa // Parent Attach Success mParentRequestTimer.Stop(); - mLeaderData.SetPartitionId(leaderData.GetPartitionId()); - mLeaderData.SetWeighting(leaderData.GetWeighting()); - mLeaderData.SetLeaderRouterId(leaderData.GetLeaderRouterId()); + SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId()); if ((mDeviceMode & ModeTlv::kModeRxOnWhenIdle) == 0) { diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 9222bfed8..713bb502b 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -888,6 +888,16 @@ protected: */ ThreadError SetStateChild(uint16_t aRloc16); + /** + * This method sets the Leader's Partition ID, Weighting, and Router ID values. + * + * @param[in] aPartitionId The Leader's Parititon ID value. + * @param[in] aWeighting The Leader's Weighting value. + * @param[in] aLeaderRouterId The Leader's Router ID value. + * + */ + void SetLeaderData(uint32_t aPartitionId, uint8_t aWeighting, uint8_t aLeaderRouterId); + ThreadNetif &mNetif; ///< The Thread Network Interface object. AddressResolver &mAddressResolver; ///< The Address Resolver object. KeyManager &mKeyManager; ///< The Key Manager object. @@ -928,8 +938,8 @@ private: void GenerateNonce(const Mac::ExtAddress &aMacAddr, uint32_t aFrameCounter, uint8_t aSecurityLevel, uint8_t *aNonce); - static void HandleUnicastAddressesChanged(void *aContext); - void HandleUnicastAddressesChanged(void); + static void HandleNetifStateChanged(uint32_t aFlags, void *aContext); + void HandleNetifStateChanged(uint32_t aFlags); static void HandleParentRequestTimer(void *aContext); void HandleParentRequestTimer(void); static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo); @@ -970,7 +980,7 @@ private: Ip6::NetifMulticastAddress mLinkLocalAllThreadNodes; Ip6::NetifMulticastAddress mRealmLocalAllThreadNodes; - Ip6::NetifHandler mNetifHandler; + Ip6::NetifCallback mNetifCallback; }; } // namespace Mle diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index e85266232..03be94466 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -227,9 +227,7 @@ ThreadError MleRouter::BecomeLeader(void) memcpy(&mRouters[mRouterId].mMacAddr, mMac.GetExtAddress(), sizeof(mRouters[mRouterId].mMacAddr)); - mLeaderData.SetPartitionId(otPlatRandomGet()); - mLeaderData.SetWeighting(mLeaderWeight); - mLeaderData.SetLeaderRouterId(mRouterId); + SetLeaderData(otPlatRandomGet(), mLeaderWeight, mRouterId); mNetworkData.Reset(); @@ -302,6 +300,16 @@ ThreadError MleRouter::HandleChildStart(otMleAttachFilter aFilter) ThreadError MleRouter::SetStateRouter(uint16_t aRloc16) { + if (mDeviceState == kDeviceStateDetached) + { + mNetif.SetStateChangedFlags(OT_NET_STATE); + } + + if (mDeviceState != kDeviceStateRouter) + { + mNetif.SetStateChangedFlags(OT_NET_ROLE); + } + SetRloc16(aRloc16); mDeviceState = kDeviceStateRouter; mParentRequestState = kParentIdle; @@ -318,6 +326,16 @@ ThreadError MleRouter::SetStateRouter(uint16_t aRloc16) ThreadError MleRouter::SetStateLeader(uint16_t aRloc16) { + if (mDeviceState == kDeviceStateDetached) + { + mNetif.SetStateChangedFlags(OT_NET_STATE); + } + + if (mDeviceState != kDeviceStateLeader) + { + mNetif.SetStateChangedFlags(OT_NET_ROLE); + } + SetRloc16(aRloc16); mDeviceState = kDeviceStateLeader; mParentRequestState = kParentIdle; @@ -819,9 +837,7 @@ ThreadError MleRouter::HandleLinkAccept(const Message &aMessage, const Ip6::Mess // Leader Data SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLeaderData, sizeof(leaderData), leaderData)); VerifyOrExit(leaderData.IsValid(), error = kThreadError_Parse); - mLeaderData.SetPartitionId(leaderData.GetPartitionId()); - mLeaderData.SetWeighting(leaderData.GetWeighting()); - mLeaderData.SetLeaderRouterId(leaderData.GetLeaderRouterId()); + SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId()); // Network Data SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kNetworkData, sizeof(networkData), networkData)); @@ -1456,6 +1472,7 @@ void MleRouter::HandleStateUpdateTimer(void) if ((Timer::GetNow() - mChildren[i].mLastHeard) >= Timer::SecToMsec(mChildren[i].mTimeout)) { mChildren[i].mState = Neighbor::kStateInvalid; + mNetif.SetStateChangedFlags(OT_THREAD_CHILD_REMOVED); } } @@ -1842,6 +1859,7 @@ ThreadError MleRouter::SendChildIdResponse(Child *aChild) } aChild->mState = Neighbor::kStateValid; + mNetif.SetStateChangedFlags(OT_THREAD_CHILD_ADDED); memset(&destination, 0, sizeof(destination)); destination.m16[0] = HostSwap16(0xfe80); diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index dfcf74128..8b3a2d826 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -224,7 +224,6 @@ static spinel_status_t ThreadErrorToSpinelStatus(ThreadError error) // ---------------------------------------------------------------------------- NcpBase::NcpBase(): - mNetifHandler(&HandleUnicastAddressesChanged, this), mUpdateAddressesTask(&RunUpdateAddressesTask, this) { mSupportedChannelMask = (0xFFFF << 11); // Default to 2.4GHz 802.15.4 channels. @@ -233,7 +232,7 @@ NcpBase::NcpBase(): sNcpContext = this; assert(sThreadNetif != NULL); - sThreadNetif->RegisterHandler(mNetifHandler); + otSetStateChangedCallback(&HandleNetifStateChanged, this); otSetReceiveIp6DatagramCallback(&HandleDatagramFromStack); } @@ -366,10 +365,13 @@ exit: // MARK: Address Table Changed Glue // ---------------------------------------------------------------------------- -void NcpBase::HandleUnicastAddressesChanged(void *context) +void NcpBase::HandleNetifStateChanged(uint32_t flags, void *context) { NcpBase *obj = reinterpret_cast(context); - obj->mUpdateAddressesTask.Post(); + if ((flags & (OT_IP6_ADDRESS_ADDED | OT_IP6_ADDRESS_REMOVED)) != 0) + { + obj->mUpdateAddressesTask.Post(); + } } void NcpBase::RunUpdateAddressesTask(void *context) diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 2ff05bc80..cdb575cff 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -95,7 +95,7 @@ private: void RunUpdateAddressesTask(void); - static void HandleUnicastAddressesChanged(void *context); + static void HandleNetifStateChanged(uint32_t flags, void *context); private: @@ -278,8 +278,6 @@ private: private: - Ip6::NetifHandler mNetifHandler; - spinel_status_t mLastStatus; uint32_t mSupportedChannelMask;