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 mle 34import network_layer 35import thread_cert 36from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, MLE_LINK_REQUEST, MLE_LINK_ACCEPT_AND_REQUEST, ADDR_SOL_URI, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, TLV_REQUEST_TLV, SCAN_MASK_TLV, CONNECTIVITY_TLV, LINK_MARGIN_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV, NL_MAC_EXTENDED_ADDRESS_TLV, NL_RLOC16_TLV, NL_STATUS_TLV, NL_ROUTER_MASK_TLV, COAP_CODE_ACK 37from pktverify.packet_verifier import PacketVerifier 38from pktverify.null_field import nullField 39 40LEADER = 1 41ROUTER = 2 42 43# Test Purpose and Description: 44# ----------------------------- 45# The purpose of this test case is to show that the Leader is able to form 46# a network and the Router attaches to it with proper steps. 47# 48# Test Topology: 49# ------------- 50# Leader 51# | 52# Router 53# 54# DUT Types: 55# ---------- 56# Leader 57# Router 58 59 60class Cert_5_1_01_RouterAttach(thread_cert.TestCase): 61 USE_MESSAGE_FACTORY = False 62 63 TOPOLOGY = { 64 LEADER: { 65 'name': 'LEADER', 66 'mode': 'rdn', 67 'allowlist': [ROUTER] 68 }, 69 ROUTER: { 70 'name': 'ROUTER', 71 'mode': 'rdn', 72 'allowlist': [LEADER] 73 }, 74 } 75 76 def test(self): 77 self.nodes[LEADER].start() 78 self.simulator.go(config.LEADER_STARTUP_DELAY) 79 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 80 81 self.nodes[ROUTER].start() 82 self.simulator.go(config.ROUTER_STARTUP_DELAY) 83 self.assertEqual(self.nodes[ROUTER].get_state(), 'router') 84 85 self.collect_rloc16s() 86 87 leader_addr = self.nodes[LEADER].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL) 88 self.assertTrue(self.nodes[ROUTER].ping(leader_addr)) 89 self.simulator.go(5) 90 91 router_addr = self.nodes[ROUTER].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL) 92 self.assertTrue(self.nodes[LEADER].ping(router_addr)) 93 94 def verify(self, pv): 95 pkts = pv.pkts 96 pv.summary.show() 97 98 LEADER = pv.vars['LEADER'] 99 LEADER_RLOC16 = pv.vars['LEADER_RLOC16'] 100 ROUTER = pv.vars['ROUTER'] 101 102 # Step 1: Leader is sending properly formatted MLE Advertisements. 103 # Advertisements MUST be sent with an IP hop limit of 255 to 104 # the Link-Local All Nodes multicast address (FF02::1). 105 # The following TLVs MUST be present in the MLE Advertisements: 106 # - Leader Data TLV 107 # - Route64 TLV 108 # - Source Address TLV 109 110 pkts.filter_wpan_src64(LEADER).\ 111 filter_LLANMA().\ 112 filter_mle_cmd(MLE_ADVERTISEMENT).\ 113 filter(lambda p: { 114 LEADER_DATA_TLV, 115 ROUTE64_TLV, 116 SOURCE_ADDRESS_TLV 117 } <= set(p.mle.tlv.type) and\ 118 p.ipv6.hlim == 255).\ 119 must_next() 120 121 # Step 2: Router sends a MLE Parent Request with an IP hop limit of 122 # 255 to the Link-Local All Routers multicast address (FF02::2). 123 # The following TLVs MUST be present in the MLE Parent Request: 124 # - Challenge TLV 125 # - Mode TLV 126 # - Scan Mask TLV 127 # If the DUT sends multiple MLE Parent Requests 128 # - The first one MUST be sent only to all Routers 129 # - Subsequent ones MAY be sent to all Routers and REEDS 130 # - Version TLV 131 # If the first MLE Parent Request was sent to all Routers and 132 # REEDS, the test fails. 133 134 pkts.filter_wpan_src64(ROUTER).\ 135 filter_LLARMA().\ 136 filter_mle_cmd(MLE_PARENT_REQUEST).\ 137 filter(lambda p: { 138 CHALLENGE_TLV, 139 MODE_TLV, 140 SCAN_MASK_TLV, 141 VERSION_TLV 142 } <= set(p.mle.tlv.type) and\ 143 p.ipv6.hlim == 255 and\ 144 p.mle.tlv.scan_mask.r == 1 and\ 145 p.mle.tlv.scan_mask.e == 0).\ 146 must_next() 147 148 # Step 3: Leader responds with a MLE Parent Response. 149 # The following TLVs MUST be present in the MLE Parent Response: 150 # - Challenge TLV 151 # - Connectivity TLV 152 # - Leader Data TLV 153 # - Link-layer Frame Counter TLV 154 # - Link Margin TLV 155 # - Response TLV 156 # - Source Address 157 # - Version TLV 158 # - MLE Frame Counter TLV (optional) 159 160 pkts.filter_wpan_src64(LEADER).\ 161 filter_wpan_dst64(ROUTER).\ 162 filter_mle_cmd(MLE_PARENT_RESPONSE).\ 163 filter(lambda p: { 164 CHALLENGE_TLV, 165 CONNECTIVITY_TLV, 166 LEADER_DATA_TLV, 167 LINK_LAYER_FRAME_COUNTER_TLV, 168 LINK_MARGIN_TLV, 169 RESPONSE_TLV, 170 SOURCE_ADDRESS_TLV, 171 VERSION_TLV 172 } <= set(p.mle.tlv.type)).\ 173 must_next() 174 175 # Step 4: Router sends a MLE Child ID Request. 176 # The following TLVs MUST be present in the MLE Child ID Request: 177 # - Link-layer Frame Counter TLV 178 # - Mode TLV 179 # - Response TLV 180 # - Timeout TLV 181 # - TLV Request TLV 182 # - Address16 TLV 183 # - Network Data TLV 184 # - Route64 TLV (optional) 185 # - Version TLV 186 # - MLE Frame Counter TLV (optional) 187 # The following TLV MUST NOT be present in the MLE Child ID Request: 188 # - Address Registration TLV 189 190 _pkt = pkts.filter_wpan_src64(ROUTER).\ 191 filter_wpan_dst64(LEADER).\ 192 filter_mle_cmd(MLE_CHILD_ID_REQUEST).\ 193 filter(lambda p: { 194 LINK_LAYER_FRAME_COUNTER_TLV, 195 MODE_TLV, 196 RESPONSE_TLV, 197 TIMEOUT_TLV, 198 TLV_REQUEST_TLV, 199 ADDRESS16_TLV, 200 NETWORK_DATA_TLV, 201 VERSION_TLV 202 } <= set(p.mle.tlv.type) and\ 203 p.mle.tlv.addr16 is nullField and\ 204 p.thread_nwd.tlv.type is nullField).\ 205 must_next() 206 _pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type) 207 208 # Step 5: Leader responds with a Child ID Response. 209 # The following TLVs MUST be present in the Child ID Response: 210 # - Address16 TLV 211 # - Leader Data TLV 212 # - Network Data TLV 213 # - Source Address TLV 214 # - Route64 TLV (if requested) 215 216 pkts.filter_wpan_src64(LEADER).\ 217 filter_wpan_dst64(ROUTER).\ 218 filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\ 219 filter(lambda p: { 220 ADDRESS16_TLV, 221 LEADER_DATA_TLV, 222 NETWORK_DATA_TLV, 223 SOURCE_ADDRESS_TLV, 224 ROUTE64_TLV 225 } <= set(p.mle.tlv.type) or\ 226 { 227 ADDRESS16_TLV, 228 LEADER_DATA_TLV, 229 NETWORK_DATA_TLV, 230 SOURCE_ADDRESS_TLV 231 } <= set(p.mle.tlv.type)).\ 232 must_next() 233 234 # Step 6: Router sends an Address Solicit Request. 235 # Ensure the Address Solicit Request is properly formatted: 236 # CoAP Request URI 237 # coap://<leader address>:MM/a/as 238 # CoAP Payload 239 # - MAC Extended Address TLV 240 # - Status TLV 241 242 _pkt = pkts.filter_wpan_src64(ROUTER).\ 243 filter_wpan_dst16(LEADER_RLOC16).\ 244 filter_coap_request(ADDR_SOL_URI).\ 245 filter(lambda p: { 246 NL_MAC_EXTENDED_ADDRESS_TLV, 247 NL_STATUS_TLV 248 } == set(p.coap.tlv.type)\ 249 ).\ 250 must_next() 251 252 # Step 7: Leader sends an Address Solicit Response. 253 # Ensure the Address Solicit Response is properly formatted: 254 # CoAP Response Code 255 # 2.04 Changed 256 # CoAP Payload 257 # - Status TLV (value = Success) 258 # - RLOC16 TLV 259 # - Router Mask TLV 260 261 pkts.filter_wpan_src64(LEADER).\ 262 filter_wpan_dst16(_pkt.wpan.src16).\ 263 filter_coap_ack(ADDR_SOL_URI).\ 264 filter(lambda p: { 265 NL_STATUS_TLV, 266 NL_RLOC16_TLV, 267 NL_ROUTER_MASK_TLV 268 } == set(p.coap.tlv.type) and\ 269 p.coap.code == COAP_CODE_ACK and\ 270 p.thread_address.tlv.status == 0\ 271 ).\ 272 must_next() 273 274 # Steps 8 and 9 are skipped due to change the Link establishment 275 # process (no multicast MLE Link Request by new router). 276 277 # Step 10: Router is sending properly formatted MLE Advertisements. 278 # MLE Advertisements MUST be sent with an IP Hop Limit of 279 # 255 to the Link-Local All Nodes multicast address (FF02::1). 280 # The following TLVs MUST be present in the MLE Advertisements: 281 # - Leader Data TLV 282 # - Route64 TLV 283 # - Source Address TLV 284 285 pkts.filter_wpan_src64(LEADER).\ 286 filter_LLANMA().\ 287 filter_mle_cmd(MLE_ADVERTISEMENT).\ 288 filter(lambda p: { 289 LEADER_DATA_TLV, 290 ROUTE64_TLV, 291 SOURCE_ADDRESS_TLV 292 } == set(p.mle.tlv.type) and\ 293 p.ipv6.hlim == 255).\ 294 must_next() 295 296 # Step 11: DUT responds with ICMPv6 Echo Reply 297 298 _pkt = pkts.filter_ping_request().\ 299 filter_wpan_src64(ROUTER).\ 300 filter_wpan_dst64(LEADER).\ 301 must_next() 302 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 303 filter_wpan_src64(LEADER).\ 304 filter_wpan_dst64(ROUTER).\ 305 must_next() 306 307 _pkt = pkts.filter_ping_request().\ 308 filter_wpan_src64(LEADER).\ 309 filter_wpan_dst64(ROUTER).\ 310 must_next() 311 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 312 filter_wpan_src64(ROUTER).\ 313 filter_wpan_dst64(LEADER).\ 314 must_next() 315 316 317if __name__ == '__main__': 318 unittest.main() 319