mirror of
https://github.com/espressif/openthread.git
synced 2026-08-04 01:47:47 +00:00
[tests] migrate low power and 1.2 tests to nexus (#12641)
This commit removes several legacy Python-based certification tests for Low Power (CSL) and Thread 1.2 features, as they have been migrated to the Nexus test framework. Specifically, the following tests and their associated CI workflows (including packet verification for low power) are removed: - CSL Transmission and Timeout - Enhanced Frame Pending and Keep-Alive - Single Probe and Forward Tracking Series Link Metrics - SSED Attachment and Parent Selection The removal of these scripts from tests/scripts/thread-cert/ and the corresponding GitHub Action workflows reduces CI overhead while maintaining coverage through the more scalable Nexus tests.
This commit is contained in:
@@ -137,12 +137,6 @@ jobs:
|
||||
packet_verification: 1
|
||||
nat64: 0
|
||||
description: "MATN"
|
||||
- otbr_mdns: "mDNSResponder"
|
||||
otbr_trel: 0
|
||||
cert_scripts: ./tests/scripts/thread-cert/border_router/LowPower/*.py
|
||||
packet_verification: 1
|
||||
nat64: 0
|
||||
description: "LowPower"
|
||||
- otbr_mdns: "mDNSResponder"
|
||||
otbr_trel: 0
|
||||
cert_scripts: ./tests/scripts/thread-cert/border_router/internet/*.py
|
||||
|
||||
@@ -121,85 +121,6 @@ jobs:
|
||||
path: tmp/coverage.info
|
||||
retention-days: 1
|
||||
|
||||
packet-verification-low-power:
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
REFERENCE_DEVICE: 1
|
||||
VIRTUAL_TIME: 1
|
||||
TEST_TIMEOUT: 300
|
||||
OT_VT_USE_UNIX_SOCKET: 1
|
||||
COVERAGE: 1
|
||||
PACKET_VERIFICATION: 1
|
||||
THREAD_VERSION: 1.4
|
||||
MAC_FILTER: 1
|
||||
INTER_OP: 1
|
||||
INTER_OP_BBR: 0
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
with:
|
||||
egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs
|
||||
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: pip
|
||||
- name: Bootstrap
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get --no-install-recommends install -y ninja-build lcov
|
||||
python3 -m pip install -r tests/scripts/thread-cert/requirements.txt
|
||||
- name: Build
|
||||
run: |
|
||||
./script/test build
|
||||
- name: Build with OT_CSL_RECEIVER_LOCAL_TIME_SYNC
|
||||
run: |
|
||||
OT_BUILDDIR="${PWD}/build_csl_receiver_local_time_sync" OT_OPTIONS="-DOT_CSL_RECEIVER_LOCAL_TIME_SYNC=ON" ./script/test build
|
||||
- name: Get Thread-Wireshark
|
||||
run: |
|
||||
./script/test get_thread_wireshark
|
||||
- name: Run
|
||||
run: |
|
||||
ulimit -c unlimited
|
||||
./script/test prepare_coredump_upload
|
||||
for i in {1..10}
|
||||
do
|
||||
./script/test cert_suite ./tests/scripts/thread-cert/v1_2_LowPower*.py
|
||||
done
|
||||
- name: Run with OT_CSL_RECEIVER_LOCAL_TIME_SYNC
|
||||
run: |
|
||||
OT_BUILDDIR="${PWD}/build_csl_receiver_local_time_sync" ./script/test cert_suite ./tests/scripts/thread-cert/v1_2_LowPower*.py
|
||||
- name: Check Crash
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
CRASHED=$(./script/test check_crash | tail -1)
|
||||
[[ $CRASHED -eq "1" ]] && echo "Crashed!" || echo "Not crashed."
|
||||
echo "CRASHED=$CRASHED" >> $GITHUB_ENV
|
||||
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
name: packet-verification-low-power-pcaps
|
||||
path: |
|
||||
*.pcap
|
||||
*.json
|
||||
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
if: ${{ failure() && env.CRASHED == '1' }}
|
||||
with:
|
||||
name: core-packet-verification-low-power
|
||||
path: |
|
||||
./ot-core-dump/*
|
||||
- name: Generate Coverage
|
||||
run: |
|
||||
./script/test generate_coverage gcc
|
||||
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: cov-packet-verification-low-power
|
||||
path: tmp/coverage.info
|
||||
retention-days: 1
|
||||
|
||||
packet-verification-1-1-on-1-4:
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
@@ -352,82 +273,11 @@ jobs:
|
||||
path: tmp/coverage.info
|
||||
retention-days: 1
|
||||
|
||||
thread-1-4-posix:
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
COVERAGE: 1
|
||||
PYTHONUNBUFFERED: 1
|
||||
READLINE: readline
|
||||
THREAD_VERSION: 1.4
|
||||
OT_NODE_TYPE: rcp
|
||||
USE_MTD: 1
|
||||
VIRTUAL_TIME: 1
|
||||
OT_VT_USE_UNIX_SOCKET: 1
|
||||
INTER_OP: 1
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
with:
|
||||
egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs
|
||||
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: pip
|
||||
- name: Bootstrap
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get --no-install-recommends install -y libreadline6-dev ninja-build llvm lcov
|
||||
python3 -m pip install -r tests/scripts/thread-cert/requirements.txt
|
||||
- name: Build
|
||||
run: |
|
||||
./script/test build
|
||||
- name: Run
|
||||
run: |
|
||||
ulimit -c unlimited
|
||||
./script/test prepare_coredump_upload
|
||||
./script/test cert tests/scripts/thread-cert/v1_2_LowPower_5_3_01_SSEDAttachment.py
|
||||
./script/test cert tests/scripts/thread-cert/v1_2_LowPower_6_1_07_PreferringARouterOverAReed.py
|
||||
./script/test cert tests/scripts/thread-cert/v1_2_router_5_1_1.py
|
||||
./script/test cert tests/scripts/thread-cert/v1_2_test_csl_transmission.py
|
||||
./script/test cert tests/scripts/thread-cert/v1_2_test_enhanced_frame_pending.py
|
||||
./script/test cert tests/scripts/thread-cert/v1_2_test_parent_selection.py
|
||||
- name: Check Crash
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
CRASHED=$(./script/test check_crash | tail -1)
|
||||
[[ $CRASHED -eq "1" ]] && echo "Crashed!" || echo "Not crashed."
|
||||
echo "CRASHED=$CRASHED" >> $GITHUB_ENV
|
||||
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
name: thread-1-4-posix-pcaps
|
||||
path: "*.pcap"
|
||||
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
if: ${{ failure() && env.CRASHED == '1' }}
|
||||
with:
|
||||
name: core-thread-1-4-posix
|
||||
path: |
|
||||
./ot-core-dump/*
|
||||
- name: Generate Coverage
|
||||
run: |
|
||||
./script/test generate_coverage gcc
|
||||
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: cov-thread-1-4-posix
|
||||
path: tmp/coverage.info
|
||||
retention-days: 1
|
||||
|
||||
upload-coverage:
|
||||
needs:
|
||||
- thread-1-4
|
||||
- packet-verification-low-power
|
||||
- packet-verification-1-1-on-1-4
|
||||
- expects
|
||||
- thread-1-4-posix
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2022, 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 unittest
|
||||
|
||||
from v1_2_LowPower_5_3_01_SSEDAttachment import LowPower_5_3_01_SSEDAttachment
|
||||
from v1_2_LowPower_5_3_01_SSEDAttachment import LEADER
|
||||
|
||||
LowPower_5_3_01_SSEDAttachment.TOPOLOGY[LEADER]['is_otbr'] = True
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2022, 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 unittest
|
||||
|
||||
from v1_2_LowPower_7_1_01_SingleProbeLinkMetricsWithEnhancedAcks import LowPower_7_1_01
|
||||
from v1_2_LowPower_7_1_01_SingleProbeLinkMetricsWithEnhancedAcks import LEADER
|
||||
|
||||
LowPower_7_1_01.TOPOLOGY[LEADER]['is_otbr'] = True
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2022, 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 unittest
|
||||
|
||||
from v1_2_LowPower_7_2_01_ForwardTrackingSeries import LEADER
|
||||
from v1_2_LowPower_7_2_01_ForwardTrackingSeries import LowPower_7_2_01_ForwardTrackingSeries
|
||||
|
||||
LowPower_7_2_01_ForwardTrackingSeries.TOPOLOGY[LEADER]['is_otbr'] = True
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,145 +0,0 @@
|
||||
#!/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 unittest
|
||||
|
||||
from config import ADDRESS_TYPE
|
||||
from mac802154 import MacHeader
|
||||
from pktverify import consts
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
|
||||
LEADER = 1
|
||||
ROUTER = 2
|
||||
SSED_1 = 3
|
||||
|
||||
|
||||
class LowPower_5_3_01_SSEDAttachment(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2',
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER, SSED_1]
|
||||
},
|
||||
ROUTER: {
|
||||
'version': '1.2',
|
||||
'name': 'ROUTER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER],
|
||||
},
|
||||
SSED_1: {
|
||||
'version': '1.2',
|
||||
'name': 'SSED_1',
|
||||
'is_mtd': True,
|
||||
'mode': '-',
|
||||
'allowlist': [LEADER],
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[ROUTER].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
|
||||
|
||||
self.nodes[SSED_1].set_csl_period(consts.CSL_DEFAULT_PERIOD)
|
||||
self.nodes[SSED_1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[SSED_1].get_state(), 'child')
|
||||
|
||||
self.simulator.go(5)
|
||||
|
||||
self.collect_rloc16s()
|
||||
self.collect_rlocs()
|
||||
|
||||
# Verify connectivity by sending an ICMP Echo Request from the Router to SSED_1 mesh-local address via the DUT
|
||||
self.assertTrue(self.nodes[ROUTER].ping(self.nodes[SSED_1].get_ip6_address(ADDRESS_TYPE.RLOC)))
|
||||
|
||||
# Verify fragmented CSL transmission
|
||||
self.assertTrue(self.nodes[ROUTER].ping(self.nodes[SSED_1].get_ip6_address(ADDRESS_TYPE.RLOC), size=128))
|
||||
|
||||
self.simulator.go(5)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
LEADER = pv.vars['LEADER']
|
||||
ROUTER = pv.vars['ROUTER']
|
||||
SSED_1 = pv.vars['SSED_1']
|
||||
|
||||
# Step 1: ensure the Leader is sending MLE Advertisements
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_ADVERTISEMENT) \
|
||||
.must_next()
|
||||
|
||||
# Step 2: Verify that the frame version is IEEE Std 802.15.4-2015 of the MLE Child Update Response from the
|
||||
# DUT to SSED_1
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_CHILD_UPDATE_RESPONSE) \
|
||||
.filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
|
||||
.must_next()
|
||||
|
||||
# Step 3:
|
||||
# Verify that SSED_1 does not send a MAC Data Request prior to receiving the ICMP Echo Request from the Leader.
|
||||
# Verify that the frame version is IEEE Std 802.15.4-2015 of the ICMP Echo Request sent to SSED_1 from the DUT
|
||||
# Verify that the Router successfully receives an Echo Response from SSED_1
|
||||
ssed_rloc16 = pv.vars['SSED_1_RLOC16']
|
||||
ssed_rloc = pv.vars['SSED_1_RLOC']
|
||||
leader_rloc16 = pv.vars['LEADER_RLOC16']
|
||||
router_rloc16 = pv.vars['ROUTER_RLOC16']
|
||||
router_rloc = pv.vars['ROUTER_RLOC']
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter('wpan.dst16 == {rloc16}', rloc16 = ssed_rloc16) \
|
||||
.filter_ipv6_dst(ssed_rloc) \
|
||||
.filter_ping_request() \
|
||||
.filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
|
||||
.must_next()
|
||||
idx1 = pkts.index
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter('wpan.dst16 == {rloc16}', rloc16 = leader_rloc16) \
|
||||
.filter_ipv6_dst(router_rloc) \
|
||||
.filter_ping_reply() \
|
||||
.filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
|
||||
.must_next() \
|
||||
.must_verify(lambda p: (p.wpan.ie_present == 1) and (consts.CSL_IE_ID in p.wpan.header_ie.id))
|
||||
idx2 = pkts.index
|
||||
pkts.range(idx1, idx2).filter(lambda p: p.wpan.cmd == MacHeader.CommandIdentifier.DATA_REQUEST) \
|
||||
.must_not_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,172 +0,0 @@
|
||||
#!/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 copy
|
||||
import unittest
|
||||
|
||||
from mle import TlvType
|
||||
from pktverify import consts
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
|
||||
LEADER = 1
|
||||
ROUTER_1 = 2
|
||||
REED_1 = 3
|
||||
DUT = 4
|
||||
|
||||
|
||||
class LowPower_6_1_07_PreferringARouterOverAReed_Base(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2',
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER_1, REED_1]
|
||||
},
|
||||
ROUTER_1: {
|
||||
'version': '1.1',
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, DUT],
|
||||
},
|
||||
REED_1: {
|
||||
'version': '1.2',
|
||||
'name': 'REED_1',
|
||||
'mode': 'rdn',
|
||||
'router_upgrade_threshold': 0,
|
||||
'allowlist': [LEADER, DUT],
|
||||
},
|
||||
DUT: {
|
||||
'version': '1.2',
|
||||
'name': 'DUT',
|
||||
'is_mtd': True,
|
||||
'allowlist': [ROUTER_1, REED_1],
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[ROUTER_1].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER_1].get_state(), 'router')
|
||||
|
||||
self.nodes[REED_1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[REED_1].get_state(), 'child')
|
||||
|
||||
self.simulator.go(5) # wait for advertisements
|
||||
|
||||
# Step 2 - set outbound link quality of ROUTER_1 and REED_1 to 2 (medium)
|
||||
self.nodes[ROUTER_1].set_outbound_link_quality(2)
|
||||
self.nodes[REED_1].set_outbound_link_quality(2)
|
||||
|
||||
# Step 3 - DUT Automatically begins attach process by sending a multicast MLE Parent Request
|
||||
self.nodes[DUT].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[DUT].get_state(), 'child')
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
LEADER = pv.vars['LEADER']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
REED_1 = pv.vars['REED_1']
|
||||
DUT = pv.vars['DUT']
|
||||
|
||||
# Step 1 - Ensure all routers and leader are sending MLE advertisements
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_ADVERTISEMENT) \
|
||||
.must_next()
|
||||
pkts.filter_wpan_src64(ROUTER_1) \
|
||||
.filter_mle_cmd(consts.MLE_ADVERTISEMENT) \
|
||||
.must_next()
|
||||
|
||||
# Step 3 - DUT begins attach process by sending a multicast MLE Parent Request
|
||||
pkts.filter_wpan_src64(DUT) \
|
||||
.filter_mle_cmd(consts.MLE_PARENT_REQUEST) \
|
||||
.filter_mle_has_tlv(TlvType.CHALLENGE, TlvType.MODE) \
|
||||
.filter(lambda p: p.mle.tlv.scan_mask.r == 1 and p.mle.tlv.scan_mask.e == 0) \
|
||||
.filter(lambda p: p.mle.tlv.version >= config.THREAD_VERSION_1_2) \
|
||||
.filter(lambda p: p.ipv6.hlim == 255) \
|
||||
.filter_LLARMA() \
|
||||
.must_next()
|
||||
|
||||
# Step 4 - Router_1 automatically Respond with MLE Parent Response
|
||||
pkts.filter_wpan_src64(ROUTER_1) \
|
||||
.filter_wpan_dst64(DUT) \
|
||||
.filter_mle_cmd(consts.MLE_PARENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.version == config.THREAD_VERSION_1_1) \
|
||||
.must_next()
|
||||
|
||||
# Step 5 - DUT sends another multicast MLE Parent Request to the all-routers multicast with the Scan Mask TLV
|
||||
# set for all routers and all REEDs
|
||||
pkts.filter_wpan_src64(DUT) \
|
||||
.filter_mle_cmd(consts.MLE_PARENT_REQUEST) \
|
||||
.filter_mle_has_tlv(TlvType.CHALLENGE, TlvType.MODE) \
|
||||
.filter(lambda p: p.mle.tlv.scan_mask.r == 1 and p.mle.tlv.scan_mask.e == 1) \
|
||||
.filter(lambda p: p.mle.tlv.version >= consts.THREAD_VERSION_1_2) \
|
||||
.filter(lambda p: p.ipv6.hlim == 255) \
|
||||
.filter_LLARMA() \
|
||||
.must_next()
|
||||
|
||||
# Step 6 - REED_1 sends MLE Parent Response to the DUT
|
||||
pkts.filter_wpan_src64(REED_1) \
|
||||
.filter_wpan_dst64(DUT) \
|
||||
.filter_mle_cmd(consts.MLE_PARENT_RESPONSE) \
|
||||
.must_next()
|
||||
|
||||
# # Step 7 - DUT sends a Child ID Request to REED_1 due to its better link quality
|
||||
pkts.filter_wpan_src64(DUT) \
|
||||
.filter_mle_cmd(consts.MLE_CHILD_ID_REQUEST) \
|
||||
.filter_wpan_dst64(ROUTER_1) \
|
||||
.filter_mle_has_tlv(TlvType.ADDRESS_REGISTRATION, TlvType.LINK_LAYER_FRAME_COUNTER, TlvType.MODE, TlvType.RESPONSE, TlvType.TIMEOUT, TlvType.TLV_REQUEST) \
|
||||
.filter(lambda p: p.mle.tlv.version >= consts.THREAD_VERSION_1_2) \
|
||||
.must_next()
|
||||
|
||||
|
||||
class LowPower_6_1_07_PreferringARouterOverAReed_MED(LowPower_6_1_07_PreferringARouterOverAReed_Base):
|
||||
TOPOLOGY = copy.deepcopy(LowPower_6_1_07_PreferringARouterOverAReed_Base.TOPOLOGY)
|
||||
TOPOLOGY[DUT]['mode'] = 'rn'
|
||||
|
||||
|
||||
class LowPower_6_1_07_PreferringARouterOverAReed_SED(LowPower_6_1_07_PreferringARouterOverAReed_Base):
|
||||
TOPOLOGY = copy.deepcopy(LowPower_6_1_07_PreferringARouterOverAReed_Base.TOPOLOGY)
|
||||
TOPOLOGY[DUT]['mode'] = '-'
|
||||
|
||||
|
||||
del (LowPower_6_1_07_PreferringARouterOverAReed_Base)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
-393
@@ -1,393 +0,0 @@
|
||||
#!/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 unittest
|
||||
|
||||
from config import ADDRESS_TYPE
|
||||
from pktverify import consts
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
|
||||
LEADER = 1
|
||||
SED_1 = 2
|
||||
SSED_1 = 3
|
||||
|
||||
POLL_PERIOD = 3000 # 3s
|
||||
|
||||
|
||||
class LowPower_7_1_01(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2',
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [SED_1, SSED_1],
|
||||
},
|
||||
SED_1: {
|
||||
'version': '1.2',
|
||||
'name': 'SED_1',
|
||||
'mode': '-',
|
||||
'allowlist': [LEADER],
|
||||
},
|
||||
SSED_1: {
|
||||
'version': '1.2',
|
||||
'name': 'SSED_1',
|
||||
'mode': '-',
|
||||
'allowlist': [LEADER],
|
||||
}
|
||||
}
|
||||
"""All nodes are created with default configurations"""
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[SED_1].set_pollperiod(POLL_PERIOD)
|
||||
self.nodes[SED_1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[SED_1].get_state(), 'child')
|
||||
|
||||
self.nodes[SSED_1].set_csl_period(consts.CSL_DEFAULT_PERIOD)
|
||||
self.nodes[SSED_1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[SSED_1].get_state(), 'child')
|
||||
|
||||
leader_addr = self.nodes[LEADER].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL)
|
||||
|
||||
# Step 3 - Verify connectivity by instructing each device to send an ICMPv6 Echo Request to the DUT
|
||||
self.assertTrue(self.nodes[SED_1].ping(leader_addr, timeout=POLL_PERIOD * 2 / 1000))
|
||||
self.assertTrue(self.nodes[SSED_1].ping(leader_addr))
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 4 - SED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
|
||||
# Request to the DUT
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(001)(010) = 0x0a
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
self.nodes[SED_1].link_metrics_config_req_enhanced_ack_based_probing(leader_addr, True, 'm', mode='async')
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 6 - SSED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
|
||||
# Request to the DUT
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(001)(010) = 0x0a
|
||||
# --- Item2: (0)(0)(001)(011) = 0x0b
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
# ---- Metrics Enum = 3 (RSSI)
|
||||
self.nodes[SSED_1].link_metrics_config_req_enhanced_ack_based_probing(leader_addr, True, 'mr', mode='async')
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 8 - SSED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
|
||||
# message to 0b10
|
||||
self.nodes[SSED_1].send_mac_emptydata()
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 10 - SED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
|
||||
# message # to 0b10
|
||||
self.nodes[SED_1].send_mac_emptydata()
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 12 - SSED_1 clears its Enhanced ACK link metrics configuration by # sending a Link Metrics Management
|
||||
# Request to the DUT
|
||||
# Enh-ACK Flags = 0 (clear enhanced ACK link metric config)
|
||||
self.nodes[SSED_1].link_metrics_config_req_enhanced_ack_based_probing(leader_addr, False, '', mode='async')
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 14 - SSED_1 Sends a MLE Data Message with setting Frame Version subfield within the MAC header of the
|
||||
# message to 0b10
|
||||
self.nodes[SSED_1].send_mac_emptydata()
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 16 - This step verifies that Enhanced ACKs cannot be enabled while requesting 3 metric types by
|
||||
# instructing the device to send the following Link Metrics Management Request to the DUT
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(001)(001) = 0x09
|
||||
# --- Item2: (0)(0)(001)(010) = 0x0a
|
||||
# --- Item3: (0)(0)(001)(011) = 0x0b
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metrics Enum = 1 (Layer 2 LQI)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
# ---- Metrics Enum = 3 (RSSI)
|
||||
self.nodes[SSED_1].link_metrics_config_req_enhanced_ack_based_probing(leader_addr, True, 'qmr', mode='async')
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 18 - This step verifies that Enhanced ACKs cannot be enabled while requesting a reserved Type/Average
|
||||
# enum of value 2 by instructing the device to send the following Link Metrics Management Request to the DUT
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(010)(010) = 0x12
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 2 (Reserved)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
self.nodes[SSED_1].link_metrics_config_req_enhanced_ack_based_probing(leader_addr,
|
||||
True,
|
||||
'm',
|
||||
'r',
|
||||
mode='async')
|
||||
self.simulator.go(5)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
LEADER = pv.vars['LEADER']
|
||||
SED_1 = pv.vars['SED_1']
|
||||
SSED_1 = pv.vars['SSED_1']
|
||||
|
||||
# Step 3 - The DUT MUST send ICMPv6 Echo Responses to both SED1 & SSED1
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SED_1) \
|
||||
.filter_ping_reply() \
|
||||
.must_next()
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_ping_reply() \
|
||||
.must_next()
|
||||
|
||||
# Step 4 - SED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
|
||||
# Request to the DUT
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(001)(010) = 0x0a
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
pkts.filter_wpan_src64(SED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
|
||||
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '0a') \
|
||||
.must_next()
|
||||
|
||||
# Step 5 - The DUT MUST send a Link Metrics Management Response to SED_1 containing the following TLVs:
|
||||
# - MLE LInk Metrics Management TLV
|
||||
# -- Link Metrics Status Sub-TLV = 0 (Success)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SED_1) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# Step 6 - SSED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
|
||||
# Request to the DUT
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(001)(010) = 0x0a
|
||||
# --- Item2: (0)(0)(001)(011) = 0x0b
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
# ---- Metrics Enum = 3 (RSSI)
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
|
||||
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '0a0b') \
|
||||
.must_next()
|
||||
|
||||
# Step 7 - The DUT MUST send a Link Metrics Management Response to SSED_1
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# Step 8 - SSED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
|
||||
# message to 0b10
|
||||
pkt = pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_data() \
|
||||
.filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
|
||||
.must_next()
|
||||
ack_seq_no = pkt.wpan.seq_no
|
||||
|
||||
# Step 9 - The DUT MUST reply to SSED_1 with an Enhanced ACK containing the following:
|
||||
# - Frame Control Field
|
||||
# -- Security Enabled = True
|
||||
# - Header IE
|
||||
# -- Element ID = 0x00
|
||||
# --- Vendor CID = 0xEAB89B (Thread Group)
|
||||
# --- Vendor Specific Information
|
||||
# ---- 1st byte = 0 (Enhanced ACK Link Metrics)
|
||||
# ---- 2nd byte ... Link Margin data
|
||||
# ---- 3rd byte ... RSSI data
|
||||
pkts.filter_wpan_ack() \
|
||||
.filter_wpan_seq(ack_seq_no) \
|
||||
.filter(lambda p: p.wpan.payload_ie.vendor.oui == consts.THREAD_IEEE_802154_COMPANY_ID) \
|
||||
.must_next()
|
||||
|
||||
# Step 10 - SED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
|
||||
# message to 0b10
|
||||
pkt = pkts.filter_wpan_src64(SED_1) \
|
||||
.filter_wpan_data() \
|
||||
.filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
|
||||
.must_next()
|
||||
ack_seq_no = pkt.wpan.seq_no
|
||||
|
||||
# Step 11 - The DUT MUST reply to SED_1 with an Enhanced ACK containing the following:
|
||||
# - Frame Control Field
|
||||
# -- Security Enabled = True
|
||||
# - Header IE
|
||||
# -- Element ID = 0x00
|
||||
# --- Vendor CID = 0xEAB89B (Thread Group)
|
||||
# --- Vendor Specific Information
|
||||
# ---- 1st byte = 0 (Enhanced ACK Link Metrics)
|
||||
# ---- 2nd byte ... Link Margin data
|
||||
pkts.filter_wpan_ack() \
|
||||
.filter_wpan_seq(ack_seq_no) \
|
||||
.filter(lambda p: p.wpan.payload_ie.vendor.oui == consts.THREAD_IEEE_802154_COMPANY_ID) \
|
||||
.must_next()
|
||||
|
||||
# Step 12 - SSED_1 clears enhanced ACK link metrics configuration by instructing it to send a Link Metrics
|
||||
# Management Request to the DUT
|
||||
# - MLE Link Metrics Management TLV Payload
|
||||
# -- Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 0 (clear enhanced ACK link metric config)
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_CLEAR) \
|
||||
.must_next()
|
||||
|
||||
# Step 13 - The DUT MUST send Link Metrics Management Response to SSED_1 containing the following:
|
||||
# - MLE Link Metrics Management TLV
|
||||
# -- Link Metrics Status Sub-TLV = 0 (Success)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# Step 14 - SSED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
|
||||
# message to 0b10
|
||||
pkt = pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_data() \
|
||||
.filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
|
||||
.must_next()
|
||||
ack_seq_no = pkt.wpan.seq_no
|
||||
|
||||
# Step 15 - The DUT MUST NOT include a Link Metrics Report in the ACK
|
||||
pkts.filter_wpan_ack() \
|
||||
.filter_wpan_seq(ack_seq_no) \
|
||||
.filter_wpan_ie_not_present() \
|
||||
.must_next()
|
||||
|
||||
# Step 16 - This step verifies that Enhanced ACKS cannot be enabled while requesting 3 metric types by
|
||||
# instructing the device to send the following Link Metrics Management Request to the DUT:
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(001)(001) = 0x09
|
||||
# --- Item2: (0)(0)(001)(010) = 0x0a
|
||||
# --- Item3: (0)(0)(001)(011) = 0x0b
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metrics Enum = 1 (Layer 2 LQI)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
# ---- Metrics Enum = 3 (RSSI)
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
|
||||
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '090a0b') \
|
||||
.must_next()
|
||||
|
||||
# Step 17 - Leader automatically responds to the invalid query from SSED_1 with a failure
|
||||
# The DUT MUST send Link Metrics Management Response to SSED_1containing the following:
|
||||
# - MLE Link Metrics Management TLV
|
||||
# -- Link Metrics Status Sub-TLV = 254 (Failure)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_OTHER_ERROR) \
|
||||
.must_next()
|
||||
|
||||
# Step 18 - This step verifies that Enhanced ACKs cannot be enabled while requesting a reserved Type/Average
|
||||
# enum of value 2 by instructing the device to send the following Link Metrics Management Request to the DUT
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(010)(010) = 0x12
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 2 (Reserved)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
|
||||
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '12') \
|
||||
.must_next()
|
||||
|
||||
# Step 19 - Leader automatically responds to the invalid query from SSED_1 with a failure
|
||||
# The DUT MUST send Link Metrics Management Response to SSED_1containing the following:
|
||||
# - MLE Link Metrics Management TLV
|
||||
# -- Link Metrics Status Sub-TLV = 254 (Failure)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_OTHER_ERROR) \
|
||||
.must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
-388
@@ -1,388 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2023, 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 unittest
|
||||
|
||||
from config import ADDRESS_TYPE
|
||||
from mle import LinkMetricsSubTlvType
|
||||
from pktverify import consts
|
||||
from pktverify.null_field import nullField
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
|
||||
LEADER = 1
|
||||
SED_1 = 2
|
||||
SSED_1 = 3
|
||||
|
||||
SERIES_ID = 1
|
||||
SERIES_ID_2 = 2
|
||||
POLL_PERIOD = 2000 # 2s
|
||||
|
||||
|
||||
class LowPower_7_1_02_SingleProbeLinkMetricsWithoutEnhancedAck(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2',
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [SED_1, SSED_1],
|
||||
},
|
||||
SED_1: {
|
||||
'version': '1.2',
|
||||
'name': 'SED_1',
|
||||
'mode': '-',
|
||||
'allowlist': [LEADER],
|
||||
},
|
||||
SSED_1: {
|
||||
'version': '1.2',
|
||||
'name': 'SSED_1',
|
||||
'mode': '-',
|
||||
'allowlist': [LEADER],
|
||||
}
|
||||
}
|
||||
"""All nodes are created with default configurations"""
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[SED_1].set_pollperiod(POLL_PERIOD)
|
||||
self.nodes[SED_1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[SED_1].get_state(), 'child')
|
||||
|
||||
self.nodes[SSED_1].set_csl_period(consts.CSL_DEFAULT_PERIOD)
|
||||
self.nodes[SSED_1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[SSED_1].get_state(), 'child')
|
||||
|
||||
leader_addr = self.nodes[LEADER].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL)
|
||||
sed_extaddr = self.nodes[SED_1].get_addr64()
|
||||
|
||||
# Step 3 - Verify connectivity by instructing each device to send an ICMPv6 Echo Request to the DUT
|
||||
self.assertTrue(self.nodes[SED_1].ping(leader_addr, timeout=POLL_PERIOD / 1000))
|
||||
self.assertTrue(self.nodes[SSED_1].ping(leader_addr, timeout=(2 * consts.CSL_DEFAULT_PERIOD_IN_SECOND)))
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 4 - SED_1 sends a Single Probe Link Metric for RSSI using MLE Data Request
|
||||
# MLE Data Request Payload:
|
||||
# - TLV Request TLV (Link Metrics Report TLV specified)
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID = 0 (Single Probe Query)
|
||||
# -- Link Metrics Query Options Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 3 (RSSI)
|
||||
#
|
||||
# In this step, SED_1 should set its TxPower to 'High'. In simulation, this will be implemented by
|
||||
# setting Macfilter on the Rx side (Leader).
|
||||
self.nodes[LEADER].add_allowlist(sed_extaddr, -30)
|
||||
res = self.nodes[SED_1].link_metrics_request_single_probe(leader_addr, 'r')
|
||||
rss_1 = int(res['RSSI'])
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 6 - SED_1 sends a Single Probe Link Metric for RSSI using MLE Data Request
|
||||
# MLE Data Request Payload:
|
||||
# - TLV Request TLV (Link Metrics Report TLV specified)
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID = 0 (Single Probe Query)
|
||||
# -- Link Metrics Query Options Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 3 (RSSI)
|
||||
#
|
||||
# In this step, SED_1 should set its TxPower to 'Low'.
|
||||
self.nodes[LEADER].add_allowlist(sed_extaddr, -95)
|
||||
res = self.nodes[SED_1].link_metrics_request_single_probe(leader_addr, 'r')
|
||||
rss_2 = int(res['RSSI'])
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 8 - Compare the rssi value in step 5 & 7, RSSI in 5 should be larger than RSSI in 7
|
||||
self.assertTrue(rss_1 > rss_2)
|
||||
|
||||
# Step 9 - SSED_1 sends a Single Probe Link Metric for Layer 2 LQI using MLE Data Request
|
||||
# MLE Data Request Payload:
|
||||
# - TLV Request TLV (Link Metrics Report TLV specified)
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID = 0 (Single Probe Query)
|
||||
# -- Link Metrics Query Options Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 1 (Layer 2 LQI)
|
||||
self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'q')
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 11 - SSED_1 sends a Single Probe Link Metric for Link Margin using MLE Data Request
|
||||
# MLE Data Request Payload:
|
||||
# - TLV Request TLV (Link Metrics Report TLV specified)
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID = 0 (Single Probe Query)
|
||||
# -- Link Metrics Query Options Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 2 (Link Margin)
|
||||
self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'm')
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 13 - SSED_1 sends a Single Probe Link Metric using MLE Data Request
|
||||
# MLE Data Request Payload:
|
||||
# - TLV Request TLV (Link Metrics Report TLV specified)
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID = 0 (Single Probe Query)
|
||||
# -- Link Metrics Query Options Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 1 (Layer 2 LQI)
|
||||
# ---- Metric Enum = 2 (Link Margin)
|
||||
# ---- Metric Enum = 3 (RSSI)
|
||||
self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'qmr')
|
||||
self.simulator.go(5)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
LEADER = pv.vars['LEADER']
|
||||
SED_1 = pv.vars['SED_1']
|
||||
SSED_1 = pv.vars['SSED_1']
|
||||
|
||||
# Step 3 - The DUT MUST send ICMPv6 Echo Responses to both SED1 & SSED1
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SED_1) \
|
||||
.filter_ping_reply() \
|
||||
.must_next()
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_ping_reply() \
|
||||
.must_next()
|
||||
|
||||
# Step 4 - SED_1 sends a Single Probe Link Metric for RSSI using MLE Data Request
|
||||
# MLE Data Request Payload:
|
||||
# - TLV Request TLV (Link Metrics Report TLV specified)
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID = 0 (Single Probe Query)
|
||||
# -- Link Metrics Query Options Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 3 (RSSI)
|
||||
# TODO: Currently the ot-pktverify version of wireshark cannot parse Link Metrics Query Options Sub-TLV correctly. Will add check for the fields after fixing this.
|
||||
pkts.filter_wpan_src64(SED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_REQUEST) \
|
||||
.filter_mle_has_tlv(consts.TLV_REQUEST_TLV) \
|
||||
.filter_mle_has_tlv(consts.LINK_METRICS_QUERY_TLV) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_ID in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.query_id == 0) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_OPTIONS in p.mle.tlv.link_sub_tlv) \
|
||||
.must_next()
|
||||
|
||||
# Step 5 The DUT MUST reply to SED_1 with MLE Data Response with the following:
|
||||
# - Link Metrics Report TLV
|
||||
# -- Link Metrics Report Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 3 (RSSI)
|
||||
# --- RSSI Value (1-byte)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SED_1) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter_mle_has_tlv(consts.LINK_METRICS_REPORT_TLV) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_RSSI in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.must_next()
|
||||
|
||||
# Step 6 - SED_1 sends a Single Probe Link Metric for RSSI using MLE Data Request
|
||||
# MLE Data Request Payload:
|
||||
# - TLV Request TLV (Link Metrics Report TLV specified)
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID = 0 (Single Probe Query)
|
||||
# -- Link Metrics Query Options Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 3 (RSSI)
|
||||
pkts.filter_wpan_src64(SED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_REQUEST) \
|
||||
.filter_mle_has_tlv(consts.TLV_REQUEST_TLV) \
|
||||
.filter_mle_has_tlv(consts.LINK_METRICS_QUERY_TLV) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_ID in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.query_id == 0) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_OPTIONS in p.mle.tlv.link_sub_tlv) \
|
||||
.must_next()
|
||||
|
||||
# Step 7 The DUT MUST reply to SED_1 with MLE Data Response with the following:
|
||||
# - Link Metrics Report TLV
|
||||
# -- Link Metrics Report Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 3 (RSSI)
|
||||
# --- RSSI Value (1-byte)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SED_1) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter_mle_has_tlv(consts.LINK_METRICS_REPORT_TLV) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_RSSI in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.must_next()
|
||||
|
||||
# Step 9 - SSED_1 sends a Single Probe Link Metric for Layer 2 LQI using MLE Data Request
|
||||
# MLE Data Request Payload:
|
||||
# - TLV Request TLV (Link Metrics Report TLV specified)
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID = 0 (Single Probe Query)
|
||||
# -- Link Metrics Query Options Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 1 (Layer 2 LQI)
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_REQUEST) \
|
||||
.filter_mle_has_tlv(consts.TLV_REQUEST_TLV) \
|
||||
.filter_mle_has_tlv(consts.LINK_METRICS_QUERY_TLV) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_ID in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.query_id == 0) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_OPTIONS in p.mle.tlv.link_sub_tlv) \
|
||||
.must_next()
|
||||
|
||||
# Step 10 The DUT MUST reply to SSED_1 with MLE Data Response with the following:
|
||||
# - Link Metrics Report TLV
|
||||
# -- Link Metrics Report Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 1 (Layer 2 LQI)
|
||||
# --- Layer 2 LQI value (1-byte)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter_mle_has_tlv(consts.LINK_METRICS_REPORT_TLV) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_LQI in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.must_next()
|
||||
|
||||
# Step 11 - SSED_1 sends a Single Probe Link Metric for Link Margin using MLE Data Request
|
||||
# MLE Data Request Payload:
|
||||
# - TLV Request TLV (Link Metrics Report TLV specified)
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID = 0 (Single Probe Query)
|
||||
# -- Link Metrics Query Options Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 2 (Link Margin)
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_REQUEST) \
|
||||
.filter_mle_has_tlv(consts.TLV_REQUEST_TLV) \
|
||||
.filter_mle_has_tlv(consts.LINK_METRICS_QUERY_TLV) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_ID in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.query_id == 0) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_OPTIONS in p.mle.tlv.link_sub_tlv) \
|
||||
.must_next()
|
||||
|
||||
# Step 12 The DUT MUST reply to SSED_1 with MLE Data Response with the following:
|
||||
# - Link Metrics Report TLV
|
||||
# -- Link Metrics Report Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 2 (Link Margin)
|
||||
# --- Link Margin value (1-byte)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter_mle_has_tlv(consts.LINK_METRICS_REPORT_TLV) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_LINK_MARGIN in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.must_next()
|
||||
|
||||
# Step 13 - SSED_1 sends a Single Probe Link Metric using MLE Data Request
|
||||
# MLE Data Request Payload:
|
||||
# - TLV Request TLV (Link Metrics Report TLV specified)
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID = 0 (Single Probe Query)
|
||||
# -- Link Metrics Query Options Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 1 (Layer 2 LQI)
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 2 (Link Margin)
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 3 (RSSI)
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_REQUEST) \
|
||||
.filter_mle_has_tlv(consts.TLV_REQUEST_TLV) \
|
||||
.filter_mle_has_tlv(consts.LINK_METRICS_QUERY_TLV) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_ID in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.query_id == 0) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_OPTIONS in p.mle.tlv.link_sub_tlv) \
|
||||
.must_next()
|
||||
|
||||
# Step 14 The DUT MUST reply to SSED_1 with MLE Data Response with the following:
|
||||
# - Link Metrics Report TLV
|
||||
# -- Link Metrics Report Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 1 (Layer 2 LQI)
|
||||
# ---- Layer 2 LQI value (1-byte)
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 2 (Link Margin)
|
||||
# ---- Link Margin value (1-byte)
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metric Enum = 3 (RSSI)
|
||||
# ---- RSSI value (1-byte)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter_mle_has_tlv(consts.LINK_METRICS_REPORT_TLV) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_LQI in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_LINK_MARGIN in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_RSSI in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,339 +0,0 @@
|
||||
#!/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 unittest
|
||||
|
||||
from config import ADDRESS_TYPE
|
||||
from mle import LinkMetricsSubTlvType, TlvType
|
||||
from pktverify import consts
|
||||
from pktverify.null_field import nullField
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
|
||||
LEADER = 1
|
||||
SED_1 = 2
|
||||
SSED_1 = 3
|
||||
|
||||
SERIES_ID = 1
|
||||
SERIES_ID_2 = 2
|
||||
POLL_PERIOD = 2000 # 2s
|
||||
|
||||
|
||||
class LowPower_7_2_01_ForwardTrackingSeries(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2',
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [SED_1, SSED_1],
|
||||
},
|
||||
SED_1: {
|
||||
'version': '1.2',
|
||||
'name': 'SED_1',
|
||||
'mode': '-',
|
||||
'allowlist': [LEADER],
|
||||
},
|
||||
SSED_1: {
|
||||
'version': '1.2',
|
||||
'name': 'SSED_1',
|
||||
'mode': '-',
|
||||
'allowlist': [LEADER],
|
||||
}
|
||||
}
|
||||
"""All nodes are created with default configurations"""
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[SED_1].set_pollperiod(POLL_PERIOD)
|
||||
self.nodes[SED_1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[SED_1].get_state(), 'child')
|
||||
|
||||
self.nodes[SSED_1].set_csl_period(consts.CSL_DEFAULT_PERIOD)
|
||||
self.nodes[SSED_1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[SSED_1].get_state(), 'child')
|
||||
|
||||
leader_addr = self.nodes[LEADER].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL)
|
||||
|
||||
# Step 3 - Verify connectivity by instructing each device to send an ICMPv6 Echo Request to the DUT
|
||||
self.assertTrue(self.nodes[SED_1].ping(leader_addr, timeout=POLL_PERIOD / 1000))
|
||||
self.assertTrue(self.nodes[SSED_1].ping(leader_addr))
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 4 - SED_1 requests a Forward Tracking Series by sending a Link Metrics Management Request
|
||||
# Forward Series Flags = 0x04:
|
||||
# - Bit 2 = 1, MAC Data Request
|
||||
# - Bits 0,1 & 3-7 = 0
|
||||
# Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# - Item1: (0)(1)(000)(000) = 0x40
|
||||
# -- E = 0
|
||||
# -- L = 1
|
||||
# -- Type/Average Enum = 0 (count)
|
||||
# -- Metrics Enum = 0 (count)
|
||||
self.nodes[SED_1].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID, 'r', 'p', 'async')
|
||||
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 6 - Configures SED_1 to send MAC Data Request every 2 seconds and wait for 30 seconds
|
||||
self.simulator.go(30)
|
||||
|
||||
# Step 7 - SED_1 sends an MLE Data Request to retrieve aggregated Forward Series Results
|
||||
result = self.nodes[SED_1].link_metrics_request_forward_tracking_series(leader_addr, SERIES_ID)
|
||||
self.assertIn("PDU Counter", result)
|
||||
|
||||
#self.simulator.go(5)
|
||||
|
||||
# Step 9 - SED_1 clears the Forward Tracking Series
|
||||
# Forward Series Flags = 0x00:
|
||||
# - Bits 0-7 = 0
|
||||
# Concatenation of Link Metric Type ID Flags = NULL:
|
||||
self.nodes[SED_1].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID, 'X', '', 'async')
|
||||
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 16 - SSED_1 requests a Forward Tracking Series by sending a Link Metrics Management Request
|
||||
# Forward Series Flags = 0x02:
|
||||
# - Bit 1 = 1, (all Link Layer Data Frames)
|
||||
# - Bits 0, 2-7 = 0
|
||||
# Concatenation of Link Metric Type ID Flags = 0x0a:
|
||||
# - Item1: (0)(0)(001)(010) = 0x0a
|
||||
# -- E = 0
|
||||
# -- L = 0
|
||||
# -- Type/Average Enum = 1 (Exponential Moving Average)
|
||||
# -- Metrics Enum = 2 (Link Margin)
|
||||
self.nodes[SSED_1].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_2, 'd', 'm', 'async')
|
||||
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 18 - SSED_1 sends MAC Data packet every 1 second for 30 seconds
|
||||
# Note: As the api to send MAC Data frame hasn't been implemented, we send MLE Link Probe message here
|
||||
for i in range(30):
|
||||
self.nodes[SSED_1].link_metrics_send_link_probe(leader_addr, SERIES_ID_2, 1)
|
||||
self.simulator.go(1)
|
||||
|
||||
# Step 19 - SSED_1 sends an MLE Data Request to retrieve aggregated Forward Series Results
|
||||
result = self.nodes[SSED_1].link_metrics_request_forward_tracking_series(leader_addr, SERIES_ID_2)
|
||||
self.assertIn("Margin", result)
|
||||
|
||||
# Step 21 - SSED_1 clears the Forward Series Link Metrics
|
||||
# Forward Series Flags = 0x00:
|
||||
# - Bits 0-7 = 0
|
||||
# Concatenation of Link Metric Type ID Flags = NULL
|
||||
self.nodes[SSED_1].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_2, 'X', '', 'async')
|
||||
|
||||
self.simulator.go(5)
|
||||
|
||||
# Step 23 - SSED_1 sends an MLE Data Request to retrieve aggregated Forward Series Results
|
||||
result = self.nodes[SSED_1].link_metrics_request_forward_tracking_series(leader_addr, SERIES_ID_2)
|
||||
self.assertIn('Status', result)
|
||||
self.assertEqual(result['Status'], 'Series ID not recognized')
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
LEADER = pv.vars['LEADER']
|
||||
SED_1 = pv.vars['SED_1']
|
||||
SSED_1 = pv.vars['SSED_1']
|
||||
|
||||
# Step 3 - The DUT MUST send ICMPv6 Echo Responses to both SED1 & SSED1
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SED_1) \
|
||||
.filter_ping_reply() \
|
||||
.must_next()
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_ping_reply() \
|
||||
.must_next()
|
||||
|
||||
# Step 4 - SED_1 requests a Forward Series Link Metrics by sending a Link Metrics Management Request
|
||||
# Forward Series Flags = 0x04:
|
||||
# - Bit 2 = 1, MAC Data Request
|
||||
# - Bits 0,1 & 3-7 = 0
|
||||
# Concatenation of Link Metric Type ID Flags = 0x40:
|
||||
# - Item1: (0)(1)(000)(000) = 0x40
|
||||
# -- E = 0
|
||||
# -- L = 1
|
||||
# -- Type/Average Enum = 0 (count)
|
||||
# -- Metrics Enum = 0 (count)
|
||||
pkts.filter_wpan_src64(SED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.FORWARD_PROBING_REGISTRATION in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: 4 in p.mle.tlv.link_forward_series) \
|
||||
.filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_COUNT in p.mle.tlv.metric_type_id_flags.type) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_PDU_COUNT in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.filter(lambda p: 1 in p.mle.tlv.metric_type_id_flags.l) \
|
||||
.must_next()
|
||||
|
||||
# Step 5 - Leader responds with a Link Metrics Management Response
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SED_1) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# Step 8 - Leader responds with an MLE Data Response
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SED_1) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter(lambda p: TlvType.LINK_METRICS_REPORT in p.mle.tlv.type) \
|
||||
.filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_COUNT in p.mle.tlv.metric_type_id_flags.type) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_PDU_COUNT in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.must_next()
|
||||
|
||||
# Step 9 - SED_1 clears the Forward Series Link Metrics
|
||||
# Forward Series Flags = 0x00:
|
||||
# - Bits 0-7 = 0
|
||||
# Concatenation of Link Metric Type ID Flags = NULL:
|
||||
pkts.filter_wpan_src64(SED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.FORWARD_PROBING_REGISTRATION in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: 0 in p.mle.tlv.link_forward_series) \
|
||||
.filter(lambda p: p.mle.tlv.metric_type_id_flags.type is nullField) \
|
||||
.filter(lambda p: p.mle.tlv.metric_type_id_flags.metric is nullField) \
|
||||
.must_next()
|
||||
|
||||
# Step 10 - Leader responds with a Link Metrics Management Response
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SED_1) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# Step 16 - SSED_1 requests a Forward Series Link Metrics by sending a Link Metrics Management Request
|
||||
# Forward Series Flags = 0x02:
|
||||
# - Bit 1 = 1, (all Link Layer Data Frames)
|
||||
# - Bits 0, 2-7 = 0
|
||||
# Concatenation of Link Metric Type ID Flags = 0x0a:
|
||||
# - Item1: (0)(0)(001)(010) = 0x0a
|
||||
# -- E = 0
|
||||
# -- L = 0
|
||||
# -- Type/Average Enum = 1 (Exponential Moving Average)
|
||||
# -- Metrics Enum = 2 (Link Margin)
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.FORWARD_PROBING_REGISTRATION in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: 2 in p.mle.tlv.link_forward_series) \
|
||||
.filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_LINK_MARGIN in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.must_next()
|
||||
|
||||
# Step 17 - Leader responds with a Link Metrics Management Response
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# Step 19 - SSED_1 sends an MLE Data Request to retrieve aggregated Forward Series results
|
||||
# - TLV Request TLV(Link Metrics Report TLV specified
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID: (ID set in step 16)
|
||||
# - Verify that the Link Metrics Query Options Sub-TLV is NOT present
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_REQUEST) \
|
||||
.filter(lambda p: TlvType.LINK_METRICS_QUERY in p.mle.tlv.type) \
|
||||
.filter(lambda p: p.mle.tlv.query_id == SERIES_ID_2) \
|
||||
.must_next()
|
||||
|
||||
# Step 20 - Leader MUST reply to SSED_1 with an MLE Data Response with the following:
|
||||
# - Link Metrics Report TLV
|
||||
# -- Link Metrics Report Sub-TLV
|
||||
# --- Metric Type ID Flags
|
||||
# ---- Type / Average Enum = 1 (Exponential Moving Average)
|
||||
# ---- Metric Enum = 2 (Link Margin)
|
||||
# --- Value (1 bytes)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter_mle_has_tlv(TlvType.LINK_METRICS_REPORT) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \
|
||||
.filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_LINK_MARGIN in p.mle.tlv.metric_type_id_flags.metric) \
|
||||
.must_next()
|
||||
|
||||
# Step 21 - SSED_1 clears the Forward Series Link Metrics
|
||||
# Forward Series Flags = 0x00:
|
||||
# - Bits 0-7 = 0
|
||||
# Concatenation of Link Metric Type ID Flags = NULL
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.FORWARD_PROBING_REGISTRATION in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: 0 in p.mle.tlv.link_forward_series) \
|
||||
.filter(lambda p: p.mle.tlv.metric_type_id_flags.type is nullField) \
|
||||
.filter(lambda p: p.mle.tlv.metric_type_id_flags.metric is nullField) \
|
||||
.must_next()
|
||||
|
||||
# Step 22 - Leader responds with a Link Metrics Management Response
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# Step 23 - SSED_1 sends an MLE Data Request to retrieve aggregated Forward Series results
|
||||
# - TLV Request TLV(Link Metrics Report TLV specified
|
||||
# - Link Metrics Query TLV
|
||||
# -- Link Metrics Query ID Sub-TLV
|
||||
# --- Query ID: (ID set in step 16)
|
||||
# This is a negative step
|
||||
pkts.filter_wpan_src64(SSED_1) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_REQUEST) \
|
||||
.filter(lambda p: TlvType.LINK_METRICS_QUERY in p.mle.tlv.type) \
|
||||
.filter(lambda p: p.mle.tlv.query_id == SERIES_ID_2) \
|
||||
.must_next()
|
||||
|
||||
# Step 24 - Leader MUST reply to SSED_1 with an MLE Data Response with the following:
|
||||
# - Link Metrics Report TLV
|
||||
# -- Link Metrics Status Sub-TLV
|
||||
# --- Status = 3 (Series ID not recognized)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(SSED_1) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter_mle_has_tlv(TlvType.LINK_METRICS_REPORT) \
|
||||
.filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_STATUS in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SERIES_ID_NOT_RECOGNIZED) \
|
||||
.must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,194 +0,0 @@
|
||||
#!/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 unittest
|
||||
|
||||
from config import ADDRESS_TYPE
|
||||
from mle import LinkMetricsSubTlvType, TlvType
|
||||
from pktverify import consts
|
||||
from pktverify.null_field import nullField
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
|
||||
LEADER = 1
|
||||
CHILD = 2
|
||||
|
||||
SERIES_ID_1 = 1
|
||||
SERIES_ID_2 = 2
|
||||
|
||||
|
||||
class LowPower_test_ForwardTrackingSeries(thread_cert.TestCase):
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2',
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [CHILD],
|
||||
},
|
||||
CHILD: {
|
||||
'version': '1.2',
|
||||
'name': 'CHILD',
|
||||
'mode': 'rn',
|
||||
'allowlist': [LEADER],
|
||||
}
|
||||
}
|
||||
"""All nodes are created with default configurations"""
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[CHILD].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[CHILD].get_state(), 'child')
|
||||
|
||||
leader_addr = self.nodes[LEADER].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL)
|
||||
|
||||
# 1. Child configures a Forward Tracking Series successfully.
|
||||
# The Series tracks the count of MAC Data Request.
|
||||
# Child should get a response with status 0 (SUCCESS).
|
||||
self.nodes[CHILD].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_1, 'r', 'p', 'async')
|
||||
self.simulator.go(1)
|
||||
|
||||
# 2. Child configures the same Forward Tracking Series again.
|
||||
# Child should get a response with status 2 (SERIES_ID_ALREADY_REGISTERED).
|
||||
self.nodes[CHILD].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_1, 'r', 'p', 'async')
|
||||
self.simulator.go(1)
|
||||
|
||||
# 3. Child queries a Series that doesn't exist (using a wrong Series ID).
|
||||
# Child should get a report with status 3 (SERIES_ID_NOT_RECOGNIZED).
|
||||
self.nodes[CHILD].link_metrics_request_forward_tracking_series(leader_addr, SERIES_ID_2, 'async')
|
||||
self.simulator.go(1)
|
||||
|
||||
# 4. Child queries a Series that don't have matched frames yet.
|
||||
# Child should get a report with status 4 (NO_MATCHING_FRAMES_RECEIVED).
|
||||
self.nodes[CHILD].link_metrics_request_forward_tracking_series(leader_addr, SERIES_ID_1, 'async')
|
||||
self.simulator.go(1)
|
||||
|
||||
# 5. Child clears a Forward Tracking Series that doesn't exist.
|
||||
# Child should get a response with status 3 (SERIES_ID_NOT_RECOGNIZED).
|
||||
self.nodes[CHILD].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_2, 'X', '', 'async')
|
||||
self.simulator.go(1)
|
||||
|
||||
# 6. Child clears a Forward Tracking Series successfully.
|
||||
# Child should get a response with status 0 (SUCCESS).
|
||||
self.nodes[CHILD].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_1, 'X', '', 'async')
|
||||
self.simulator.go(1)
|
||||
|
||||
# 7. Child configures a new Forward Tracking Series successfully.
|
||||
# The Series tracks the count of all MAC Data frames.
|
||||
# Child should get a response with status 0 (SUCCESS).
|
||||
self.nodes[CHILD].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_2, 'd', 'pqmr',
|
||||
'async')
|
||||
self.simulator.go(1)
|
||||
|
||||
# 8. Child sends an MLE Link Probe message to the Subject for the newly configured Series.
|
||||
self.nodes[CHILD].link_metrics_send_link_probe(leader_addr, SERIES_ID_2, 1)
|
||||
|
||||
# 9. Child queries the newly configured Series successfully.
|
||||
# Child should get a report with valid values.
|
||||
self.nodes[CHILD].link_metrics_request_forward_tracking_series(leader_addr, SERIES_ID_2, 'async')
|
||||
self.simulator.go(1)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
LEADER = pv.vars['LEADER']
|
||||
CHILD = pv.vars['CHILD']
|
||||
|
||||
# 1. Child should get a response with status 0 (SUCCESS).
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(CHILD) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# 2. Child should get a response with status 2 (SERIES_ID_ALREADY_REGISTERED).
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(CHILD) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SERIES_ID_ALREADY_REGISTERED) \
|
||||
.must_next()
|
||||
|
||||
# 3. Child should get a report with status 3 (SERIES_ID_NOT_RECOGNIZED).
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(CHILD) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter_mle_has_tlv(TlvType.LINK_METRICS_REPORT) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SERIES_ID_NOT_RECOGNIZED) \
|
||||
.must_next()
|
||||
|
||||
# 4. Child should get a report with status 4 (NO_MATCHING_FRAMES_RECEIVED).
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(CHILD) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter_mle_has_tlv(TlvType.LINK_METRICS_REPORT) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED) \
|
||||
.must_next()
|
||||
|
||||
# 5. Child should get a response with status 3 (SERIES_ID_NOT_RECOGNIZED).
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(CHILD) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SERIES_ID_NOT_RECOGNIZED) \
|
||||
.must_next()
|
||||
|
||||
# 6. Child should get a response with status 0 (SUCCESS).
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(CHILD) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# 7. Child should get a response with status 0 (SUCCESS).
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(CHILD) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# 8. Child sends an MLE Link Probe message to the Subject for the newly configured Series.
|
||||
pkts.filter_wpan_src64(CHILD) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_PROBE) \
|
||||
.must_next()
|
||||
|
||||
# 9. Child should get a report with valid values.
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(CHILD) \
|
||||
.filter_mle_cmd(consts.MLE_DATA_RESPONSE) \
|
||||
.filter(lambda p: TlvType.LINK_METRICS_REPORT in p.mle.tlv.type) \
|
||||
.must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,271 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2023, 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 unittest
|
||||
|
||||
from config import ADDRESS_TYPE
|
||||
from mle import LinkMetricsSubTlvType, TlvType
|
||||
from pktverify import consts
|
||||
from pktverify.null_field import nullField
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
|
||||
LEADER = 1
|
||||
ROUTER = 2
|
||||
CHILD = 3
|
||||
"""
|
||||
Acronyms:
|
||||
- EAP - Enhanced-ACK Based Probing
|
||||
|
||||
Test Process:
|
||||
1. Initiate a leader and a router at the beginning.
|
||||
2. Enable Link Metrics Manager on leader.
|
||||
3. Wait a few seconds.
|
||||
- At this moment, leader should have configured EAP successfully at router.
|
||||
4. Instruct the leader ping the router.
|
||||
- Enhanced ACK sent by router should have Thread IE containing Link Metrics data.
|
||||
5. Add a child into the network. The child should attach to the leader.
|
||||
6. Wait 150 seconds.
|
||||
- At this moment, leader should have configured EAP successfully at the child.
|
||||
7. Instruct both the router and the child ping the leader.
|
||||
- Enhanced ACK sent by router and child should have Thread IE containing Link Metrics data.
|
||||
8. Shutdown the child.
|
||||
9. Wait 300 seconds.
|
||||
- The leader should not send a Link Management Request to the child.
|
||||
- The leader should have sent a Link Management Request to the router and get a response.
|
||||
10. Disable Link Metrics Manager on leader.
|
||||
- The leader shonld send a Link Management Request to the router to unregister EAP.
|
||||
"""
|
||||
|
||||
|
||||
class LowPower_test_LinkMetricsManager(thread_cert.TestCase):
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2',
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER, CHILD],
|
||||
},
|
||||
ROUTER: {
|
||||
'version': '1.2',
|
||||
'name': 'ROUTER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER],
|
||||
},
|
||||
CHILD: {
|
||||
'version': '1.2',
|
||||
'name': 'CHILD',
|
||||
'mode': 'r',
|
||||
'allowlist': [LEADER],
|
||||
}
|
||||
}
|
||||
"""All nodes are created with default configurations"""
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[ROUTER].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
|
||||
|
||||
leader_addr = self.nodes[LEADER].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL)
|
||||
router_addr = self.nodes[ROUTER].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL)
|
||||
|
||||
# Step 2 - Enable Link Metrics Manager on leader.
|
||||
self.nodes[LEADER].link_metrics_mgr_set_enabled(True)
|
||||
|
||||
self.simulator.go(10)
|
||||
|
||||
# Step 4 - Instruct the leader ping the router.
|
||||
self.nodes[LEADER].ping(router_addr)
|
||||
|
||||
# Step 5 - Add a child into the network.
|
||||
self.nodes[CHILD].start()
|
||||
self.simulator.go(10)
|
||||
self.assertEqual(self.nodes[CHILD].get_state(), 'child')
|
||||
child_addr = self.nodes[CHILD].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL)
|
||||
|
||||
# Step 6 - Wait the leader to configure EAP at the child.
|
||||
self.simulator.go(150)
|
||||
|
||||
# Step 7 - Instruct both the router and the child ping the leader.
|
||||
self.nodes[LEADER].ping(router_addr)
|
||||
self.nodes[LEADER].ping(child_addr)
|
||||
|
||||
# Step 8 - Shutdown the child.
|
||||
self.nodes[CHILD].stop()
|
||||
|
||||
# Step 9 - Wait the leader to refresh EAP.
|
||||
self.simulator.go(300)
|
||||
|
||||
# Step 10 - Disable Link Metrics Manager on leader.
|
||||
self.nodes[LEADER].link_metrics_mgr_set_enabled(False)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
LEADER = pv.vars['LEADER']
|
||||
ROUTER = pv.vars['ROUTER']
|
||||
CHILD = pv.vars['CHILD']
|
||||
|
||||
# Step 3 - Leader enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
|
||||
# Request to the Router
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(001)(010) = 0x0a
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(ROUTER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
|
||||
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '0a0b') \
|
||||
.must_next()
|
||||
|
||||
# Step 3 - The Router MUST send a Link Metrics Management Response to Leader containing the following TLVs:
|
||||
# - MLE LInk Metrics Management TLV
|
||||
# -- Link Metrics Status Sub-TLV = 0 (Success)
|
||||
pkts.filter_wpan_src64(ROUTER) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# Step 4 - The Enhanced Ack sent by both Router should contain Thread specific IE
|
||||
pkt = pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(ROUTER) \
|
||||
.filter_ping_request() \
|
||||
.must_next()
|
||||
ack_seq_no = pkt.wpan.seq_no
|
||||
pkts.filter_wpan_ack() \
|
||||
.filter_wpan_seq(ack_seq_no) \
|
||||
.filter(lambda p: p.wpan.payload_ie.vendor.oui == consts.THREAD_IEEE_802154_COMPANY_ID) \
|
||||
.must_next()
|
||||
|
||||
# Step 6 - Leader enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
|
||||
# Request to the Child
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(001)(010) = 0x0a
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(CHILD) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
|
||||
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '0a0b') \
|
||||
.must_next()
|
||||
|
||||
# Step 6 - The Child MUST send a Link Metrics Management Response to Leader containing the following TLVs:
|
||||
# - MLE LInk Metrics Management TLV
|
||||
# -- Link Metrics Status Sub-TLV = 0 (Success)
|
||||
pkts.filter_wpan_src64(CHILD) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# Step 7 - The Enhanced Ack sent by both Router and Child should contain Thread specific IE
|
||||
pkt1 = pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(ROUTER) \
|
||||
.filter_ping_request() \
|
||||
.must_next()
|
||||
ack_seq_no = pkt1.wpan.seq_no
|
||||
pkts.filter_wpan_ack() \
|
||||
.filter_wpan_seq(ack_seq_no) \
|
||||
.filter(lambda p: p.wpan.payload_ie.vendor.oui == consts.THREAD_IEEE_802154_COMPANY_ID) \
|
||||
.must_next()
|
||||
|
||||
pkt2 = pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(CHILD) \
|
||||
.filter_ping_request() \
|
||||
.must_next()
|
||||
ack_seq_no = pkt2.wpan.seq_no
|
||||
pkts.filter_wpan_ack() \
|
||||
.filter_wpan_seq(ack_seq_no) \
|
||||
.filter(lambda p: p.wpan.payload_ie.vendor.oui == consts.THREAD_IEEE_802154_COMPANY_ID) \
|
||||
.must_next()
|
||||
|
||||
# Step 9 - Leader refreshes IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
|
||||
# Request to the Router
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 1 (register a configuration)
|
||||
# -- Concatenation of Link Metric Type ID Flags = 0x00:
|
||||
# --- Item1: (0)(0)(001)(010) = 0x0a
|
||||
# ---- E = 0
|
||||
# ---- L = 0
|
||||
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
|
||||
# ---- Metrics Enum = 2 (Link Margin)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(ROUTER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
|
||||
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '0a0b') \
|
||||
.must_next()
|
||||
|
||||
# Step 9 - The Router MUST send a Link Metrics Management Response to Leader containing the following TLVs:
|
||||
# - MLE LInk Metrics Management TLV
|
||||
# -- Link Metrics Status Sub-TLV = 0 (Success)
|
||||
pkts.filter_wpan_src64(ROUTER) \
|
||||
.filter_wpan_dst64(LEADER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
|
||||
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
|
||||
.must_next()
|
||||
|
||||
# Step 10 - Leader unregisters IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
|
||||
# Request to the Router
|
||||
# MLE Link Metrics Management TLV Payload:
|
||||
# - Enhanced ACK Configuration Sub-TLV
|
||||
# -- Enh-ACK Flags = 0 (unregister a configuration)
|
||||
pkts.filter_wpan_src64(LEADER) \
|
||||
.filter_wpan_dst64(ROUTER) \
|
||||
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
|
||||
.filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
|
||||
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_CLEAR) \
|
||||
.must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,145 +0,0 @@
|
||||
#!/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 unittest
|
||||
|
||||
import config
|
||||
import mle
|
||||
import thread_cert
|
||||
from pktverify import consts
|
||||
|
||||
LEADER = 1
|
||||
SSED_1 = 2
|
||||
|
||||
|
||||
class SSED_CslTransmission(thread_cert.TestCase):
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2',
|
||||
},
|
||||
SSED_1: {
|
||||
'version': '1.2',
|
||||
'is_mtd': True,
|
||||
'mode': '-',
|
||||
},
|
||||
}
|
||||
"""All nodes are created with default configurations"""
|
||||
|
||||
def test(self):
|
||||
|
||||
self.nodes[SSED_1].set_csl_period(consts.CSL_DEFAULT_PERIOD)
|
||||
self.nodes[SSED_1].set_csl_timeout(consts.CSL_DEFAULT_TIMEOUT)
|
||||
|
||||
self.nodes[SSED_1].get_csl_info()
|
||||
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[SSED_1].start()
|
||||
self.simulator.go(7)
|
||||
self.assertEqual(self.nodes[SSED_1].get_state(), 'child')
|
||||
|
||||
print('SSED rloc:%s' % self.nodes[SSED_1].get_rloc())
|
||||
self.assertTrue(self.nodes[LEADER].ping(self.nodes[SSED_1].get_rloc()))
|
||||
self.simulator.go(5)
|
||||
|
||||
ssed_messages = self.simulator.get_messages_sent_by(SSED_1)
|
||||
msg = ssed_messages.next_mle_message(mle.CommandType.CHILD_UPDATE_REQUEST)
|
||||
|
||||
self.nodes[SSED_1].set_csl_channel(consts.CSL_DEFAULT_CHANNEL)
|
||||
self.simulator.go(1)
|
||||
ssed_messages = self.simulator.get_messages_sent_by(SSED_1)
|
||||
msg = ssed_messages.next_mle_message(mle.CommandType.CHILD_UPDATE_REQUEST)
|
||||
msg.assertMleMessageContainsTlv(mle.CslChannel)
|
||||
self.assertTrue(self.nodes[LEADER].ping(self.nodes[SSED_1].get_rloc()))
|
||||
self.simulator.go(5)
|
||||
|
||||
self.nodes[SSED_1].set_csl_channel(0)
|
||||
self.simulator.go(1)
|
||||
self.assertTrue(self.nodes[LEADER].ping(self.nodes[SSED_1].get_rloc()))
|
||||
self.simulator.go(5)
|
||||
|
||||
ssed_messages = self.simulator.get_messages_sent_by(SSED_1)
|
||||
msg = ssed_messages.next_mle_message(mle.CommandType.CHILD_UPDATE_REQUEST)
|
||||
|
||||
self.nodes[SSED_1].set_csl_period(0)
|
||||
self.assertFalse(self.nodes[LEADER].ping(self.nodes[SSED_1].get_rloc()))
|
||||
self.simulator.go(2)
|
||||
|
||||
self.nodes[SSED_1].set_pollperiod(1000)
|
||||
self.simulator.go(2)
|
||||
self.nodes[SSED_1].set_pollperiod(0)
|
||||
self.simulator.go(5)
|
||||
|
||||
# Check if data poll is not sent if data packet with CSL IE is sent to parent
|
||||
self.nodes[SSED_1].set_csl_period(consts.CSL_DEFAULT_PERIOD)
|
||||
self.simulator.go(consts.CSL_DEFAULT_TIMEOUT / 2)
|
||||
self.assertTrue(self.nodes[LEADER].ping(self.nodes[SSED_1].get_rloc()))
|
||||
self.flush_all()
|
||||
self.simulator.go(consts.CSL_DEFAULT_TIMEOUT / 2)
|
||||
ssed_messages = self.simulator.get_messages_sent_by(SSED_1)
|
||||
self.assertIsNone(ssed_messages.next_data_poll())
|
||||
|
||||
# Check if data poll is used to sync SSED's parent before CSL timeout
|
||||
self.assertTrue(self.nodes[LEADER].ping(self.nodes[SSED_1].get_rloc()))
|
||||
self.flush_all()
|
||||
self.simulator.go(consts.CSL_DEFAULT_TIMEOUT)
|
||||
ssed_messages = self.simulator.get_messages_sent_by(SSED_1)
|
||||
self.assertIsNotNone(ssed_messages.next_data_poll())
|
||||
|
||||
# Check if data poll is used to resync SSED's parent after retransmission
|
||||
leader_rloc = self.nodes[LEADER].get_rloc()
|
||||
self.nodes[LEADER].stop()
|
||||
self.flush_all()
|
||||
self.assertFalse(self.nodes[SSED_1].ping(leader_rloc))
|
||||
self.simulator.go(2)
|
||||
ssed_messages = self.simulator.get_messages_sent_by(SSED_1)
|
||||
self.assertIsNotNone(ssed_messages.next_data_poll())
|
||||
|
||||
# Check if SSED is able to resynchronize with the parent after it is gone longer than the timeout
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_RESET_DELAY)
|
||||
self.nodes[SSED_1].set_csl_timeout(8)
|
||||
self.nodes[SSED_1].set_timeout(10)
|
||||
self.simulator.go(2)
|
||||
self.nodes[LEADER].stop()
|
||||
self.simulator.go(25)
|
||||
self.flush_all()
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_RESET_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[SSED_1].get_state(), 'child')
|
||||
ssed_messages = self.simulator.get_messages_sent_by(SSED_1)
|
||||
self.assertIsNotNone(ssed_messages.next_mle_message(mle.CommandType.CHILD_UPDATE_REQUEST))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,111 +0,0 @@
|
||||
#!/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.
|
||||
#
|
||||
"""This test case verifies Thread 1.2 enhanced frame pending feature.
|
||||
|
||||
Topology
|
||||
|
||||
Leader ----- SED_1
|
||||
|
||||
1. Set up topology a Leader and a SED.
|
||||
2. SED pings leader so a data poll is just sent.
|
||||
3. Leader sends a UDP packet to SED to put a pending frame in queue.
|
||||
4. Wait for half polling period, verify no packet received by SED.
|
||||
5. SED sends a UDP packet to Leader to solicit an ACK with frame pending set.
|
||||
* Verify Leader receives a UDP packet
|
||||
* Verify SED sends a data poll
|
||||
* Verify SED receives a UDP packet
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
|
||||
import thread_cert
|
||||
import config
|
||||
import common
|
||||
|
||||
LEADER = 1
|
||||
SED_1 = 2
|
||||
|
||||
CHILD_TIMEOUT = 30
|
||||
UDP_BYTES_COUNT = 73
|
||||
|
||||
DEFAULT_POLL_PERIOD = CHILD_TIMEOUT - 4
|
||||
"""The default poll period calculated from child timeout."""
|
||||
|
||||
|
||||
class SED_EnhancedFramePending(thread_cert.TestCase):
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2'
|
||||
},
|
||||
SED_1: {
|
||||
'mode': '-',
|
||||
'version': '1.2',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[SED_1].set_timeout(CHILD_TIMEOUT)
|
||||
|
||||
# 1 - Set up topology
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[SED_1].start()
|
||||
self.simulator.go(7)
|
||||
self.assertEqual(self.nodes[SED_1].get_state(), 'child')
|
||||
|
||||
self.nodes[LEADER].udp_start('::', common.UDP_TEST_PORT)
|
||||
self.nodes[SED_1].udp_start('::', common.UDP_TEST_PORT)
|
||||
|
||||
# 2 - Ping Leader
|
||||
self.assertTrue(self.nodes[SED_1].ping(self.nodes[LEADER].get_rloc(), timeout=CHILD_TIMEOUT))
|
||||
|
||||
self.flush_all()
|
||||
|
||||
# 3 - Send to SED
|
||||
self.nodes[LEADER].udp_send(UDP_BYTES_COUNT, self.nodes[SED_1].get_rloc(), common.UDP_TEST_PORT)
|
||||
|
||||
# 4 - Wait for half polling period
|
||||
self.simulator.go(DEFAULT_POLL_PERIOD // 2)
|
||||
with self.assertRaises(pexpect.TIMEOUT):
|
||||
self.nodes[SED_1].udp_check_rx(UDP_BYTES_COUNT)
|
||||
|
||||
# 5 - Send to Leader
|
||||
self.nodes[SED_1].udp_send(UDP_BYTES_COUNT, self.nodes[LEADER].get_rloc(), common.UDP_TEST_PORT)
|
||||
self.simulator.go(1)
|
||||
self.nodes[LEADER].udp_check_rx(UDP_BYTES_COUNT)
|
||||
sed_messages = self.simulator.get_messages_sent_by(SED_1)
|
||||
self.assertNotEqual(sed_messages.next_data_poll(), None)
|
||||
self.nodes[SED_1].udp_check_rx(UDP_BYTES_COUNT)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,183 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019, 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 unittest
|
||||
|
||||
import thread_cert
|
||||
import config
|
||||
import mle
|
||||
|
||||
LEADER = 1
|
||||
SED_1 = 2
|
||||
|
||||
CHILD_TIMEOUT = 30
|
||||
|
||||
DEFAULT_POLL_PERIOD = CHILD_TIMEOUT - 4
|
||||
"""The default poll period calculated by ot::Mac::DataPollSender::GetDefaultPollPeriod()."""
|
||||
|
||||
USER_POLL_PERIOD = CHILD_TIMEOUT // 3
|
||||
"""The poll period explicitly set by this test for verifying enhanced keep-alive."""
|
||||
|
||||
|
||||
class SED_EnhancedKeepAlive(thread_cert.TestCase):
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2'
|
||||
},
|
||||
SED_1: {
|
||||
'mode': '-',
|
||||
'version': '1.2',
|
||||
},
|
||||
}
|
||||
"""All nodes are created with default configurations"""
|
||||
|
||||
def test(self):
|
||||
self.nodes[SED_1].set_timeout(CHILD_TIMEOUT)
|
||||
self.nodes[SED_1].set_pollperiod(USER_POLL_PERIOD * 1000)
|
||||
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[SED_1].start()
|
||||
self.simulator.go(7)
|
||||
self.assertEqual(self.nodes[SED_1].get_state(), 'child')
|
||||
|
||||
leader_messages = self.simulator.get_messages_sent_by(LEADER)
|
||||
sed_messages = self.simulator.get_messages_sent_by(SED_1)
|
||||
|
||||
# 1 - Leader transmits MLE advertisements
|
||||
msg = leader_messages.next_mle_message(mle.CommandType.ADVERTISEMENT)
|
||||
msg.assertSentWithHopLimit(255)
|
||||
msg.assertSentToDestinationAddress('ff02::1')
|
||||
msg.assertMleMessageContainsTlv(mle.SourceAddress)
|
||||
msg.assertMleMessageContainsTlv(mle.LeaderData)
|
||||
msg.assertMleMessageContainsTlv(mle.Route64)
|
||||
|
||||
# 2 - SED_1 begins attach process by sending a multicast MLE Parent Request
|
||||
msg = sed_messages.next_mle_message(mle.CommandType.PARENT_REQUEST)
|
||||
msg.assertSentWithHopLimit(255)
|
||||
msg.assertSentToDestinationAddress('ff02::2')
|
||||
msg.assertMleMessageContainsTlv(mle.Mode)
|
||||
msg.assertMleMessageContainsTlv(mle.Challenge)
|
||||
msg.assertMleMessageContainsTlv(mle.ScanMask)
|
||||
msg.assertMleMessageContainsTlv(mle.Version)
|
||||
self.assertGreaterEqual(msg.get_mle_message_tlv(mle.Version).version, config.THREAD_VERSION_1_2)
|
||||
|
||||
scan_mask_tlv = msg.get_mle_message_tlv(mle.ScanMask)
|
||||
self.assertEqual(1, scan_mask_tlv.router)
|
||||
self.assertEqual(0, scan_mask_tlv.end_device)
|
||||
|
||||
# 3 - Leader sends a MLE Parent Response
|
||||
msg = leader_messages.next_mle_message(mle.CommandType.PARENT_RESPONSE)
|
||||
msg.assertSentToNode(self.nodes[SED_1])
|
||||
msg.assertMleMessageContainsTlv(mle.SourceAddress)
|
||||
msg.assertMleMessageContainsTlv(mle.LeaderData)
|
||||
msg.assertMleMessageContainsTlv(mle.LinkLayerFrameCounter)
|
||||
msg.assertMleMessageContainsOptionalTlv(mle.MleFrameCounter)
|
||||
msg.assertMleMessageContainsTlv(mle.Response)
|
||||
msg.assertMleMessageContainsTlv(mle.Challenge)
|
||||
msg.assertMleMessageContainsTlv(mle.LinkMargin)
|
||||
msg.assertMleMessageContainsTlv(mle.Connectivity)
|
||||
msg.assertMleMessageContainsTlv(mle.Version)
|
||||
self.assertGreaterEqual(msg.get_mle_message_tlv(mle.Version).version, config.THREAD_VERSION_1_2)
|
||||
|
||||
# 4 - SED_1 receives the MLE Parent Response and sends a Child ID Request
|
||||
msg = sed_messages.next_mle_message(mle.CommandType.CHILD_ID_REQUEST)
|
||||
msg.assertSentToNode(self.nodes[LEADER])
|
||||
msg.assertMleMessageContainsTlv(mle.Response)
|
||||
msg.assertMleMessageContainsTlv(mle.LinkLayerFrameCounter)
|
||||
msg.assertMleMessageContainsOptionalTlv(mle.MleFrameCounter)
|
||||
msg.assertMleMessageContainsTlv(mle.Mode)
|
||||
msg.assertMleMessageContainsTlv(mle.Timeout)
|
||||
msg.assertMleMessageContainsTlv(mle.Version)
|
||||
msg.assertMleMessageContainsTlv(mle.TlvRequest)
|
||||
self.assertGreaterEqual(msg.get_mle_message_tlv(mle.Version).version, config.THREAD_VERSION_1_2)
|
||||
|
||||
# 5 - Leader responds with a Child ID Response
|
||||
msg = leader_messages.next_mle_message(mle.CommandType.CHILD_ID_RESPONSE)
|
||||
msg.assertSentToNode(self.nodes[SED_1])
|
||||
msg.assertMleMessageContainsTlv(mle.SourceAddress)
|
||||
msg.assertMleMessageContainsTlv(mle.LeaderData)
|
||||
msg.assertMleMessageContainsTlv(mle.Address16)
|
||||
msg.assertMleMessageContainsOptionalTlv(mle.NetworkData)
|
||||
msg.assertMleMessageContainsOptionalTlv(mle.Route64)
|
||||
msg.assertMleMessageContainsOptionalTlv(mle.AddressRegistration)
|
||||
|
||||
leader_aloc = self.nodes[LEADER].get_addr_leader_aloc()
|
||||
self.assertTrue(self.nodes[SED_1].ping(leader_aloc, timeout=USER_POLL_PERIOD * 2))
|
||||
|
||||
# 6 - Timeout Child
|
||||
self.nodes[SED_1].set_pollperiod(CHILD_TIMEOUT * 1000 * 4)
|
||||
self.simulator.go(CHILD_TIMEOUT + 1)
|
||||
self.assertEqual(self.nodes[SED_1].get_state(), 'child')
|
||||
self.assertFalse(self.nodes[SED_1].ping(leader_aloc, timeout=USER_POLL_PERIOD * 2))
|
||||
self.flush_all()
|
||||
|
||||
self.nodes[SED_1].stop()
|
||||
self.nodes[SED_1].set_pollperiod(USER_POLL_PERIOD * 1000)
|
||||
self.nodes[SED_1].start()
|
||||
|
||||
# 7 - Wait SED_1 to re-attach
|
||||
self.simulator.go(240)
|
||||
self.assertEqual(self.nodes[SED_1].get_state(), 'child')
|
||||
leader_messages = self.simulator.get_messages_sent_by(LEADER)
|
||||
msg = leader_messages.next_mle_message(mle.CommandType.CHILD_ID_RESPONSE)
|
||||
msg.assertSentToNode(self.nodes[SED_1])
|
||||
msg.assertMleMessageContainsTlv(mle.SourceAddress)
|
||||
msg.assertMleMessageContainsTlv(mle.LeaderData)
|
||||
msg.assertMleMessageContainsTlv(mle.Address16)
|
||||
msg.assertMleMessageContainsOptionalTlv(mle.NetworkData)
|
||||
msg.assertMleMessageContainsOptionalTlv(mle.Route64)
|
||||
msg.assertMleMessageContainsOptionalTlv(mle.AddressRegistration)
|
||||
self.assertTrue(self.nodes[SED_1].ping(leader_aloc, timeout=USER_POLL_PERIOD * 2))
|
||||
self.flush_all()
|
||||
|
||||
# 8 - Verify enhanced keep-alive works
|
||||
self.nodes[SED_1].set_pollperiod(CHILD_TIMEOUT * 1000 * 4)
|
||||
self.simulator.go(CHILD_TIMEOUT // 2)
|
||||
self.assertEqual(self.nodes[SED_1].get_state(), 'child')
|
||||
non_exist_addr = leader_aloc.replace('fc00', 'fc12')
|
||||
self.assertFalse(self.nodes[SED_1].ping(non_exist_addr))
|
||||
self.simulator.go(CHILD_TIMEOUT // 2)
|
||||
self.nodes[SED_1].set_pollperiod(USER_POLL_PERIOD * 1000)
|
||||
self.assertTrue(self.nodes[SED_1].ping(leader_aloc, timeout=USER_POLL_PERIOD * 2))
|
||||
|
||||
# 9 - Verify child resets keep-alive timer
|
||||
self.nodes[SED_1].set_pollperiod(DEFAULT_POLL_PERIOD * 1000)
|
||||
self.simulator.go(DEFAULT_POLL_PERIOD // 3 * 2)
|
||||
self.flush_all()
|
||||
self.nodes[SED_1].ping(leader_aloc, timeout=1)
|
||||
self.simulator.go(DEFAULT_POLL_PERIOD // 3 * 2)
|
||||
sed_messages = self.simulator.get_messages_sent_by(SED_1)
|
||||
self.assertEqual(sed_messages.next_data_poll(), None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/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 unittest
|
||||
|
||||
import mle
|
||||
import thread_cert
|
||||
import config
|
||||
|
||||
LEADER = 1
|
||||
SSED_1 = 2
|
||||
|
||||
CSL_PERIOD = 500 * 1000 # 0.5 in usec
|
||||
CSL_TIMEOUT = 30 # 30s
|
||||
|
||||
|
||||
class SSED_SingleProbe(thread_cert.TestCase):
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'version': '1.2',
|
||||
},
|
||||
SSED_1: {
|
||||
'version': '1.2',
|
||||
'mode': '-',
|
||||
},
|
||||
}
|
||||
"""All nodes are created with default configurations"""
|
||||
|
||||
def test(self):
|
||||
|
||||
self.nodes[SSED_1].set_csl_period(CSL_PERIOD)
|
||||
self.nodes[SSED_1].set_csl_timeout(CSL_TIMEOUT)
|
||||
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[SSED_1].start()
|
||||
self.simulator.go(7)
|
||||
self.assertEqual(self.nodes[SSED_1].get_state(), 'child')
|
||||
|
||||
leader_addr = self.nodes[LEADER].get_linklocal()
|
||||
|
||||
leader_messages = self.simulator.get_messages_sent_by(LEADER)
|
||||
|
||||
# SSED_1 sends a Single Probe Link Metrics for L2 PDU count using MLE Data Request
|
||||
result = self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'p')
|
||||
self.assertIn('PDU Counter', result)
|
||||
self.assertEqual(len(result), 1)
|
||||
|
||||
leader_messages = self.simulator.get_messages_sent_by(LEADER)
|
||||
msg = leader_messages.next_mle_message(mle.CommandType.DATA_RESPONSE)
|
||||
msg.assertMleMessageContainsTlv(mle.LinkMetricsReport)
|
||||
|
||||
# SSED_1 sends a Single Probe Link Metrics for L2 LQI using MLE Data Request
|
||||
result = self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'q')
|
||||
self.assertIn('LQI', result)
|
||||
self.assertEqual(len(result), 1)
|
||||
|
||||
leader_messages = self.simulator.get_messages_sent_by(LEADER)
|
||||
msg = leader_messages.next_mle_message(mle.CommandType.DATA_RESPONSE)
|
||||
msg.assertMleMessageContainsTlv(mle.LinkMetricsReport)
|
||||
|
||||
# SSED_1 sends a Single Probe Link Metrics for Link Margin using MLE Data Request
|
||||
result = self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'm')
|
||||
self.assertIn('Margin', result)
|
||||
self.assertEqual(len(result), 1)
|
||||
|
||||
leader_messages = self.simulator.get_messages_sent_by(LEADER)
|
||||
msg = leader_messages.next_mle_message(mle.CommandType.DATA_RESPONSE)
|
||||
msg.assertMleMessageContainsTlv(mle.LinkMetricsReport)
|
||||
|
||||
# SSED_1 sends a Single Probe Link Metrics for Link Margin using MLE Data Request
|
||||
result = self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'r')
|
||||
self.assertIn('RSSI', result)
|
||||
self.assertEqual(len(result), 1)
|
||||
|
||||
leader_messages = self.simulator.get_messages_sent_by(LEADER)
|
||||
msg = leader_messages.next_mle_message(mle.CommandType.DATA_RESPONSE)
|
||||
msg.assertMleMessageContainsTlv(mle.LinkMetricsReport)
|
||||
|
||||
# SSED_1 sends a Single Probe Link Metrics for all metrics using MLE Data Request
|
||||
result = self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'pqmr')
|
||||
self.assertIn('PDU Counter', result)
|
||||
self.assertIn('LQI', result)
|
||||
self.assertIn('Margin', result)
|
||||
self.assertIn('RSSI', result)
|
||||
self.assertEqual(len(result), 4)
|
||||
|
||||
leader_messages = self.simulator.get_messages_sent_by(LEADER)
|
||||
msg = leader_messages.next_mle_message(mle.CommandType.DATA_RESPONSE)
|
||||
msg.assertMleMessageContainsTlv(mle.LinkMetricsReport)
|
||||
|
||||
self.assertTrue(self.nodes[LEADER].ping(self.nodes[SSED_1].get_rloc()))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user