diff --git a/include/openthread.h b/include/openthread.h index 4aedc0dcc..2d481a5a9 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -651,26 +651,27 @@ const otNetifAddress *otGetUnicastAddresses(void); /** * Add a Network Interface Address to the Thread interface. * - * The passed in instance @p aAddress will be added and stored by the Thread interface, so the caller should ensure - * that the address instance remains valid (not de-alloacted) and is not modified after a successful call to this - * method. + * The passed in instance @p aAddress will be copied by the Thread interface. The Thread interface only + * supports a fixed number of externally added unicast addresses. See OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS. * * @param[in] aAddress A pointer to a Network Interface Address. * - * @retval kThreadErrorNone Successfully added the Network Interface Address. - * @retval kThreadErrorBusy The Network Interface Address pointed to by @p aAddress is already added. + * @retval kThreadErrorNone Successfully added (or updated) the Network Interface Address. + * @retval kThreadError_InvalidArgs The IP Address indicated by @p aAddress is an internal address. + * @retval kThreadError_NoBufs The Network Interface is already storing the maximum allowed external addresses. */ -ThreadError otAddUnicastAddress(otNetifAddress *aAddress); +ThreadError otAddUnicastAddress(const otNetifAddress *aAddress); /** * Remove a Network Interface Address from the Thread interface. * - * @param[in] aAddress A pointer to a Network Interface Address. + * @param[in] aAddress A pointer to an IP Address. * - * @retval kThreadErrorNone Successfully removed the Network Interface Address. - * @retval kThreadErrorNotFound The Network Interface Address point to by @p aAddress was not added. + * @retval kThreadErrorNone Successfully removed the Network Interface Address. + * @retval kThreadError_InvalidArgs The IP Address indicated by @p aAddress is an internal address. + * @retval kThreadError_NotFound The IP Address indicated by @p aAddress was not found. */ -ThreadError otRemoveUnicastAddress(otNetifAddress *aAddress); +ThreadError otRemoveUnicastAddress(const otIp6Address *aAddress); /** * This function pointer is called to notify certain configuration or state changes within OpenThread. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 523b12682..3a4d00546 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -102,8 +102,6 @@ const struct Command Interpreter::sCommands[] = #endif }; -otNetifAddress Interpreter::sAddress; - static otDEFINE_ALIGNED_VAR(sPingTimerBuf, sizeof(Timer), uint64_t); Timer *Interpreter::sPingTimer; @@ -611,14 +609,15 @@ exit: ThreadError Interpreter::ProcessIpAddrAdd(int argc, char *argv[]) { ThreadError error; + otNetifAddress aAddress; VerifyOrExit(argc > 0, error = kThreadError_Parse); - SuccessOrExit(error = otIp6AddressFromString(argv[0], &sAddress.mAddress)); - sAddress.mPrefixLength = 64; - sAddress.mPreferredLifetime = 0xffffffff; - sAddress.mValidLifetime = 0xffffffff; - error = otAddUnicastAddress(&sAddress); + SuccessOrExit(error = otIp6AddressFromString(argv[0], &aAddress.mAddress)); + aAddress.mPrefixLength = 64; + aAddress.mPreferredLifetime = 0xffffffff; + aAddress.mValidLifetime = 0xffffffff; + error = otAddUnicastAddress(&aAddress); exit: return error; @@ -632,8 +631,7 @@ ThreadError Interpreter::ProcessIpAddrDel(int argc, char *argv[]) VerifyOrExit(argc > 0, error = kThreadError_Parse); SuccessOrExit(error = otIp6AddressFromString(argv[0], &address)); - VerifyOrExit(otIsIp6AddressEqual(&address, &sAddress.mAddress), error = kThreadError_Parse); - error = otRemoveUnicastAddress(&sAddress); + error = otRemoveUnicastAddress(&address); exit: return error; @@ -1989,7 +1987,7 @@ void Interpreter::HandleNetifStateChanged(uint32_t aFlags, void *aContext) if (!found) { - otRemoveUnicastAddress(address); + otRemoveUnicastAddress(&address->mAddress); address->mValidLifetime = 0; } } diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 0a96cfb4e..4ad46f29e 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -192,7 +192,6 @@ private: static void HandleLinkPcapReceive(const RadioPacket *aFrame, void *aContext); static const struct Command sCommands[]; - static otNetifAddress sAddress; static Ip6::MessageInfo sMessageInfo; static Server *sServer; diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp index a7f0f8180..0d5ef8266 100644 --- a/src/core/net/netif.cpp +++ b/src/core/net/netif.cpp @@ -51,6 +51,7 @@ Netif::Netif() : mInterfaceId = -1; mAllRoutersSubscribed = false; mNext = NULL; + mMaskExtUnicastAddresses = 0; mStateChangedFlags = 0; } @@ -313,7 +314,7 @@ ThreadError Netif::RemoveUnicastAddress(const NetifUnicastAddress &aAddress) } } - ExitNow(error = kThreadError_Error); + ExitNow(error = kThreadError_NotFound); exit: @@ -325,6 +326,96 @@ exit: return error; } + +ThreadError Netif::AddExternalUnicastAddress(const NetifUnicastAddress &aAddress) +{ + ThreadError error = kThreadError_None; + int8_t index = 0; + + for (NetifUnicastAddress *cur = mUnicastAddresses; cur; cur = cur->GetNext()) + { + if (memcmp(&cur->mAddress, &aAddress.mAddress, sizeof(otIp6Address)) == 0) + { + VerifyOrExit(GetExtUnicastAddressIndex(cur) != -1, error = kThreadError_InvalidArgs); + + cur->mPreferredLifetime = aAddress.mPreferredLifetime; + cur->mValidLifetime = aAddress.mValidLifetime; + cur->mPrefixLength = aAddress.mPrefixLength; + ExitNow(); + } + } + + // Make sure we haven't set all the bits in the mask already + VerifyOrExit(mMaskExtUnicastAddresses != ((1 << OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS) - 1), + error = kThreadError_NoBufs); + + // Get next available entry index + while ((mMaskExtUnicastAddresses & (1 << index)) != 0) + { + index++; + } + + assert(index < OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS); + + // Increase the count and mask the index + mMaskExtUnicastAddresses |= 1 << index; + + // Copy the address to the next available dynamic address + mExtUnicastAddresses[index] = aAddress; + mExtUnicastAddresses[index].mNext = mUnicastAddresses; + + mUnicastAddresses = &mExtUnicastAddresses[index]; + + SetStateChangedFlags(OT_IP6_ADDRESS_ADDED); + +exit: + return error; +} + +ThreadError Netif::RemoveExternalUnicastAddress(const Address &aAddress) +{ + ThreadError error = kThreadError_None; + NetifUnicastAddress *last = NULL; + int8_t aAddressIndexToRemove = -1; + + for (NetifUnicastAddress *cur = mUnicastAddresses; cur; cur = cur->GetNext()) + { + if (memcmp(&cur->mAddress, &aAddress, sizeof(otIp6Address)) == 0) + { + aAddressIndexToRemove = GetExtUnicastAddressIndex(cur); + VerifyOrExit(aAddressIndexToRemove != -1, error = kThreadError_InvalidArgs); + + if (last) + { + last->mNext = cur->mNext; + } + else + { + mUnicastAddresses = cur->GetNext(); + } + + break; + } + + last = cur; + } + + if (aAddressIndexToRemove != -1) + { + mMaskExtUnicastAddresses &= ~(1 << aAddressIndexToRemove); + + SetStateChangedFlags(OT_IP6_ADDRESS_REMOVED); + } + else + { + error = kThreadError_NotFound; + } + +exit: + + return error; +} + Netif *Netif::GetNetifList() { return sNetifListHead; diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp index 2dd7eed09..9bc9e92c3 100644 --- a/src/core/net/netif.hpp +++ b/src/core/net/netif.hpp @@ -256,12 +256,36 @@ public: * * @param[in] aAddress A reference to the unicast address. * - * @retval kThreadError_None Successfully removed the unicast address. - * @retval kThreadError_Busy The unicast address was already removed. + * @retval kThreadError_None Successfully removed the unicast address. + * @retval kThreadError_NotFound The unicast address wasn't found to be removed. * */ ThreadError RemoveUnicastAddress(const NetifUnicastAddress &aAddress); + /** + * This method adds an external (to OpenThread) unicast address to the network interface. + * + * @param[in] aAddress A reference to the unicast address. + * + * @retval kThreadError_None Successfully added (or updated) the unicast address. + * @retval kThreadError_InvalidArgs The address indicated by @p aAddress is an internal address. + * @retval kThreadError_NoBufs The maximum number of allowed external addresses are already added. + * + */ + ThreadError AddExternalUnicastAddress(const NetifUnicastAddress &aAddress); + + /** + * This method removes a external (to OpenThread) unicast address from the network interface. + * + * @param[in] aAddress A reference to the unicast address. + * + * @retval kThreadError_None Successfully removed the unicast address. + * @retval kThreadError_InvalidArgs The address indicated by @p aAddress is an internal address. + * @retval kThreadError_NotFound The unicast address was not found. + * + */ + ThreadError RemoveExternalUnicastAddress(const Address &aAddress); + /** * This method indicates whether or not the network interface is subscribed to a multicast address. * @@ -450,8 +474,29 @@ private: uint32_t mStateChangedFlags; + NetifUnicastAddress mExtUnicastAddresses[OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS]; + uint8_t mMaskExtUnicastAddresses; // Must have enough bits to hold OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS + static Netif *sNetifListHead; static int8_t sNextInterfaceId; + + /** + * This method determines if an address is one of the external unicast addresses, and if so returns + * the index in the mExtUnicastAddresses array. + * + * @param[in] aAddress A pointer to the Network Interface address. + * + * @returns The index in the mExtUnicastAddresses array or -1 if not part of the array. + * + */ + int8_t GetExtUnicastAddressIndex(const NetifUnicastAddress *address) { + if (address < &mExtUnicastAddresses[0] || + address >= &mExtUnicastAddresses[0] + OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS) { + return -1; + } + + return static_cast(address - &mExtUnicastAddresses[0]); + } }; /** diff --git a/src/core/openthread-core-default-config.h b/src/core/openthread-core-default-config.h index fc3787233..9d4f59b94 100644 --- a/src/core/openthread-core-default-config.h +++ b/src/core/openthread-core-default-config.h @@ -115,6 +115,16 @@ #define OPENTHREAD_CONFIG_IP_ADDRS_PER_CHILD 4 #endif // OPENTHREAD_CONFIG_IP_ADDRS_PER_CHILD +/** + * @def OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS + * + * The maximum number of supported IPv6 addresses allows to be externally added. + * + */ +#ifndef OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS +#define OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS 4 +#endif // OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS + /** * @def OPENTHREAD_CONFIG_6LOWPAN_REASSEMBLY_TIMEOUT * diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index 0d7302304..d6a99b978 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -824,14 +824,14 @@ const otNetifAddress *otGetUnicastAddresses(void) return sThreadNetif->GetUnicastAddresses(); } -ThreadError otAddUnicastAddress(otNetifAddress *address) +ThreadError otAddUnicastAddress(const otNetifAddress *address) { - return sThreadNetif->AddUnicastAddress(*static_cast(address)); + return sThreadNetif->AddExternalUnicastAddress(*static_cast(address)); } -ThreadError otRemoveUnicastAddress(otNetifAddress *address) +ThreadError otRemoveUnicastAddress(const otIp6Address *address) { - return sThreadNetif->RemoveUnicastAddress(*static_cast(address)); + return sThreadNetif->RemoveExternalUnicastAddress(*static_cast(address)); } void otSetStateChangedCallback(otStateChangedCallback aCallback, void *aContext) diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 302218992..38d5f028b 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -426,11 +426,6 @@ NcpBase::NcpBase(): mDroppedOutboundIpFrameCounter = 0; mDroppedInboundIpFrameCounter = 0; - for (unsigned i = 0; i < sizeof(mNetifAddresses) / sizeof(mNetifAddresses[0]); i++) - { - mNetifAddresses[i].mPrefixLength = kUnusedNetifAddressPrefixLen; - } - assert(sThreadNetif != NULL); otSetStateChangedCallback(&HandleNetifStateChanged, this); otSetReceiveIp6DatagramCallback(&HandleDatagramFromStack, this); @@ -3785,7 +3780,7 @@ ThreadError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t header, sp spinel_ssize_t parsedLength; ThreadError errorCode = kThreadError_None; spinel_status_t errorStatus = SPINEL_STATUS_OK; - otNetifAddress *netif_addr = NULL; + otNetifAddress netif_addr; otIp6Address *addr_ptr; uint32_t preferred_lifetime; uint32_t valid_lifetime; @@ -3803,41 +3798,14 @@ ThreadError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t header, sp VerifyOrExit(parsedLength > 0, errorStatus = SPINEL_STATUS_PARSE_ERROR); - VerifyOrExit(prefix_len != kUnusedNetifAddressPrefixLen, errorStatus = SPINEL_STATUS_INVALID_ARGUMENT); + netif_addr.mAddress = *addr_ptr; + netif_addr.mPrefixLength = prefix_len; + netif_addr.mPreferredLifetime = preferred_lifetime; + netif_addr.mValidLifetime = valid_lifetime; - for (unsigned i = 0; i < sizeof(mNetifAddresses) / sizeof(mNetifAddresses[0]); i++) - { - if (mNetifAddresses[i].mPrefixLength != kUnusedNetifAddressPrefixLen) - { - // If the address matches an already added address. - if (memcmp(&mNetifAddresses[i].mAddress, addr_ptr, sizeof(otIp6Address)) == 0) - { - netif_addr = &mNetifAddresses[i]; - break; - } - } - else - { - if (netif_addr == NULL) - { - netif_addr = &mNetifAddresses[i]; - } - } - } + errorCode = otAddUnicastAddress(&netif_addr); - VerifyOrExit(netif_addr != NULL, errorStatus = SPINEL_STATUS_NOMEM); - - netif_addr->mAddress = *addr_ptr; - netif_addr->mPrefixLength = prefix_len; - netif_addr->mPreferredLifetime = preferred_lifetime; - netif_addr->mValidLifetime = valid_lifetime; - - errorCode = otAddUnicastAddress(netif_addr); - - // `kThreadError_Busy` indicates that the address was already on the list. In this case the lifetimes and prefix len - // are updated, and the add/insert operation is considered a success. - - VerifyOrExit(errorCode == kThreadError_None || errorCode == kThreadError_Busy, + VerifyOrExit(errorCode == kThreadError_None, errorStatus = ThreadErrorToSpinelStatus(errorCode)); errorCode = SendPropertyUpdate( @@ -4110,7 +4078,6 @@ ThreadError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(uint8_t header, sp { spinel_ssize_t parsedLength; ThreadError errorCode = kThreadError_None; - otNetifAddress *netif_addr = NULL; otIp6Address *addr_ptr; parsedLength = spinel_datatype_unpack( @@ -4125,42 +4092,21 @@ ThreadError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(uint8_t header, sp if (parsedLength > 0) { - for (unsigned i = 0; i < sizeof(mNetifAddresses) / sizeof(mNetifAddresses[0]); i++) + errorCode = otRemoveUnicastAddress(addr_ptr); + + if (errorCode == kThreadError_None) { - if (mNetifAddresses[i].mPrefixLength != kUnusedNetifAddressPrefixLen) - { - if (memcmp(&mNetifAddresses[i].mAddress, addr_ptr, sizeof(otIp6Address)) == 0) - { - netif_addr = &mNetifAddresses[i]; - break; - } - } - } - - if (netif_addr != NULL) - { - errorCode = otRemoveUnicastAddress(netif_addr); - - if (errorCode == kThreadError_None) - { - netif_addr->mNext = NULL; - - errorCode = SendPropertyUpdate( - header, - SPINEL_CMD_PROP_VALUE_REMOVED, - key, - value_ptr, - value_len - ); - } - else - { - errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(errorCode)); - } + errorCode = SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_REMOVED, + key, + value_ptr, + value_len + ); } else { - errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(kThreadError_NoAddress)); + errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(errorCode)); } } else diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 1dff45c44..de7839bdc 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -411,11 +411,6 @@ private: uint16_t value_len); private: - enum - { - kNetifAddressListSize = 8, // Size of mNetifAddresses array. - kUnusedNetifAddressPrefixLen = 0xff, // Prefix len value to indicate an unused/available NetifAddress element. - }; spinel_status_t mLastStatus; @@ -435,8 +430,6 @@ private: uint16_t mDroppedReplyTidBitSet; - otNetifAddress mNetifAddresses[kNetifAddressListSize]; - bool mAllowLocalNetworkDataChange; bool mRequireJoinExistingNetwork;