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 thread_cert 35from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_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 36from pktverify.packet_verifier import PacketVerifier 37from pktverify.null_field import nullField 38 39LEADER = 1 40ROUTER1 = 2 41REED1 = 3 42REED2 = 4 43ROUTER2 = 5 44 45# Test Purpose and Description: 46# ----------------------------- 47# The purpose of this test case is to verify that the DUT will 48# pick REED_1 as its parent because of its better connectivity 49# 50# Test Topology: 51# ------------- 52# Leader--Router1 53# / \ / 54# REED2 REED1 55# \ / 56# Router2[DUT] 57# 58# DUT Types: 59# ---------- 60# Router 61 62 63class Cert_5_1_09_REEDAttachConnectivity(thread_cert.TestCase): 64 USE_MESSAGE_FACTORY = False 65 66 TOPOLOGY = { 67 LEADER: { 68 'name': 'LEADER', 69 'mode': 'rdn', 70 'allowlist': [ROUTER1, REED1, REED2] 71 }, 72 ROUTER1: { 73 'name': 'ROUTER_1', 74 'mode': 'rdn', 75 'allowlist': [LEADER, REED1] 76 }, 77 REED1: { 78 'name': 'REED_1', 79 'mode': 'rdn', 80 'router_upgrade_threshold': 0, 81 'allowlist': [LEADER, ROUTER1, ROUTER2] 82 }, 83 REED2: { 84 'name': 'REED_2', 85 'mode': 'rdn', 86 'router_upgrade_threshold': 0, 87 'allowlist': [LEADER, ROUTER2] 88 }, 89 ROUTER2: { 90 'name': 'ROUTER_2', 91 'mode': 'rdn', 92 'allowlist': [REED1, REED2] 93 }, 94 } 95 96 def test(self): 97 self.nodes[LEADER].start() 98 self.simulator.go(config.LEADER_STARTUP_DELAY) 99 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 100 101 for i in range(2, 5): 102 self.nodes[i].start() 103 104 self.simulator.go(config.ROUTER_STARTUP_DELAY) 105 106 self.assertEqual(self.nodes[ROUTER1].get_state(), 'router') 107 self.assertEqual(self.nodes[REED1].get_state(), 'child') 108 self.assertEqual(self.nodes[REED2].get_state(), 'child') 109 110 self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL) 111 112 self.nodes[ROUTER2].start() 113 self.simulator.go(config.ROUTER_STARTUP_DELAY) 114 self.assertEqual(self.nodes[ROUTER2].get_state(), 'router') 115 self.assertEqual(self.nodes[REED1].get_state(), 'router') 116 117 def verify(self, pv): 118 pkts = pv.pkts 119 pv.summary.show() 120 121 LEADER = pv.vars['LEADER'] 122 REED_1 = pv.vars['REED_1'] 123 ROUTER_1 = pv.vars['ROUTER_1'] 124 ROUTER_2 = pv.vars['ROUTER_2'] 125 126 # Step 1: Verify ROUTER_1 and Leader are sending MLE advertisements. 127 pkts.filter_wpan_src64(LEADER).\ 128 filter_mle_cmd(MLE_ADVERTISEMENT).\ 129 must_next() 130 pv.verify_attached('ROUTER_1') 131 132 # Step 3: The DUT sends a MLE Parent Request with an IP hop limit of 133 # 255 to the Link-Local All Routers multicast address (FF02::2). 134 # The following TLVs MUST be present in the MLE Parent Request: 135 # - Challenge TLV 136 # - Mode TLV 137 # - Scan Mask TLV 138 # If the DUT sends multiple MLE Parent Requests 139 # - The first one MUST be sent only to all Routers 140 # - Subsequent ones MAY be sent to all Routers and REEDS 141 # - Version TLV 142 # If the first MLE Parent Request was sent to all Routers and 143 # REEDS, the test fails. 144 145 pkts.filter_wpan_src64(ROUTER_2).\ 146 filter_LLARMA().\ 147 filter_mle_cmd(MLE_PARENT_REQUEST).\ 148 filter(lambda p: { 149 CHALLENGE_TLV, 150 MODE_TLV, 151 SCAN_MASK_TLV, 152 VERSION_TLV 153 } <= set(p.mle.tlv.type) and\ 154 p.ipv6.hlim == 255 and\ 155 p.mle.tlv.scan_mask.r == 1 and\ 156 p.mle.tlv.scan_mask.e == 0 157 ).\ 158 must_next() 159 lstart = pkts.index 160 161 # Step 5: The DUT MUST send a MLE Parent Request with an IP hop limit of 162 # 255 to the Link-Local All Routers multicast address (FF02::2). 163 # The following TLVs MUST be present in the MLE Parent Request: 164 # - Challenge TLV 165 # - Mode TLV 166 # - Scan Mask TLV 167 # - The Scan Mask TLV MUST be sent to Routers And REEDs 168 # - Version TLV 169 # 170 # In securing the first three messages of the attaching process, 171 # the full four-byte key sequence number MUST be included in 172 # the Auxiliary Security Header used for MLE security. 173 # 174 # To send the full four-byte key sequence number, the Key 175 # Identifier Mode of the Security Control Field SHALL be set to 176 # ‘0x02’, indicating the presence of a four-byte Key Source, 177 # which SHALL contain the four-byte key sequence number in 178 # network byte order. 179 180 pkts.filter_wpan_src64(ROUTER_2).\ 181 filter_LLARMA().\ 182 filter_mle_cmd(MLE_PARENT_REQUEST).\ 183 filter(lambda p: { 184 CHALLENGE_TLV, 185 MODE_TLV, 186 SCAN_MASK_TLV, 187 VERSION_TLV 188 } <= set(p.mle.tlv.type) and\ 189 p.ipv6.hlim == 255 and\ 190 p.mle.tlv.scan_mask.r == 1 and\ 191 p.mle.tlv.scan_mask.e == 1 and\ 192 p.wpan.aux_sec.key_id_mode == 0x2 193 ).\ 194 must_next() 195 lend = pkts.index 196 197 # Step 4: REED_1 and REED_2 no response to Parent Request meant for all routers. 198 199 for i in (1, 2): 200 pkts.range(lstart, lend).\ 201 filter_wpan_src64(pv.vars['REED_%d' % i]).\ 202 filter_wpan_dst64(ROUTER_2).\ 203 filter_mle_cmd(MLE_PARENT_RESPONSE).\ 204 must_not_next() 205 206 # Step 6: REED_1 and REED_2 respond with a MLE Parent Response. 207 # The following TLVs MUST be present in the MLE Parent Response: 208 # - Challenge TLV 209 # - Connectivity TLV 210 # - Leader Data TLV 211 # - Link-layer Frame Counter TLV 212 # - Link Margin TLV 213 # - Response TLV 214 # - Source Address 215 # - Version TLV 216 # - MLE Frame Counter TLV (optional) 217 218 for i in (1, 2): 219 with pkts.save_index(): 220 pkts.filter_wpan_src64(pv.vars['REED_%d' % i]).\ 221 filter_wpan_dst64(ROUTER_2).\ 222 filter_mle_cmd(MLE_PARENT_RESPONSE).\ 223 filter(lambda p: { 224 CHALLENGE_TLV, 225 CONNECTIVITY_TLV, 226 LEADER_DATA_TLV, 227 LINK_LAYER_FRAME_COUNTER_TLV, 228 LINK_MARGIN_TLV, 229 RESPONSE_TLV, 230 SOURCE_ADDRESS_TLV, 231 VERSION_TLV 232 } <= set(p.mle.tlv.type) and\ 233 p.wpan.aux_sec.key_id_mode == 0x2 234 ).\ 235 must_next() 236 237 # Step 7: DUT sends a MLE Child ID Request to REED_1. 238 # The following TLVs MUST be present in the MLE Child ID Request: 239 # - Link-layer Frame Counter TLV 240 # - Mode TLV 241 # - Response TLV 242 # - Timeout TLV 243 # - TLV Request TLV 244 # - Address16 TLV 245 # - Network Data TLV 246 # - Route64 TLV (optional) 247 # - Version TLV 248 # - MLE Frame Counter TLV (optional) 249 # The following TLV MUST NOT be present in the MLE Child ID Request: 250 # - Address Registration TLV 251 252 _pkt = pkts.filter_wpan_src64(ROUTER_2).\ 253 filter_wpan_dst64(REED_1).\ 254 filter_mle_cmd(MLE_CHILD_ID_REQUEST).\ 255 filter(lambda p: { 256 LINK_LAYER_FRAME_COUNTER_TLV, 257 MODE_TLV, 258 RESPONSE_TLV, 259 TIMEOUT_TLV, 260 TLV_REQUEST_TLV, 261 ADDRESS16_TLV, 262 NETWORK_DATA_TLV, 263 VERSION_TLV 264 } <= set(p.mle.tlv.type) and\ 265 p.mle.tlv.addr16 is nullField and\ 266 p.thread_nwd.tlv.type is nullField and\ 267 p.wpan.aux_sec.key_id_mode == 0x2 268 ).\ 269 must_next() 270 _pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type) 271 272 273if __name__ == '__main__': 274 unittest.main() 275