Skip to content

Commit

Permalink
[slaac] simplify adding/removing addresses and other enhancements (op…
Browse files Browse the repository at this point in the history
…enthread#9579)

This commit makes the following smaller enhancements in `Slaac`
class:
- Adds a new `ShouldUseForSlaac()` method to check if a network data
  prefix should be used for SLAAC, checking flags and applying the
  filter if set.
- Introduces separate `RemoveAddresses()` and `AddAddresses()` methods
  to manage SLAAC addresses, replacing the previous `Update()` method.
- Adds helper methods to `RemoveAllAddresses()`, `RemoveAddress()` to
  remove a specific address, and `AddAddressFor(prefix)` to  generate
  and add an address for a given prefix.
- Simplifies `GenerateIid()` by removing unused input parameters.
  • Loading branch information
abtink authored Nov 7, 2023
1 parent 3b30c84 commit a05954b
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 142 deletions.
2 changes: 1 addition & 1 deletion src/core/thread/dua_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ Error DuaManager::GenerateDomainUnicastAddressIid(void)
Error error;
uint8_t dadCounter = mDadCounter;

if ((error = Get<Utils::Slaac>().GenerateIid(mDomainUnicastAddress, nullptr, 0, &dadCounter)) == kErrorNone)
if ((error = Get<Utils::Slaac>().GenerateIid(mDomainUnicastAddress, dadCounter)) == kErrorNone)
{
if (dadCounter != mDadCounter)
{
Expand Down
235 changes: 119 additions & 116 deletions src/core/utils/slaac_address.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ void Slaac::Enable(void)
{
VerifyOrExit(!mEnabled);

LogInfo("Enabling");
mEnabled = true;
Update(kModeAdd);
LogInfo("Enabled");

AddAddresses();

exit:
return;
Expand All @@ -74,42 +75,56 @@ void Slaac::Disable(void)
{
VerifyOrExit(mEnabled);

LogInfo("Disabling");
RemoveAllAddresses();
LogInfo("Disabled");
mEnabled = false;
Update(kModeRemove);

exit:
return;
}

void Slaac::SetFilter(otIp6SlaacPrefixFilter aFilter)
void Slaac::SetFilter(PrefixFilter aFilter)
{
VerifyOrExit(aFilter != mFilter);

mFilter = aFilter;
LogInfo("Filter %s", (mFilter != nullptr) ? "updated" : "disabled");

VerifyOrExit(mEnabled);
Update(kModeAdd | kModeRemove);
RemoveAddresses();
AddAddresses();

exit:
return;
}

bool Slaac::ShouldFilter(const Ip6::Prefix &aPrefix) const
bool Slaac::ShouldUseForSlaac(const NetworkData::OnMeshPrefixConfig &aConfig) const
{
return (mFilter != nullptr) && mFilter(&GetInstance(), &aPrefix);
bool shouldUse = false;

VerifyOrExit(aConfig.mSlaac && !aConfig.mDp);
VerifyOrExit(aConfig.GetPrefix().GetLength() == Ip6::NetworkPrefix::kLength);

if (mFilter != nullptr)
{
VerifyOrExit(!mFilter(&GetInstance(), &aConfig.GetPrefix()));
}

shouldUse = true;

exit:
return shouldUse;
}

void Slaac::HandleNotifierEvents(Events aEvents)
{
UpdateMode mode = kModeNone;

VerifyOrExit(mEnabled);

if (aEvents.Contains(kEventThreadNetdataChanged))
{
mode |= kModeAdd | kModeRemove;
RemoveAddresses();
AddAddresses();
ExitNow();
}

if (aEvents.Contains(kEventIp6AddressRemoved))
Expand All @@ -123,12 +138,7 @@ void Slaac::HandleNotifierEvents(Events aEvents)
// prefix. So on IPv6 address removal event, we check if SLAAC module need
// to add any addresses.

mode |= kModeAdd;
}

if (mode != kModeNone)
{
Update(mode);
AddAddresses();
}

exit:
Expand All @@ -143,122 +153,126 @@ bool Slaac::DoesConfigMatchNetifAddr(const NetworkData::OnMeshPrefixConfig &aCon
(aAddr.GetAddress().MatchesPrefix(aConfig.GetPrefix())));
}

void Slaac::Update(UpdateMode aMode)
void Slaac::RemoveAddresses(void)
{
NetworkData::Iterator iterator;
NetworkData::OnMeshPrefixConfig config;
bool found;
// Remove any SLAAC addresses with no matching on-mesh prefix.

if (aMode & kModeRemove)
for (Ip6::Netif::UnicastAddress &slaacAddr : mAddresses)
{
// If enabled, remove any SLAAC addresses with no matching on-mesh prefix,
// otherwise (when disabled) remove all previously added SLAAC addresses.
NetworkData::Iterator iterator;
NetworkData::OnMeshPrefixConfig config;
bool found = false;

for (Ip6::Netif::UnicastAddress &slaacAddr : mAddresses)
if (!slaacAddr.mValid)
{
if (!slaacAddr.mValid)
{
continue;
}
continue;
}

found = false;
iterator = NetworkData::kIteratorInit;

if (mEnabled)
while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, config) == kErrorNone)
{
if (ShouldUseForSlaac(config) && DoesConfigMatchNetifAddr(config, slaacAddr))
{
iterator = NetworkData::kIteratorInit;

while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, config) == kErrorNone)
{
if (config.mDp)
{
// Skip domain prefix which is processed in MLE.
continue;
}

if (config.mSlaac && !ShouldFilter(config.GetPrefix()) &&
DoesConfigMatchNetifAddr(config, slaacAddr))
{
found = true;
break;
}
}
found = true;
break;
}
}

if (!found)
{
LogInfo("Removing address %s", slaacAddr.GetAddress().ToString().AsCString());

Get<ThreadNetif>().RemoveUnicastAddress(slaacAddr);
slaacAddr.mValid = false;
}
if (!found)
{
RemoveAddress(slaacAddr);
}
}
}

if ((aMode & kModeAdd) && mEnabled)
void Slaac::RemoveAllAddresses(void)
{
for (Ip6::Netif::UnicastAddress &slaacAddr : mAddresses)
{
// Generate and add SLAAC addresses for any newly added on-mesh prefixes.
if (slaacAddr.mValid)
{
RemoveAddress(slaacAddr);
}
}
}

iterator = NetworkData::kIteratorInit;
void Slaac::RemoveAddress(Ip6::Netif::UnicastAddress &aAddress)
{
LogInfo("Removing %s", aAddress.GetAddress().ToString().AsCString());

while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, config) == kErrorNone)
{
Ip6::Prefix &prefix = config.GetPrefix();
Get<ThreadNetif>().RemoveUnicastAddress(aAddress);
aAddress.mValid = false;
}

if (config.mDp || !config.mSlaac || (prefix.GetLength() != Ip6::NetworkPrefix::kLength) ||
ShouldFilter(prefix))
{
continue;
}
void Slaac::AddAddresses(void)
{
NetworkData::Iterator iterator;
NetworkData::OnMeshPrefixConfig config;

// Generate and add SLAAC addresses for any newly added on-mesh prefixes.

found = false;
iterator = NetworkData::kIteratorInit;

for (const Ip6::Netif::UnicastAddress &netifAddr : Get<ThreadNetif>().GetUnicastAddresses())
while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, config) == kErrorNone)
{
bool found = false;

if (!ShouldUseForSlaac(config))
{
continue;
}

for (const Ip6::Netif::UnicastAddress &netifAddr : Get<ThreadNetif>().GetUnicastAddresses())
{
if (DoesConfigMatchNetifAddr(config, netifAddr))
{
if (DoesConfigMatchNetifAddr(config, netifAddr))
{
found = true;
break;
}
found = true;
break;
}
}

if (!found)
{
bool added = false;
if (!found)
{
AddAddressFor(config);
}
}
}

for (Ip6::Netif::UnicastAddress &slaacAddr : mAddresses)
{
if (slaacAddr.mValid)
{
continue;
}
void Slaac::AddAddressFor(const NetworkData::OnMeshPrefixConfig &aConfig)
{
Ip6::Netif::UnicastAddress *newAddress = nullptr;
uint8_t dadCounter = 0;

slaacAddr.InitAsSlaacOrigin(config.mOnMesh ? prefix.mLength : 128, config.mPreferred);
slaacAddr.GetAddress().SetPrefix(prefix);
for (Ip6::Netif::UnicastAddress &slaacAddr : mAddresses)
{
if (!slaacAddr.mValid)
{
newAddress = &slaacAddr;
break;
}
}

IgnoreError(GenerateIid(slaacAddr));
if (newAddress == nullptr)
{
LogWarn("Failed to add - already have max %u addresses", kNumAddresses);
ExitNow();
}

LogInfo("Adding address %s", slaacAddr.GetAddress().ToString().AsCString());
newAddress->InitAsSlaacOrigin(aConfig.mOnMesh ? aConfig.GetPrefix().mLength : 128, aConfig.mPreferred);
newAddress->GetAddress().SetPrefix(aConfig.GetPrefix());

Get<ThreadNetif>().AddUnicastAddress(slaacAddr);
IgnoreError(GenerateIid(*newAddress, dadCounter));

added = true;
break;
}
LogInfo("Adding address %s", newAddress->GetAddress().ToString().AsCString());

if (!added)
{
LogWarn("Failed to add - max %d addresses supported and already in use",
GetArrayLength(mAddresses));
}
}
}
}
Get<ThreadNetif>().AddUnicastAddress(*newAddress);

exit:
return;
}

Error Slaac::GenerateIid(Ip6::Netif::UnicastAddress &aAddress,
uint8_t *aNetworkId,
uint8_t aNetworkIdLength,
uint8_t *aDadCounter) const
Error Slaac::GenerateIid(Ip6::Netif::UnicastAddress &aAddress, uint8_t &aDadCounter) const
{
/*
* This method generates a semantically opaque IID per RFC 7217.
Expand All @@ -268,7 +282,7 @@ Error Slaac::GenerateIid(Ip6::Netif::UnicastAddress &aAddress,
* - RID is random (but stable) Identifier.
* - For pseudo-random function `F()` SHA-256 is used in this method.
* - `Net_Iface` is set to constant string "wpan".
* - `Network_ID` is not used if `aNetworkId` is `nullptr` (optional per RF-7217).
* - `Network_ID` is not used (optional per RFC 7217).
* - The `secret_key` is randomly generated on first use (using true
* random number generator) and saved in non-volatile settings for
* future use.
Expand All @@ -277,7 +291,6 @@ Error Slaac::GenerateIid(Ip6::Netif::UnicastAddress &aAddress,

Error error = kErrorFailed;
const uint8_t netIface[] = {'w', 'p', 'a', 'n'};
uint8_t dadCounter = aDadCounter ? *aDadCounter : 0;
IidSecretKey secretKey;
Crypto::Sha256 sha256;
Crypto::Sha256::Hash hash;
Expand All @@ -287,18 +300,13 @@ Error Slaac::GenerateIid(Ip6::Netif::UnicastAddress &aAddress,

GetIidSecretKey(secretKey);

for (uint16_t count = 0; count < kMaxIidCreationAttempts; count++, dadCounter++)
for (uint16_t count = 0; count < kMaxIidCreationAttempts; count++, aDadCounter++)
{
sha256.Start();
sha256.Update(aAddress.mAddress.mFields.m8, BitVectorBytes(aAddress.mPrefixLength));

if (aNetworkId)
{
sha256.Update(aNetworkId, aNetworkIdLength);
}

sha256.Update(netIface);
sha256.Update(dadCounter);
sha256.Update(aDadCounter);
sha256.Update(secretKey);
sha256.Finish(hash);

Expand All @@ -310,11 +318,6 @@ Error Slaac::GenerateIid(Ip6::Netif::UnicastAddress &aAddress,
continue;
}

if (aDadCounter)
{
*aDadCounter = dadCounter;
}

// Exit and return the address if the IID is not reserved,
ExitNow(error = kErrorNone);
}
Expand Down
Loading

0 comments on commit a05954b

Please sign in to comment.