From 9a7d831cb1cefcf1ff51477cc90f18df12c0c936 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 13 Mar 2020 08:07:07 -0700 Subject: [PATCH] [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. --- src/core/net/ip6_address.cpp | 22 +++++++++ src/core/net/ip6_address.hpp | 12 +++++ src/core/thread/lowpan.cpp | 8 +-- src/core/thread/mle.cpp | 12 ++--- tests/unit/test_ip6_address.cpp | 86 +++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 13 deletions(-) diff --git a/src/core/net/ip6_address.cpp b/src/core/net/ip6_address.cpp index 8e0981096..3967bc09c 100644 --- a/src/core/net/ip6_address.cpp +++ b/src/core/net/ip6_address.cpp @@ -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); diff --git a/src/core/net/ip6_address.hpp b/src/core/net/ip6_address.hpp index 3b7a9ff17..e3f42505c 100644 --- a/src/core/net/ip6_address.hpp +++ b/src/core/net/ip6_address.hpp @@ -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. * diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp index 75edcadee..eb4d4807a 100644 --- a/src/core/thread/lowpan.cpp +++ b/src/core/thread/lowpan.cpp @@ -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) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 1d37e9d99..62f9ca9a9 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -915,9 +915,9 @@ void Mle::SetMeshLocalPrefix(const otMeshLocalPrefix &aMeshLocalPrefix) Get().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().IsUp()); @@ -937,7 +937,7 @@ void Mle::ApplyMeshLocalPrefix(void) if (HostSwap16(mServiceAlocs[i].GetAddress().mFields.m16[7]) != Mac::kShortAddrInvalid) { Get().RemoveUnicastAddress(mServiceAlocs[i]); - memcpy(mServiceAlocs[i].GetAddress().mFields.m8, mMeshLocal64.GetAddress().mFields.m8, 8); + mServiceAlocs[i].GetAddress().SetPrefix(GetMeshLocalPrefix().m8, Ip6::Address::kMeshLocalPrefixLength); Get().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); diff --git a/tests/unit/test_ip6_address.cpp b/tests/unit/test_ip6_address.cpp index e3a390bb9..d60587f4e 100644 --- a/tests/unit/test_ip6_address.cpp +++ b/tests/unit/test_ip6_address.cpp @@ -26,6 +26,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include + #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;