1#!/usr/bin/env python3 2# 3# Copyright (c) 2023, 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 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 42SED_1 = 2 43SSED_1 = 3 44 45SERIES_ID = 1 46SERIES_ID_2 = 2 47POLL_PERIOD = 2000 # 2s 48 49 50class LowPower_7_1_02_SingleProbeLinkMetricsWithoutEnhancedAck(thread_cert.TestCase): 51 USE_MESSAGE_FACTORY = False 52 TOPOLOGY = { 53 LEADER: { 54 'version': '1.2', 55 'name': 'LEADER', 56 'mode': 'rdn', 57 'allowlist': [SED_1, SSED_1], 58 }, 59 SED_1: { 60 'version': '1.2', 61 'name': 'SED_1', 62 'mode': '-', 63 'allowlist': [LEADER], 64 }, 65 SSED_1: { 66 'version': '1.2', 67 'name': 'SSED_1', 68 'mode': '-', 69 'allowlist': [LEADER], 70 } 71 } 72 """All nodes are created with default configurations""" 73 74 def test(self): 75 self.nodes[LEADER].start() 76 self.simulator.go(config.LEADER_STARTUP_DELAY) 77 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 78 79 self.nodes[SED_1].set_pollperiod(POLL_PERIOD) 80 self.nodes[SED_1].start() 81 self.simulator.go(5) 82 self.assertEqual(self.nodes[SED_1].get_state(), 'child') 83 84 self.nodes[SSED_1].set_csl_period(consts.CSL_DEFAULT_PERIOD) 85 self.nodes[SSED_1].start() 86 self.simulator.go(5) 87 self.assertEqual(self.nodes[SSED_1].get_state(), 'child') 88 89 leader_addr = self.nodes[LEADER].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL) 90 sed_extaddr = self.nodes[SED_1].get_addr64() 91 92 # Step 3 - Verify connectivity by instructing each device to send an ICMPv6 Echo Request to the DUT 93 self.assertTrue(self.nodes[SED_1].ping(leader_addr, timeout=POLL_PERIOD / 1000)) 94 self.assertTrue(self.nodes[SSED_1].ping(leader_addr, timeout=(2 * consts.CSL_DEFAULT_PERIOD_IN_SECOND))) 95 self.simulator.go(5) 96 97 # Step 4 - SED_1 sends a Single Probe Link Metric for RSSI using MLE Data Request 98 # MLE Data Request Payload: 99 # - TLV Request TLV (Link Metrics Report TLV specified) 100 # - Link Metrics Query TLV 101 # -- Link Metrics Query ID Sub-TLV 102 # --- Query ID = 0 (Single Probe Query) 103 # -- Link Metrics Query Options Sub-TLV 104 # --- Metric Type ID Flags 105 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 106 # ---- Metric Enum = 3 (RSSI) 107 # 108 # In this step, SED_1 should set its TxPower to 'High'. In simulation, this will be implemented by 109 # setting Macfilter on the Rx side (Leader). 110 self.nodes[LEADER].add_allowlist(sed_extaddr, -30) 111 res = self.nodes[SED_1].link_metrics_request_single_probe(leader_addr, 'r') 112 rss_1 = int(res['RSSI']) 113 self.simulator.go(5) 114 115 # Step 6 - SED_1 sends a Single Probe Link Metric for RSSI using MLE Data Request 116 # MLE Data Request Payload: 117 # - TLV Request TLV (Link Metrics Report TLV specified) 118 # - Link Metrics Query TLV 119 # -- Link Metrics Query ID Sub-TLV 120 # --- Query ID = 0 (Single Probe Query) 121 # -- Link Metrics Query Options Sub-TLV 122 # --- Metric Type ID Flags 123 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 124 # ---- Metric Enum = 3 (RSSI) 125 # 126 # In this step, SED_1 should set its TxPower to 'Low'. 127 self.nodes[LEADER].add_allowlist(sed_extaddr, -95) 128 res = self.nodes[SED_1].link_metrics_request_single_probe(leader_addr, 'r') 129 rss_2 = int(res['RSSI']) 130 self.simulator.go(5) 131 132 # Step 8 - Compare the rssi value in step 5 & 7, RSSI in 5 should be larger than RSSI in 7 133 self.assertTrue(rss_1 > rss_2) 134 135 # Step 9 - SSED_1 sends a Single Probe Link Metric for Layer 2 LQI using MLE Data Request 136 # MLE Data Request Payload: 137 # - TLV Request TLV (Link Metrics Report TLV specified) 138 # - Link Metrics Query TLV 139 # -- Link Metrics Query ID Sub-TLV 140 # --- Query ID = 0 (Single Probe Query) 141 # -- Link Metrics Query Options Sub-TLV 142 # --- Metric Type ID Flags 143 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 144 # ---- Metric Enum = 1 (Layer 2 LQI) 145 self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'q') 146 self.simulator.go(5) 147 148 # Step 11 - SSED_1 sends a Single Probe Link Metric for Link Margin using MLE Data Request 149 # MLE Data Request Payload: 150 # - TLV Request TLV (Link Metrics Report TLV specified) 151 # - Link Metrics Query TLV 152 # -- Link Metrics Query ID Sub-TLV 153 # --- Query ID = 0 (Single Probe Query) 154 # -- Link Metrics Query Options Sub-TLV 155 # --- Metric Type ID Flags 156 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 157 # ---- Metric Enum = 2 (Link Margin) 158 self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'm') 159 self.simulator.go(5) 160 161 # Step 13 - SSED_1 sends a Single Probe Link Metric using MLE Data Request 162 # MLE Data Request Payload: 163 # - TLV Request TLV (Link Metrics Report TLV specified) 164 # - Link Metrics Query TLV 165 # -- Link Metrics Query ID Sub-TLV 166 # --- Query ID = 0 (Single Probe Query) 167 # -- Link Metrics Query Options Sub-TLV 168 # --- Metric Type ID Flags 169 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 170 # ---- Metric Enum = 1 (Layer 2 LQI) 171 # ---- Metric Enum = 2 (Link Margin) 172 # ---- Metric Enum = 3 (RSSI) 173 self.nodes[SSED_1].link_metrics_request_single_probe(leader_addr, 'qmr') 174 self.simulator.go(5) 175 176 def verify(self, pv): 177 pkts = pv.pkts 178 pv.summary.show() 179 LEADER = pv.vars['LEADER'] 180 SED_1 = pv.vars['SED_1'] 181 SSED_1 = pv.vars['SSED_1'] 182 183 # Step 3 - The DUT MUST send ICMPv6 Echo Responses to both SED1 & SSED1 184 pkts.filter_wpan_src64(LEADER) \ 185 .filter_wpan_dst64(SED_1) \ 186 .filter_ping_reply() \ 187 .must_next() 188 pkts.filter_wpan_src64(LEADER) \ 189 .filter_wpan_dst64(SSED_1) \ 190 .filter_ping_reply() \ 191 .must_next() 192 193 # Step 4 - SED_1 sends a Single Probe Link Metric for RSSI using MLE Data Request 194 # MLE Data Request Payload: 195 # - TLV Request TLV (Link Metrics Report TLV specified) 196 # - Link Metrics Query TLV 197 # -- Link Metrics Query ID Sub-TLV 198 # --- Query ID = 0 (Single Probe Query) 199 # -- Link Metrics Query Options Sub-TLV 200 # --- Metric Type ID Flags 201 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 202 # ---- Metric Enum = 3 (RSSI) 203 # 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. 204 pkts.filter_wpan_src64(SED_1) \ 205 .filter_wpan_dst64(LEADER) \ 206 .filter_mle_cmd(consts.MLE_DATA_REQUEST) \ 207 .filter_mle_has_tlv(consts.TLV_REQUEST_TLV) \ 208 .filter_mle_has_tlv(consts.LINK_METRICS_QUERY_TLV) \ 209 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_ID in p.mle.tlv.link_sub_tlv) \ 210 .filter(lambda p: p.mle.tlv.query_id == 0) \ 211 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_OPTIONS in p.mle.tlv.link_sub_tlv) \ 212 .must_next() 213 214 # Step 5 The DUT MUST reply to SED_1 with MLE Data Response with the following: 215 # - Link Metrics Report TLV 216 # -- Link Metrics Report Sub-TLV 217 # --- Metric Type ID Flags 218 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 219 # ---- Metric Enum = 3 (RSSI) 220 # --- RSSI Value (1-byte) 221 pkts.filter_wpan_src64(LEADER) \ 222 .filter_wpan_dst64(SED_1) \ 223 .filter_mle_cmd(consts.MLE_DATA_RESPONSE) \ 224 .filter_mle_has_tlv(consts.LINK_METRICS_REPORT_TLV) \ 225 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \ 226 .filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \ 227 .filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_RSSI in p.mle.tlv.metric_type_id_flags.metric) \ 228 .must_next() 229 230 # Step 6 - SED_1 sends a Single Probe Link Metric for RSSI using MLE Data Request 231 # MLE Data Request Payload: 232 # - TLV Request TLV (Link Metrics Report TLV specified) 233 # - Link Metrics Query TLV 234 # -- Link Metrics Query ID Sub-TLV 235 # --- Query ID = 0 (Single Probe Query) 236 # -- Link Metrics Query Options Sub-TLV 237 # --- Metric Type ID Flags 238 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 239 # ---- Metric Enum = 3 (RSSI) 240 pkts.filter_wpan_src64(SED_1) \ 241 .filter_wpan_dst64(LEADER) \ 242 .filter_mle_cmd(consts.MLE_DATA_REQUEST) \ 243 .filter_mle_has_tlv(consts.TLV_REQUEST_TLV) \ 244 .filter_mle_has_tlv(consts.LINK_METRICS_QUERY_TLV) \ 245 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_ID in p.mle.tlv.link_sub_tlv) \ 246 .filter(lambda p: p.mle.tlv.query_id == 0) \ 247 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_OPTIONS in p.mle.tlv.link_sub_tlv) \ 248 .must_next() 249 250 # Step 7 The DUT MUST reply to SED_1 with MLE Data Response with the following: 251 # - Link Metrics Report TLV 252 # -- Link Metrics Report Sub-TLV 253 # --- Metric Type ID Flags 254 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 255 # ---- Metric Enum = 3 (RSSI) 256 # --- RSSI Value (1-byte) 257 pkts.filter_wpan_src64(LEADER) \ 258 .filter_wpan_dst64(SED_1) \ 259 .filter_mle_cmd(consts.MLE_DATA_RESPONSE) \ 260 .filter_mle_has_tlv(consts.LINK_METRICS_REPORT_TLV) \ 261 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \ 262 .filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \ 263 .filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_RSSI in p.mle.tlv.metric_type_id_flags.metric) \ 264 .must_next() 265 266 # Step 9 - SSED_1 sends a Single Probe Link Metric for Layer 2 LQI using MLE Data Request 267 # MLE Data Request Payload: 268 # - TLV Request TLV (Link Metrics Report TLV specified) 269 # - Link Metrics Query TLV 270 # -- Link Metrics Query ID Sub-TLV 271 # --- Query ID = 0 (Single Probe Query) 272 # -- Link Metrics Query Options Sub-TLV 273 # --- Metric Type ID Flags 274 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 275 # ---- Metric Enum = 1 (Layer 2 LQI) 276 pkts.filter_wpan_src64(SSED_1) \ 277 .filter_wpan_dst64(LEADER) \ 278 .filter_mle_cmd(consts.MLE_DATA_REQUEST) \ 279 .filter_mle_has_tlv(consts.TLV_REQUEST_TLV) \ 280 .filter_mle_has_tlv(consts.LINK_METRICS_QUERY_TLV) \ 281 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_ID in p.mle.tlv.link_sub_tlv) \ 282 .filter(lambda p: p.mle.tlv.query_id == 0) \ 283 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_OPTIONS in p.mle.tlv.link_sub_tlv) \ 284 .must_next() 285 286 # Step 10 The DUT MUST reply to SSED_1 with MLE Data Response with the following: 287 # - Link Metrics Report TLV 288 # -- Link Metrics Report Sub-TLV 289 # --- Metric Type ID Flags 290 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 291 # ---- Metric Enum = 1 (Layer 2 LQI) 292 # --- Layer 2 LQI value (1-byte) 293 pkts.filter_wpan_src64(LEADER) \ 294 .filter_wpan_dst64(SSED_1) \ 295 .filter_mle_cmd(consts.MLE_DATA_RESPONSE) \ 296 .filter_mle_has_tlv(consts.LINK_METRICS_REPORT_TLV) \ 297 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \ 298 .filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \ 299 .filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_LQI in p.mle.tlv.metric_type_id_flags.metric) \ 300 .must_next() 301 302 # Step 11 - SSED_1 sends a Single Probe Link Metric for Link Margin using MLE Data Request 303 # MLE Data Request Payload: 304 # - TLV Request TLV (Link Metrics Report TLV specified) 305 # - Link Metrics Query TLV 306 # -- Link Metrics Query ID Sub-TLV 307 # --- Query ID = 0 (Single Probe Query) 308 # -- Link Metrics Query Options Sub-TLV 309 # --- Metric Type ID Flags 310 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 311 # ---- Metric Enum = 2 (Link Margin) 312 pkts.filter_wpan_src64(SSED_1) \ 313 .filter_wpan_dst64(LEADER) \ 314 .filter_mle_cmd(consts.MLE_DATA_REQUEST) \ 315 .filter_mle_has_tlv(consts.TLV_REQUEST_TLV) \ 316 .filter_mle_has_tlv(consts.LINK_METRICS_QUERY_TLV) \ 317 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_ID in p.mle.tlv.link_sub_tlv) \ 318 .filter(lambda p: p.mle.tlv.query_id == 0) \ 319 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_OPTIONS in p.mle.tlv.link_sub_tlv) \ 320 .must_next() 321 322 # Step 12 The DUT MUST reply to SSED_1 with MLE Data Response with the following: 323 # - Link Metrics Report TLV 324 # -- Link Metrics Report Sub-TLV 325 # --- Metric Type ID Flags 326 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 327 # ---- Metric Enum = 2 (Link Margin) 328 # --- Link Margin value (1-byte) 329 pkts.filter_wpan_src64(LEADER) \ 330 .filter_wpan_dst64(SSED_1) \ 331 .filter_mle_cmd(consts.MLE_DATA_RESPONSE) \ 332 .filter_mle_has_tlv(consts.LINK_METRICS_REPORT_TLV) \ 333 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \ 334 .filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \ 335 .filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_LINK_MARGIN in p.mle.tlv.metric_type_id_flags.metric) \ 336 .must_next() 337 338 # Step 13 - SSED_1 sends a Single Probe Link Metric using MLE Data Request 339 # MLE Data Request Payload: 340 # - TLV Request TLV (Link Metrics Report TLV specified) 341 # - Link Metrics Query TLV 342 # -- Link Metrics Query ID Sub-TLV 343 # --- Query ID = 0 (Single Probe Query) 344 # -- Link Metrics Query Options Sub-TLV 345 # --- Metric Type ID Flags 346 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 347 # ---- Metric Enum = 1 (Layer 2 LQI) 348 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 349 # ---- Metric Enum = 2 (Link Margin) 350 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 351 # ---- Metric Enum = 3 (RSSI) 352 pkts.filter_wpan_src64(SSED_1) \ 353 .filter_wpan_dst64(LEADER) \ 354 .filter_mle_cmd(consts.MLE_DATA_REQUEST) \ 355 .filter_mle_has_tlv(consts.TLV_REQUEST_TLV) \ 356 .filter_mle_has_tlv(consts.LINK_METRICS_QUERY_TLV) \ 357 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_ID in p.mle.tlv.link_sub_tlv) \ 358 .filter(lambda p: p.mle.tlv.query_id == 0) \ 359 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_QUERY_OPTIONS in p.mle.tlv.link_sub_tlv) \ 360 .must_next() 361 362 # Step 14 The DUT MUST reply to SSED_1 with MLE Data Response with the following: 363 # - Link Metrics Report TLV 364 # -- Link Metrics Report Sub-TLV 365 # --- Metric Type ID Flags 366 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 367 # ---- Metric Enum = 1 (Layer 2 LQI) 368 # ---- Layer 2 LQI value (1-byte) 369 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 370 # ---- Metric Enum = 2 (Link Margin) 371 # ---- Link Margin value (1-byte) 372 # ---- Type / Average Enum = 1 (Exponential Moving Avg) 373 # ---- Metric Enum = 3 (RSSI) 374 # ---- RSSI value (1-byte) 375 pkts.filter_wpan_src64(LEADER) \ 376 .filter_wpan_dst64(SSED_1) \ 377 .filter_mle_cmd(consts.MLE_DATA_RESPONSE) \ 378 .filter_mle_has_tlv(consts.LINK_METRICS_REPORT_TLV) \ 379 .filter(lambda p: LinkMetricsSubTlvType.LINK_METRICS_REPORT in p.mle.tlv.link_sub_tlv) \ 380 .filter(lambda p: consts.LINK_METRICS_TYPE_AVERAGE_ENUM_EXPONENTIAL in p.mle.tlv.metric_type_id_flags.type) \ 381 .filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_LQI in p.mle.tlv.metric_type_id_flags.metric) \ 382 .filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_LINK_MARGIN in p.mle.tlv.metric_type_id_flags.metric) \ 383 .filter(lambda p: consts.LINK_METRICS_METRIC_TYPE_ENUM_RSSI in p.mle.tlv.metric_type_id_flags.metric) \ 384 .must_next() 385 386 387if __name__ == '__main__': 388 unittest.main() 389