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 command 33import config 34import thread_cert 35from pktverify.consts import MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, ADDR_QRY_URI, ADDR_NTF_URI, NL_ML_EID_TLV, NL_RLOC16_TLV, NL_TARGET_EID_TLV, COAP_CODE_POST 36from pktverify.packet_verifier import PacketVerifier 37 38LEADER = 1 39DUT_ROUTER1 = 2 40SED1 = 3 41MED1 = 4 42MED2 = 5 43MED3 = 6 44MED4 = 7 45 46MTDS = [SED1, MED1, MED2, MED3, MED4] 47 48# Test Purpose and Description: 49# ----------------------------- 50# The purpose of this test case is to validate that the DUT is able to 51# maintain an EID-to-RLOC Map Cache for a Sleepy End Device child attached to 52# it. Each EID-to-RLOC Set MUST support at least four non-link-local unicast 53# IPv6 addresses. 54# 55# Test Topology: 56# ------------- 57# Router_1 - Leader 58# | / \ 59# SED MED_1 .. MED_4 60# 61# DUT Types: 62# ---------- 63# Router 64 65 66class Cert_5_3_4_AddressMapCache(thread_cert.TestCase): 67 USE_MESSAGE_FACTORY = False 68 69 TOPOLOGY = { 70 LEADER: { 71 'name': 'LEADER', 72 'mode': 'rdn', 73 'allowlist': [DUT_ROUTER1, MED1, MED2, MED3, MED4] 74 }, 75 DUT_ROUTER1: { 76 'name': 'ROUTER', 77 'mode': 'rdn', 78 'allowlist': [LEADER, SED1] 79 }, 80 SED1: { 81 'name': 'SED', 82 'is_mtd': True, 83 'mode': '-', 84 'timeout': 5, 85 'allowlist': [DUT_ROUTER1] 86 }, 87 MED1: { 88 'name': 'MED_1', 89 'is_mtd': True, 90 'mode': 'rn', 91 'allowlist': [LEADER] 92 }, 93 MED2: { 94 'name': 'MED_2', 95 'is_mtd': True, 96 'mode': 'rn', 97 'allowlist': [LEADER] 98 }, 99 MED3: { 100 'name': 'MED_3', 101 'is_mtd': True, 102 'mode': 'rn', 103 'allowlist': [LEADER] 104 }, 105 MED4: { 106 'name': 'MED_4', 107 'is_mtd': True, 108 'mode': 'rn', 109 'allowlist': [LEADER] 110 }, 111 } 112 113 def test(self): 114 # 1 115 self.nodes[LEADER].start() 116 self.simulator.go(config.LEADER_STARTUP_DELAY) 117 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 118 119 self.nodes[DUT_ROUTER1].start() 120 self.simulator.go(config.ROUTER_STARTUP_DELAY) 121 self.assertEqual(self.nodes[DUT_ROUTER1].get_state(), 'router') 122 123 for i in MTDS: 124 self.nodes[i].start() 125 self.simulator.go(5) 126 127 for i in MTDS: 128 self.assertEqual(self.nodes[i].get_state(), 'child') 129 130 self.collect_ipaddrs() 131 self.collect_rlocs() 132 self.collect_rloc16s() 133 134 # 2 135 for MED in [MED1, MED2, MED3, MED4]: 136 ed_mleid = self.nodes[MED].get_ip6_address(config.ADDRESS_TYPE.ML_EID) 137 self.assertTrue(self.nodes[SED1].ping(ed_mleid)) 138 self.simulator.go(5) 139 140 # 3 & 4 141 for MED in [MED1, MED2, MED3, MED4]: 142 ed_mleid = self.nodes[MED].get_ip6_address(config.ADDRESS_TYPE.ML_EID) 143 self.assertTrue(self.nodes[SED1].ping(ed_mleid)) 144 self.simulator.go(5) 145 146 def verify(self, pv): 147 pkts = pv.pkts 148 pv.summary.show() 149 150 LEADER = pv.vars['LEADER'] 151 LEADER_RLOC16 = pv.vars['LEADER_RLOC16'] 152 ROUTER = pv.vars['ROUTER'] 153 ROUTER_RLOC = pv.vars['ROUTER_RLOC'] 154 SED = pv.vars['SED'] 155 SED_RLOC = pv.vars['SED_RLOC'] 156 SED_RLOC16 = pv.vars['SED_RLOC16'] 157 SED_MLEID = pv.vars['SED_MLEID'] 158 MM = pv.vars['MM_PORT'] 159 160 # Step 1: Build the topology as described 161 pv.verify_attached('ROUTER') 162 for i in range(1, 5): 163 with pkts.save_index(): 164 pkts.filter_wpan_src64(pv.vars['MED_%d' %i]).\ 165 filter_wpan_dst64(LEADER).\ 166 filter_mle_cmd(MLE_CHILD_ID_REQUEST).\ 167 must_next() 168 pkts.filter_wpan_src64(LEADER).\ 169 filter_wpan_dst64(pv.vars['MED_%d' %i]).\ 170 filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\ 171 must_next() 172 pkts.filter_wpan_src64(pv.vars['SED']).\ 173 filter_wpan_dst64(ROUTER).\ 174 filter_mle_cmd(MLE_CHILD_ID_REQUEST).\ 175 must_next() 176 pkts.filter_wpan_src64(ROUTER).\ 177 filter_wpan_dst64(pv.vars['SED']).\ 178 filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\ 179 must_next() 180 181 # Step 2: SED sends an ICMPv6 Echo Request to MED_1, MED_2, MED_3, MED_4 ML-EID 182 # The DUT MUST generate an Address Query Request on SED’s behalf 183 # to find each node’s RLOC. 184 # The Address Query Request MUST be sent to the Realm-Local 185 # All-Routers address (FF03::2) 186 # CoAP URI-Path 187 # - NON POST coap://<FF03::2> 188 # CoAP Payload 189 # - Target EID TLV 190 191 # Step 3: Leader sends Address Notification Messages with RLOC of MED_1, MED_2, MED_3, MED_4 192 for i in range(1, 5): 193 _pkt = pkts.filter_ping_request().\ 194 filter_wpan_src64(SED).\ 195 filter_ipv6_dst(pv.vars['MED_%d_MLEID' %i]).\ 196 must_next() 197 pkts.filter_wpan_src64(ROUTER).\ 198 filter_RLARMA().\ 199 filter_coap_request(ADDR_QRY_URI, port=MM).\ 200 filter(lambda p: p.thread_address.tlv.target_eid == pv.vars['MED_%d_MLEID' %i]).\ 201 must_next() 202 pkts.filter_wpan_src64(LEADER).\ 203 filter_ipv6_dst(ROUTER_RLOC).\ 204 filter_coap_request(ADDR_NTF_URI, port=MM).\ 205 filter(lambda p: { 206 NL_ML_EID_TLV, 207 NL_RLOC16_TLV, 208 NL_TARGET_EID_TLV 209 } <= set(p.coap.tlv.type) and\ 210 p.thread_address.tlv.target_eid == pv.vars['MED_%d_MLEID' %i] and\ 211 p.thread_address.tlv.rloc16 == LEADER_RLOC16 and\ 212 p.coap.code == COAP_CODE_POST 213 ).\ 214 must_next() 215 pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\ 216 filter_wpan_src64(ROUTER).\ 217 filter_ipv6_dst(pv.vars['MED_%d_MLEID' %i]).\ 218 must_next() 219 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 220 filter_wpan_src64(pv.vars['MED_%d' %i]).\ 221 filter_ipv6_dst(SED_MLEID).\ 222 must_next() 223 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 224 filter_wpan_src64(ROUTER).\ 225 filter_wpan_dst16(SED_RLOC16).\ 226 must_next() 227 228 # Step 4: SED sends another ICMPv6 Echo Request to MED_1, MED_2, MED_3, MED_4 ML-EID 229 # The DUT MUST not send an Address Query during this step; If an address query 230 # message is sent, the test fails 231 # An ICMPv6 Echo Reply MUST be sent for each ICMPv6 Echo Request from SED 232 for i in range(1, 5): 233 _pkt = pkts.filter_ping_request().\ 234 filter_wpan_src64(SED).\ 235 filter_ipv6_dst(pv.vars['MED_%d_MLEID' %i]).\ 236 must_next() 237 pkts.filter_wpan_src64(ROUTER).\ 238 filter_RLARMA().\ 239 filter_coap_request(ADDR_QRY_URI, port=MM).\ 240 must_not_next() 241 pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\ 242 filter_wpan_src64(ROUTER).\ 243 filter_ipv6_dst(pv.vars['MED_%d_MLEID' %i]).\ 244 must_next() 245 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 246 filter_wpan_src64(pv.vars['MED_%d' %i]).\ 247 filter_ipv6_dst(SED_MLEID).\ 248 must_next() 249 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 250 filter_wpan_src64(ROUTER).\ 251 filter_wpan_dst16(SED_RLOC16).\ 252 must_next() 253 254 255if __name__ == '__main__': 256 unittest.main() 257