1#!/usr/bin/env python3 2# 3# Copyright (c) 2020, 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 config 34import thread_cert 35from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, SVR_DATA_URI, ACTIVE_TIMESTAMP_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, VERSION_TLV, TLV_REQUEST_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, CHALLENGE_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV 36from pktverify.packet_verifier import PacketVerifier 37from pktverify.bytes import Bytes 38from pktverify.addrs import Ipv6Addr 39from pktverify.null_field import nullField 40 41LEADER = 1 42ROUTER_1 = 2 43ROUTER_2 = 3 44MED = 4 45SED = 5 46 47MTDS = [MED, SED] 48PREFIX_2001 = '2001:0db8:0001::/64' 49 50# Test Purpose and Description: 51# ----------------------------- 52# The purpose of this test case is to verify that network data is properly updated 53# when a server from the network leaves and rejoins. 54# Router_1 is configured as Border Router for prefix 2001:db8:1::/64. 55# Router_2 is configured as Border Router for prefix 2001:db8:1::/64. 56# MED is configured to require complete network data. 57# SED is configured to request only stable network data. 58# 59# Test Topology: 60# ------------- 61# SED 62# | 63# Router_1 - Leader(DUT) - MED 64# | 65# Router_2 66# 67# DUT Types: 68# ---------- 69# Leader 70 71 72class Cert_7_1_6_BorderRouterAsLeader(thread_cert.TestCase): 73 USE_MESSAGE_FACTORY = False 74 75 TOPOLOGY = { 76 LEADER: { 77 'name': 'LEADER', 78 'mode': 'rdn', 79 'allowlist': [ROUTER_1, ROUTER_2, MED, SED] 80 }, 81 ROUTER_1: { 82 'name': 'ROUTER_1', 83 'mode': 'rdn', 84 'allowlist': [LEADER] 85 }, 86 ROUTER_2: { 87 'name': 'ROUTER_2', 88 'mode': 'rdn', 89 'allowlist': [LEADER] 90 }, 91 MED: { 92 'name': 'MED', 93 'is_mtd': True, 94 'mode': 'rn', 95 'allowlist': [LEADER] 96 }, 97 SED: { 98 'name': 'SED', 99 'is_mtd': True, 100 'mode': '-', 101 'timeout': config.DEFAULT_CHILD_TIMEOUT, 102 'allowlist': [LEADER] 103 }, 104 } 105 # override wireshark preferences with case needed parameters 106 CASE_WIRESHARK_PREFS = WIRESHARK_OVERRIDE_PREFS 107 CASE_WIRESHARK_PREFS['6lowpan.context1'] = PREFIX_2001 108 109 def _setUpRouter_1(self): 110 self.nodes[ROUTER_1].add_allowlist(self.nodes[LEADER].get_addr64()) 111 self.nodes[ROUTER_1].enable_allowlist() 112 self.nodes[ROUTER_1].set_router_selection_jitter(1) 113 114 def test(self): 115 self.nodes[LEADER].start() 116 self.simulator.go(config.LEADER_STARTUP_DELAY) 117 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 118 119 for i in (2, 3): 120 self.nodes[i].start() 121 self.simulator.go(config.ROUTER_STARTUP_DELAY) 122 self.assertEqual(self.nodes[i].get_state(), 'router') 123 124 self.nodes[MED].start() 125 self.simulator.go(5) 126 self.assertEqual(self.nodes[MED].get_state(), 'child') 127 128 self.nodes[SED].start() 129 self.simulator.go(5) 130 self.assertEqual(self.nodes[SED].get_state(), 'child') 131 132 self.collect_rlocs() 133 134 self.nodes[ROUTER_1].add_prefix(PREFIX_2001, 'paros') 135 self.nodes[ROUTER_1].register_netdata() 136 self.nodes[ROUTER_2].add_prefix(PREFIX_2001, 'paro') 137 self.nodes[ROUTER_2].register_netdata() 138 self.simulator.go(10) 139 self.collect_ipaddrs() 140 141 self.nodes[ROUTER_1].reset() 142 self._setUpRouter_1() 143 self.simulator.go(720) 144 145 self.nodes[ROUTER_1].start() 146 self.simulator.go(config.ROUTER_RESET_DELAY) 147 self.assertEqual(self.nodes[ROUTER_1].get_state(), 'router') 148 self.collect_rloc16s() 149 150 self.nodes[ROUTER_1].add_prefix(PREFIX_2001, 'paros') 151 self.nodes[ROUTER_1].register_netdata() 152 self.simulator.go(10) 153 154 dut_addr = self.nodes[LEADER].get_addr(PREFIX_2001) 155 self.assertTrue(self.nodes[ROUTER_1].ping(dut_addr)) 156 self.simulator.go(1) 157 self.assertTrue(self.nodes[SED].ping(dut_addr)) 158 159 def verify(self, pv): 160 pkts = pv.pkts 161 pv.summary.show() 162 163 LEADER = pv.vars['LEADER'] 164 LEADER_RLOC = pv.vars['LEADER_RLOC'] 165 LEADER_RLOC16 = pv.vars['LEADER_RLOC16'] 166 ROUTER_1 = pv.vars['ROUTER_1'] 167 ROUTER_1_RLOC16 = pv.vars['ROUTER_1_RLOC16'] 168 ROUTER_1_RLOC = pv.vars['ROUTER_1_RLOC'] 169 ROUTER_2 = pv.vars['ROUTER_2'] 170 ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16'] 171 SED = pv.vars['SED'] 172 MED = pv.vars['MED'] 173 GUA = {} 174 175 for node in ('LEADER', 'ROUTER_1', 'SED'): 176 for addr in pv.vars['%s_IPADDRS' % node]: 177 if addr.startswith(Bytes(PREFIX_2001[:-5])): 178 GUA[node] = addr 179 180 # Step 1: Ensure topology is formed correctly 181 pv.verify_attached('ROUTER_1', 'LEADER') 182 pv.verify_attached('ROUTER_2', 'LEADER') 183 pv.verify_attached('MED', 'LEADER', 'MTD') 184 pv.verify_attached('SED', 'LEADER', 'MTD') 185 _pkt = pkts.last() 186 187 # Step 2,3: Router_1 and Router_2 MUST send a CoAP Server Data 188 # Notification frame to the Leader including the server’s 189 # information(Prefix, Border Router): 190 # CoAP Request URI 191 # coap://[<Leader address>]:MM/a/sd 192 # CoAP Payload 193 # Thread Network Data TLV 194 195 # Step 4: Leader sends a CoAP ACK frame to each of Router_1 and 196 # Router_2 197 for i in (1, 2): 198 with pkts.save_index(): 199 pkts.filter_wpan_src64(pv.vars['ROUTER_%d' %i]).\ 200 filter_wpan_dst16(LEADER_RLOC16).\ 201 filter_coap_request(SVR_DATA_URI).\ 202 filter(lambda p: 203 [Ipv6Addr(PREFIX_2001[:-3])] == 204 p.thread_nwd.tlv.prefix and\ 205 [pv.vars['ROUTER_%d_RLOC16' %i]] == 206 p.thread_nwd.tlv.border_router_16 207 ).\ 208 must_next() 209 pkts.filter_wpan_src64(LEADER).\ 210 filter_ipv6_dst(pv.vars['ROUTER_%d_RLOC' %i]).\ 211 filter_coap_ack(SVR_DATA_URI).\ 212 must_next() 213 214 # Step 5: Leader MUST multicast MLE Data Response with the new 215 # information collected from Router_1 and Router_2, 216 # including the following TLVs:, 217 # - Source Address TLV 218 # - Leader Data TLV 219 # - Data Version field <incremented> 220 # - Stable Data Version field <incremented> 221 # - Network Data TLV 222 # - At least one Prefix TLV (Prefix 1) 223 # - Two Border Router sub-TLVs 224 # - 6LoWPAN ID sub-TLV 225 _dr_pkt = pkts.filter_wpan_src64(LEADER).\ 226 filter_LLANMA().\ 227 filter_mle_cmd(MLE_DATA_RESPONSE).\ 228 filter(lambda p: { 229 NETWORK_DATA_TLV, 230 SOURCE_ADDRESS_TLV, 231 LEADER_DATA_TLV 232 } <= set(p.mle.tlv.type) and\ 233 p.thread_nwd.tlv.border_router.flag.p == [1] and\ 234 p.thread_nwd.tlv.border_router.flag.s == [1] and\ 235 p.thread_nwd.tlv.border_router.flag.r == [1] and\ 236 p.thread_nwd.tlv.border_router.flag.o == [1] and\ 237 [Ipv6Addr(PREFIX_2001[:-3])] == 238 p.thread_nwd.tlv.prefix 239 ).\ 240 must_next() 241 with pkts.save_index(): 242 _dr_pkt1 = pkts.filter_wpan_src64(LEADER).\ 243 filter_LLANMA().\ 244 filter_mle_cmd(MLE_DATA_RESPONSE).\ 245 filter(lambda p: { 246 NETWORK_DATA_TLV, 247 SOURCE_ADDRESS_TLV, 248 LEADER_DATA_TLV 249 } <= set(p.mle.tlv.type) and\ 250 { 251 NWD_BORDER_ROUTER_TLV, 252 NWD_BORDER_ROUTER_TLV, 253 NWD_6LOWPAN_ID_TLV 254 } <= set(p.thread_nwd.tlv.type) and\ 255 p.thread_nwd.tlv.border_router.flag.p == [1, 1] and\ 256 p.thread_nwd.tlv.border_router.flag.s == [1, 1] and\ 257 p.thread_nwd.tlv.border_router.flag.r == [1, 1] and\ 258 p.thread_nwd.tlv.border_router.flag.o == [1, 1] and\ 259 p.mle.tlv.leader_data.data_version == 260 (_dr_pkt.mle.tlv.leader_data.data_version + 1) % 256 and\ 261 (p.mle.tlv.leader_data.stable_data_version == 262 (_dr_pkt.mle.tlv.leader_data.stable_data_version + 1) % 256 or\ 263 p.mle.tlv.leader_data.stable_data_version == 264 (_pkt.mle.tlv.leader_data.stable_data_version + 1) % 256) and\ 265 [Ipv6Addr(PREFIX_2001[:-3])] == 266 p.thread_nwd.tlv.prefix 267 ).\ 268 must_next() 269 270 # Step 6: Leader MUST send a MLE Child Update Request or MLE Data 271 # Response to SED, including the following TLVs: 272 # - Network Data TLV 273 # At least one Prefix TLV (Prefix 1) including: 274 # - Border Router sub-TLV(corresponding to Router_1) 275 # - 6LoWPAN ID sub-TLV 276 # - P_border_router_16<0xFFFE> 277 # - Source Address TLV 278 # - Leader Data TLV 279 # Data version numbers should be the same as the ones 280 # sent in the multicast data response in step 5. 281 # - Active Timestamp TLV 282 pkts.filter_wpan_src64(LEADER).\ 283 filter_wpan_dst64(SED).\ 284 filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\ 285 filter(lambda p: { 286 NETWORK_DATA_TLV, 287 SOURCE_ADDRESS_TLV, 288 LEADER_DATA_TLV, 289 ACTIVE_TIMESTAMP_TLV 290 } <= set(p.mle.tlv.type) and\ 291 [Ipv6Addr(PREFIX_2001[:-3])] == 292 p.thread_nwd.tlv.prefix and\ 293 p.thread_nwd.tlv.stable == [1, 1, 1] and\ 294 p.mle.tlv.leader_data.data_version == 295 _dr_pkt1.mle.tlv.leader_data.data_version and\ 296 p.mle.tlv.leader_data.stable_data_version == 297 _dr_pkt1.mle.tlv.leader_data.stable_data_version and\ 298 [0xFFFE] == p.thread_nwd.tlv.border_router_16 299 ).\ 300 must_next() 301 302 # Step 8: Leader MUST detect that Router_1 is removed from the network and 303 # update the Router ID Set. Leader MUST remove the Network Data 304 # section corresponding to Router_1 and increment the Data Version 305 # and Stable Data Version 306 307 # Step 9: Leader MUST multicast MLE Data Response neighbors and rx-on-when-idle 308 # Children (MED) including the following TLVs:, 309 # - Source Address TLV 310 # - Leader Data TLV 311 # - Data Version field <incremented> 312 # - Stable Data Version field <incremented> 313 # - Network Data TLV 314 # - Router_1’s Network Data section MUST be removed 315 pkts.filter_wpan_src64(LEADER).\ 316 filter_LLANMA().\ 317 filter_mle_cmd(MLE_DATA_RESPONSE).\ 318 filter(lambda p: { 319 NETWORK_DATA_TLV, 320 SOURCE_ADDRESS_TLV, 321 LEADER_DATA_TLV, 322 } <= set(p.mle.tlv.type) and\ 323 [Ipv6Addr(PREFIX_2001[:-3])] == 324 p.thread_nwd.tlv.prefix and\ 325 [ROUTER_2_RLOC16] == p.thread_nwd.tlv.border_router_16 and\ 326 p.mle.tlv.leader_data.data_version == 327 (_dr_pkt1.mle.tlv.leader_data.data_version + 1) % 256 and\ 328 p.mle.tlv.leader_data.stable_data_version == 329 (_dr_pkt1.mle.tlv.leader_data.stable_data_version + 1) % 256 330 ).\ 331 must_next() 332 333 # Step 10: The DUT MUST send a MLE Child Update Request or MLE Data 334 # Response to SED, containing the updated Network Data: 335 # - Network Data TLV 336 # - Source Address TLV 337 # - Active Timestamp TLV 338 _pkt = pkts.filter_wpan_src64(LEADER).\ 339 filter_wpan_dst64(SED).\ 340 filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\ 341 filter(lambda p: { 342 NETWORK_DATA_TLV, 343 SOURCE_ADDRESS_TLV, 344 LEADER_DATA_TLV, 345 } <= set(p.mle.tlv.type) and\ 346 [Ipv6Addr(PREFIX_2001[:-3])] == 347 p.thread_nwd.tlv.prefix and\ 348 p.thread_nwd.tlv.border_router_16 is nullField and\ 349 p.mle.tlv.leader_data.data_version == 350 (_dr_pkt1.mle.tlv.leader_data.data_version + 1) % 256 and\ 351 p.mle.tlv.leader_data.stable_data_version == 352 (_dr_pkt1.mle.tlv.leader_data.stable_data_version + 1) % 256 353 ).\ 354 must_next() 355 356 # Step 12: Leader MUST send MLE Child ID Response to Router_1, which 357 # includes the following TLVs: 358 # - Source Address TLV 359 # - Leader Data TLV 360 # - Address16 TLV 361 # - Route64 TLV 362 # - Network Data TLV 363 # - At least one Prefix TLV (Prefix 1) 364 # including: 365 # - Border Router sub-tlv corresponding to Router_2 366 # - 6LoWPAN ID sub-TLV 367 pkts.filter_wpan_src64(LEADER).\ 368 filter_wpan_dst64(ROUTER_1).\ 369 filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\ 370 filter(lambda p: { 371 ADDRESS16_TLV, 372 LEADER_DATA_TLV, 373 NETWORK_DATA_TLV, 374 SOURCE_ADDRESS_TLV, 375 ROUTE64_TLV 376 } <= set(p.mle.tlv.type) and\ 377 { 378 NWD_BORDER_ROUTER_TLV, 379 NWD_6LOWPAN_ID_TLV 380 } <= set(p.thread_nwd.tlv.type) and\ 381 [Ipv6Addr(PREFIX_2001[:-3])] == 382 p.thread_nwd.tlv.prefix and\ 383 [ROUTER_2_RLOC16] == p.thread_nwd.tlv.border_router_16 384 ).\ 385 must_next() 386 387 # Step 13: Router_1 MUST send a CoAP Server DataNotification frame to 388 # the Leader including the server’s information(Prefix, Border Router): 389 # CoAP Request URI 390 # coap://[<Leader address>]:MM/a/sd 391 # CoAP Payload 392 # Thread Network Data TLV 393 394 # Step 14: Leader sends a CoAP ACK frame to each of Router_1 395 with pkts.save_index(): 396 pkts.filter_wpan_src64(ROUTER_1).\ 397 filter_wpan_dst16(LEADER_RLOC16).\ 398 filter_coap_request(SVR_DATA_URI).\ 399 filter(lambda p: 400 [Ipv6Addr(PREFIX_2001[:-3])] == 401 p.thread_nwd.tlv.prefix and\ 402 [ROUTER_1_RLOC16] == 403 p.thread_nwd.tlv.border_router_16 404 ).\ 405 must_next() 406 pkts.filter_wpan_src64(LEADER).\ 407 filter_ipv6_dst(ROUTER_1_RLOC).\ 408 filter_coap_ack(SVR_DATA_URI).\ 409 must_next() 410 411 # Step 15: Leader MUST multicast MLE Data Response with the new 412 # information collected from Router_1 and Router_2, 413 # including the following TLVs:, 414 # - Source Address TLV 415 # - Leader Data TLV 416 # - Data Version field <incremented> 417 # - Stable Data Version field <incremented> 418 # - Network Data TLV 419 # - At least one Prefix TLV (Prefix 1) 420 # - Two Border Router sub-TLVs 421 # corresponding to Router_1 and Router_2 422 # - 6LoWPAN ID sub-TLV 423 _dr_pkt2 = pkts.filter_wpan_src64(LEADER).\ 424 filter_LLANMA().\ 425 filter_mle_cmd(MLE_DATA_RESPONSE).\ 426 filter(lambda p: { 427 NETWORK_DATA_TLV, 428 SOURCE_ADDRESS_TLV, 429 LEADER_DATA_TLV 430 } <= set(p.mle.tlv.type) and\ 431 {ROUTER_1_RLOC16, ROUTER_2_RLOC16} == 432 set(p.thread_nwd.tlv.border_router_16) and\ 433 [Ipv6Addr(PREFIX_2001[:-3])] == 434 p.thread_nwd.tlv.prefix and\ 435 p.mle.tlv.leader_data.data_version == 436 (_pkt.mle.tlv.leader_data.data_version + 1) % 256 and\ 437 p.mle.tlv.leader_data.stable_data_version == 438 (_pkt.mle.tlv.leader_data.stable_data_version + 1) % 256 439 ).\ 440 must_next() 441 442 # Step 16: Leader MUST send a MLE Child Update Request or MLE Data 443 # Response to SED, including the following TLVs: 444 # - Network Data TLV 445 # At least one Prefix TLV (Prefix 1) 446 # - Border Router TLV (corresponding to Router_1) 447 # - 6LoWPAN ID sub-TLV 448 # - P_border_router_16<0xFFFE> 449 # - Source Address TLV 450 # - Leader Data TLV 451 # Data version numbers should be the same as those 452 # sent in the multicast data response in step 15. 453 # - Active Timestamp TLV 454 pkts.filter_wpan_src64(LEADER).\ 455 filter_wpan_dst64(SED).\ 456 filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\ 457 filter(lambda p: { 458 NETWORK_DATA_TLV, 459 SOURCE_ADDRESS_TLV, 460 LEADER_DATA_TLV, 461 ACTIVE_TIMESTAMP_TLV 462 } <= set(p.mle.tlv.type) and\ 463 [Ipv6Addr(PREFIX_2001[:-3])] == 464 p.thread_nwd.tlv.prefix and\ 465 p.mle.tlv.leader_data.data_version == 466 _dr_pkt2.mle.tlv.leader_data.data_version and\ 467 p.thread_nwd.tlv.stable == [1, 1, 1] and\ 468 [0xFFFE] == p.thread_nwd.tlv.border_router_16 469 ).\ 470 must_next() 471 472 # Step 17: Verifies connectivity by sending ICMPv6 Echo Requests from 473 # Router_1 and SED_1 to the Leader Prefix_1 based address. 474 # Leader must respond with ICMPv6 Echo Replies 475 for node in ('ROUTER_1', 'SED'): 476 _pkt = pkts.filter_ping_request().\ 477 filter_ipv6_src_dst(GUA[node], GUA['LEADER']).\ 478 must_next() 479 pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 480 filter_ipv6_src_dst(GUA['LEADER'], GUA[node]).\ 481 must_next() 482 483 484if __name__ == '__main__': 485 unittest.main() 486