mirror of
https://github.com/espressif/openthread.git
synced 2026-08-08 03:37:46 +00:00
[ip6-address] adding SetPrefix() to set the IPv6 address prefix (#4677)
This commit adds a new method `SetPrefix()` in `Ip6::Address` class to allow the prefix in an IPv6 address to be updated. Unit test `test_ip6_address` is updated to verify behavior of new method. The `Mle` and `Lowpan` classes are updated to use the new `SetPrefix()` method.
This commit is contained in:
@@ -144,6 +144,28 @@ bool Address::IsIidReserved(void) const
|
||||
return IsSubnetRouterAnycast() || IsReservedSubnetAnycast() || IsAnycastRoutingLocator();
|
||||
}
|
||||
|
||||
void Address::SetPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength)
|
||||
{
|
||||
uint8_t extraBits = (aPrefixLength % CHAR_BIT);
|
||||
|
||||
OT_ASSERT(aPrefixLength <= sizeof(Address) * CHAR_BIT);
|
||||
|
||||
memcpy(mFields.m8, aPrefix, (aPrefixLength - extraBits) / CHAR_BIT);
|
||||
|
||||
if (extraBits > 0)
|
||||
{
|
||||
uint8_t index = aPrefixLength / CHAR_BIT;
|
||||
uint8_t mask = ((0x80 >> (extraBits - 1)) - 1);
|
||||
|
||||
// `mask` has its higher (msb) `extraBits` bits as `0` and the reminaing as `1`.
|
||||
// Example with `extraBits` = 3:
|
||||
// ((0x80 >> 2) - 1) = (0b0010_0000 - 1) = 0b0001_1111
|
||||
|
||||
mFields.m8[index] &= mask;
|
||||
mFields.m8[index] |= (aPrefix[index] & ~mask);
|
||||
}
|
||||
}
|
||||
|
||||
void Address::SetIid(const uint8_t *aIid)
|
||||
{
|
||||
memcpy(mFields.m8 + kInterfaceIdentifierOffset, aIid, kInterfaceIdentifierSize);
|
||||
|
||||
@@ -270,6 +270,18 @@ public:
|
||||
*/
|
||||
bool IsIidReserved(void) const;
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 address prefix.
|
||||
*
|
||||
* This method only changes the first @p aPrefixLength bits of the address and keeps the rest of the bits in the
|
||||
* address as before.
|
||||
*
|
||||
* @param[in] aPrefix A buffer containing the prefix
|
||||
* @param[in] aPrefixLength The prefix length (in bits).
|
||||
*
|
||||
*/
|
||||
void SetPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength);
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the Interface Identifier.
|
||||
*
|
||||
|
||||
@@ -57,13 +57,7 @@ Lowpan::Lowpan(Instance &aInstance)
|
||||
|
||||
void Lowpan::CopyContext(const Context &aContext, Ip6::Address &aAddress)
|
||||
{
|
||||
memcpy(&aAddress, aContext.mPrefix, aContext.mPrefixLength / CHAR_BIT);
|
||||
|
||||
for (int i = (aContext.mPrefixLength & ~7); i < aContext.mPrefixLength; i++)
|
||||
{
|
||||
aAddress.mFields.m8[i / CHAR_BIT] &= ~(0x80 >> (i % CHAR_BIT));
|
||||
aAddress.mFields.m8[i / CHAR_BIT] |= aContext.mPrefix[i / CHAR_BIT] & (0x80 >> (i % CHAR_BIT));
|
||||
}
|
||||
aAddress.SetPrefix(aContext.mPrefix, aContext.mPrefixLength);
|
||||
}
|
||||
|
||||
otError Lowpan::ComputeIid(const Mac::Address &aMacAddr, const Context &aContext, Ip6::Address &aIpAddress)
|
||||
|
||||
@@ -915,9 +915,9 @@ void Mle::SetMeshLocalPrefix(const otMeshLocalPrefix &aMeshLocalPrefix)
|
||||
Get<ThreadNetif>().UnsubscribeMulticast(mRealmLocalAllThreadNodes);
|
||||
}
|
||||
|
||||
memcpy(mMeshLocal64.GetAddress().mFields.m8, aMeshLocalPrefix.m8, sizeof(aMeshLocalPrefix));
|
||||
memcpy(mMeshLocal16.GetAddress().mFields.m8, aMeshLocalPrefix.m8, sizeof(aMeshLocalPrefix));
|
||||
memcpy(mLeaderAloc.GetAddress().mFields.m8, aMeshLocalPrefix.m8, sizeof(aMeshLocalPrefix));
|
||||
mMeshLocal64.GetAddress().SetPrefix(aMeshLocalPrefix.m8, Ip6::Address::kMeshLocalPrefixLength);
|
||||
mMeshLocal16.GetAddress().SetPrefix(aMeshLocalPrefix.m8, Ip6::Address::kMeshLocalPrefixLength);
|
||||
mLeaderAloc.GetAddress().SetPrefix(aMeshLocalPrefix.m8, Ip6::Address::kMeshLocalPrefixLength);
|
||||
|
||||
// Just keep mesh local prefix if network interface is down
|
||||
VerifyOrExit(Get<ThreadNetif>().IsUp());
|
||||
@@ -937,7 +937,7 @@ void Mle::ApplyMeshLocalPrefix(void)
|
||||
if (HostSwap16(mServiceAlocs[i].GetAddress().mFields.m16[7]) != Mac::kShortAddrInvalid)
|
||||
{
|
||||
Get<ThreadNetif>().RemoveUnicastAddress(mServiceAlocs[i]);
|
||||
memcpy(mServiceAlocs[i].GetAddress().mFields.m8, mMeshLocal64.GetAddress().mFields.m8, 8);
|
||||
mServiceAlocs[i].GetAddress().SetPrefix(GetMeshLocalPrefix().m8, Ip6::Address::kMeshLocalPrefixLength);
|
||||
Get<ThreadNetif>().AddUnicastAddress(mServiceAlocs[i]);
|
||||
}
|
||||
}
|
||||
@@ -1033,7 +1033,7 @@ otError Mle::GetLeaderAddress(Ip6::Address &aAddress) const
|
||||
|
||||
VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = OT_ERROR_DETACHED);
|
||||
|
||||
memcpy(&aAddress, &mMeshLocal16.GetAddress(), 8);
|
||||
aAddress.SetPrefix(GetMeshLocalPrefix().m8, Ip6::Address::kMeshLocalPrefixLength);
|
||||
aAddress.mFields.m16[4] = HostSwap16(0x0000);
|
||||
aAddress.mFields.m16[5] = HostSwap16(0x00ff);
|
||||
aAddress.mFields.m16[6] = HostSwap16(0xfe00);
|
||||
@@ -1062,7 +1062,7 @@ otError Mle::GetServiceAloc(uint8_t aServiceId, Ip6::Address &aAddress) const
|
||||
|
||||
VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = OT_ERROR_DETACHED);
|
||||
|
||||
memcpy(&aAddress, &mMeshLocal16.GetAddress(), 8);
|
||||
aAddress.SetPrefix(GetMeshLocalPrefix().m8, Ip6::Address::kMeshLocalPrefixLength);
|
||||
aAddress.mFields.m16[4] = HostSwap16(0x0000);
|
||||
aAddress.mFields.m16[5] = HostSwap16(0x00ff);
|
||||
aAddress.mFields.m16[6] = HostSwap16(0xfe00);
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "net/ip6_address.hpp"
|
||||
|
||||
#include "test_util.h"
|
||||
@@ -134,8 +136,92 @@ void TestIp6AddressFromString(void)
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckPrefix(const ot::Ip6::Address &aAddress, const uint8_t *aPrefix, uint8_t aPrefixLength)
|
||||
{
|
||||
// Check the first aPrefixLength bits of aAddress to match the given aPrefix.
|
||||
|
||||
bool matches = true;
|
||||
|
||||
for (uint8_t bit = 0; bit < aPrefixLength; bit++)
|
||||
{
|
||||
uint8_t index = bit / CHAR_BIT;
|
||||
uint8_t mask = (0x80 >> (bit % CHAR_BIT));
|
||||
|
||||
if ((aAddress.mFields.m8[index] & mask) != (aPrefix[index] & mask))
|
||||
{
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
bool CheckInterfaceId(const ot::Ip6::Address &aAddress1, const ot::Ip6::Address &aAddress2, uint8_t aPrefixLength)
|
||||
{
|
||||
// Check whether all the bits after aPrefixLength of the two given IPv6 Address match or not.
|
||||
|
||||
bool matches = true;
|
||||
|
||||
for (uint8_t bit = aPrefixLength; bit < sizeof(ot::Ip6::Address) * CHAR_BIT; bit++)
|
||||
{
|
||||
uint8_t index = bit / CHAR_BIT;
|
||||
uint8_t mask = (0x80 >> (bit % CHAR_BIT));
|
||||
|
||||
if ((aAddress1.mFields.m8[index] & mask) != (aAddress2.mFields.m8[index] & mask))
|
||||
{
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
void TestIp6AddressSetPrefix(void)
|
||||
{
|
||||
const uint8_t kPrefixes[][OT_IP6_ADDRESS_SIZE] = {
|
||||
{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
|
||||
{0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
};
|
||||
|
||||
ot::Ip6::Address address;
|
||||
ot::Ip6::Address allZeroAddress;
|
||||
ot::Ip6::Address allOneAddress;
|
||||
|
||||
allZeroAddress.Clear();
|
||||
memset(&allOneAddress, 0xff, sizeof(allOneAddress));
|
||||
|
||||
for (uint8_t index = 0; index < OT_ARRAY_LENGTH(kPrefixes); index++)
|
||||
{
|
||||
const uint8_t *prefix = kPrefixes[index];
|
||||
|
||||
memcpy(address.mFields.m8, prefix, sizeof(address));
|
||||
printf("Prefix is %s\n", address.ToString().AsCString());
|
||||
|
||||
for (uint8_t prefixLength = 0; prefixLength <= sizeof(ot::Ip6::Address) * CHAR_BIT; prefixLength++)
|
||||
{
|
||||
address = allZeroAddress;
|
||||
address.SetPrefix(prefix, prefixLength);
|
||||
printf(" prefix-len:%-3d --> %s\n", prefixLength, address.ToString().AsCString());
|
||||
VerifyOrQuit(CheckPrefix(address, prefix, prefixLength), "Prefix does not match after SetPrefix()");
|
||||
VerifyOrQuit(CheckInterfaceId(address, allZeroAddress, prefixLength),
|
||||
"SetPrefix changed bits beyond the prefix length");
|
||||
|
||||
address = allOneAddress;
|
||||
address.SetPrefix(prefix, prefixLength);
|
||||
VerifyOrQuit(CheckPrefix(address, prefix, prefixLength), "Prefix does not match after SetPrefix()");
|
||||
VerifyOrQuit(CheckInterfaceId(address, allOneAddress, prefixLength),
|
||||
"SetPrefix changed bits beyond the prefix length");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
TestIp6AddressSetPrefix();
|
||||
TestIp6AddressFromString();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user