From 16a5c52d9fa0e4be8cf85028cdf30b23a426dede Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Sat, 15 Aug 2020 13:09:14 +0800 Subject: [PATCH] [netdata] add api to check if joiner is in steering data (#5392) --- include/openthread/instance.h | 2 +- include/openthread/netdata.h | 30 ++++++++++++++++ src/cli/README.md | 17 +++++++++ src/cli/README_COMMISSIONER.md | 11 ++++-- src/cli/cli.cpp | 43 +++++++++++++++++++++++ src/cli/cli.hpp | 1 + src/cli/cli_commissioner.cpp | 9 ++++- src/core/api/netdata_api.cpp | 12 +++++++ src/core/meshcop/meshcop_tlvs.cpp | 2 +- src/core/meshcop/meshcop_tlvs.hpp | 2 +- src/core/thread/network_data_leader.cpp | 37 +++++++++++++++++++ src/core/thread/network_data_leader.hpp | 27 ++++++++++++++ tests/scripts/expect/_multinode.exp | 1 + tests/scripts/expect/cli-commissioner.exp | 9 +++++ tests/scripts/expect/cli-discerner.exp | 16 +++++++++ 15 files changed, 213 insertions(+), 6 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 06676156c..da60c784c 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (23) +#define OPENTHREAD_API_VERSION (24) /** * @addtogroup api-instance diff --git a/include/openthread/netdata.h b/include/openthread/netdata.h index 6e29bd554..17c64945d 100644 --- a/include/openthread/netdata.h +++ b/include/openthread/netdata.h @@ -274,6 +274,36 @@ uint8_t otNetDataGetVersion(otInstance *aInstance); */ uint8_t otNetDataGetStableVersion(otInstance *aInstance); +/** + * Check if the steering data includes a Joiner. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aEui64 A pointer to the Joiner's IEEE EUI-64. + * + * @retval OT_ERROR_NONE @p aEui64 is included in the steering data. + * @retval OT_ERROR_INVALID_STATE No steering data present. + * @retval OT_ERROR_NOT_FOUND @p aEui64 is not included in the steering data. + * + */ +otError otNetDataSteeringDataCheckJoiner(otInstance *aInstance, const otExtAddress *aEui64); + +// Forward declaration +struct otJoinerDiscerner; + +/** + * Check if the steering data includes a Joiner with a given discerner value. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aDiscerner A pointer to the Joiner Discerner. + * + * @retval OT_ERROR_NONE @p aDiscerner is included in the steering data. + * @retval OT_ERROR_INVALID_STATE No steering data present. + * @retval OT_ERROR_NOT_FOUND @p aDiscerner is not included in the steering data. + * + */ +otError otNetDataSteeringDataCheckJoinerWithDiscerner(otInstance * aInstance, + const struct otJoinerDiscerner *aDiscerner); + /** * @} * diff --git a/src/cli/README.md b/src/cli/README.md index b5d3a1e3d..d021bfcd5 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -61,6 +61,7 @@ Done - [masterkey](#masterkey) - [mode](#mode) - [neighbor](#neighbor-list) +- [netdata](#netdata-steeringdata-check-eui64discerner) - [netdataregister](#netdataregister) - [netdatashow](#netdatashow) - [netstat](#netstat) @@ -1046,6 +1047,22 @@ Print table of neighbors. Done ``` +### netdata steeringdata check \|\ + +Check whether the steering data includes a joiner. + +- eui64: The IEEE EUI-64 of the Joiner. +- discerner: The Joiner discerner in format `number/length`. + +```bash +> netdata steeeringdata check d45e64fa83f81cf7 +Done +> netdata steeeringdata check 0xabc/12 +Done +> netdata steeeringdata check 0xdef/12 +Error: NotFound +``` + ### netdataregister Register local network data with Thread Leader. diff --git a/src/cli/README_COMMISSIONER.md b/src/cli/README_COMMISSIONER.md index 99310eaa1..035620068 100644 --- a/src/cli/README_COMMISSIONER.md +++ b/src/cli/README_COMMISSIONER.md @@ -82,13 +82,14 @@ Energy: 00050000 0 0 0 0 ### joiner add -Usage: `commissioner joiner add | ` +Usage: `commissioner joiner add | [timeout]` Add a Joiner entry. - eui64: The IEEE EUI-64 of the Joiner or '\*' to match any Joiner. - discerner: The Joiner discerner in format `number/length`. - pskd: Pre-Shared Key for the Joiner. +- timeout: joiner timeout in seconds. ```bash > commissioner joiner add d45e64fa83f81cf7 J01NME @@ -102,17 +103,23 @@ Done ### joiner remove -Usage: `commissioner joiner remove ` +Usage: `commissioner joiner remove |` Remove a Joiner entry. - eui64: The IEEE EUI-64 of the Joiner or '\*' to match any Joiner. +- discerner: The Joiner discerner in format `number/length`. ```bash > commissioner joiner remove d45e64fa83f81cf7 Done ``` +```bash +> commissioner joiner remove 0xabc/12 +Done +``` + ### mgmtget Usage: `commissioner mgmtget [locator] [sessionid] [steeringdata] [joinerudpport] [binary ]` diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 470554c8e..0fdbbcca2 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -186,6 +186,7 @@ const struct Command Interpreter::sCommands[] = { #if OPENTHREAD_FTD {"neighbor", &Interpreter::ProcessNeighbor}, #endif + {"netdata", &Interpreter::ProcessNetworkData}, #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE {"netdataregister", &Interpreter::ProcessNetworkDataRegister}, #endif @@ -2236,6 +2237,48 @@ exit: } #endif +void Interpreter::ProcessNetworkData(uint8_t aArgsLength, char *aArgs[]) +{ + otError error; + + if (aArgsLength > 2 && strcmp(aArgs[0], "steeringdata") == 0) + { + if (strcmp(aArgs[1], "check") == 0) + { + otExtAddress addr; + otJoinerDiscerner discerner; + + discerner.mLength = 0; + + error = Interpreter::ParseJoinerDiscerner(aArgs[2], discerner); + + if (error == OT_ERROR_NOT_FOUND) + { + VerifyOrExit(Interpreter::Hex2Bin(aArgs[2], addr.m8, sizeof(addr)) == sizeof(addr), + error = OT_ERROR_INVALID_ARGS); + } + else if (error != OT_ERROR_NONE) + { + ExitNow(); + } + + if (discerner.mLength) + { + ExitNow(error = otNetDataSteeringDataCheckJoinerWithDiscerner(mInstance, &discerner)); + } + else + { + ExitNow(error = otNetDataSteeringDataCheckJoiner(mInstance, &addr)); + } + } + } + + error = OT_ERROR_INVALID_COMMAND; + +exit: + AppendResult(error); +} + #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE void Interpreter::ProcessNetworkDataRegister(uint8_t aArgsLength, char *aArgs[]) { diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index d57c31c1f..a0ce44905 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -292,6 +292,7 @@ private: #if OPENTHREAD_FTD void ProcessNeighbor(uint8_t aArgsLength, char *aArgs[]); #endif + void ProcessNetworkData(uint8_t aArgsLength, char *aArgs[]); #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE void ProcessNetworkDataRegister(uint8_t aArgsLength, char *aArgs[]); #endif diff --git a/src/cli/cli_commissioner.cpp b/src/cli/cli_commissioner.cpp index 1ebbda249..7505a7cf7 100644 --- a/src/cli/cli_commissioner.cpp +++ b/src/cli/cli_commissioner.cpp @@ -162,7 +162,14 @@ otError Commissioner::ProcessJoiner(uint8_t aArgsLength, char *aArgs[]) } else if (strcmp(aArgs[1], "remove") == 0) { - SuccessOrExit(error = otCommissionerRemoveJoiner(mInterpreter.mInstance, addrPtr)); + if (discerner.mLength) + { + SuccessOrExit(error = otCommissionerRemoveJoinerWithDiscerner(mInterpreter.mInstance, &discerner)); + } + else + { + SuccessOrExit(error = otCommissionerRemoveJoiner(mInterpreter.mInstance, addrPtr)); + } } else { diff --git a/src/core/api/netdata_api.cpp b/src/core/api/netdata_api.cpp index 38b494f75..8afa0bee2 100644 --- a/src/core/api/netdata_api.cpp +++ b/src/core/api/netdata_api.cpp @@ -106,3 +106,15 @@ uint8_t otNetDataGetStableVersion(otInstance *aInstance) return instance.Get().GetLeaderData().GetStableDataVersion(); } + +otError otNetDataSteeringDataCheckJoiner(otInstance *aInstance, const otExtAddress *aEui64) +{ + return static_cast(aInstance)->Get().SteeringDataCheckJoiner( + *static_cast(aEui64)); +} + +otError otNetDataSteeringDataCheckJoinerWithDiscerner(otInstance *aInstance, const otJoinerDiscerner *aDiscerner) +{ + return static_cast(aInstance)->Get().SteeringDataCheckJoiner( + *static_cast(aDiscerner)); +} diff --git a/src/core/meshcop/meshcop_tlvs.cpp b/src/core/meshcop/meshcop_tlvs.cpp index e209f9c27..7b400a3c2 100644 --- a/src/core/meshcop/meshcop_tlvs.cpp +++ b/src/core/meshcop/meshcop_tlvs.cpp @@ -129,7 +129,7 @@ void NetworkNameTlv::SetNetworkName(const Mac::NameData &aNameData) SetLength(len); } -void SteeringDataTlv::CopyTo(SteeringData &aSteeringData) +void SteeringDataTlv::CopyTo(SteeringData &aSteeringData) const { aSteeringData.Init(GetSteeringDataLength()); memcpy(aSteeringData.GetData(), mSteeringData, GetSteeringDataLength()); diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index 1c6f5fe36..2cab07290 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -784,7 +784,7 @@ public: * @param[out] aSteeringData A reference to a `SteeringData` to copy into. * */ - void CopyTo(SteeringData &aSteeringData); + void CopyTo(SteeringData &aSteeringData) const; private: uint8_t mSteeringData[OT_STEERING_DATA_MAX_LENGTH]; diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index ed36817ad..f2cdcac73 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -541,5 +541,42 @@ exit: return; } +otError LeaderBase::SteeringDataCheck(const FilterIndexes &aFilterIndexes) const +{ + otError error = OT_ERROR_NONE; + const MeshCoP::Tlv * steeringDataTlv; + MeshCoP::SteeringData steeringData; + + steeringDataTlv = GetCommissioningDataSubTlv(MeshCoP::Tlv::kSteeringData); + VerifyOrExit(steeringDataTlv != nullptr, error = OT_ERROR_INVALID_STATE); + + static_cast(steeringDataTlv)->CopyTo(steeringData); + + VerifyOrExit(steeringData.Contains(aFilterIndexes), error = OT_ERROR_NOT_FOUND); + +exit: + return error; +} + +otError LeaderBase::SteeringDataCheckJoiner(const Mac::ExtAddress &aEui64) const +{ + FilterIndexes filterIndexes; + Mac::ExtAddress joinerId; + + MeshCoP::ComputeJoinerId(aEui64, joinerId); + MeshCoP::SteeringData::CalculateHashBitIndexes(joinerId, filterIndexes); + + return SteeringDataCheck(filterIndexes); +} + +otError LeaderBase::SteeringDataCheckJoiner(const MeshCoP::JoinerDiscerner &aDiscerner) const +{ + FilterIndexes filterIndexes; + + MeshCoP::SteeringData::CalculateHashBitIndexes(aDiscerner, filterIndexes); + + return SteeringDataCheck(filterIndexes); +} + } // namespace NetworkData } // namespace ot diff --git a/src/core/thread/network_data_leader.hpp b/src/core/thread/network_data_leader.hpp index 774d58608..81991e1a4 100644 --- a/src/core/thread/network_data_leader.hpp +++ b/src/core/thread/network_data_leader.hpp @@ -245,6 +245,30 @@ public: */ otError SetCommissioningData(const uint8_t *aValue, uint8_t aValueLength); + /** + * This method checks if the steering data includes a Joiner. + * + * @param[in] aEui64 A reference to the Joiner's IEEE EUI-64. + * + * @retval OT_ERROR_NONE @p aEui64 is in the bloom filter. + * @retval OT_ERROR_INVALID_STATE No steering data present. + * @retval OT_ERROR_NOT_FOUND @p aEui64 is not in the bloom filter. + * + */ + otError SteeringDataCheckJoiner(const Mac::ExtAddress &aEui64) const; + + /** + * This method checks if the steering data includes a Joiner with a given discerner value. + * + * @param[in] aDiscerner A reference to the Joiner Discerner. + * + * @retval OT_ERROR_NONE @p aDiscerner is in the bloom filter. + * @retval OT_ERROR_INVALID_STATE No steering data present. + * @retval OT_ERROR_NOT_FOUND @p aDiscerner is not in the bloom filter. + * + */ + otError SteeringDataCheckJoiner(const MeshCoP::JoinerDiscerner &aDiscerner) const; + /** * This method gets the Rloc of Dhcp Agent of specified contextId. * @@ -294,6 +318,8 @@ protected: uint8_t mVersion; private: + using FilterIndexes = MeshCoP::SteeringData::HashBitIndexes; + const PrefixTlv *FindNextMatchingPrefix(const Ip6::Address &aAddress, const PrefixTlv *aPrevTlv) const; void RemoveCommissioningData(void); @@ -303,6 +329,7 @@ private: uint8_t * aPrefixMatchLength, uint16_t * aRloc16) const; otError DefaultRouteLookup(const PrefixTlv &aPrefix, uint16_t *aRloc16) const; + otError SteeringDataCheck(const FilterIndexes &aFilterIndexes) const; }; /** diff --git a/tests/scripts/expect/_multinode.exp b/tests/scripts/expect/_multinode.exp index 0771305c3..a394dbd23 100644 --- a/tests/scripts/expect/_multinode.exp +++ b/tests/scripts/expect/_multinode.exp @@ -55,6 +55,7 @@ proc setup_nodes {} { expect "Commissioner: active" send "commissioner joiner add $eui64 $psk\n" expect "Done" + wait_for "netdata steeringdata check $eui64" "Done" send "channel\n" expect -re {(\d+)} set channel $expect_out(1,string) diff --git a/tests/scripts/expect/cli-commissioner.exp b/tests/scripts/expect/cli-commissioner.exp index 16a64815d..14513d272 100755 --- a/tests/scripts/expect/cli-commissioner.exp +++ b/tests/scripts/expect/cli-commissioner.exp @@ -32,6 +32,15 @@ source "tests/scripts/expect/_multinode.exp" setup_nodes +set eui64 "d45e64fa83f81cf7" +set spawn_id $spawn_1 +send "commissioner joiner add $eui64 J01NME\n" +expect "Done" +wait_for "netdata steeringdata check $eui64" "Done" +send "commissioner joiner remove $eui64\n" +expect "Done" +wait_for "netdata steeringdata check $eui64" "NotFound" + set spawn_id $spawn_2 send "commissioner state\n" expect "disabled" diff --git a/tests/scripts/expect/cli-discerner.exp b/tests/scripts/expect/cli-discerner.exp index 26b261ffa..46f56c613 100755 --- a/tests/scripts/expect/cli-discerner.exp +++ b/tests/scripts/expect/cli-discerner.exp @@ -34,11 +34,27 @@ setup_leader set pskd "J01NME" set discerner "0xabc/12" +send "netdata typo check $discerner\n" +expect "InvalidCommand" +send "netdata steeringdata typo $discerner\n" +expect "InvalidCommand" +send "netdata steeringdata check $discerner/0\n" +expect "InvalidArgs" +send "netdata steeringdata check $discerner\n" +expect "InvalidState" send "commissioner start\n" expect "Done" expect "Commissioner: active" send "commissioner joiner add 1/0 $pskd\n" expect "InvalidArgs" +send "netdata steeringdata check 0xabc/12\n" +expect "NotFound" +send "commissioner joiner add $discerner $pskd\n" +expect "Done" +wait_for "netdata steeringdata check $discerner" "Done" +send "commissioner joiner remove $discerner\n" +expect "Done" +wait_for "netdata steeringdata check $discerner" "NotFound" send "commissioner joiner add $discerner $pskd\n" expect "Done"