[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:
Abtin Keshavarzian
2020-03-13 08:07:07 -07:00
committed by GitHub
parent 3884f05739
commit 9a7d831cb1
5 changed files with 127 additions and 13 deletions
+22
View File
@@ -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);
+12
View File
@@ -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.
*
+1 -7
View File
@@ -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)
+6 -6
View File
@@ -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);
+86
View File
@@ -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;