1#!/usr/bin/env python3 2# 3# Copyright (c) 2016, 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 32import config 33import thread_cert 34from pktverify.consts import MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, REALM_LOCAL_ALL_NODES_ADDRESS, REALM_LOCAL_ALL_ROUTERS_ADDRESS, REALM_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS 35from pktverify.packet_verifier import PacketVerifier 36 37LEADER = 1 38ROUTER1 = 2 39DUT_ROUTER2 = 3 40SED1 = 4 41FRAGMENTED_DATA_LEN = 256 42 43# Test Purpose and Description: 44# ----------------------------- 45# The purpose of this test case is to validate the Realm-Local addresses 46# that the DUT auto-configures. 47# 48# Test Topology: 49# ------------- 50# Leader 51# | 52# Router_1 - Router_2(DUT) 53# | 54# SED 55# 56# DUT Types: 57# ---------- 58# Router 59 60 61class Cert_5_3_2_RealmLocal(thread_cert.TestCase): 62 USE_MESSAGE_FACTORY = False 63 64 TOPOLOGY = { 65 LEADER: { 66 'name': 'LEADER', 67 'mode': 'rdn', 68 'allowlist': [ROUTER1] 69 }, 70 ROUTER1: { 71 'name': 'ROUTER_1', 72 'mode': 'rdn', 73 'allowlist': [LEADER, DUT_ROUTER2] 74 }, 75 DUT_ROUTER2: { 76 'name': 'ROUTER_2', 77 'mode': 'rdn', 78 'allowlist': [ROUTER1, SED1] 79 }, 80 SED1: { 81 'name': 'SED', 82 'is_mtd': True, 83 'mode': 'n', 84 'timeout': config.DEFAULT_CHILD_TIMEOUT, 85 'allowlist': [DUT_ROUTER2] 86 }, 87 } 88 89 def test(self): 90 # 1 91 self.nodes[LEADER].start() 92 self.simulator.go(config.LEADER_STARTUP_DELAY) 93 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 94 95 self.nodes[ROUTER1].start() 96 self.simulator.go(config.ROUTER_STARTUP_DELAY) 97 self.assertEqual(self.nodes[ROUTER1].get_state(), 'router') 98 99 self.nodes[DUT_ROUTER2].start() 100 self.simulator.go(config.ROUTER_STARTUP_DELAY) 101 self.assertEqual(self.nodes[DUT_ROUTER2].get_state(), 'router') 102 103 self.nodes[SED1].start() 104 self.simulator.go(5) 105 self.assertEqual(self.nodes[SED1].get_state(), 'child') 106 107 self.collect_ipaddrs() 108 self.collect_rloc16s() 109 110 # 2 & 3 111 mleid = self.nodes[DUT_ROUTER2].get_ip6_address(config.ADDRESS_TYPE.ML_EID) 112 self.assertTrue(self.nodes[LEADER].ping(mleid, size=FRAGMENTED_DATA_LEN)) 113 self.simulator.go(2) 114 self.assertTrue(self.nodes[LEADER].ping(mleid)) 115 self.simulator.go(2) 116 117 # 4 & 5 118 self.assertTrue(self.nodes[LEADER].ping('ff03::1', num_responses=2, size=FRAGMENTED_DATA_LEN)) 119 self.simulator.go(5) 120 self.assertTrue(self.nodes[LEADER].ping('ff03::1', num_responses=2)) 121 self.simulator.go(5) 122 123 # 6 & 7 124 self.assertTrue(self.nodes[LEADER].ping('ff03::2', num_responses=2, size=FRAGMENTED_DATA_LEN)) 125 self.simulator.go(5) 126 self.assertTrue(self.nodes[LEADER].ping('ff03::2', num_responses=2)) 127 self.simulator.go(5) 128 129 # 8 130 self.assertTrue(self.nodes[LEADER].ping( 131 config.REALM_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS, 132 num_responses=3, 133 size=FRAGMENTED_DATA_LEN, 134 )) 135 self.simulator.go(5) 136 137 def verify(self, pv): 138 pkts = pv.pkts 139 pv.summary.show() 140 141 LEADER = pv.vars['LEADER'] 142 LEADER_MLEID = pv.vars['LEADER_MLEID'] 143 ROUTER_1 = pv.vars['ROUTER_1'] 144 ROUTER_2 = pv.vars['ROUTER_2'] 145 ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16'] 146 ROUTER_2_MLEID = pv.vars['ROUTER_2_MLEID'] 147 SED = pv.vars['SED'] 148 SED_RLOC16 = pv.vars['SED_RLOC16'] 149 150 # Step 1: Build the topology as described 151 pv.verify_attached('ROUTER_1', 'LEADER') 152 pv.verify_attached('ROUTER_2', 'ROUTER_1') 153 pv.verify_attached('SED', 'ROUTER_2', 'MTD') 154 155 # Step 2: Leader sends a Fragmented ICMPv6 Echo Request to 156 # DUT's ML-EID 157 # The DUT MUST respond with an ICMPv6 Echo Reply 158 159 _pkt = pkts.filter_ping_request().\ 160 filter_ipv6_src_dst(LEADER_MLEID, ROUTER_2_MLEID).\ 161 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 162 must_next() 163 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 164 filter_ipv6_src_dst(ROUTER_2_MLEID, LEADER_MLEID).\ 165 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 166 must_next() 167 168 # Step 3: Leader sends a Unfragmented ICMPv6 Echo Request to 169 # DUT’s ML-EID 170 # The DUT MUST respond with an ICMPv6 Echo Reply 171 172 _pkt = pkts.filter_ping_request().\ 173 filter_ipv6_src_dst(LEADER_MLEID, ROUTER_2_MLEID).\ 174 must_next() 175 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 176 filter_ipv6_src_dst(ROUTER_2_MLEID, LEADER_MLEID).\ 177 must_next() 178 179 # Step 4: Leader sends a Fragmented ICMPv6 Echo Request to the 180 # Realm-Local All Nodes multicast address (FF03::1) 181 # The DUT MUST respond with an ICMPv6 Echo Reply 182 # The DUT MUST NOT forward the ICMPv6 Echo Request to SED 183 184 _pkt1 = pkts.filter_ping_request().\ 185 filter_wpan_src64(LEADER).\ 186 filter_ipv6_dst(REALM_LOCAL_ALL_NODES_ADDRESS).\ 187 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 188 must_next() 189 with pkts.save_index(): 190 pkts.filter_ping_reply(identifier=_pkt1.icmpv6.echo.identifier).\ 191 filter_ipv6_src_dst(ROUTER_2_MLEID, LEADER_MLEID).\ 192 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 193 must_next() 194 pkts.filter_ping_request(identifier=_pkt1.icmpv6.echo.identifier).\ 195 filter_wpan_src16_dst16(ROUTER_2_RLOC16, SED_RLOC16).\ 196 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 197 must_not_next() 198 199 # Step 5: Leader sends an Unfragmented ICMPv6 Echo Request to the 200 # Realm-Local All Nodes multicast address (FF03::1) 201 # The DUT MUST respond with an ICMPv6 Echo Reply 202 # The DUT MUST NOT forward the ICMPv6 Echo Request to SED 203 204 _pkt2 = pkts.filter_ping_request().\ 205 filter_wpan_src64(LEADER).\ 206 filter_ipv6_dst(REALM_LOCAL_ALL_NODES_ADDRESS).\ 207 filter(lambda p: p.icmpv6.echo.sequence_number != 208 _pkt1.icmpv6.echo.sequence_number 209 ).\ 210 must_next() 211 with pkts.save_index(): 212 pkts.filter_ping_reply(identifier=_pkt2.icmpv6.echo.identifier).\ 213 filter_ipv6_src_dst(ROUTER_2_MLEID, LEADER_MLEID).\ 214 must_next() 215 pkts.filter_ping_request(identifier = _pkt2.icmpv6.echo.identifier).\ 216 filter_wpan_src16_dst16(ROUTER_2_RLOC16, SED_RLOC16).\ 217 must_not_next() 218 219 # Step 6: Leader sends a Fragmented ICMPv6 Echo Request to the 220 # Realm-Local All Routers multicast address (FF03::2) 221 # The DUT MUST respond with an ICMPv6 Echo Reply 222 # The DUT MUST NOT forward the ICMPv6 Echo Request to SED 223 224 _pkt1 = pkts.filter_ping_request().\ 225 filter_wpan_src64(LEADER).\ 226 filter_ipv6_dst(REALM_LOCAL_ALL_ROUTERS_ADDRESS).\ 227 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 228 must_next() 229 with pkts.save_index(): 230 pkts.filter_ping_reply(identifier=_pkt1.icmpv6.echo.identifier).\ 231 filter_ipv6_src_dst(ROUTER_2_MLEID, LEADER_MLEID).\ 232 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 233 must_next() 234 pkts.filter_ping_request(identifier=_pkt1.icmpv6.echo.identifier).\ 235 filter_wpan_src16_dst16(ROUTER_2_RLOC16, SED_RLOC16).\ 236 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 237 must_not_next() 238 239 # Step 7: Leader sends an Unfragmented ICMPv6 Echo Request to the 240 # Realm-Local All Routers multicast address (FF03::2) 241 # The DUT MUST respond with an ICMPv6 Echo Reply 242 # The DUT MUST NOT forward the ICMPv6 Echo Request to SED 243 244 _pkt2 = pkts.filter_ping_request().\ 245 filter_wpan_src64(LEADER).\ 246 filter_ipv6_dst(REALM_LOCAL_ALL_ROUTERS_ADDRESS).\ 247 filter(lambda p: p.icmpv6.echo.sequence_number != 248 _pkt1.icmpv6.echo.sequence_number 249 ).\ 250 must_next() 251 with pkts.save_index(): 252 pkts.filter_ping_reply(identifier=_pkt2.icmpv6.echo.identifier).\ 253 filter_ipv6_src_dst(ROUTER_2_MLEID, LEADER_MLEID).\ 254 must_next() 255 pkts.filter_ping_request(identifier=_pkt2.icmpv6.echo.identifier).\ 256 filter_wpan_src16_dst16(ROUTER_2_RLOC16, SED_RLOC16).\ 257 must_not_next() 258 259 # Step 8: Leader sends a Fragmented ICMPv6 Echo Request to the 260 # Realm-Local All Thread Nodes multicast address 261 # The DUT MUST respond with an ICMPv6 Echo Reply 262 # The Realm-Local All Thread Nodes multicast address 263 # MUST be a realm-local Unicast Prefix-Based Multicast 264 # Address [RFC 3306], with: 265 # - flgs set to 3 (P = 1 and T = 1) 266 # - scop set to 3 267 # - plen set to the Mesh Local Prefix length 268 # - network prefix set to the Mesh Local Prefix 269 # - group ID set to 1 270 # The DUT MUST use IEEE 802.15.4 indirect transmissions 271 # to forward packet to SED 272 273 _pkt = pkts.filter_ping_request().\ 274 filter_wpan_src64(LEADER).\ 275 filter_ipv6_dst(REALM_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS).\ 276 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 277 must_next() 278 with pkts.save_index(): 279 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 280 filter_ipv6_src_dst(ROUTER_2_MLEID, LEADER_MLEID).\ 281 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 282 must_next() 283 pkts.filter_ping_request(identifier = _pkt.icmpv6.echo.identifier).\ 284 filter_wpan_src16_dst16(ROUTER_2_RLOC16, SED_RLOC16).\ 285 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 286 must_next() 287 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 288 filter_wpan_src64(SED).\ 289 filter_ipv6_dst(LEADER_MLEID).\ 290 filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\ 291 must_next() 292 293 294if __name__ == '__main__': 295 unittest.main() 296