[cli] support joiner discerner (#5298)

This commit adds support joiner discerner in CLI. The format of joiner
discerner is `number/length`. For example `0xabc/12` means the discerner
value is `0xabc` and the length is `12`.
This commit is contained in:
Yakun Xu
2020-07-27 20:27:21 -07:00
committed by GitHub
parent 2117dae5f8
commit cbf1a19483
10 changed files with 239 additions and 30 deletions
+7 -1
View File
@@ -81,11 +81,12 @@ Energy: 00050000 0 0 0 0
### joiner add ### joiner add
Usage: `commissioner joiner add <eui64> <pskd>` Usage: `commissioner joiner add <eui64>|<discerner> <pskd>`
Add a Joiner entry. Add a Joiner entry.
- eui64: The IEEE EUI-64 of the Joiner or '\*' to match any Joiner. - 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. - pskd: Pre-Shared Key for the Joiner.
```bash ```bash
@@ -93,6 +94,11 @@ Add a Joiner entry.
Done Done
``` ```
```bash
> commissioner joiner add 0xabc/12 J01NME
Done
```
### joiner remove ### joiner remove
Usage: `commissioner joiner remove <eui64>` Usage: `commissioner joiner remove <eui64>`
+19
View File
@@ -7,6 +7,7 @@ See [README_COMMISSIONING.md](README_COMMISSIONING.md).
## Command List ## Command List
- [help](#help) - [help](#help)
- [discerner](#discerner)
- [id](#id) - [id](#id)
- [start](#start) - [start](#start)
- [stop](#stop) - [stop](#stop)
@@ -28,6 +29,24 @@ stop
Done Done
``` ```
### discerner
Usage: `joiner discerner [discerner]`
Print or set the Joiner Discerner. Note this value takes the place of the place of EUI-64 during the joiner session of Thread commissioning.
- discerner: `clear` to clear discerner, `number/length` to set discerner
```bash
> joiner discerner 0xabc/12
Done
> joiner discerner
0xabc/12
Done
> joiner discerner clear
Done
```
### id ### id
Usage: `joiner id` Usage: `joiner id`
+24
View File
@@ -399,6 +399,30 @@ otError Interpreter::ParseUnsignedLong(char *aString, unsigned long &aUnsignedLo
return (*endptr == '\0') ? OT_ERROR_NONE : OT_ERROR_INVALID_ARGS; return (*endptr == '\0') ? OT_ERROR_NONE : OT_ERROR_INVALID_ARGS;
} }
otError Interpreter::ParseJoinerDiscerner(char *aString, otJoinerDiscerner &aDiscerner)
{
otError error = OT_ERROR_NONE;
char * separator = strstr(aString, "/");
unsigned long length;
VerifyOrExit(separator != nullptr, error = OT_ERROR_NOT_FOUND);
SuccessOrExit(error = ParseUnsignedLong(separator + 1, length));
VerifyOrExit(length > 0 && length <= 64, error = OT_ERROR_INVALID_ARGS);
{
char * end;
unsigned long long value = strtoull(aString, &end, 0);
aDiscerner.mValue = value;
VerifyOrExit(end == separator, error = OT_ERROR_INVALID_ARGS);
}
aDiscerner.mLength = static_cast<uint8_t>(length);
exit:
return error;
}
otError Interpreter::ParsePingInterval(const char *aString, uint32_t &aInterval) otError Interpreter::ParsePingInterval(const char *aString, uint32_t &aInterval)
{ {
otError error = OT_ERROR_NONE; otError error = OT_ERROR_NONE;
+5 -4
View File
@@ -204,10 +204,11 @@ private:
kDefaultPingCount = 1, kDefaultPingCount = 1,
}; };
otError ParsePingInterval(const char *aString, uint32_t &aInterval); otError ParsePingInterval(const char *aString, uint32_t &aInterval);
void ProcessHelp(uint8_t aArgsLength, char *aArgs[]); static otError ParseJoinerDiscerner(char *aString, otJoinerDiscerner &aJoinerDiscerner);
void ProcessBufferInfo(uint8_t aArgsLength, char *aArgs[]); void ProcessHelp(uint8_t aArgsLength, char *aArgs[]);
void ProcessChannel(uint8_t aArgsLength, char *aArgs[]); void ProcessBufferInfo(uint8_t aArgsLength, char *aArgs[]);
void ProcessChannel(uint8_t aArgsLength, char *aArgs[]);
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
void ProcessBackboneRouter(uint8_t aArgsLength, char *aArgs[]); void ProcessBackboneRouter(uint8_t aArgsLength, char *aArgs[]);
+20 -5
View File
@@ -116,20 +116,27 @@ otError Commissioner::ProcessJoiner(uint8_t aArgsLength, char *aArgs[])
{ {
otError error; otError error;
otExtAddress addr; otExtAddress addr;
const otExtAddress *addrPtr; const otExtAddress *addrPtr = nullptr;
otJoinerDiscerner discerner;
VerifyOrExit(aArgsLength > 2, error = OT_ERROR_INVALID_ARGS); VerifyOrExit(aArgsLength > 2, error = OT_ERROR_INVALID_ARGS);
memset(&discerner, 0, sizeof(discerner));
if (strcmp(aArgs[2], "*") == 0) if (strcmp(aArgs[2], "*") == 0)
{ {
addrPtr = nullptr; // Intentionally empty
} }
else else if ((error = Interpreter::ParseJoinerDiscerner(aArgs[2], discerner)) == OT_ERROR_NOT_FOUND)
{ {
VerifyOrExit(Interpreter::Hex2Bin(aArgs[2], addr.m8, sizeof(addr)) == sizeof(addr), VerifyOrExit(Interpreter::Hex2Bin(aArgs[2], addr.m8, sizeof(addr)) == sizeof(addr),
error = OT_ERROR_INVALID_ARGS); error = OT_ERROR_INVALID_ARGS);
addrPtr = &addr; addrPtr = &addr;
} }
else if (error != OT_ERROR_NONE)
{
ExitNow();
}
if (strcmp(aArgs[1], "add") == 0) if (strcmp(aArgs[1], "add") == 0)
{ {
@@ -142,8 +149,16 @@ otError Commissioner::ProcessJoiner(uint8_t aArgsLength, char *aArgs[])
SuccessOrExit(error = Interpreter::ParseUnsignedLong(aArgs[4], timeout)); SuccessOrExit(error = Interpreter::ParseUnsignedLong(aArgs[4], timeout));
} }
SuccessOrExit( if (discerner.mLength)
error = otCommissionerAddJoiner(mInterpreter.mInstance, addrPtr, aArgs[3], static_cast<uint32_t>(timeout))); {
SuccessOrExit(error = otCommissionerAddJoinerWithDiscerner(mInterpreter.mInstance, &discerner, aArgs[3],
static_cast<uint32_t>(timeout)));
}
else
{
SuccessOrExit(error = otCommissionerAddJoiner(mInterpreter.mInstance, addrPtr, aArgs[3],
static_cast<uint32_t>(timeout)));
}
} }
else if (strcmp(aArgs[1], "remove") == 0) else if (strcmp(aArgs[1], "remove") == 0)
{ {
+41 -4
View File
@@ -33,6 +33,8 @@
#include "cli_joiner.hpp" #include "cli_joiner.hpp"
#include <inttypes.h>
#include "cli/cli.hpp" #include "cli/cli.hpp"
#include "cli/cli_server.hpp" #include "cli/cli_server.hpp"
@@ -42,12 +44,47 @@ namespace ot {
namespace Cli { namespace Cli {
const struct Joiner::Command Joiner::sCommands[] = { const struct Joiner::Command Joiner::sCommands[] = {
{"help", &Joiner::ProcessHelp}, {"discerner", &Joiner::ProcessDiscerner}, {"help", &Joiner::ProcessHelp}, {"id", &Joiner::ProcessId},
{"id", &Joiner::ProcessId}, {"start", &Joiner::ProcessStart}, {"stop", &Joiner::ProcessStop},
{"start", &Joiner::ProcessStart},
{"stop", &Joiner::ProcessStop},
}; };
otError Joiner::ProcessDiscerner(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgsLength == 2)
{
otJoinerDiscerner discerner;
memset(&discerner, 0, sizeof(discerner));
if (strcmp(aArgs[1], "clear") == 0)
{
SuccessOrExit(error = otJoinerSetDiscerner(mInterpreter.mInstance, nullptr));
}
else
{
VerifyOrExit(OT_ERROR_NONE == Interpreter::ParseJoinerDiscerner(aArgs[1], discerner),
error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = otJoinerSetDiscerner(mInterpreter.mInstance, &discerner));
}
}
else if (aArgsLength == 1)
{
const otJoinerDiscerner *discerner = otJoinerGetDiscerner(mInterpreter.mInstance);
VerifyOrExit(discerner != nullptr, error = OT_ERROR_NOT_FOUND);
mInterpreter.mServer->OutputFormat("0x%" PRIx64 "/%u\r\n", discerner->mValue, discerner->mLength);
}
else
{
error = OT_ERROR_INVALID_ARGS;
}
exit:
return error;
}
otError Joiner::ProcessHelp(uint8_t aArgsLength, char *aArgs[]) otError Joiner::ProcessHelp(uint8_t aArgsLength, char *aArgs[])
{ {
OT_UNUSED_VARIABLE(aArgsLength); OT_UNUSED_VARIABLE(aArgsLength);
+1
View File
@@ -79,6 +79,7 @@ private:
otError (Joiner::*mCommand)(uint8_t aArgsLength, char *aArgs[]); otError (Joiner::*mCommand)(uint8_t aArgsLength, char *aArgs[]);
}; };
otError ProcessDiscerner(uint8_t aArgsLength, char *aArgs[]);
otError ProcessHelp(uint8_t aArgsLength, char *aArgs[]); otError ProcessHelp(uint8_t aArgsLength, char *aArgs[]);
otError ProcessId(uint8_t aArgsLength, char *aArgs[]); otError ProcessId(uint8_t aArgsLength, char *aArgs[]);
otError ProcessStart(uint8_t aArgsLength, char *aArgs[]); otError ProcessStart(uint8_t aArgsLength, char *aArgs[]);
+34 -2
View File
@@ -27,7 +27,7 @@
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
# #
proc wait_for {command expected} { proc wait_for {command success {failure {[\r\n]FAILURE_NOT_EXPECTED[\r\n]}}} {
set result 0 set result 0
set timeout 1 set timeout 1
for {set i 0} {$i < 20} {incr i} { for {set i 0} {$i < 20} {incr i} {
@@ -36,9 +36,12 @@ proc wait_for {command expected} {
} }
expect { expect {
-re $expected { -re $success {
set result 1 set result 1
} }
-re $failure {
exit 1
}
timeout { timeout {
# Do nothing # Do nothing
} }
@@ -64,9 +67,38 @@ proc spawn_node {id} {
return $spawn_id return $spawn_id
} }
proc setup_leader {} {
# Sets up a Thread network spawn_1 as the leader.
global spawn_1
global spawn_id
global env
set spawn_1 [spawn_node 1]
set spawn_id $spawn_1
send "dataset init new\n"
expect "Done"
send "dataset commit active\n"
expect "Done"
send "ifconfig up\n"
expect "Done"
send "thread start\n"
expect "Done"
wait_for "state" "leader"
expect "Done"
}
proc dispose {} { proc dispose {} {
send "\x04" send "\x04"
expect eof expect eof
} }
proc dispose_leader {} {
global spawn_1
global spawn_id
set spawn_id $spawn_1
dispose
}
set timeout 10 set timeout 10
+3 -14
View File
@@ -38,7 +38,6 @@ proc setup_nodes {} {
global spawn_id global spawn_id
global env global env
set spawn_1 [spawn_node 1]
set spawn_2 [spawn_node 2] set spawn_2 [spawn_node 2]
set psk "J01NME" set psk "J01NME"
@@ -48,17 +47,9 @@ proc setup_nodes {} {
set eui64 $expect_out(1,string) set eui64 $expect_out(1,string)
expect "Done" expect "Done"
setup_leader
set spawn_id $spawn_1 set spawn_id $spawn_1
send "dataset init new\n"
expect "Done"
send "dataset commit active\n"
expect "Done"
send "ifconfig up\n"
expect "Done"
send "thread start\n"
expect "Done"
wait_for "state" "leader"
expect "Done"
send "commissioner start\n" send "commissioner start\n"
expect "Done" expect "Done"
expect "Commissioner: active" expect "Commissioner: active"
@@ -84,12 +75,10 @@ proc setup_nodes {} {
} }
proc dispose_nodes {} { proc dispose_nodes {} {
global spawn_1
global spawn_2 global spawn_2
global spawn_id global spawn_id
set spawn_id $spawn_1 dispose_leader
dispose
set spawn_id $spawn_2 set spawn_id $spawn_2
dispose dispose
} }
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/expect -f
#
# Copyright (c) 2020, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
source "tests/scripts/expect/_common.exp"
setup_leader
set pskd "J01NME"
set discerner "0xabc/12"
send "commissioner start\n"
expect "Done"
expect "Commissioner: active"
send "commissioner joiner add 1/0 $pskd\n"
expect "InvalidArgs"
send "commissioner joiner add $discerner $pskd\n"
expect "Done"
set spawn_2 [spawn_node 2]
set spawn_id $spawn_2
send "mode rs\n"
expect "Done"
send "ifconfig up\n"
expect "Done"
send "joiner discerner\n"
expect "NotFound"
send "joiner discerner 1/1 2\n"
expect "InvalidArgs"
send "joiner discerner 1\n"
expect "InvalidArgs"
send "joiner discerner 1/\n"
expect "InvalidArgs"
send "joiner discerner 1/128\n"
expect "InvalidArgs"
send "joiner discerner 1/-1\n"
expect "InvalidArgs"
send "joiner discerner 1/0\n"
expect "InvalidArgs"
send "joiner discerner invalid/20\n"
expect "InvalidArgs"
send "joiner discerner clear\n"
expect "Done"
send "joiner discerner $discerner\n"
expect "Done"
send "joiner discerner\n"
expect "$discerner"
expect "Done"
send "joiner start $pskd\n"
expect "Done"
wait_for "" "Join success" "Join failed"
send "thread start\n"
expect "Done"
wait_for "state" "child"
expect "Done"
dispose
dispose_leader