From aeba71b1a18f7afa4fc51704c10cc08fd8b99805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Mi=C5=9B?= Date: Thu, 29 Sep 2016 17:37:10 +0200 Subject: [PATCH] Pr/slaac utility (#698) * Provide utility for IPv6 SLAAC (#651) * Semantically Opaque Interface Identifier with IPv6 SLAAC (#651) --- etc/visual-studio/libopenthread.vcxproj | 2 + .../libopenthread.vcxproj.filters | 12 + etc/visual-studio/libopenthread_k.vcxproj | 2 + .../libopenthread_k.vcxproj.filters | 12 + examples/apps/cli/Makefile.am | 2 +- include/openthread-types.h | 23 ++ include/openthread.h | 64 +++++ src/cli/cli.cpp | 97 +------ src/cli/cli.hpp | 3 +- src/core/Makefile.am | 2 + src/core/net/ip6_address.cpp | 17 ++ src/core/net/ip6_address.hpp | 27 ++ src/core/openthread.cpp | 27 ++ src/core/utils/global_address.cpp | 244 ++++++++++++++++++ src/core/utils/global_address.hpp | 162 ++++++++++++ 15 files changed, 599 insertions(+), 97 deletions(-) create mode 100644 src/core/utils/global_address.cpp create mode 100644 src/core/utils/global_address.hpp diff --git a/etc/visual-studio/libopenthread.vcxproj b/etc/visual-studio/libopenthread.vcxproj index 85e8f48f2..da4665943 100644 --- a/etc/visual-studio/libopenthread.vcxproj +++ b/etc/visual-studio/libopenthread.vcxproj @@ -71,6 +71,7 @@ + @@ -135,6 +136,7 @@ + {DD5018BE-54C6-4FD4-9F8D-08D52FC0CD40} diff --git a/etc/visual-studio/libopenthread.vcxproj.filters b/etc/visual-studio/libopenthread.vcxproj.filters index 3435ded2b..fe2cf0c07 100644 --- a/etc/visual-studio/libopenthread.vcxproj.filters +++ b/etc/visual-studio/libopenthread.vcxproj.filters @@ -49,6 +49,12 @@ {635aaabf-80f0-40e2-9218-22ff75bc0e32} + + {A0D2E990-DC5E-4B56-A552-888F97214A17} + + + {5ac96cb9-6257-4387-9238-27649915463a} + @@ -207,6 +213,9 @@ Source Files\crypto + + Source Files\utils + @@ -395,5 +404,8 @@ Header Files\crypto + + Header Files\utils + \ No newline at end of file diff --git a/etc/visual-studio/libopenthread_k.vcxproj b/etc/visual-studio/libopenthread_k.vcxproj index 298025c32..d9e15b352 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj +++ b/etc/visual-studio/libopenthread_k.vcxproj @@ -71,6 +71,7 @@ + @@ -135,6 +136,7 @@ + {9B33C190-5D07-40BF-9536-68843DC5D7AF} diff --git a/etc/visual-studio/libopenthread_k.vcxproj.filters b/etc/visual-studio/libopenthread_k.vcxproj.filters index 8cd7dd231..fe7bb636b 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj.filters +++ b/etc/visual-studio/libopenthread_k.vcxproj.filters @@ -49,6 +49,12 @@ {8f54e8b3-d8fb-4fed-88ce-42b39f171d0b} + + {A0D2E990-DC5E-4B56-A552-888F97214A17} + + + {5ac96cb9-6257-4387-9238-27649915463a} + @@ -207,6 +213,9 @@ Source Files\crypto + + Source Files\utils + @@ -395,5 +404,8 @@ Header Files\crypto + + Header Files\utils + \ No newline at end of file diff --git a/examples/apps/cli/Makefile.am b/examples/apps/cli/Makefile.am index 4107604f4..e076b22c2 100644 --- a/examples/apps/cli/Makefile.am +++ b/examples/apps/cli/Makefile.am @@ -39,8 +39,8 @@ ot_cli_CPPFLAGS = \ $(NULL) ot_cli_LDADD = \ - $(top_builddir)/src/core/libopenthread.a \ $(top_builddir)/src/cli/libopenthread-cli.a \ + $(top_builddir)/src/core/libopenthread.a \ $(top_builddir)/third_party/mbedtls/libmbedcrypto.a \ $(NULL) diff --git a/include/openthread-types.h b/include/openthread-types.h index ec1d1f234..4595a0eac 100644 --- a/include/openthread-types.h +++ b/include/openthread-types.h @@ -132,6 +132,11 @@ typedef enum ThreadError */ kThreadError_BlacklistFiltered = 27, + /** + * The creation of IPv6 address failed. + */ + kThreadError_Ipv6AddressCreationFailure = 28, + kThreadError_Error = 255, } ThreadError; @@ -807,6 +812,24 @@ typedef struct otNetifAddress struct otNetifAddress *mNext; ///< A pointer to the next network interface address. } otNetifAddress; +/** + * This structure represents data used by Semantically Opaque IID Generator. + * + */ +typedef struct +{ + uint8_t *mInterfaceId; ///< String of bytes representing interface ID. Like "eth0" or "wlan0". + uint8_t mInterfaceIdLength; ///< Length of interface ID string. + + uint8_t *mNetworkId; ///< Network ID (or name). Can be null if mNetworkIdLength is 0. + uint8_t mNetworkIdLength; ///< Length of Network ID string. + + uint8_t mDadCounter; ///< Duplicate address detection counter. + + uint8_t *mSecretKey; ///< Secret key used to create IID. Cannot be null. + uint16_t mSecretKeyLength; ///< Secret key length in bytes. Should be at least 16 bytes == 128 bits. +} otSemanticallyOpaqueIidGeneratorData; + /** * @addtogroup messages Message Buffers * diff --git a/include/openthread.h b/include/openthread.h index 3c0c346fc..6450736c1 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -83,6 +83,7 @@ extern "C" { * * @defgroup core-6lowpan 6LoWPAN * @defgroup core-coap CoAP + * @defgroup core-global-address Global IPv6 Address * @defgroup core-ipv6 IPv6 * @defgroup core-mac MAC * @defgroup core-mesh-forwarding Mesh Forwarding @@ -786,6 +787,69 @@ ThreadError otAddUnicastAddress(otInstance *aInstance, const otNetifAddress *aAd */ ThreadError otRemoveUnicastAddress(otInstance *aInstance, const otIp6Address *aAddress); +/** + * This function pointer is called to create IPv6 IID during SLAAC procedure. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[inout] aAddress A pointer to structure containing IPv6 address for which IID is being created. + * @param[inout] aContext A pointer to creator-specific context. + * + * @retval kThreadError_None Created valid IID for given IPv6 address. + * @retval kThreadError_Ipv6AddressCreationFailure Creation of valid IID for given IPv6 address failed. + * + */ +typedef ThreadError(*otSlaacIidCreate)(otInstance *aInstance, otNetifAddress *aAddress, void *aContext); + +/** + * Update all automatically created IPv6 addresses for prefixes from current Network Data with SLAAC procedure. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[inout] aAddresses A pointer to an array of automatically created IPv6 addresses. + * @param[in] aNumAddresses The number of slots in aAddresses array. + * @param[in] aIidCreate A pointer to a function that is called to create IPv6 IIDs. + * @param[in] aContext A pointer to data passed to aIidCreate function. + * + */ +void otSlaacUpdate(otInstance *aInstance, otNetifAddress *aAddresses, uint32_t aNumAddresses, + otSlaacIidCreate aIidCreate, void *aContext); + +/** + * Create random IID for given IPv6 address. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[inout] aAddress A pointer to structure containing IPv6 address for which IID is being created. + * @param[in] aContext A pointer to unused data. + * + * @retval kThreadError_None Created valid IID for given IPv6 address. + * + */ +ThreadError otCreateRandomIid(otInstance *aInstance, otNetifAddress *aAddresses, void *aContext); + +/** + * Create IID for given IPv6 address using extended MAC address. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[inout] aAddress A pointer to structure containing IPv6 address for which IID is being created. + * @param[in] aContext A pointer to unused data. + * + * @retval kThreadError_None Created valid IID for given IPv6 address. + * + */ +ThreadError otCreateMacIid(otInstance *aInstance, otNetifAddress *aAddresses, void *aContext); + +/** + * Create semantically opaque IID for given IPv6 address. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[inout] aAddress A pointer to structure containing IPv6 address for which IID is being created. + * @param[inout] aContext A pointer to a otSemanticallyOpaqueIidGeneratorData structure. + * + * @retval kThreadError_None Created valid IID for given IPv6 address. + * @retval kThreadError_Ipv6AddressCreationFailure Could not create valid IID for given IPv6 address. + * + */ +ThreadError otCreateSemanticallyOpaqueIid(otInstance *aInstance, otNetifAddress *aAddresses, void *aContext); + /** * 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 065c367b8..6a1ac85ee 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -52,7 +52,6 @@ #include #include #include -#include #include using Thread::Encoding::BigEndian::HostSwap16; @@ -2389,102 +2388,10 @@ void Interpreter::s_HandleNetifStateChanged(uint32_t aFlags, void *aContext) void Interpreter::HandleNetifStateChanged(uint32_t aFlags) { - otNetworkDataIterator iterator; - otBorderRouterConfig config; - VerifyOrExit((aFlags & OT_THREAD_NETDATA_UPDATED) != 0, ;); - // remove addresses - for (size_t i = 0; i < sizeof(sAutoAddresses) / sizeof(sAutoAddresses[0]); i++) - { - otNetifAddress *address = &sAutoAddresses[i]; - bool found = false; - - if (address->mValidLifetime == 0) - { - continue; - } - - iterator = OT_NETWORK_DATA_ITERATOR_INIT; - - while (otGetNextOnMeshPrefix(mInstance, false, &iterator, &config) == kThreadError_None) - { - if (config.mSlaac == false) - { - continue; - } - - if (otIp6PrefixMatch(&config.mPrefix.mPrefix, &address->mAddress) >= config.mPrefix.mLength && - config.mPrefix.mLength == address->mPrefixLength) - { - found = true; - break; - } - } - - if (!found) - { - otRemoveUnicastAddress(mInstance, &address->mAddress); - address->mValidLifetime = 0; - } - } - - // add addresses - iterator = OT_NETWORK_DATA_ITERATOR_INIT; - - while (otGetNextOnMeshPrefix(mInstance, false, &iterator, &config) == kThreadError_None) - { - bool found = false; - - if (config.mSlaac == false) - { - continue; - } - - for (size_t i = 0; i < sizeof(sAutoAddresses) / sizeof(sAutoAddresses[0]); i++) - { - otNetifAddress *address = &sAutoAddresses[i]; - - if (address->mValidLifetime == 0) - { - continue; - } - - if (otIp6PrefixMatch(&config.mPrefix.mPrefix, &address->mAddress) >= config.mPrefix.mLength && - config.mPrefix.mLength == address->mPrefixLength) - { - found = true; - break; - } - } - - if (!found) - { - for (size_t i = 0; i < sizeof(sAutoAddresses) / sizeof(sAutoAddresses[0]); i++) - { - otNetifAddress *address = &sAutoAddresses[i]; - - if (address->mValidLifetime != 0) - { - continue; - } - - memset(address, 0, sizeof(*address)); - memcpy(&address->mAddress, &config.mPrefix.mPrefix, 8); - - for (size_t j = 8; j < sizeof(address->mAddress); j++) - { - address->mAddress.mFields.m8[j] = (uint8_t)otPlatRandomGet(); - } - - address->mPrefixLength = config.mPrefix.mLength; - address->mPreferredLifetime = config.mPreferred ? 0xffffffff : 0; - address->mValidLifetime = 0xffffffff; - otAddUnicastAddress(mInstance, address); - break; - } - } - } + otSlaacUpdate(mInstance, mAutoAddresses, sizeof(mAutoAddresses) / sizeof(mAutoAddresses[0]), otCreateRandomIid, + NULL); exit: return; diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 474f86633..85efa9381 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -131,6 +131,7 @@ private: enum { kMaxArgs = 32, + kMaxAutoAddresses = 8, }; void AppendResult(ThreadError error); @@ -232,7 +233,7 @@ private: uint32_t sInterval; Timer sPingTimer; - otNetifAddress sAutoAddresses[8]; + otNetifAddress mAutoAddresses[kMaxAutoAddresses]; otInstance *mInstance; }; diff --git a/src/core/Makefile.am b/src/core/Makefile.am index c383c2d84..6ee5aeda4 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -83,6 +83,7 @@ libopenthread_a_SOURCES = \ thread/network_diag_tlvs.cpp \ thread/thread_netif.cpp \ thread/thread_tlvs.cpp \ + utils/global_address.cpp \ $(NULL) if OPENTHREAD_ENABLE_COMMISSIONER @@ -171,6 +172,7 @@ noinst_HEADERS = \ thread/thread_tlvs.hpp \ thread/thread_uris.hpp \ thread/topology.hpp \ + utils/global_address.hpp \ $(NULL) if OPENTHREAD_BUILD_COVERAGE diff --git a/src/core/net/ip6_address.cpp b/src/core/net/ip6_address.cpp index 27b561802..7fb409ab6 100644 --- a/src/core/net/ip6_address.cpp +++ b/src/core/net/ip6_address.cpp @@ -111,6 +111,23 @@ bool Address::IsRoutingLocator(void) const mFields.m16[6] == HostSwap16(0xfe00)); } +bool Address::IsSubnetRouterAnycast(void) const +{ + return (mFields.m32[2] == 0 && mFields.m32[3] == 0); +} + +bool Address::IsReservedSubnetAnycast(void) const +{ + return (mFields.m32[2] == HostSwap32(0xfdffffff) && mFields.m16[6] == 0xffff && mFields.m8[14] == 0xff && + mFields.m8[15] >= 0x80); +} + +bool Address::IsIidReserved(void) const +{ + return IsSubnetRouterAnycast() || IsReservedSubnetAnycast(); +} + + const uint8_t *Address::GetIid(void) const { return mFields.m8 + kInterfaceIdentifierOffset; diff --git a/src/core/net/ip6_address.hpp b/src/core/net/ip6_address.hpp index 33666c274..bd9f0bf66 100644 --- a/src/core/net/ip6_address.hpp +++ b/src/core/net/ip6_address.hpp @@ -188,6 +188,33 @@ public: */ bool IsRoutingLocator(void) const; + /** + * This method indicates whether or not the IPv6 address is Subnet-Router Anycast (RFC 4291), + * + * @retval TRUE If the IPv6 address is a Subnet-Router Anycast address. + * @retval FALSE If the IPv6 address is not a Subnet-Router Anycast address. + * + */ + bool IsSubnetRouterAnycast(void) const; + + /** + * This method indicates whether or not the IPv6 address is Reserved Subnet Anycast (RFC 2526), + * + * @retval TRUE If the IPv6 address is a Reserved Subnet Anycast address. + * @retval FALSE If the IPv6 address is not a Reserved Subnet Anycast address. + * + */ + bool IsReservedSubnetAnycast(void) const; + + /** + * This method indicates whether or not the IPv6 address contains Reserved IPv6 IID (RFC 5453), + * + * @retval TRUE If the IPv6 address contains a reserved IPv6 IID. + * @retval FALSE If the IPv6 address does not contain a reserved IPv6 IID. + * + */ + bool IsIidReserved(void) const; + /** * This method returns a pointer to the Interface Identifier. * diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index 577f83c81..799998dbf 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -48,10 +48,12 @@ #include #include #include +#include #include #include #include #include +#include // Temporary definition typedef struct otInstance @@ -906,6 +908,31 @@ ThreadError otRemoveUnicastAddress(otInstance *, const otIp6Address *address) return sThreadNetif->RemoveExternalUnicastAddress(*static_cast(address)); } +void otSlaacUpdate(otInstance *aInstance, otNetifAddress *aAddresses, uint32_t aNumAddresses, + otSlaacIidCreate aIidCreate, void *aContext) +{ + Utils::Slaac::UpdateAddresses(aInstance, aAddresses, aNumAddresses, aIidCreate, aContext); +} + +ThreadError otCreateRandomIid(otInstance *aInstance, otNetifAddress *aAddress, void *aContext) +{ + return Utils::Slaac::CreateRandomIid(aInstance, aAddress, aContext); +} + +ThreadError otCreateMacIid(otInstance *, otNetifAddress *aAddress, void *) +{ + memcpy(&aAddress->mAddress.mFields.m8[OT_IP6_ADDRESS_SIZE - OT_IP6_IID_SIZE], + sThreadNetif->GetMac().GetExtAddress(), OT_IP6_IID_SIZE); + aAddress->mAddress.mFields.m8[OT_IP6_ADDRESS_SIZE - OT_IP6_IID_SIZE] ^= 0x02; + + return kThreadError_None; +} + +ThreadError otCreateSemanticallyOpaqueIid(otInstance *aInstance, otNetifAddress *aAddress, void *aContext) +{ + return static_cast(aContext)->CreateIid(aInstance, aAddress); +} + void otSetStateChangedCallback(otInstance *, otStateChangedCallback aCallback, void *aCallbackContext) { sNetifCallback.Set(aCallback, aCallbackContext); diff --git a/src/core/utils/global_address.cpp b/src/core/utils/global_address.cpp new file mode 100644 index 000000000..35cd58e85 --- /dev/null +++ b/src/core/utils/global_address.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2016, 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 Thread IPv6 global addresses configuration utilities. + */ + +#ifdef OPENTHREAD_CONFIG_FILE +#include OPENTHREAD_CONFIG_FILE +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace Thread { +namespace Utils { + +void Slaac::UpdateAddresses(otInstance *aInstance, otNetifAddress *aAddresses, uint32_t aNumAddresses, + IidCreator aIidCreator, void *aContext) +{ + otNetworkDataIterator iterator; + otBorderRouterConfig config; + + // remove addresses + for (size_t i = 0; i < aNumAddresses; i++) + { + otNetifAddress *address = &aAddresses[i]; + bool found = false; + + if (address->mValidLifetime == 0) + { + continue; + } + + iterator = OT_NETWORK_DATA_ITERATOR_INIT; + + while (otGetNextOnMeshPrefix(aInstance, false, &iterator, &config) == kThreadError_None) + { + if (config.mSlaac == false) + { + continue; + } + + if (otIp6PrefixMatch(&config.mPrefix.mPrefix, &address->mAddress) >= config.mPrefix.mLength && + config.mPrefix.mLength == address->mPrefixLength) + { + found = true; + break; + } + } + + if (!found) + { + otRemoveUnicastAddress(aInstance, &address->mAddress); + address->mValidLifetime = 0; + } + } + + // add addresses + iterator = OT_NETWORK_DATA_ITERATOR_INIT; + + while (otGetNextOnMeshPrefix(aInstance, false, &iterator, &config) == kThreadError_None) + { + bool found = false; + + if (config.mSlaac == false) + { + continue; + } + + for (size_t i = 0; i < aNumAddresses; i++) + { + otNetifAddress *address = &aAddresses[i]; + + if (address->mValidLifetime == 0) + { + continue; + } + + if (otIp6PrefixMatch(&config.mPrefix.mPrefix, &address->mAddress) >= config.mPrefix.mLength && + config.mPrefix.mLength == address->mPrefixLength) + { + found = true; + break; + } + } + + if (!found) + { + for (size_t i = 0; i < aNumAddresses; i++) + { + otNetifAddress *address = &aAddresses[i]; + + if (address->mValidLifetime != 0) + { + continue; + } + + memset(address, 0, sizeof(*address)); + memcpy(&address->mAddress, &config.mPrefix.mPrefix, 8); + + address->mPrefixLength = config.mPrefix.mLength; + address->mPreferredLifetime = config.mPreferred ? 0xffffffff : 0; + address->mValidLifetime = 0xffffffff; + + if (aIidCreator(aInstance, address, aContext) != kThreadError_None) + { + CreateRandomIid(aInstance, address, aContext); + } + + otAddUnicastAddress(aInstance, address); + break; + } + } + } +} + +ThreadError Slaac::CreateRandomIid(otInstance *aInstance, otNetifAddress *aAddress, void *aContext) +{ + (void) aInstance; + (void) aContext; + + for (size_t i = sizeof(aAddress[i].mAddress) - OT_IP6_IID_SIZE; i < sizeof(aAddress[i].mAddress); i++) + { + aAddress->mAddress.mFields.m8[i] = static_cast(otPlatRandomGet()); + } + + return kThreadError_None; +} + +ThreadError SemanticallyOpaqueIidGenerator::CreateIid(otInstance *aInstance, otNetifAddress *aAddress) +{ + (void) aInstance; + + ThreadError error = kThreadError_None; + + for (uint32_t i = 0; i <= kMaxRetries; i++) + { + error = CreateIidOnce(aInstance, aAddress); + VerifyOrExit(error == kThreadError_Ipv6AddressCreationFailure,); + + mDadCounter++; + } + +exit: + return error; +} + +ThreadError SemanticallyOpaqueIidGenerator::CreateIidOnce(otInstance *aInstance, otNetifAddress *aAddress) +{ + ThreadError error = kThreadError_None; + Crypto::Sha256 sha256; + uint8_t hash[Crypto::Sha256::kHashSize]; + Ip6::Address *address = static_cast(&aAddress->mAddress); + + sha256.Start(); + + sha256.Update(aAddress->mAddress.mFields.m8, aAddress->mPrefixLength / 8); + + VerifyOrExit(mInterfaceId != NULL, error = kThreadError_InvalidArgs); + sha256.Update(mInterfaceId, mInterfaceIdLength); + + if (mNetworkIdLength) + { + VerifyOrExit(mNetworkId != NULL, error = kThreadError_InvalidArgs); + sha256.Update(mNetworkId, mNetworkIdLength); + } + + sha256.Update(static_cast(&mDadCounter), sizeof(mDadCounter)); + + VerifyOrExit(mSecretKey != NULL, error = kThreadError_InvalidArgs); + sha256.Update(mSecretKey, mSecretKeyLength); + + sha256.Finish(hash); + + memcpy(&aAddress->mAddress.mFields.m8[OT_IP6_ADDRESS_SIZE - OT_IP6_IID_SIZE], + &hash[sizeof(hash) - OT_IP6_IID_SIZE], OT_IP6_IID_SIZE); + + VerifyOrExit(!IsAddressRegistered(aInstance, aAddress), error = kThreadError_Ipv6AddressCreationFailure); + VerifyOrExit(!address->IsIidReserved(), error = kThreadError_Ipv6AddressCreationFailure); + +exit: + return error; +} + +bool SemanticallyOpaqueIidGenerator::IsAddressRegistered(otInstance *aInstance, otNetifAddress *aCreatedAddress) +{ + bool result = false; + const otNetifAddress *address = otGetUnicastAddresses(aInstance); + + while (address != NULL) + { + if (0 == memcmp(aCreatedAddress->mAddress.mFields.m8, address->mAddress.mFields.m8, + sizeof(address->mAddress.mFields))) + { + ExitNow(result = true); + } + + address = address->mNext; + } + +exit: + return result; +} + + +} // namespace Slaac +} // namespace Thread diff --git a/src/core/utils/global_address.hpp b/src/core/utils/global_address.hpp new file mode 100644 index 000000000..501df93b8 --- /dev/null +++ b/src/core/utils/global_address.hpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2016, 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 includes definitions for Thread global IPv6 address configuration with SLAAC. + */ + +#ifndef GLOBAL_ADDRESS_HPP_ +#define GLOBAL_ADDRESS_HPP_ + +#include +#include + +namespace Thread { +namespace Utils { + +/** + * @addtogroup core-global-address + * + * @brief + * This module includes definitions for Thread global IPv6 address configuration with SLAAC. + * + * @{ + */ + +/** + * This class implements the SLAAC utility for Thread protocol. + * + */ +class Slaac +{ +public: + /** + * This function pointer is called when SLAAC creates global address. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[inout] aAddress A pointer to structure containing IPv6 address for which IID is being created. + * @param[in] aContext A pointer to creator-specific context. + * + * @retval kThreadError_None if generated valid IID. + * @retval kThreadError_Failed if creating IID failed. + * + */ + typedef ThreadError(*IidCreator)(otInstance *aInstance, otNetifAddress *aAddress, void *aContext); + + /** + * This function update addresses that shall be automatically created using SLAAC. + * + * @param[in] aInstance A pointer to openThread instance. + * @param[inout] aAddresses A pointer to an array containing addresses created by this module. + * @param[in] aNumAddresses The number of elements in aAddresses array. + * @param[in] aIidCreator A pointer to function that will be used to create IID for IPv6 addresses. + * @param[in] aContext A pointer to IID creator-specific context data. + * + */ + static void UpdateAddresses(otInstance *aInstance, otNetifAddress *aAddresses, uint32_t aNumAddresses, + IidCreator aIidCreator, void *aContext); + + /** + * This function creates randomly generated IPv6 IID for given IPv6 address. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[inout] aAddress A pointer to structure containing IPv6 address for which IID is being created. + * @param[in] aContext Unused pointer. + * + * @retval kThreadError_None Generated valid IID. + */ + static ThreadError CreateRandomIid(otInstance *aInstance, otNetifAddress *aAddress, void *aContext); +}; + +/** + * This class implements the Method for Generating Semantically Opaque IIDs with IPv6 SLAAC (RFC 7217). + * + */ +class SemanticallyOpaqueIidGenerator: public otSemanticallyOpaqueIidGeneratorData +{ +public: + /** + * This function creates semantically opaque IID for given IPv6 address and context. + * + * The generator starts with DAD counter provided as a class member field. The DAD counter is automatically + * incremented at most kMaxRetries times if creation of valid IPv6 address fails. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[inout] aAddress A pointer to structure containing IPv6 address for which IID is being created. + * + * @retval kThreadError_None Generated valid IID. + * @retval kThreadError_InvalidArgs Any given parameter is invalid. + * @retval kThreadError_Ipv6AddressCreationFailure Could not generate IID due to RFC 7217 restrictions. + * + */ + ThreadError CreateIid(otInstance *aInstance, otNetifAddress *aAddress); + +private: + enum + { + kMaxRetries = 255, + }; + + /** + * This function creates semantically opaque IID for given arguments. + * + * This function creates IID only for given DAD counter value. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[inout] aAddress A pointer to structure containing IPv6 address for which IID is being created. + * + * @retval kThreadError_None Generated valid IID. + * @retval kThreadError_InvalidArgs Any given parameter is invalid. + * @retval kThreadError_Ipv6AddressCreationFailure Could not generate IID due to RFC 7217 restrictions. + * + */ + ThreadError CreateIidOnce(otInstance *aInstance, otNetifAddress *aAddress); + + /** + * This function checks if created IPv6 address is already registered in the Thread interface. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aCreatedAddress A pointer to created IPv6 address. + * + * @retval true Given address is present in the address list. + * @retval false Given address is missing in the address list. + * + */ + bool IsAddressRegistered(otInstance *aInstance, otNetifAddress *aCreatedAddress); +}; + +/** + * @} + */ + +} // namespace Slaac +} // namespace Thread + +#endif // GLOBAL_ADDRESS_HPP_ +