[ip6] add otIp6PrefixFromString() (#9016)

This commit adds the `Ip6::Prefix::FromString()` method, which parses
a human-readable IPv6 prefix string into a binary representation. It
also updates the unit test `test_ip_address` to validate the new
method, and updates the `parse_cmdline` module to use the new
function.
This commit is contained in:
Abtin Keshavarzian
2023-05-03 18:28:32 -07:00
committed by GitHub
parent a7edd859ee
commit 2caf6b818a
7 changed files with 132 additions and 31 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (316)
#define OPENTHREAD_API_VERSION (317)
/**
* @addtogroup api-instance
+17 -2
View File
@@ -610,12 +610,27 @@ bool otIp6ArePrefixesEqual(const otIp6Prefix *aFirst, const otIp6Prefix *aSecond
* @param[in] aString A pointer to a NULL-terminated string.
* @param[out] aAddress A pointer to an IPv6 address.
*
* @retval OT_ERROR_NONE Successfully parsed the string.
* @retval OT_ERROR_INVALID_ARGS Failed to parse the string.
* @retval OT_ERROR_NONE Successfully parsed @p aString and updated @p aAddress.
* @retval OT_ERROR_PARSE Failed to parse @p aString as an IPv6 address.
*
*/
otError otIp6AddressFromString(const char *aString, otIp6Address *aAddress);
/**
* This function converts a human-readable IPv6 prefix string into a binary representation.
*
* The @p aString parameter should be a string in the format "<address>/<plen>", where `<address>` is an IPv6
* address and `<plen>` is a prefix length.
*
* @param[in] aString A pointer to a NULL-terminated string.
* @param[out] aPrefix A pointer to an IPv6 prefix.
*
* @retval OT_ERROR_NONE Successfully parsed the string as an IPv6 prefix and updated @p aPrefix.
* @retval OT_ERROR_PARSE Failed to parse @p aString as an IPv6 prefix.
*
*/
otError otIp6PrefixFromString(const char *aString, otIp6Prefix *aPrefix);
#define OT_IP6_ADDRESS_STRING_SIZE 40 ///< Recommended size for string representation of an IPv6 address.
/**
+5
View File
@@ -188,6 +188,11 @@ otError otIp6AddressFromString(const char *aString, otIp6Address *aAddress)
return AsCoreType(aAddress).FromString(aString);
}
otError otIp6PrefixFromString(const char *aString, otIp6Prefix *aPrefix)
{
return AsCoreType(aPrefix).FromString(aString);
}
void otIp6AddressToString(const otIp6Address *aAddress, char *aBuffer, uint16_t aSize)
{
AssertPointerIsNotNull(aBuffer);
+43 -4
View File
@@ -157,6 +157,39 @@ bool Prefix::IsValidNat64PrefixLength(uint8_t aLength)
(aLength == 96);
}
Error Prefix::FromString(const char *aString)
{
constexpr char kSlashChar = '/';
constexpr char kNullChar = '\0';
Error error = kErrorParse;
const char *slashPosition;
uint16_t plen = 0;
VerifyOrExit(aString != nullptr);
slashPosition = StringFind(aString, kSlashChar);
VerifyOrExit(slashPosition != nullptr);
SuccessOrExit(AsCoreType(&mPrefix).ParseFrom(aString, kSlashChar));
VerifyOrExit(slashPosition[1] != kNullChar);
for (const char *cur = slashPosition + 1; *cur != kNullChar; cur++)
{
VerifyOrExit((*cur >= '0') && (*cur <= '9'));
plen *= 10;
plen += static_cast<uint8_t>(*cur - '0');
VerifyOrExit(plen <= kMaxLength);
}
SetLength(static_cast<uint8_t>(plen));
error = kErrorNone;
exit:
return error;
}
Prefix::InfoString Prefix::ToString(void) const
{
InfoString string;
@@ -491,11 +524,17 @@ void Address::SynthesizeFromIp4Address(const Prefix &aPrefix, const Ip4::Address
}
Error Address::FromString(const char *aString)
{
constexpr char kNullChar = '\0';
return ParseFrom(aString, kNullChar);
}
Error Address::ParseFrom(const char *aString, char aTerminatorChar)
{
constexpr uint8_t kInvalidIndex = 0xff;
constexpr char kColonChar = ':';
constexpr char kDotChar = '.';
constexpr char kNullChar = '\0';
Error error = kErrorParse;
uint8_t index = 0;
@@ -513,7 +552,7 @@ Error Address::FromString(const char *aString)
colonIndex = index;
}
while (*aString != kNullChar)
while (*aString != aTerminatorChar)
{
const char *start = aString;
uint32_t value = 0;
@@ -560,7 +599,7 @@ Error Address::FromString(const char *aString)
break;
}
VerifyOrExit((*aString == kColonChar) || (*aString == kNullChar));
VerifyOrExit((*aString == kColonChar) || (*aString == aTerminatorChar));
VerifyOrExit(index < endIndex);
mFields.m16[index++] = HostSwap16(static_cast<uint16_t>(value));
@@ -594,7 +633,7 @@ Error Address::FromString(const char *aString)
{
Ip4::Address ip4Addr;
SuccessOrExit(error = ip4Addr.FromString(aString));
SuccessOrExit(error = ip4Addr.FromString(aString, aTerminatorChar));
memcpy(GetArrayEnd(mFields.m8) - Ip4::Address::kSize, ip4Addr.GetBytes(), Ip4::Address::kSize);
}
+13
View File
@@ -315,6 +315,17 @@ public:
*/
bool IsValidNat64(void) const { return IsValidNat64PrefixLength(mLength); }
/**
* This method parses a given IPv6 prefix string and sets the prefix.
*
* @param[in] aString A null-terminated string, with format "<prefix>/<plen>"
*
* @retval kErrorNone Successfully parsed the IPv6 prefix from @p aString.
* @retval kErrorParse Failed to parse the IPv6 prefix from @p aString.
*
*/
Error FromString(const char *aString);
/**
* This method converts the prefix to a string.
*
@@ -1028,6 +1039,8 @@ private:
static void CopyBits(uint8_t *aDst, const uint8_t *aSrc, uint8_t aNumBits);
Error ParseFrom(const char *aString, char aTerminatorChar);
} OT_TOOL_PACKED_END;
/**
+1 -24
View File
@@ -250,30 +250,7 @@ Error ParseAsIp4Address(const char *aString, otIp4Address &aAddress)
Error ParseAsIp6Prefix(const char *aString, otIp6Prefix &aPrefix)
{
enum : uint8_t
{
kMaxIp6AddressStringSize = 45,
};
Error error = kErrorInvalidArgs;
char string[kMaxIp6AddressStringSize];
const char *prefixLengthStr;
VerifyOrExit(aString != nullptr);
prefixLengthStr = StringFind(aString, '/');
VerifyOrExit(prefixLengthStr != nullptr);
VerifyOrExit(prefixLengthStr - aString < static_cast<int32_t>(sizeof(string)));
memcpy(string, aString, static_cast<uint8_t>(prefixLengthStr - aString));
string[prefixLengthStr - aString] = '\0';
SuccessOrExit(static_cast<Ip6::Address &>(aPrefix.mPrefix).FromString(string));
error = ParseAsUint8(prefixLengthStr + 1, aPrefix.mLength);
exit:
return error;
return (aString != nullptr) ? otIp6PrefixFromString(aString, &aPrefix) : kErrorInvalidArgs;
}
#endif // #if OPENTHREAD_FTD || OPENTHREAD_MTD
+52
View File
@@ -29,6 +29,7 @@
#include <limits.h>
#include "common/encoding.hpp"
#include "common/string.hpp"
#include "net/ip4_types.hpp"
#include "net/ip6_address.hpp"
@@ -166,6 +167,56 @@ void TestIp6AddressFromString(void)
{
checkAddressFromString(&testVector);
}
// Validate parsing all test vectors now as an IPv6 prefix.
for (Ip6AddressTestVector &testVector : testVectors)
{
constexpr uint16_t kMaxString = 80;
ot::Ip6::Prefix prefix;
char string[kMaxString];
uint16_t length;
length = ot::StringLength(testVector.mString, kMaxString);
memcpy(string, testVector.mString, length);
VerifyOrQuit(length + sizeof("/128") <= kMaxString);
strcpy(&string[length], "/128");
printf("%s\n", string);
VerifyOrQuit(prefix.FromString(string) == testVector.mError);
if (testVector.mError == ot::kErrorNone)
{
VerifyOrQuit(memcmp(prefix.GetBytes(), testVector.mAddr, sizeof(ot::Ip6::Address)) == 0);
VerifyOrQuit(prefix.GetLength() == 128);
}
}
}
void TestIp6PrefixFromString(void)
{
ot::Ip6::Prefix prefix;
SuccessOrQuit(prefix.FromString("::/128"));
VerifyOrQuit(prefix.GetLength() == 128);
SuccessOrQuit(prefix.FromString("::/0128"));
VerifyOrQuit(prefix.GetLength() == 128);
SuccessOrQuit(prefix.FromString("::/5"));
VerifyOrQuit(prefix.GetLength() == 5);
SuccessOrQuit(prefix.FromString("::/0"));
VerifyOrQuit(prefix.GetLength() == 0);
VerifyOrQuit(prefix.FromString("::") == ot::kErrorParse);
VerifyOrQuit(prefix.FromString("::/") == ot::kErrorParse);
VerifyOrQuit(prefix.FromString("::/129") == ot::kErrorParse);
VerifyOrQuit(prefix.FromString(":: /12") == ot::kErrorParse);
VerifyOrQuit(prefix.FromString("::/a1") == ot::kErrorParse);
VerifyOrQuit(prefix.FromString("::/12 ") == ot::kErrorParse);
}
void TestIp4AddressFromString(void)
@@ -651,6 +702,7 @@ int main(void)
TestIp6AddressSetPrefix();
TestIp4AddressFromString();
TestIp6AddressFromString();
TestIp6PrefixFromString();
TestIp6Prefix();
TestIp4Ip6Translation();
TestIp4Cidr();