1#!/usr/bin/env python3 2# 3# Copyright (c) 2020, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29 30import unittest 31 32from config import ADDRESS_TYPE 33from mle import LinkMetricsSubTlvType, TlvType 34from pktverify import consts 35from pktverify.null_field import nullField 36from pktverify.packet_verifier import PacketVerifier 37 38import config 39import thread_cert 40 41LEADER = 1 42CHILD = 2 43 44SERIES_ID_1 = 1 45SERIES_ID_2 = 2 46 47 48class LowPower_test_ForwardTrackingSeries(thread_cert.TestCase): 49 TOPOLOGY = { 50 LEADER: { 51 'version': '1.2', 52 'name': 'LEADER', 53 'mode': 'rdn', 54 'allowlist': [CHILD], 55 }, 56 CHILD: { 57 'version': '1.2', 58 'name': 'CHILD', 59 'mode': 'rn', 60 'allowlist': [LEADER], 61 } 62 } 63 """All nodes are created with default configurations""" 64 65 def test(self): 66 self.nodes[LEADER].start() 67 self.simulator.go(config.LEADER_STARTUP_DELAY) 68 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 69 70 self.nodes[CHILD].start() 71 self.simulator.go(5) 72 self.assertEqual(self.nodes[CHILD].get_state(), 'child') 73 74 leader_addr = self.nodes[LEADER].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL) 75 76 # 1. Child configures a Forward Tracking Series successfully. 77 # The Series tracks the count of MAC Data Request. 78 # Child should get a response with status 0 (SUCCESS). 79 self.nodes[CHILD].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_1, 'r', 'p', 'async') 80 self.simulator.go(1) 81 82 # 2. Child configures the same Forward Tracking Series again. 83 # Child should get a response with status 2 (SERIES_ID_ALREADY_REGISTERED). 84 self.nodes[CHILD].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_1, 'r', 'p', 'async') 85 self.simulator.go(1) 86 87 # 3. Child queries a Series that doesn't exist (using a wrong Series ID). 88 # Child should get a report with status 3 (SERIES_ID_NOT_RECOGNIZED). 89 self.nodes[CHILD].link_metrics_request_forward_tracking_series(leader_addr, SERIES_ID_2, 'async') 90 self.simulator.go(1) 91 92 # 4. Child queries a Series that don't have matched frames yet. 93 # Child should get a report with status 4 (NO_MATCHING_FRAMES_RECEIVED). 94 self.nodes[CHILD].link_metrics_request_forward_tracking_series(leader_addr, SERIES_ID_1, 'async') 95 self.simulator.go(1) 96 97 # 5. Child clears a Forward Tracking Series that doesn't exist. 98 # Child should get a response with status 3 (SERIES_ID_NOT_RECOGNIZED). 99 self.nodes[CHILD].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_2, 'X', '', 'async') 100 self.simulator.go(1) 101 102 # 6. Child clears a Forward Tracking Series successfully. 103 # Child should get a response with status 0 (SUCCESS). 104 self.nodes[CHILD].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_1, 'X', '', 'async') 105 self.simulator.go(1) 106 107 # 7. Child configures a new Forward Tracking Series successfully. 108 # The Series tracks the count of all MAC Data frames. 109 # Child should get a response with status 0 (SUCCESS). 110 self.nodes[CHILD].link_metrics_config_req_forward_tracking_series(leader_addr, SERIES_ID_2, 'd', 'pqmr', 111 'async') 112 self.simulator.go(1) 113 114 # 8. Child sends an MLE Link Probe message to the Subject for the newly configured Series. 115 self.nodes[CHILD].link_metrics_send_link_probe(leader_addr, SERIES_ID_2, 1) 116 117 # 9. Child queries the newly configured Series successfully. 118 # Child should get a report with valid values. 119 self.nodes[CHILD].link_metrics_request_forward_tracking_series(leader_addr, SERIES_ID_2, 'async') 120 self.simulator.go(1) 121 122 def verify(self, pv): 123 pkts = pv.pkts 124 pv.summary.show() 125 LEADER = pv.vars['LEADER'] 126 CHILD = pv.vars['CHILD'] 127 128 # 1. Child should get a response with status 0 (SUCCESS). 129 pkts.filter_wpan_src64(LEADER) \ 130 .filter_wpan_dst64(CHILD) \ 131 .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \ 132 .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \ 133 .must_next() 134 135 # 2. Child should get a response with status 2 (SERIES_ID_ALREADY_REGISTERED). 136 pkts.filter_wpan_src64(LEADER) \ 137 .filter_wpan_dst64(CHILD) \ 138 .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \ 139 .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SERIES_ID_ALREADY_REGISTERED) \ 140 .must_next() 141 142 # 3. Child should get a report with status 3 (SERIES_ID_NOT_RECOGNIZED). 143 pkts.filter_wpan_src64(LEADER) \ 144 .filter_wpan_dst64(CHILD) \ 145 .filter_mle_cmd(consts.MLE_DATA_RESPONSE) \ 146 .filter_mle_has_tlv(TlvType.LINK_METRICS_REPORT) \ 147 .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SERIES_ID_NOT_RECOGNIZED) \ 148 .must_next() 149 150 # 4. Child should get a report with status 4 (NO_MATCHING_FRAMES_RECEIVED). 151 pkts.filter_wpan_src64(LEADER) \ 152 .filter_wpan_dst64(CHILD) \ 153 .filter_mle_cmd(consts.MLE_DATA_RESPONSE) \ 154 .filter_mle_has_tlv(TlvType.LINK_METRICS_REPORT) \ 155 .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED) \ 156 .must_next() 157 158 # 5. Child should get a response with status 3 (SERIES_ID_NOT_RECOGNIZED). 159 pkts.filter_wpan_src64(LEADER) \ 160 .filter_wpan_dst64(CHILD) \ 161 .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \ 162 .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SERIES_ID_NOT_RECOGNIZED) \ 163 .must_next() 164 165 # 6. Child should get a response with status 0 (SUCCESS). 166 pkts.filter_wpan_src64(LEADER) \ 167 .filter_wpan_dst64(CHILD) \ 168 .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \ 169 .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \ 170 .must_next() 171 172 # 7. Child should get a response with status 0 (SUCCESS). 173 pkts.filter_wpan_src64(LEADER) \ 174 .filter_wpan_dst64(CHILD) \ 175 .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \ 176 .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \ 177 .must_next() 178 179 # 8. Child sends an MLE Link Probe message to the Subject for the newly configured Series. 180 pkts.filter_wpan_src64(CHILD) \ 181 .filter_wpan_dst64(LEADER) \ 182 .filter_mle_cmd(consts.MLE_LINK_PROBE) \ 183 .must_next() 184 185 # 9. Child should get a report with valid values. 186 pkts.filter_wpan_src64(LEADER) \ 187 .filter_wpan_dst64(CHILD) \ 188 .filter_mle_cmd(consts.MLE_DATA_RESPONSE) \ 189 .filter(lambda p: TlvType.LINK_METRICS_REPORT in p.mle.tlv.type) \ 190 .must_next() 191 192 193if __name__ == '__main__': 194 unittest.main() 195