1#!/usr/bin/env python3 2# 3# Copyright (c) 2018, 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 31import copy 32 33import thread_cert 34import config 35from pktverify.consts import WPAN_DATA_REQUEST, WPAN_ACK, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, 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 36from pktverify.packet_verifier import PacketVerifier 37from pktverify.null_field import nullField 38 39LEADER = 1 40REED = 2 41MTD = 3 42 43# Test Purpose and Description: 44# ----------------------------- 45# The purpose of this test case is to validate that the DUT is able to successfully 46# attach to a network as an End Device through a REED. 47# 48# Test Topology: 49# ------------- 50# Leader 51# | 52# REED 53# | 54# DUT 55# 56# DUT Types: 57# ---------- 58# ED 59# SED 60 61 62class Cert_6_1_2_REEDAttach_Base(thread_cert.TestCase): 63 USE_MESSAGE_FACTORY = False 64 65 TOPOLOGY = { 66 LEADER: { 67 'name': 'LEADER', 68 'mode': 'rdn', 69 'allowlist': [REED] 70 }, 71 REED: { 72 'name': 'REED', 73 'mode': 'rdn', 74 'router_upgrade_threshold': 0, 75 'allowlist': [LEADER, MTD] 76 }, 77 MTD: { 78 'name': 'DUT', 79 'is_mtd': True, 80 'timeout': config.DEFAULT_CHILD_TIMEOUT, 81 'allowlist': [REED] 82 }, 83 } 84 85 def test(self): 86 self.nodes[LEADER].start() 87 self.simulator.go(config.LEADER_STARTUP_DELAY) 88 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 89 90 self.nodes[REED].start() 91 self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL) 92 self.assertEqual(self.nodes[REED].get_state(), 'child') 93 self.collect_rloc16s() 94 95 self.nodes[MTD].start() 96 self.simulator.go(5) 97 self.assertEqual(self.nodes[MTD].get_state(), 'child') 98 self.assertEqual(self.nodes[REED].get_state(), 'router') 99 self.collect_ipaddrs() 100 self.collect_rlocs() 101 102 self.simulator.go(config.DEFAULT_CHILD_TIMEOUT) 103 104 dut_addr = self.nodes[MTD].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL) 105 self.assertTrue(self.nodes[REED].ping(dut_addr)) 106 107 def verify(self, pv): 108 pkts = pv.pkts 109 pv.summary.show() 110 111 LEADER = pv.vars['LEADER'] 112 LEADER_RLOC = pv.vars['LEADER_RLOC'] 113 REED = pv.vars['REED'] 114 REED_RLOC = pv.vars['REED_RLOC'] 115 REED_LLA = pv.vars['REED_LLA'] 116 REED_RLOC16 = pv.vars['REED_RLOC16'] 117 DUT = pv.vars['DUT'] 118 DUT_RLOC = pv.vars['DUT_RLOC'] 119 DUT_LLA = pv.vars['DUT_LLA'] 120 121 # Step 1: Ensure the Leader is sending MLE Advertisements and is connected to REED 122 123 pkts.filter_wpan_src64(LEADER).\ 124 filter_mle_advertisement('Leader').\ 125 must_next() 126 127 pv.verify_attached('REED', 'LEADER') 128 129 # Step 2: DUT sends a MLE Parent Request with an IP hop limit of 130 # 255 to the Link-Local All Routers multicast address (FF02::2). 131 # The following TLVs MUST be present in the MLE Parent Request: 132 # - Challenge TLV 133 # - Mode TLV 134 # - Scan Mask TLV 135 # Verify that the first one is sent to routers only 136 # - Version TLV 137 # If the first MLE Parent Request was sent to all Routers and 138 # REEDS, the test fails. 139 # In securing the first three messages of the attaching process, 140 # the full four-byte key sequence number MUST be included in 141 # the Auxiliary Security Header used for MLE security. 142 # 143 # To send the full four-byte key sequence number, the Key 144 # Identifier Mode of the Security Control Field SHALL be set to 145 # ‘0x02’, indicating the presence of a four-byte Key Source, 146 # which SHALL contain the four-byte key sequence number in 147 # network byte order. 148 149 pkts.filter_wpan_src64(DUT).\ 150 filter_LLARMA().\ 151 filter_mle_cmd(MLE_PARENT_REQUEST).\ 152 filter(lambda p: { 153 CHALLENGE_TLV, 154 MODE_TLV, 155 SCAN_MASK_TLV, 156 VERSION_TLV 157 } <= set(p.mle.tlv.type) and\ 158 p.ipv6.hlim == 255 and\ 159 p.mle.tlv.scan_mask.r == 1 and\ 160 p.mle.tlv.scan_mask.e == 0 and\ 161 p.wpan.aux_sec.key_id_mode == 0x2 162 ).\ 163 must_next() 164 index1 = pkts.index 165 166 # Step 4: DUT sends a MLE Parent Request with an IP hop limit of 167 # 255 to the Link-Local All Routers multicast address (FF02::2). 168 # The following TLVs MUST be present in the MLE Parent Request: 169 # - Challenge TLV 170 # - Mode TLV 171 # - Scan Mask TLV 172 # Verify that it is sent to Routers AND REEDs 173 # - Version TLV 174 # If request was not sent to all routers and REEDS, then the test 175 # has failed. 176 # In securing the first three messages of the attaching process, 177 # the full four-byte key sequence number MUST be included in 178 # the Auxiliary Security Header used for MLE security. 179 # To send the full four-byte key sequence number, the Key 180 # Identifier Mode of the Security Control Field SHALL be set to 181 # ‘0x02’, indicating the presence of a four-byte Key Source, 182 # which SHALL contain the four-byte key sequence number in 183 # network byte order. 184 185 pkts.filter_wpan_src64(DUT).\ 186 filter_LLARMA().\ 187 filter_mle_cmd(MLE_PARENT_REQUEST).\ 188 filter(lambda p: { 189 CHALLENGE_TLV, 190 MODE_TLV, 191 SCAN_MASK_TLV, 192 VERSION_TLV 193 } <= set(p.mle.tlv.type) and\ 194 p.ipv6.hlim == 255 and\ 195 p.mle.tlv.scan_mask.r == 1 and\ 196 p.mle.tlv.scan_mask.e == 1 and\ 197 p.wpan.aux_sec.key_id_mode == 0x2 198 ).\ 199 must_next() 200 index2 = pkts.index 201 202 # Step 3: REED doesn't response to the first Parent Request 203 204 pkts.range(index1, index2).\ 205 filter_wpan_src64(REED).\ 206 filter_wpan_dst64(DUT).\ 207 filter_mle_cmd(MLE_PARENT_RESPONSE).\ 208 must_not_next() 209 210 # Step 5: REED responds with MLE Parent Response for the second Parent Request 211 212 pkts.filter_wpan_src64(REED).\ 213 filter_wpan_dst64(DUT).\ 214 filter_mle_cmd(MLE_PARENT_RESPONSE).\ 215 filter(lambda p: { 216 CHALLENGE_TLV, 217 CONNECTIVITY_TLV, 218 LEADER_DATA_TLV, 219 LINK_LAYER_FRAME_COUNTER_TLV, 220 LINK_MARGIN_TLV, 221 RESPONSE_TLV, 222 SOURCE_ADDRESS_TLV, 223 VERSION_TLV 224 } <= set(p.mle.tlv.type)).\ 225 must_next() 226 227 # Step 6: DUT sends a MLE Child ID Request. 228 # The following TLVs MUST be present in the MLE Child ID Request: 229 # - Address Registration TLV 230 # - Link-layer Frame Counter TLV 231 # - Mode TLV 232 # - Response TLV 233 # - Timeout TLV 234 # - TLV Request TLV 235 # - Version TLV 236 # - MLE Frame Counter TLV (optional) 237 238 pkts.filter_wpan_src64(DUT).\ 239 filter_wpan_dst64(REED).\ 240 filter_mle_cmd(MLE_CHILD_ID_REQUEST).\ 241 filter(lambda p: { 242 ADDRESS_REGISTRATION_TLV, 243 LINK_LAYER_FRAME_COUNTER_TLV, 244 MODE_TLV, 245 RESPONSE_TLV, 246 TIMEOUT_TLV, 247 TLV_REQUEST_TLV, 248 VERSION_TLV 249 } <= set(p.mle.tlv.type) and\ 250 p.wpan.aux_sec.key_id_mode == 0x2 251 ).\ 252 must_next() 253 254 # Step 7: REED sends an Address Solicit Request to Leader; 255 # Leader responds with an Address Solicit Response and REED 256 # becomes active router; 257 # REED sends Child ID Response with DUT’s new 16-bit Address. 258 259 _pkt = pkts.filter_wpan_src64(REED).\ 260 filter_ipv6_dst(LEADER_RLOC).\ 261 filter_coap_request(ADDR_SOL_URI).\ 262 filter(lambda p: { 263 NL_MAC_EXTENDED_ADDRESS_TLV, 264 NL_STATUS_TLV 265 } <= set(p.coap.tlv.type) 266 ).\ 267 must_next() 268 pkts.filter_wpan_src64(LEADER).\ 269 filter_wpan_dst16(_pkt.wpan.src16).\ 270 filter_coap_ack(ADDR_SOL_URI).\ 271 filter(lambda p: { 272 NL_STATUS_TLV, 273 NL_RLOC16_TLV, 274 NL_ROUTER_MASK_TLV 275 } <= set(p.coap.tlv.type) and\ 276 p.coap.code == COAP_CODE_ACK and\ 277 p.thread_address.tlv.status == 0\ 278 ).\ 279 must_next() 280 _pkt = pkts.filter_wpan_src64(REED).\ 281 filter_wpan_dst64(DUT).\ 282 filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\ 283 filter(lambda p: { 284 ADDRESS16_TLV, 285 LEADER_DATA_TLV, 286 NETWORK_DATA_TLV, 287 SOURCE_ADDRESS_TLV 288 } <= set(p.mle.tlv.type) and\ 289 p.mle.tlv.source_addr != REED_RLOC16 290 ).\ 291 must_next() 292 293 if self.TOPOLOGY[MTD]['mode'] == 'rn': 294 # Step 8: DUT sends periodic Child Update messages as part of the 295 # keep-alive message 296 # The DUT MUST send MLE Child Update messages containing 297 # the following TLVs: 298 # - Leader Data TLV 299 # - Mode TLV 300 # - Source Address TLV 301 pkts.filter_wpan_src64(DUT).\ 302 filter_wpan_dst64(REED).\ 303 filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).\ 304 filter(lambda p: { 305 SOURCE_ADDRESS_TLV, 306 MODE_TLV, 307 LEADER_DATA_TLV 308 } <= set(p.mle.tlv.type) 309 ).\ 310 must_next() 311 312 # Step 9: REED Respond to Child Update messages with a MLE Update 313 # Response. 314 pkts.filter_wpan_src64(REED).\ 315 filter_wpan_dst64(DUT).\ 316 filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).\ 317 filter(lambda p: { 318 SOURCE_ADDRESS_TLV, 319 MODE_TLV, 320 LEADER_DATA_TLV 321 } <= set(p.mle.tlv.type) 322 ).\ 323 must_next() 324 325 # Step 10: Go to Step 12 326 327 else: 328 # Step 11: DUT sends periodic 802.15.4 Data Request messages as part 329 # of the keep-alive message 330 # The DUT must send a 802.15.4 Data Request command to the 331 # parent device and receive an ACK message in response 332 _pkt2 = pkts.filter_wpan_src64(DUT).\ 333 filter_wpan_dst16(_pkt.mle.tlv.source_addr).\ 334 filter_wpan_cmd(WPAN_DATA_REQUEST).\ 335 must_next() 336 337 pkts.filter(lambda p: 338 p.wpan.seq_no == _pkt2.wpan.seq_no and\ 339 p.wpan.frame_type == WPAN_ACK 340 ).\ 341 must_next() 342 343 # Step 12: REED verifies connectivity by sending an ICMPv6 Echo Request 344 # to the DUT link local address 345 # DUT responds with ICMPv6 Echo Reply 346 347 _pkt = pkts.filter_ping_request().\ 348 filter_ipv6_src_dst(REED_LLA, DUT_LLA).\ 349 must_next() 350 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 351 filter_ipv6_src_dst(DUT_LLA, REED_LLA).\ 352 must_next() 353 354 355class Cert_6_1_2_REEDAttach_ED(Cert_6_1_2_REEDAttach_Base): 356 TOPOLOGY = copy.deepcopy(Cert_6_1_2_REEDAttach_Base.TOPOLOGY) 357 TOPOLOGY[MTD]['mode'] = 'rn' 358 359 360class Cert_6_1_2_REEDAttach_SED(Cert_6_1_2_REEDAttach_Base): 361 TOPOLOGY = copy.deepcopy(Cert_6_1_2_REEDAttach_Base.TOPOLOGY) 362 TOPOLOGY[MTD]['mode'] = '-' 363 364 365del (Cert_6_1_2_REEDAttach_Base) 366 367if __name__ == '__main__': 368 unittest.main() 369