diff --git a/src/ncp/ncp_host.cpp b/src/ncp/ncp_host.cpp index 26bd7f85e5b..cb95025f492 100644 --- a/src/ncp/ncp_host.cpp +++ b/src/ncp/ncp_host.cpp @@ -86,6 +86,7 @@ void NcpHost::Init(void) mNcpSpinel.Ip6SetAddressCallback( [this](const std::vector &aAddrInfos) { mNetif.UpdateIp6UnicastAddresses(aAddrInfos); }); + mNcpSpinel.NetifSetStateChangedCallback([this](bool aState) { mNetif.SetNetifState(aState); }); } void NcpHost::Deinit(void) diff --git a/src/ncp/ncp_spinel.cpp b/src/ncp/ncp_spinel.cpp index 4cc85ce5119..84c1dd65306 100644 --- a/src/ncp/ncp_spinel.cpp +++ b/src/ncp/ncp_spinel.cpp @@ -72,7 +72,9 @@ void NcpSpinel::Init(ot::Spinel::SpinelDriver &aSpinelDriver, PropsObserver &aOb void NcpSpinel::Deinit(void) { - mSpinelDriver = nullptr; + mSpinelDriver = nullptr; + mIp6AddressTableCallback = nullptr; + mNetifStateChangedCallback = nullptr; } otbrError NcpSpinel::SpinelDataUnpack(const uint8_t *aDataIn, spinel_size_t aDataLen, const char *aPackFormat, ...) @@ -364,6 +366,14 @@ void NcpSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, ui break; } + case SPINEL_PROP_NET_IF_UP: + { + bool isUp; + SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_BOOL_S, &isUp)); + SafeInvoke(mNetifStateChangedCallback, isUp); + break; + } + default: otbrLogWarning("Received uncognized key: %u", aKey); break; @@ -394,6 +404,11 @@ otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t aTid, case SPINEL_PROP_NET_IF_UP: VerifyOrExit(aKey == SPINEL_PROP_NET_IF_UP, error = OTBR_ERROR_INVALID_STATE); CallAndClear(mIp6SetEnabledTask, OT_ERROR_NONE); + { + bool isUp; + SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_BOOL_S, &isUp)); + SafeInvoke(mNetifStateChangedCallback, isUp); + } break; case SPINEL_PROP_NET_STACK_UP: diff --git a/src/ncp/ncp_spinel.hpp b/src/ncp/ncp_spinel.hpp index 2221d757fdd..3db6dcedfbb 100644 --- a/src/ncp/ncp_spinel.hpp +++ b/src/ncp/ncp_spinel.hpp @@ -83,7 +83,8 @@ class PropsObserver class NcpSpinel { public: - using Ip6AddressTableCallback = std::function &)>; + using Ip6AddressTableCallback = std::function &)>; + using NetifStateChangedCallback = std::function; /** * Constructor. @@ -195,6 +196,17 @@ class NcpSpinel */ void ThreadErasePersistentInfo(AsyncTaskPtr aAsyncTask); + /** + * This method sets the callback invoked when the network interface state changes. + * + * @param[in] aCallback The callback invoked when the network interface state changes. + * + */ + void NetifSetStateChangedCallback(const NetifStateChangedCallback &aCallback) + { + mNetifStateChangedCallback = aCallback; + } + private: using FailureHandler = std::function; @@ -271,7 +283,8 @@ class NcpSpinel AsyncTaskPtr mThreadDetachGracefullyTask; AsyncTaskPtr mThreadErasePersistentInfoTask; - Ip6AddressTableCallback mIp6AddressTableCallback; + Ip6AddressTableCallback mIp6AddressTableCallback; + NetifStateChangedCallback mNetifStateChangedCallback; }; } // namespace Ncp diff --git a/tests/scripts/expect/ncp_netif_address_update.exp b/tests/scripts/expect/ncp_netif_address_update.exp index 95329e0bef3..7c672ca9c80 100755 --- a/tests/scripts/expect/ncp_netif_address_update.exp +++ b/tests/scripts/expect/ncp_netif_address_update.exp @@ -62,11 +62,16 @@ expect -re {fd0d:7fc:a1b9:f050(:[0-9a-f]{1,4}){4,4}} expect -re {fe80:(:[0-9a-f]{1,4}){4,4}} expect eof -# Step 4. Use dbus leave method to let the node leave the network +# Step 4. Verify the wpan isUp state +spawn ip link show wpan0 +expect -re {UP} +expect eof + +# Step 5. Use dbus leave method to let the node leave the network spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.LeaveNetwork expect eof -# Step 5. Verify the addresses on wpan. +# Step 6. Verify the addresses on wpan. # There should be: # 1. link local spawn ip addr show wpan0