From 3bf281d32da7ccde2153c5c90076e327a488d38e Mon Sep 17 00:00:00 2001 From: Li Cao Date: Thu, 2 May 2024 01:56:18 +0800 Subject: [PATCH] [cli] move a few static util methods to `Cli::Utils` class (#10138) This commit moves a few static util methods from the `Interpreter` class to the `Cli::Utils` class. Since the `Interpreter` class and other classes for cli components inherit the `Cli::Utils`, they can still access these methods. Putting these methods in utils class is more intuitive. This change also makes other cli classes less dependent on the `Interpreter` class. --- src/cli/cli.cpp | 264 ---------------------------------- src/cli/cli.hpp | 75 ---------- src/cli/cli_br.cpp | 11 +- src/cli/cli_commissioner.cpp | 2 +- src/cli/cli_dns.cpp | 3 +- src/cli/cli_history.cpp | 4 +- src/cli/cli_joiner.cpp | 2 +- src/cli/cli_network_data.cpp | 12 +- src/cli/cli_ping.cpp | 2 +- src/cli/cli_tcp.cpp | 2 +- src/cli/cli_udp.cpp | 5 +- src/cli/cli_utils.cpp | 265 +++++++++++++++++++++++++++++++++++ src/cli/cli_utils.hpp | 112 +++++++++++++++ 13 files changed, 397 insertions(+), 362 deletions(-) diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index c1aaecf5e..1619aca5d 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -207,35 +207,6 @@ exit: return; } -const char *Interpreter::LinkModeToString(const otLinkModeConfig &aLinkMode, char (&aStringBuffer)[kLinkModeStringSize]) -{ - char *flagsPtr = &aStringBuffer[0]; - - if (aLinkMode.mRxOnWhenIdle) - { - *flagsPtr++ = 'r'; - } - - if (aLinkMode.mDeviceType) - { - *flagsPtr++ = 'd'; - } - - if (aLinkMode.mNetworkData) - { - *flagsPtr++ = 'n'; - } - - if (flagsPtr == &aStringBuffer[0]) - { - *flagsPtr++ = '-'; - } - - *flagsPtr = '\0'; - - return aStringBuffer; -} - #if OPENTHREAD_CONFIG_DIAG_ENABLE template <> otError Interpreter::Process(Arg aArgs[]) { @@ -416,101 +387,6 @@ otError Interpreter::SetUserCommands(const otCliCommand *aCommands, uint8_t aLen #if OPENTHREAD_FTD || OPENTHREAD_MTD -otError Interpreter::ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner) -{ - otError error; - char *separator; - - VerifyOrExit(!aArg.IsEmpty(), error = OT_ERROR_INVALID_ARGS); - - separator = strstr(aArg.GetCString(), "/"); - - VerifyOrExit(separator != nullptr, error = OT_ERROR_NOT_FOUND); - - SuccessOrExit(error = ot::Utils::CmdLineParser::ParseAsUint8(separator + 1, aDiscerner.mLength)); - VerifyOrExit(aDiscerner.mLength > 0 && aDiscerner.mLength <= 64, error = OT_ERROR_INVALID_ARGS); - *separator = '\0'; - error = aArg.ParseAsUint64(aDiscerner.mValue); - -exit: - return error; -} - -otError Interpreter::ParsePreference(const Arg &aArg, otRoutePreference &aPreference) -{ - otError error = OT_ERROR_NONE; - - if (aArg == "high") - { - aPreference = OT_ROUTE_PREFERENCE_HIGH; - } - else if (aArg == "med") - { - aPreference = OT_ROUTE_PREFERENCE_MED; - } - else if (aArg == "low") - { - aPreference = OT_ROUTE_PREFERENCE_LOW; - } - else - { - error = OT_ERROR_INVALID_ARGS; - } - - return error; -} - -const char *Interpreter::PreferenceToString(signed int aPreference) -{ - const char *str = ""; - - switch (aPreference) - { - case OT_ROUTE_PREFERENCE_LOW: - str = "low"; - break; - - case OT_ROUTE_PREFERENCE_MED: - str = "med"; - break; - - case OT_ROUTE_PREFERENCE_HIGH: - str = "high"; - break; - - default: - break; - } - - return str; -} - -otError Interpreter::ParseToIp6Address(otInstance *aInstance, - const Arg &aArg, - otIp6Address &aAddress, - bool &aSynthesized) -{ - Error error = OT_ERROR_NONE; - - VerifyOrExit(!aArg.IsEmpty(), error = OT_ERROR_INVALID_ARGS); - error = aArg.ParseAsIp6Address(aAddress); - aSynthesized = false; - - if (error != OT_ERROR_NONE) - { - // It might be an IPv4 address, let's have a try. - otIp4Address ip4Address; - - // Do not touch the error value if we failed to parse it as an IPv4 address. - SuccessOrExit(aArg.ParseAsIp4Address(ip4Address)); - SuccessOrExit(error = otNat64SynthesizeIp6Address(aInstance, &ip4Address, &aAddress)); - aSynthesized = true; - } - -exit: - return error; -} - #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE template <> otError Interpreter::Process(Arg aArgs[]) { return mHistory.Process(aArgs); } #endif @@ -3277,23 +3153,6 @@ template <> otError Interpreter::Process(Arg aArgs[]) return error; } -const char *Interpreter::AddressOriginToString(uint8_t aOrigin) -{ - static const char *const kOriginStrings[4] = { - "thread", // 0, OT_ADDRESS_ORIGIN_THREAD - "slaac", // 1, OT_ADDRESS_ORIGIN_SLAAC - "dhcp6", // 2, OT_ADDRESS_ORIGIN_DHCPV6 - "manual", // 3, OT_ADDRESS_ORIGIN_MANUAL - }; - - static_assert(0 == OT_ADDRESS_ORIGIN_THREAD, "OT_ADDRESS_ORIGIN_THREAD value is incorrect"); - static_assert(1 == OT_ADDRESS_ORIGIN_SLAAC, "OT_ADDRESS_ORIGIN_SLAAC value is incorrect"); - static_assert(2 == OT_ADDRESS_ORIGIN_DHCPV6, "OT_ADDRESS_ORIGIN_DHCPV6 value is incorrect"); - static_assert(3 == OT_ADDRESS_ORIGIN_MANUAL, "OT_ADDRESS_ORIGIN_MANUAL value is incorrect"); - - return Stringify(aOrigin, kOriginStrings); -} - template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; @@ -5853,80 +5712,6 @@ void Interpreter::HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx) } #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE -otError Interpreter::ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig) -{ - otError error = OT_ERROR_NONE; - - ClearAllBytes(aConfig); - - SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(aConfig.mPrefix)); - aArgs++; - - for (; !aArgs->IsEmpty(); aArgs++) - { - otRoutePreference preference; - - if (ParsePreference(*aArgs, preference) == OT_ERROR_NONE) - { - aConfig.mPreference = preference; - } - else - { - for (char *arg = aArgs->GetCString(); *arg != '\0'; arg++) - { - switch (*arg) - { - case 'p': - aConfig.mPreferred = true; - break; - - case 'a': - aConfig.mSlaac = true; - break; - - case 'd': - aConfig.mDhcp = true; - break; - - case 'c': - aConfig.mConfigure = true; - break; - - case 'r': - aConfig.mDefaultRoute = true; - break; - - case 'o': - aConfig.mOnMesh = true; - break; - - case 's': - aConfig.mStable = true; - break; - - case 'n': - aConfig.mNdDns = true; - break; - -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE - case 'D': - aConfig.mDp = true; - break; -#endif - case '-': - break; - - default: - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - } - } - -exit: - return error; -} - template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; @@ -6280,55 +6065,6 @@ template <> otError Interpreter::Process(Arg aArgs[]) } #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE -otError Interpreter::ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig) -{ - otError error = OT_ERROR_NONE; - - ClearAllBytes(aConfig); - - SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(aConfig.mPrefix)); - aArgs++; - - for (; !aArgs->IsEmpty(); aArgs++) - { - otRoutePreference preference; - - if (ParsePreference(*aArgs, preference) == OT_ERROR_NONE) - { - aConfig.mPreference = preference; - } - else - { - for (char *arg = aArgs->GetCString(); *arg != '\0'; arg++) - { - switch (*arg) - { - case 's': - aConfig.mStable = true; - break; - - case 'n': - aConfig.mNat64 = true; - break; - - case 'a': - aConfig.mAdvPio = true; - break; - - case '-': - break; - - default: - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - } - } - -exit: - return error; -} - template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index b808f7455..d5fe30ad9 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -191,76 +191,6 @@ public: */ otError SetUserCommands(const otCliCommand *aCommands, uint8_t aLength, void *aContext); - static constexpr uint8_t kLinkModeStringSize = sizeof("rdn"); ///< Size of string buffer for a MLE Link Mode. - - /** - * Converts a given MLE Link Mode to flag string. - * - * The characters 'r', 'd', and 'n' are respectively used for `mRxOnWhenIdle`, `mDeviceType` and `mNetworkData` - * flags. If all flags are `false`, then "-" is returned. - * - * @param[in] aLinkMode The MLE Link Mode to convert. - * @param[out] aStringBuffer A reference to an string array to place the string. - * - * @returns A pointer @p aStringBuffer which contains the converted string. - * - */ - static const char *LinkModeToString(const otLinkModeConfig &aLinkMode, char (&aStringBuffer)[kLinkModeStringSize]); - - /** - * Converts an IPv6 address origin `OT_ADDRESS_ORIGIN_*` value to human-readable string. - * - * @param[in] aOrigin The IPv6 address origin to convert. - * - * @returns A human-readable string representation of @p aOrigin. - * - */ - static const char *AddressOriginToString(uint8_t aOrigin); - - /** - * Parses a given argument string as a route preference comparing it against "high", "med", or - * "low". - * - * @param[in] aArg The argument string to parse. - * @param[out] aPreference Reference to a `otRoutePreference` to return the parsed preference. - * - * @retval OT_ERROR_NONE Successfully parsed @p aArg and updated @p aPreference. - * @retval OT_ERROR_INVALID_ARG @p aArg is not a valid preference string "high", "med", or "low". - * - */ - static otError ParsePreference(const Arg &aArg, otRoutePreference &aPreference); - - /** - * Converts a route preference value to human-readable string. - * - * @param[in] aPreference The preference value to convert (`OT_ROUTE_PREFERENCE_*` values). - * - * @returns A string representation @p aPreference. - * - */ - static const char *PreferenceToString(signed int aPreference); - - /** - * Parses the argument as an IP address. - * - * If the argument string is an IPv4 address, this method will try to synthesize an IPv6 address using preferred - * NAT64 prefix in the network data. - * - * @param[in] aInstance A pointer to OpenThread instance. - * @param[in] aArg The argument string to parse. - * @param[out] aAddress A reference to an `otIp6Address` to output the parsed IPv6 address. - * @param[out] aSynthesized Whether @p aAddress is synthesized from an IPv4 address. - * - * @retval OT_ERROR_NONE The argument was parsed successfully. - * @retval OT_ERROR_INVALID_ARGS The argument is empty or does not contain a valid IP address. - * @retval OT_ERROR_INVALID_STATE No valid NAT64 prefix in the network data. - * - */ - static otError ParseToIp6Address(otInstance *aInstance, - const Arg &aArg, - otIp6Address &aAddress, - bool &aSynthesized); - protected: static Interpreter *sInterpreter; @@ -280,11 +210,6 @@ private: void OutputPrompt(void); void OutputResult(otError aError); - static otError ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner); -#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE - static otError ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig); - static otError ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig); -#endif #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE void OutputBorderRouterCounters(void); #endif diff --git a/src/cli/cli_br.cpp b/src/cli/cli_br.cpp index 53f2b3274..3aaa1959f 100644 --- a/src/cli/cli_br.cpp +++ b/src/cli/cli_br.cpp @@ -233,7 +233,7 @@ template <> otError Br::Process(Arg aArgs[]) OutputFormat("%s", outputPrefixTypes == kPrefixTypeFavored ? "" : "Favored: "); OutputIp6Prefix(favored); - OutputLine(" prf:%s", Interpreter::PreferenceToString(preference)); + OutputLine(" prf:%s", PreferenceToString(preference)); } exit: @@ -365,7 +365,7 @@ template <> otError Br::Process(Arg aArgs[]) OutputFormat("%s", outputPrefixTypes == kPrefixTypeFavored ? "" : "Favored: "); OutputIp6Prefix(favored); - OutputLine(" prf:%s", Interpreter::PreferenceToString(preference)); + OutputLine(" prf:%s", PreferenceToString(preference)); } exit: @@ -424,7 +424,7 @@ template <> otError Br::Process(Arg aArgs[]) } else { - OutputFormat("route-prf:%s, ", Interpreter::PreferenceToString(entry.mRoutePreference)); + OutputFormat("route-prf:%s, ", PreferenceToString(entry.mRoutePreference)); } OutputFormat("router:"); @@ -594,8 +594,7 @@ template <> otError Br::Process(Arg aArgs[]) */ if (aArgs[0].IsEmpty()) { - OutputLine("%s", - Interpreter::PreferenceToString(otBorderRoutingGetRouteInfoOptionPreference(GetInstancePtr()))); + OutputLine("%s", PreferenceToString(otBorderRoutingGetRouteInfoOptionPreference(GetInstancePtr()))); } /** * @cli br rioprf clear @@ -648,7 +647,7 @@ template <> otError Br::Process(Arg aArgs[]) */ if (aArgs[0].IsEmpty()) { - OutputLine("%s", Interpreter::PreferenceToString(otBorderRoutingGetRoutePreference(GetInstancePtr()))); + OutputLine("%s", PreferenceToString(otBorderRoutingGetRoutePreference(GetInstancePtr()))); } /** * @cli br routeprf clear diff --git a/src/cli/cli_commissioner.cpp b/src/cli/cli_commissioner.cpp index 03aa8389a..76d61925b 100644 --- a/src/cli/cli_commissioner.cpp +++ b/src/cli/cli_commissioner.cpp @@ -194,7 +194,7 @@ template <> otError Commissioner::Process(Arg aArgs[]) } else { - error = Interpreter::ParseJoinerDiscerner(aArgs[1], discerner); + error = ParseJoinerDiscerner(aArgs[1], discerner); if (error == OT_ERROR_NOT_FOUND) { diff --git a/src/cli/cli_dns.cpp b/src/cli/cli_dns.cpp index 9e36e2751..c4d72d1c9 100644 --- a/src/cli/cli_dns.cpp +++ b/src/cli/cli_dns.cpp @@ -422,8 +422,7 @@ otError Dns::GetDnsConfig(Arg aArgs[], otDnsQueryConfig *&aConfig) VerifyOrExit(!aArgs[0].IsEmpty(), aConfig = nullptr); - SuccessOrExit(error = Interpreter::ParseToIp6Address(GetInstancePtr(), aArgs[0], aConfig->mServerSockAddr.mAddress, - nat64Synth)); + SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], aConfig->mServerSockAddr.mAddress, nat64Synth)); if (nat64Synth) { OutputFormat("Synthesized IPv6 DNS server address: "); diff --git a/src/cli/cli_history.cpp b/src/cli/cli_history.cpp index 82d75557a..f0964fdba 100644 --- a/src/cli/cli_history.cpp +++ b/src/cli/cli_history.cpp @@ -1341,7 +1341,7 @@ template <> otError History::Process(Arg aArgs[]) OutputLine(isList ? "%s -> event:%s prefix:%s flags:%s pref:%s rloc16:0x%04x" : "| %20s | %-7s | %-43s | %-9s | %-4s | 0x%04x |", ageString, Stringify(info->mEvent, kSimpleEventStrings), prefixString, flagsString, - Interpreter::PreferenceToString(info->mPrefix.mPreference), info->mPrefix.mRloc16); + PreferenceToString(info->mPrefix.mPreference), info->mPrefix.mRloc16); } exit: @@ -1430,7 +1430,7 @@ template <> otError History::Process(Arg aArgs[]) OutputLine(isList ? "%s -> event:%s route:%s flags:%s pref:%s rloc16:0x%04x" : "| %20s | %-7s | %-43s | %-9s | %-4s | 0x%04x |", ageString, Stringify(info->mEvent, kSimpleEventStrings), prefixString, flagsString, - Interpreter::PreferenceToString(info->mRoute.mPreference), info->mRoute.mRloc16); + PreferenceToString(info->mRoute.mPreference), info->mRoute.mRloc16); } exit: diff --git a/src/cli/cli_joiner.cpp b/src/cli/cli_joiner.cpp index 805087989..b47966ef6 100644 --- a/src/cli/cli_joiner.cpp +++ b/src/cli/cli_joiner.cpp @@ -108,7 +108,7 @@ template <> otError Joiner::Process(Arg aArgs[]) else { VerifyOrExit(aArgs[1].IsEmpty()); - SuccessOrExit(Interpreter::ParseJoinerDiscerner(aArgs[0], discerner)); + SuccessOrExit(ParseJoinerDiscerner(aArgs[0], discerner)); error = otJoinerSetDiscerner(GetInstancePtr(), &discerner); } } diff --git a/src/cli/cli_network_data.cpp b/src/cli/cli_network_data.cpp index 7aa0dd5ed..5d1d769c0 100644 --- a/src/cli/cli_network_data.cpp +++ b/src/cli/cli_network_data.cpp @@ -117,7 +117,7 @@ void NetworkData::OutputPrefix(const otBorderRouterConfig &aConfig) OutputFormat(" %s", flagsString); } - OutputLine(" %s %04x", Interpreter::PreferenceToString(aConfig.mPreference), aConfig.mRloc16); + OutputLine(" %s %04x", PreferenceToString(aConfig.mPreference), aConfig.mRloc16); } void NetworkData::RouteFlagsToString(const otExternalRouteConfig &aConfig, FlagsString &aString) @@ -155,7 +155,7 @@ void NetworkData::OutputRoute(const otExternalRouteConfig &aConfig) OutputFormat(" %s", flagsString); } - OutputLine(" %s %04x", Interpreter::PreferenceToString(aConfig.mPreference), aConfig.mRloc16); + OutputLine(" %s %04x", PreferenceToString(aConfig.mPreference), aConfig.mRloc16); } void NetworkData::OutputService(const otServiceConfig &aConfig) @@ -343,7 +343,7 @@ template <> otError NetworkData::Process(Arg aArgs[]) { otBorderRouterConfig config; - SuccessOrExit(error = Interpreter::ParsePrefix(aArgs + 1, config)); + SuccessOrExit(error = ParsePrefix(aArgs + 1, config)); error = otNetDataPublishOnMeshPrefix(GetInstancePtr(), &config); ExitNow(); } @@ -364,7 +364,7 @@ template <> otError NetworkData::Process(Arg aArgs[]) { otExternalRouteConfig config; - SuccessOrExit(error = Interpreter::ParseRoute(aArgs + 1, config)); + SuccessOrExit(error = ParseRoute(aArgs + 1, config)); error = otNetDataPublishExternalRoute(GetInstancePtr(), &config); ExitNow(); } @@ -387,7 +387,7 @@ template <> otError NetworkData::Process(Arg aArgs[]) otExternalRouteConfig config; SuccessOrExit(error = aArgs[1].ParseAsIp6Prefix(prefix)); - SuccessOrExit(error = Interpreter::ParseRoute(aArgs + 2, config)); + SuccessOrExit(error = ParseRoute(aArgs + 2, config)); error = otNetDataReplacePublishedExternalRoute(GetInstancePtr(), &prefix, &config); ExitNow(); } @@ -493,7 +493,7 @@ template <> otError NetworkData::Process(Arg aArgs[]) VerifyOrExit(aArgs[0] == "check", error = OT_ERROR_INVALID_ARGS); - error = Interpreter::ParseJoinerDiscerner(aArgs[1], discerner); + error = ParseJoinerDiscerner(aArgs[1], discerner); if (error == OT_ERROR_NOT_FOUND) { diff --git a/src/cli/cli_ping.cpp b/src/cli/cli_ping.cpp index 1111e3d1f..73c626c2f 100644 --- a/src/cli/cli_ping.cpp +++ b/src/cli/cli_ping.cpp @@ -96,7 +96,7 @@ otError PingSender::Process(Arg aArgs[]) aArgs++; } - SuccessOrExit(error = Interpreter::ParseToIp6Address(GetInstancePtr(), aArgs[0], config.mDestination, nat64Synth)); + SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], config.mDestination, nat64Synth)); if (nat64Synth) { diff --git a/src/cli/cli_tcp.cpp b/src/cli/cli_tcp.cpp index b891c2df6..6d3158d1c 100644 --- a/src/cli/cli_tcp.cpp +++ b/src/cli/cli_tcp.cpp @@ -383,7 +383,7 @@ template <> otError TcpExample::Process(Arg aArgs[]) VerifyOrExit(mInitialized, error = OT_ERROR_INVALID_STATE); - SuccessOrExit(error = Interpreter::ParseToIp6Address(GetInstancePtr(), aArgs[0], sockaddr.mAddress, nat64Synth)); + SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], sockaddr.mAddress, nat64Synth)); if (nat64Synth) { diff --git a/src/cli/cli_udp.cpp b/src/cli/cli_udp.cpp index b4c77fe3f..65e774f59 100644 --- a/src/cli/cli_udp.cpp +++ b/src/cli/cli_udp.cpp @@ -134,7 +134,7 @@ template <> otError UdpExample::Process(Arg aArgs[]) otSockAddr sockaddr; bool nat64Synth; - SuccessOrExit(error = Interpreter::ParseToIp6Address(GetInstancePtr(), aArgs[0], sockaddr.mAddress, nat64Synth)); + SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], sockaddr.mAddress, nat64Synth)); if (nat64Synth) { @@ -269,8 +269,7 @@ template <> otError UdpExample::Process(Arg aArgs[]) { bool nat64Synth; - SuccessOrExit( - error = Interpreter::ParseToIp6Address(GetInstancePtr(), aArgs[0], messageInfo.mPeerAddr, nat64Synth)); + SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], messageInfo.mPeerAddr, nat64Synth)); if (nat64Synth) { diff --git a/src/cli/cli_utils.cpp b/src/cli/cli_utils.cpp index f2f53593d..c2ee2c2dc 100644 --- a/src/cli/cli_utils.cpp +++ b/src/cli/cli_utils.cpp @@ -517,5 +517,270 @@ otError Utils::ProcessEnableDisable(Arg aArgs[], return error; } +otError Utils::ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner) +{ + otError error; + char *separator; + + VerifyOrExit(!aArg.IsEmpty(), error = OT_ERROR_INVALID_ARGS); + + separator = strstr(aArg.GetCString(), "/"); + + VerifyOrExit(separator != nullptr, error = OT_ERROR_NOT_FOUND); + + SuccessOrExit(error = ot::Utils::CmdLineParser::ParseAsUint8(separator + 1, aDiscerner.mLength)); + VerifyOrExit(aDiscerner.mLength > 0 && aDiscerner.mLength <= 64, error = OT_ERROR_INVALID_ARGS); + *separator = '\0'; + error = aArg.ParseAsUint64(aDiscerner.mValue); + +exit: + return error; +} + +otError Utils::ParsePreference(const Arg &aArg, otRoutePreference &aPreference) +{ + otError error = OT_ERROR_NONE; + + if (aArg == "high") + { + aPreference = OT_ROUTE_PREFERENCE_HIGH; + } + else if (aArg == "med") + { + aPreference = OT_ROUTE_PREFERENCE_MED; + } + else if (aArg == "low") + { + aPreference = OT_ROUTE_PREFERENCE_LOW; + } + else + { + error = OT_ERROR_INVALID_ARGS; + } + + return error; +} + +const char *Utils::PreferenceToString(signed int aPreference) +{ + const char *str = ""; + + switch (aPreference) + { + case OT_ROUTE_PREFERENCE_LOW: + str = "low"; + break; + + case OT_ROUTE_PREFERENCE_MED: + str = "med"; + break; + + case OT_ROUTE_PREFERENCE_HIGH: + str = "high"; + break; + + default: + break; + } + + return str; +} + +#if OPENTHREAD_FTD || OPENTHREAD_MTD +otError Utils::ParseToIp6Address(otInstance *aInstance, const Arg &aArg, otIp6Address &aAddress, bool &aSynthesized) +{ + Error error = OT_ERROR_NONE; + + VerifyOrExit(!aArg.IsEmpty(), error = OT_ERROR_INVALID_ARGS); + error = aArg.ParseAsIp6Address(aAddress); + aSynthesized = false; + + if (error != OT_ERROR_NONE) + { + // It might be an IPv4 address, let's have a try. + otIp4Address ip4Address; + + // Do not touch the error value if we failed to parse it as an IPv4 address. + SuccessOrExit(aArg.ParseAsIp4Address(ip4Address)); + SuccessOrExit(error = otNat64SynthesizeIp6Address(aInstance, &ip4Address, &aAddress)); + aSynthesized = true; + } + +exit: + return error; +} + +#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE +otError Utils::ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig) +{ + otError error = OT_ERROR_NONE; + + ClearAllBytes(aConfig); + + SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(aConfig.mPrefix)); + aArgs++; + + for (; !aArgs->IsEmpty(); aArgs++) + { + otRoutePreference preference; + + if (ParsePreference(*aArgs, preference) == OT_ERROR_NONE) + { + aConfig.mPreference = preference; + } + else + { + for (char *arg = aArgs->GetCString(); *arg != '\0'; arg++) + { + switch (*arg) + { + case 'p': + aConfig.mPreferred = true; + break; + + case 'a': + aConfig.mSlaac = true; + break; + + case 'd': + aConfig.mDhcp = true; + break; + + case 'c': + aConfig.mConfigure = true; + break; + + case 'r': + aConfig.mDefaultRoute = true; + break; + + case 'o': + aConfig.mOnMesh = true; + break; + + case 's': + aConfig.mStable = true; + break; + + case 'n': + aConfig.mNdDns = true; + break; + +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + case 'D': + aConfig.mDp = true; + break; +#endif + case '-': + break; + + default: + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + } + } + } + +exit: + return error; +} + +otError Utils::ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig) +{ + otError error = OT_ERROR_NONE; + + ClearAllBytes(aConfig); + + SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(aConfig.mPrefix)); + aArgs++; + + for (; !aArgs->IsEmpty(); aArgs++) + { + otRoutePreference preference; + + if (ParsePreference(*aArgs, preference) == OT_ERROR_NONE) + { + aConfig.mPreference = preference; + } + else + { + for (char *arg = aArgs->GetCString(); *arg != '\0'; arg++) + { + switch (*arg) + { + case 's': + aConfig.mStable = true; + break; + + case 'n': + aConfig.mNat64 = true; + break; + + case 'a': + aConfig.mAdvPio = true; + break; + + case '-': + break; + + default: + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + } + } + } + +exit: + return error; +} +#endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE +#endif // #if OPENTHREAD_FTD || OPENTHREAD_MTD + +const char *Utils::LinkModeToString(const otLinkModeConfig &aLinkMode, char (&aStringBuffer)[kLinkModeStringSize]) +{ + char *flagsPtr = &aStringBuffer[0]; + + if (aLinkMode.mRxOnWhenIdle) + { + *flagsPtr++ = 'r'; + } + + if (aLinkMode.mDeviceType) + { + *flagsPtr++ = 'd'; + } + + if (aLinkMode.mNetworkData) + { + *flagsPtr++ = 'n'; + } + + if (flagsPtr == &aStringBuffer[0]) + { + *flagsPtr++ = '-'; + } + + *flagsPtr = '\0'; + + return aStringBuffer; +} + +const char *Utils::AddressOriginToString(uint8_t aOrigin) +{ + static const char *const kOriginStrings[4] = { + "thread", // 0, OT_ADDRESS_ORIGIN_THREAD + "slaac", // 1, OT_ADDRESS_ORIGIN_SLAAC + "dhcp6", // 2, OT_ADDRESS_ORIGIN_DHCPV6 + "manual", // 3, OT_ADDRESS_ORIGIN_MANUAL + }; + + static_assert(0 == OT_ADDRESS_ORIGIN_THREAD, "OT_ADDRESS_ORIGIN_THREAD value is incorrect"); + static_assert(1 == OT_ADDRESS_ORIGIN_SLAAC, "OT_ADDRESS_ORIGIN_SLAAC value is incorrect"); + static_assert(2 == OT_ADDRESS_ORIGIN_DHCPV6, "OT_ADDRESS_ORIGIN_DHCPV6 value is incorrect"); + static_assert(3 == OT_ADDRESS_ORIGIN_MANUAL, "OT_ADDRESS_ORIGIN_MANUAL value is incorrect"); + + return Stringify(aOrigin, kOriginStrings); +} + } // namespace Cli } // namespace ot diff --git a/src/cli/cli_utils.hpp b/src/cli/cli_utils.hpp index d2a994ed8..0ed5d943f 100644 --- a/src/cli/cli_utils.hpp +++ b/src/cli/cli_utils.hpp @@ -38,7 +38,11 @@ #include +#include +#include #include +#include +#include #include "cli_config.h" @@ -645,6 +649,114 @@ public: IsEnabledHandler aIsEnabledHandler, SetEnabledHandlerFailable aSetEnabledHandler); + /** + * Parses a given argument string as a route preference comparing it against "high", "med", or + * "low". + * + * @param[in] aArg The argument string to parse. + * @param[out] aPreference Reference to a `otRoutePreference` to return the parsed preference. + * + * @retval OT_ERROR_NONE Successfully parsed @p aArg and updated @p aPreference. + * @retval OT_ERROR_INVALID_ARG @p aArg is not a valid preference string "high", "med", or "low". + * + */ + static otError ParsePreference(const Arg &aArg, otRoutePreference &aPreference); + + /** + * Converts a route preference value to human-readable string. + * + * @param[in] aPreference The preference value to convert (`OT_ROUTE_PREFERENCE_*` values). + * + * @returns A string representation @p aPreference. + * + */ + static const char *PreferenceToString(signed int aPreference); + + /** + * Parses the argument as an IP address. + * + * If the argument string is an IPv4 address, this method will try to synthesize an IPv6 address using preferred + * NAT64 prefix in the network data. + * + * @param[in] aInstance A pointer to OpenThread instance. + * @param[in] aArg The argument string to parse. + * @param[out] aAddress A reference to an `otIp6Address` to output the parsed IPv6 address. + * @param[out] aSynthesized Whether @p aAddress is synthesized from an IPv4 address. + * + * @retval OT_ERROR_NONE The argument was parsed successfully. + * @retval OT_ERROR_INVALID_ARGS The argument is empty or does not contain a valid IP address. + * @retval OT_ERROR_INVALID_STATE No valid NAT64 prefix in the network data. + * + */ + static otError ParseToIp6Address(otInstance *aInstance, + const Arg &aArg, + otIp6Address &aAddress, + bool &aSynthesized); + + /** + * Parses the argument as a Joiner Discerner. + * + * @param[in] aArg The argument string to parse. + * @param[out] aDiscerner A reference to an `otJoinerDiscerner` to output the parsed discerner + * + * @retval OT_ERROR_NONE The argument was parsed successfully. + * @retval OT_ERROR_INVALID_ARGS The argument is empty or does not contain a valid joiner discerner. + * + */ + static otError ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner); + +#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE + /** + * Parses the argument as a Border Router configuration. + * + * @param[in] aArg The argument string to parse. + * @param[out] aConfig A reference to an `otBorderRouterConfig` to output the configuration. + * + * @retval OT_ERROR_NONE The argument was parsed successfully. + * @retval OT_ERROR_INVALID_ARGS The argument is empty or does not contain a valid configuration. + * + */ + static otError ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig); + + /** + * Parses the argument as a External Route configuration. + * + * @param[in] aArg The argument string to parse. + * @param[out] aConfig A reference to an `otExternalRouteConfig` to output the configuration. + * + * @retval OT_ERROR_NONE The argument was parsed successfully. + * @retval OT_ERROR_INVALID_ARGS The argument is empty or does not contain a valid configuration. + * + */ + static otError ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig); +#endif + + static constexpr uint8_t kLinkModeStringSize = sizeof("rdn"); ///< Size of string buffer for a MLE Link Mode. + + /** + * Converts a given MLE Link Mode to flag string. + * + * The characters 'r', 'd', and 'n' are respectively used for `mRxOnWhenIdle`, `mDeviceType` and `mNetworkData` + * flags. If all flags are `false`, then "-" is returned. + * + * @param[in] aLinkMode The MLE Link Mode to convert. + * @param[out] aStringBuffer A reference to an string array to place the string. + * + * @returns A pointer @p aStringBuffer which contains the converted string. + * + */ + static const char *LinkModeToString(const otLinkModeConfig &aLinkMode, char (&aStringBuffer)[kLinkModeStringSize]); + + /** + * Converts an IPv6 address origin `OT_ADDRESS_ORIGIN_*` value to human-readable string. + * + * @param[in] aOrigin The IPv6 address origin to convert. + * + * @returns A human-readable string representation of @p aOrigin. + * + */ + static const char *AddressOriginToString(uint8_t aOrigin); + protected: void OutputFormatV(const char *aFormat, va_list aArguments);