mirror of
https://github.com/espressif/openthread.git
synced 2026-08-21 09:59:52 +00:00
[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:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user