[ip6] add ApplyPrefix() to Ip6::InterfaceIdentifier (#7973)

This commit adds a new method `InterfaceIdentifier::ApplyPrefix()`
which applies a given prefix to an IID. This is applicable only when
the prefix length is longer than 64 bit. In this case, only the bits
in the IID up the prefix length are changed to match the prefix and
the remaining bits are left unchanged. This commit also updates the
unit test to validate the behavior of the new method.
This commit is contained in:
Abtin Keshavarzian
2022-08-04 20:19:56 -07:00
committed by Jonathan Hui
parent 3b0738542c
commit 21c5bf7025
3 changed files with 78 additions and 17 deletions
+21 -11
View File
@@ -254,6 +254,15 @@ bool InterfaceIdentifier::IsAnycastServiceLocator(void) const
return (IsLocator() && (locator >= Mle::kAloc16ServiceStart) && (locator <= Mle::kAloc16ServiceEnd));
}
void InterfaceIdentifier::ApplyPrefix(const Prefix &aPrefix)
{
if (aPrefix.GetLength() > NetworkPrefix::kLength)
{
Address::CopyBits(mFields.m8, aPrefix.GetBytes() + NetworkPrefix::kSize,
aPrefix.GetLength() - NetworkPrefix::kLength);
}
}
InterfaceIdentifier::InfoString InterfaceIdentifier::ToString(void) const
{
InfoString string;
@@ -377,35 +386,36 @@ void Address::SetPrefix(const NetworkPrefix &aNetworkPrefix)
void Address::SetPrefix(const Prefix &aPrefix)
{
SetPrefix(0, aPrefix.GetBytes(), aPrefix.GetLength());
CopyBits(mFields.m8, aPrefix.GetBytes(), aPrefix.GetLength());
}
void Address::SetPrefix(uint8_t aOffset, const uint8_t *aPrefix, uint8_t aPrefixLength)
void Address::CopyBits(uint8_t *aDst, const uint8_t *aSrc, uint8_t aNumBits)
{
uint8_t bytes = aPrefixLength / CHAR_BIT;
uint8_t extraBits = aPrefixLength % CHAR_BIT;
// This method copies `aNumBits` from `aSrc` into `aDst` handling
// the case where `aNumBits` may not be a multiple of 8. It leaves the
// remaining bits beyond `aNumBits` in `aDst` unchanged.
OT_ASSERT(aPrefixLength <= (sizeof(Address) - aOffset) * CHAR_BIT);
uint8_t numBytes = aNumBits / CHAR_BIT;
uint8_t extraBits = aNumBits % CHAR_BIT;
memcpy(mFields.m8 + aOffset, aPrefix, bytes);
memcpy(aDst, aSrc, numBytes);
if (extraBits > 0)
{
uint8_t index = aOffset + bytes;
uint8_t mask = ((0x80 >> (extraBits - 1)) - 1);
uint8_t mask = ((0x80 >> (extraBits - 1)) - 1);
// `mask` has its higher (msb) `extraBits` bits as `0` and the remaining as `1`.
// Example with `extraBits` = 3:
// ((0x80 >> 2) - 1) = (0b0010_0000 - 1) = 0b0001_1111
mFields.m8[index] &= mask;
mFields.m8[index] |= (aPrefix[index] & ~mask);
aDst[numBytes] &= mask;
aDst[numBytes] |= (aSrc[numBytes] & ~mask);
}
}
void Address::SetMulticastNetworkPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength)
{
SetPrefix(kMulticastNetworkPrefixOffset, aPrefix, aPrefixLength);
CopyBits(&mFields.m8[kMulticastNetworkPrefixOffset], aPrefix, aPrefixLength);
mFields.m8[kMulticastNetworkPrefixLengthOffset] = aPrefixLength;
}
+18 -4
View File
@@ -539,6 +539,17 @@ public:
*/
void SetLocator(uint16_t aLocator) { mFields.m16[3] = HostSwap16(aLocator); }
/**
* This method applies a prefix to IID.
*
* If the prefix length is longer than 64 bits, the prefix bits after 64 are written into the IID. This method only
* changes the bits in IID up the prefix length and keeps the rest of the bits in IID as before.
*
* @param[in] aPrefix An IPv6 prefix.
*
*/
void ApplyPrefix(const Prefix &aPrefix);
/**
* This method converts an Interface Identifier to a string.
*
@@ -561,6 +572,7 @@ OT_TOOL_PACKED_BEGIN
class Address : public otIp6Address, public Equatable<Address>, public Clearable<Address>
{
friend class Prefix;
friend class InterfaceIdentifier;
public:
static constexpr uint8_t kAloc16Mask = InterfaceIdentifier::kAloc16Mask; ///< The mask for ALOC16.
@@ -839,7 +851,7 @@ public:
* @param[in] aPrefixLength The prefix length (in bits).
*
*/
void SetPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) { SetPrefix(0, aPrefix, aPrefixLength); }
void SetPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) { CopyBits(mFields.m8, aPrefix, aPrefixLength); }
/**
* This method sets the IPv6 address prefix to the given Network Prefix.
@@ -1007,7 +1019,9 @@ public:
bool operator<(const Address &aOther) const { return memcmp(mFields.m8, aOther.mFields.m8, sizeof(Address)) < 0; }
private:
void SetPrefix(uint8_t aOffset, const uint8_t *aPrefix, uint8_t aPrefixLength);
static constexpr uint8_t kMulticastNetworkPrefixLengthOffset = 3; // Prefix-Based Multicast Address (RFC3306)
static constexpr uint8_t kMulticastNetworkPrefixOffset = 4; // Prefix-Based Multicast Address (RFC3306)
void SetToLocator(const NetworkPrefix &aNetworkPrefix, uint16_t aLocator);
void ToString(StringWriter &aWriter) const;
void AppendHexWords(StringWriter &aWriter, uint8_t aLength) const;
@@ -1018,8 +1032,8 @@ private:
static const Address &GetRealmLocalAllRoutersMulticast(void);
static const Address &GetRealmLocalAllMplForwarders(void);
static constexpr uint8_t kMulticastNetworkPrefixLengthOffset = 3; // Prefix-Based Multicast Address (RFC3306).
static constexpr uint8_t kMulticastNetworkPrefixOffset = 4; // Prefix-Based Multicast Address (RFC3306).
static void CopyBits(uint8_t *aDst, const uint8_t *aSrc, uint8_t aNumBits);
} OT_TOOL_PACKED_END;
/**
+39 -2
View File
@@ -215,6 +215,27 @@ bool CheckPrefix(const ot::Ip6::Address &aAddress, const uint8_t *aPrefix, uint8
return matches;
}
bool CheckPrefixInIid(const ot::Ip6::InterfaceIdentifier &aIid, const uint8_t *aPrefix, uint8_t aPrefixLength)
{
// Check the IID to contain the prefix bits (applicable when prefix length is longer than 64).
bool matches = true;
for (uint8_t bit = 64; bit < aPrefixLength; bit++)
{
uint8_t index = bit / CHAR_BIT;
uint8_t mask = (0x80 >> (bit % CHAR_BIT));
if ((aIid.mFields.m8[index - 8] & 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.
@@ -248,6 +269,7 @@ void TestIp6AddressSetPrefix(void)
ot::Ip6::Address address;
ot::Ip6::Address allZeroAddress;
ot::Ip6::Address allOneAddress;
ot::Ip6::Prefix ip6Prefix;
allZeroAddress.Clear();
memset(&allOneAddress, 0xff, sizeof(allOneAddress));
@@ -259,18 +281,33 @@ void TestIp6AddressSetPrefix(void)
for (uint8_t prefixLength = 0; prefixLength <= sizeof(ot::Ip6::Address) * CHAR_BIT; prefixLength++)
{
ip6Prefix.Clear();
ip6Prefix.Set(prefix, prefixLength);
address = allZeroAddress;
address.SetPrefix(prefix, prefixLength);
address.SetPrefix(ip6Prefix);
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);
address.SetPrefix(ip6Prefix);
VerifyOrQuit(CheckPrefix(address, prefix, prefixLength), "Prefix does not match after SetPrefix()");
VerifyOrQuit(CheckInterfaceId(address, allOneAddress, prefixLength),
"SetPrefix changed bits beyond the prefix length");
address = allZeroAddress;
address.GetIid().ApplyPrefix(ip6Prefix);
VerifyOrQuit(CheckPrefixInIid(address.GetIid(), prefix, prefixLength), "IID is not correct");
VerifyOrQuit(CheckInterfaceId(address, allZeroAddress, prefixLength),
"Iid:ApplyPrefrix() changed bits beyond the prefix length");
address = allOneAddress;
address.GetIid().ApplyPrefix(ip6Prefix);
VerifyOrQuit(CheckPrefixInIid(address.GetIid(), prefix, prefixLength), "IID is not correct");
VerifyOrQuit(CheckInterfaceId(address, allOneAddress, prefixLength),
"Iid:ApplyPrefrix() changed bits beyond the prefix length");
}
}
}