mirror of
https://github.com/espressif/openthread.git
synced 2026-10-10 01:37:38 +00:00
Make client responsible for configuring IPv6 addresses. (#410)
* OpenThread no longer automatically configures IPv6 addresses based on network data. * Added IPv6 address configuration to CLI to support certification tests. * Added notification to indicate when the Thread Network Data is updated. * Added otIp6PrefixMatch API to compute prefix match.
This commit is contained in:
@@ -343,18 +343,19 @@ typedef struct otLinkModeConfig
|
||||
*/
|
||||
enum
|
||||
{
|
||||
OT_IP6_ADDRESS_ADDED = 1 << 0, ///< IPv6 address was added
|
||||
OT_IP6_ADDRESS_REMOVED = 1 << 1, ///< IPv6 address was removed
|
||||
OT_IP6_ADDRESS_ADDED = 1 << 0, ///< IPv6 address was added
|
||||
OT_IP6_ADDRESS_REMOVED = 1 << 1, ///< IPv6 address was removed
|
||||
|
||||
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_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
|
||||
OT_THREAD_CHILD_ADDED = 1 << 6, ///< Child was added
|
||||
OT_THREAD_CHILD_REMOVED = 1 << 7, ///< Child was removed
|
||||
OT_THREAD_NETDATA_UPDATED = 1 << 8, ///< Thread Network Data updated
|
||||
|
||||
OT_IP6_LL_ADDR_CHANGED = 1 << 8, ///< The link-local address has changed
|
||||
OT_IP6_ML_ADDR_CHANGED = 1 << 9, ///< The mesh-local address has changed
|
||||
OT_IP6_LL_ADDR_CHANGED = 1 << 9, ///< The link-local address has changed
|
||||
OT_IP6_ML_ADDR_CHANGED = 1 << 10, ///< The mesh-local address has changed
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1657,6 +1657,17 @@ bool otIsIcmpEchoEnabled(void);
|
||||
*/
|
||||
void otSetIcmpEchoEnabled(bool aEnabled);
|
||||
|
||||
/**
|
||||
* This function returns the prefix match length (bits) for two IPv6 addresses.
|
||||
*
|
||||
* @param[in] aFirst A pointer to the first IPv6 address.
|
||||
* @param[in] aSecond A pointer to the second IPv6 address.
|
||||
*
|
||||
* @returns The prefix match length in bits.
|
||||
*
|
||||
*/
|
||||
uint8_t otIp6PrefixMatch(const otIp6Address *aFirst, const otIp6Address *aSecond);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
+108
@@ -42,6 +42,7 @@
|
||||
#include "cli_dataset.hpp"
|
||||
#include <common/encoding.hpp>
|
||||
#include <common/new.hpp>
|
||||
#include <platform/random.h>
|
||||
#include <platform/uart.h>
|
||||
|
||||
using Thread::Encoding::BigEndian::HostSwap16;
|
||||
@@ -113,6 +114,8 @@ uint16_t Interpreter::sLength;
|
||||
uint16_t Interpreter::sCount;
|
||||
uint32_t Interpreter::sInterval;
|
||||
|
||||
static otNetifAddress sAutoAddresses[8];
|
||||
|
||||
void Interpreter::Init(void)
|
||||
{
|
||||
sIcmpEcho = new(&sIcmpEchoBuf) Ip6::IcmpEcho(&HandleEchoResponse, NULL);
|
||||
@@ -120,6 +123,7 @@ void Interpreter::Init(void)
|
||||
sLength = 8;
|
||||
sCount = 1;
|
||||
sInterval = 1000;
|
||||
otSetStateChangedCallback(&HandleNetifStateChanged, NULL);
|
||||
}
|
||||
|
||||
int Interpreter::Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength)
|
||||
@@ -1780,5 +1784,109 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Interpreter::HandleNetifStateChanged(uint32_t aFlags, void *aContext)
|
||||
{
|
||||
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(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(address);
|
||||
address->mValidLifetime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// add addresses
|
||||
iterator = OT_NETWORK_DATA_ITERATOR_INIT;
|
||||
|
||||
while (otGetNextOnMeshPrefix(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(address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
(void)aContext;
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace Cli
|
||||
} // namespace Thread
|
||||
|
||||
@@ -185,6 +185,7 @@ private:
|
||||
static void HandleEchoResponse(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
static void HandlePingTimer(void *aContext);
|
||||
static void HandleActiveScanResult(otActiveScanResult *aResult);
|
||||
static void HandleNetifStateChanged(uint32_t aFlags, void *aContext);
|
||||
|
||||
static const struct Command sCommands[];
|
||||
static otNetifAddress sAddress;
|
||||
|
||||
@@ -1094,6 +1094,18 @@ void otSetIcmpEchoEnabled(bool aEnabled)
|
||||
Ip6::Icmp::SetEchoEnabled(aEnabled);
|
||||
}
|
||||
|
||||
uint8_t otIp6PrefixMatch(const otIp6Address *aFirst, const otIp6Address *aSecond)
|
||||
{
|
||||
uint8_t rval;
|
||||
|
||||
VerifyOrExit(aFirst != NULL && aSecond != NULL, rval = 0);
|
||||
|
||||
rval = static_cast<const Ip6::Address *>(aFirst)->PrefixMatch(*static_cast<const Ip6::Address *>(aSecond));
|
||||
|
||||
exit:
|
||||
return rval;
|
||||
}
|
||||
|
||||
ThreadError otGetActiveDataset(otOperationalDataset *aDataset)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
|
||||
@@ -63,7 +63,6 @@ Leader::Leader(ThreadNetif &aThreadNetif):
|
||||
|
||||
void Leader::Reset(void)
|
||||
{
|
||||
memset(mAddresses, 0, sizeof(mAddresses));
|
||||
memset(mContextLastUsed, 0, sizeof(mContextLastUsed));
|
||||
mVersion = static_cast<uint8_t>(otPlatRandomGet());
|
||||
mStableVersion = static_cast<uint8_t>(otPlatRandomGet());
|
||||
@@ -212,97 +211,6 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
ThreadError Leader::ConfigureAddresses(void)
|
||||
{
|
||||
PrefixTlv *prefix;
|
||||
|
||||
// clear out addresses that are not on-mesh
|
||||
for (size_t i = 0; i < sizeof(mAddresses) / sizeof(mAddresses[0]); i++)
|
||||
{
|
||||
if (mAddresses[i].mValidLifetime == 0 ||
|
||||
IsOnMesh(mAddresses[i].GetAddress()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mNetif.RemoveUnicastAddress(mAddresses[i]);
|
||||
mAddresses[i].mValidLifetime = 0;
|
||||
}
|
||||
|
||||
// configure on-mesh addresses
|
||||
for (NetworkDataTlv *cur = reinterpret_cast<NetworkDataTlv *>(mTlvs);
|
||||
cur < reinterpret_cast<NetworkDataTlv *>(mTlvs + mLength);
|
||||
cur = cur->GetNext())
|
||||
{
|
||||
if (cur->GetType() != NetworkDataTlv::kTypePrefix)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
prefix = reinterpret_cast<PrefixTlv *>(cur);
|
||||
ConfigureAddress(*prefix);
|
||||
}
|
||||
|
||||
return kThreadError_None;
|
||||
}
|
||||
|
||||
ThreadError Leader::ConfigureAddress(PrefixTlv &aPrefix)
|
||||
{
|
||||
BorderRouterTlv *borderRouter;
|
||||
BorderRouterEntry *entry;
|
||||
|
||||
// look for Border Router TLV
|
||||
if ((borderRouter = FindBorderRouter(aPrefix)) == NULL)
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// check if SLAAC flag is set
|
||||
if ((entry = borderRouter->GetEntry(0)) == NULL ||
|
||||
entry->IsSlaac() == false)
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// check if address is already added for this prefix
|
||||
for (size_t i = 0; i < sizeof(mAddresses) / sizeof(mAddresses[0]); i++)
|
||||
{
|
||||
if (mAddresses[i].mValidLifetime != 0 &&
|
||||
mAddresses[i].mPrefixLength == aPrefix.GetPrefixLength() &&
|
||||
PrefixMatch(mAddresses[i].mAddress.mFields.m8, aPrefix.GetPrefix(), aPrefix.GetPrefixLength()) >= 0)
|
||||
{
|
||||
mAddresses[i].mPreferredLifetime = entry->IsPreferred() ? 0xffffffff : 0;
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
// configure address for this prefix
|
||||
for (size_t i = 0; i < sizeof(mAddresses) / sizeof(mAddresses[0]); i++)
|
||||
{
|
||||
if (mAddresses[i].mValidLifetime != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&mAddresses[i], 0, sizeof(mAddresses[i]));
|
||||
memcpy(mAddresses[i].mAddress.mFields.m8, aPrefix.GetPrefix(), BitVectorBytes(aPrefix.GetPrefixLength()));
|
||||
|
||||
for (size_t j = 8; j < sizeof(mAddresses[i].mAddress); j++)
|
||||
{
|
||||
mAddresses[i].mAddress.mFields.m8[j] = static_cast<uint8_t>(otPlatRandomGet());
|
||||
}
|
||||
|
||||
mAddresses[i].mPrefixLength = aPrefix.GetPrefixLength();
|
||||
mAddresses[i].mPreferredLifetime = entry->IsPreferred() ? 0xffffffff : 0;
|
||||
mAddresses[i].mValidLifetime = 0xffffffff;
|
||||
mNetif.AddUnicastAddress(mAddresses[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return kThreadError_None;
|
||||
}
|
||||
|
||||
bool Leader::IsOnMesh(const Ip6::Address &aAddress)
|
||||
{
|
||||
PrefixTlv *prefix;
|
||||
@@ -527,8 +435,8 @@ void Leader::SetNetworkData(uint8_t aVersion, uint8_t aStableVersion, bool aStab
|
||||
|
||||
otDumpDebgNetData("set network data", mTlvs, mLength);
|
||||
|
||||
ConfigureAddresses();
|
||||
mMle.HandleNetworkDataUpdate();
|
||||
mNetif.SetStateChangedFlags(OT_THREAD_NETDATA_UPDATED);
|
||||
}
|
||||
|
||||
void Leader::RemoveBorderRouter(uint16_t aRloc16)
|
||||
@@ -546,11 +454,10 @@ void Leader::RemoveBorderRouter(uint16_t aRloc16)
|
||||
{
|
||||
mStableVersion++;
|
||||
}
|
||||
|
||||
ConfigureAddresses();
|
||||
}
|
||||
|
||||
mMle.HandleNetworkDataUpdate();
|
||||
mNetif.SetStateChangedFlags(OT_THREAD_NETDATA_UPDATED);
|
||||
}
|
||||
|
||||
void Leader::HandleServerData(void *aContext, Coap::Header &aHeader, Message &aMessage,
|
||||
@@ -785,8 +692,8 @@ ThreadError Leader::RegisterNetworkData(uint16_t aRloc16, uint8_t *aTlvs, uint8_
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAddresses();
|
||||
mMle.HandleNetworkDataUpdate();
|
||||
mNetif.SetStateChangedFlags(OT_THREAD_NETDATA_UPDATED);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
|
||||
@@ -263,8 +263,6 @@ private:
|
||||
uint32_t mContextIdReuseDelay;
|
||||
Timer mTimer;
|
||||
|
||||
Ip6::NetifUnicastAddress mAddresses[4];
|
||||
|
||||
Coap::Resource mServerData;
|
||||
uint8_t mStableVersion;
|
||||
uint8_t mVersion;
|
||||
|
||||
Reference in New Issue
Block a user