From 560fee9698d425a00ef5e155783b81f4e5b66058 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 25 Jun 2020 18:58:50 -0700 Subject: [PATCH] [toranj] add test covering meshcop with Joiner Discerner (#5154) This commit adds a `toranj` test-case covering the commissioning behavior using a Joiner Discerner: - Verifies setting and clearing discriminator with different values and bit-lengths (on a Joiner). - Verifies commissioning using discerner (and EUI64). - Verifies that commissioner would prefer a Joiner entry with the longest matching discerner length. --- tests/toranj/openthread-core-toranj-config.h | 8 + tests/toranj/start.sh | 1 + .../test-042-meshcop-joiner-discerner.py | 180 ++++++++++++++++++ tests/toranj/wpan.py | 12 ++ 4 files changed, 201 insertions(+) create mode 100644 tests/toranj/test-042-meshcop-joiner-discerner.py diff --git a/tests/toranj/openthread-core-toranj-config.h b/tests/toranj/openthread-core-toranj-config.h index 982302c37..15c6ff36f 100644 --- a/tests/toranj/openthread-core-toranj-config.h +++ b/tests/toranj/openthread-core-toranj-config.h @@ -55,6 +55,14 @@ */ #define OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 1 +/** + * @def OPENTHREAD_CONFIG_COMMISSIONER_MAX_JOINER_ENTRIES + * + * The maximum number of Joiner entries maintained by the Commissioner. + * + */ +#define OPENTHREAD_CONFIG_COMMISSIONER_MAX_JOINER_ENTRIES 4 + /** * @def OPENTHREAD_CONFIG_DIAG_ENABLE * diff --git a/tests/toranj/start.sh b/tests/toranj/start.sh index 4dcd6a123..ba8abdad5 100755 --- a/tests/toranj/start.sh +++ b/tests/toranj/start.sh @@ -142,6 +142,7 @@ run test-038-clear-address-cache-for-sed.py run test-039-address-cache-table-snoop.py run test-040-network-data-stable-full.py run test-041-lowpan-fragmentation.py +run test-042-meshcop-joiner-discerner.py run test-100-mcu-power-state.py run test-600-channel-manager-properties.py run test-601-channel-manager-channel-change.py diff --git a/tests/toranj/test-042-meshcop-joiner-discerner.py b/tests/toranj/test-042-meshcop-joiner-discerner.py new file mode 100644 index 000000000..abd2d85c6 --- /dev/null +++ b/tests/toranj/test-042-meshcop-joiner-discerner.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +# +# 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. + +import wpan +from wpan import verify + +# ----------------------------------------------------------------------------------------------------------------------- +# Test description: Test use of Joiner Discerner for commissioning +# + +test_name = __file__[:-3] if __file__.endswith('.py') else __file__ +print('-' * 120) +print('Starting \'{}\''.format(test_name)) + +# ----------------------------------------------------------------------------------------------------------------------- +# Creating `wpan.Nodes` instances + +speedup = 4 +wpan.Node.set_time_speedup_factor(speedup) + +commr = wpan.Node() +joiner1 = wpan.Node() +joiner2 = wpan.Node() +joiner3 = wpan.Node() + +# ----------------------------------------------------------------------------------------------------------------------- +# Init all nodes + +wpan.Node.init_all_nodes() + +# ----------------------------------------------------------------------------------------------------------------------- +# Build network topology + +commr.form('discerner') + +# ----------------------------------------------------------------------------------------------------------------------- +# Test implementation + +WAIT_TIME = 2 # seconds + +PSK1 = 'UNCHARTEDTHEL0STLEGACY' +PSK2 = 'UNCHARTED4ATH1EFSEND' +PSK3 = 'THELAST0FUS' + +DISCERNER1 = '0x777' +D_LEN1 = 12 + +DISCERNER2 = '0x7777777' +D_LEN2 = 32 + +EUI64_3 = joiner3.get(wpan.WPAN_HW_ADDRESS)[1:-1] # Remove the "[]" + +JOINER_TIMOUT = '500' # in seconds + +# Verify Discerner value after device reset on Joiner + +verify(int(joiner1.get(wpan.WPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH), 0) == 0) +verify(int(joiner1.get(wpan.WPAN_THREAD_JOINER_DISCERNER_VALUE), 0) == 0) + +# Set Joiner Discerner on `joiner1` and `joiner2` + +joiner1.set(wpan.WPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH, str(D_LEN1)) +joiner1.set(wpan.WPAN_THREAD_JOINER_DISCERNER_VALUE, DISCERNER1) +verify( + int(joiner1.get(wpan.WPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH), 0) == D_LEN1) +verify( + int(joiner1.get(wpan.WPAN_THREAD_JOINER_DISCERNER_VALUE), 0) == int( + DISCERNER1, 0)) + +joiner2.set(wpan.WPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH, str(D_LEN2)) +joiner2.set(wpan.WPAN_THREAD_JOINER_DISCERNER_VALUE, DISCERNER2) +verify( + int(joiner2.get(wpan.WPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH), 0) == D_LEN2) +verify( + int(joiner2.get(wpan.WPAN_THREAD_JOINER_DISCERNER_VALUE), 0) == int( + DISCERNER2, 0)) + +# Check clearing of a previously set Joiner Discerner + +joiner3.set(wpan.WPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH, str(D_LEN2)) +joiner3.set(wpan.WPAN_THREAD_JOINER_DISCERNER_VALUE, DISCERNER2) +verify( + int(joiner3.get(wpan.WPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH), 0) == D_LEN2) +verify( + int(joiner3.get(wpan.WPAN_THREAD_JOINER_DISCERNER_VALUE), 0) == int( + DISCERNER2, 0)) + +joiner3.set(wpan.WPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH, '0') +verify(int(joiner3.get(wpan.WPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH), 0) == 0) +verify(int(joiner3.get(wpan.WPAN_THREAD_JOINER_DISCERNER_VALUE), 0) == 0) + +# Adding Joiners on Commissioner + +commr.commissioner_start() + +commr.commissioner_add_joiner_with_discerner(DISCERNER1, D_LEN1, PSK1, + JOINER_TIMOUT) +commr.commissioner_add_joiner_with_discerner(DISCERNER2, D_LEN2, PSK2, + JOINER_TIMOUT) +commr.commissioner_add_joiner(EUI64_3, PSK3, JOINER_TIMOUT) + +verify( + len(wpan.parse_list(commr.get(wpan.WPAN_THREAD_COMMISSIONER_JOINERS))) == 3) + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Start `joiner2` first + +# Starting with `joiner2` verifies the behavior of Commissioner to +# prefer the Joiner entry with the longest matching discriminator. Note +# that `joiner2` uses a longer discriminator compared to `joiner1` with +# similar value. + +joiner2.joiner_join(PSK2) +verify(joiner2.get(wpan.WPAN_STATE) == wpan.STATE_COMMISSIONED) +joiner2.joiner_attach() + + +def joiner2_is_associated(): + verify(joiner2.is_associated()) + + +wpan.verify_within(joiner2_is_associated, WAIT_TIME) + +# Start `joiner1` + +joiner1.joiner_join(PSK1) +verify(joiner1.get(wpan.WPAN_STATE) == wpan.STATE_COMMISSIONED) +joiner1.joiner_attach() + + +def joiner1_is_associated(): + verify(joiner1.is_associated()) + + +wpan.verify_within(joiner1_is_associated, WAIT_TIME) + +# Start `joiner3` + +joiner3.joiner_join(PSK3) +verify(joiner3.get(wpan.WPAN_STATE) == wpan.STATE_COMMISSIONED) +joiner3.joiner_attach() + + +def joiner3_is_associated(): + verify(joiner3.is_associated()) + + +wpan.verify_within(joiner3_is_associated, WAIT_TIME) + +# ----------------------------------------------------------------------------------------------------------------------- +# Test finished + +wpan.Node.finalize_all_nodes() + +print('\'{}\' passed.'.format(test_name)) diff --git a/tests/toranj/wpan.py b/tests/toranj/wpan.py index 8922c4176..244cbb085 100644 --- a/tests/toranj/wpan.py +++ b/tests/toranj/wpan.py @@ -110,6 +110,9 @@ WPAN_THREAD_PENDING_DATASET = "Thread:PendingDataset" WPAN_THREAD_PENDING_DATASET_ASVALMAP = "Thread:PendingDataset:AsValMap" WPAN_THREAD_ADDRESS_CACHE_TABLE = "Thread:AddressCacheTable" WPAN_THREAD_ADDRESS_CACHE_TABLE_ASVALMAP = "Thread:AddressCacheTable:AsValMap" +WPAN_THREAD_JOINER_DISCERNER_VALUE = "Joiner:Discerner:Value" +WPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH = "Joiner:Discerner:BitLength" +WPAN_THREAD_COMMISSIONER_JOINERS = "Commissioner:Joiners" WPAN_OT_LOG_LEVEL = "OpenThread:LogLevel" WPAN_OT_SLAAC_ENABLED = "OpenThread:SLAAC:Enabled" @@ -581,6 +584,15 @@ class Node(object): return self.wpanctl('commissioner joiner-add {} {} {}'.format( eui64, timeout, pskd)) + def commissioner_add_joiner_with_discerner(self, + discerner_value, + discerner_bit_len, + pskd, + timeout='100'): + return self.wpanctl( + 'commissioner joiner-add-discerner {} {} {} {}'.format( + discerner_value, discerner_bit_len, timeout, pskd)) + def joiner_join(self, pskd): return self.wpanctl('joiner --join {}'.format(pskd))