1#!/usr/bin/env python3 2# 3# Copyright (c) 2024, 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 29from cli import verify 30from cli import verify_within 31import cli 32import time 33 34# ----------------------------------------------------------------------------------------------------------------------- 35# Test description: 36# 37# This test validates the behavior of MTD children regarding the 38# registration of their IPv6 addresses with their parent. 39# Specifically, it covers the scenario where SLAAC-based addresses 40# remain unchanged, but their assigned LoWPAN Context ID for the 41# corresponding on-mesh prefix in the Network Data changes. In this 42# case, the MTD child should schedule an MLE Child Update Request 43# exchange with its parent to re-register the addresses. This ensures 44# that any earlier registration failures due to incorrect context ID 45# compression are resolved. 46# 47 48test_name = __file__[:-3] if __file__.endswith('.py') else __file__ 49print('-' * 120) 50print('Starting \'{}\''.format(test_name)) 51 52# ----------------------------------------------------------------------------------------------------------------------- 53# Creating `cli.Nodes` instances 54 55speedup = 25 56cli.Node.set_time_speedup_factor(speedup) 57 58leader = cli.Node() 59sed = cli.Node() 60 61# ----------------------------------------------------------------------------------------------------------------------- 62# Form topology 63 64leader.form('cid-chng') 65 66verify(leader.get_state() == 'leader') 67 68# ----------------------------------------------------------------------------------------------------------------------- 69# Test Implementation 70 71# Set the "context ID reuse delay" to a short interval of 3 seconds. 72 73leader.set_context_reuse_delay(3) 74verify(int(leader.get_context_reuse_delay()) == 3) 75 76# Add two on-link prefixes on `leader`. 77 78leader.add_prefix('fd00:1::/64', 'poas') 79leader.add_prefix('fd00:2::/64', 'poas') 80leader.register_netdata() 81 82# Check that context ID 2 is assigned to prefix `fd00:2::/64`. 83 84time.sleep(0.5 / speedup) 85 86netdata = leader.get_netdata() 87contexts = netdata['contexts'] 88verify(len(contexts) == 2) 89verify(any([context.startswith('fd00:1:0:0::/64 1 c') for context in contexts])) 90verify(any([context.startswith('fd00:2:0:0::/64 2 c') for context in contexts])) 91 92# Remove the first prefix. 93 94leader.remove_prefix('fd00:1::/64') 95leader.register_netdata() 96 97# Wait longer than Context ID reuse delay to ensure that context ID 98# associated with the removed prefix is aged and removed. 99 100# Wait longer than the Context ID reuse delay to ensure the removed 101# prefix's associated context ID is aged out and removed. 102 103time.sleep(3.5 / speedup) 104 105netdata = leader.get_netdata() 106contexts = netdata['contexts'] 107verify(len(contexts) == 1) 108verify(any([context.startswith('fd00:2:0:0::/64 2 c') for context in contexts])) 109 110# Have `sed` attach as a child of `leader`. 111 112sed.set_child_timeout(10) 113sed.set_pollperiod(1000) 114 115sed.join(leader, cli.JOIN_TYPE_SLEEPY_END_DEVICE) 116verify(sed.get_state() == 'child') 117 118verify(int(sed.get_child_timeout()) == 10) 119 120# Check the Network Data on `sed`. 121 122netdata = sed.get_netdata() 123contexts = netdata['contexts'] 124verify(len(contexts) == 1) 125verify(any([context.startswith('fd00:2:0:0::/64 2 c') for context in contexts])) 126 127# Find the `sed` address associated with on-mesh prefix `fd00:2::`. 128 129sed_ip_addrs = sed.get_ip_addrs() 130 131for ip_addr in sed_ip_addrs: 132 if ip_addr.startswith('fd00:2:0:0:'): 133 sed_addr = ip_addr 134 break 135else: 136 verify(False) 137 138# Check the parent's child table, and that `sed` child has registered its 139# IPv6 addresses with the parent. 140 141verify(len(leader.get_child_table()) == 1) 142ip_addrs = leader.get_child_ip() 143verify(len(ip_addrs) == 2) 144 145# Stop MLE operation on `sed` 146 147sed.thread_stop() 148verify(sed.get_state() == 'disabled') 149 150# Remove the `fd00::2` prefix and wait for the child entry 151# on parent to expire. Child timeout is set to 10 seconds. 152 153leader.remove_prefix('fd00:2::/64') 154leader.register_netdata() 155 156time.sleep(10.5 / speedup) 157 158# Validate that the Context ID associated with `fd00::2` is expired 159# and removed. 160 161netdata = leader.get_netdata() 162contexts = netdata['contexts'] 163verify(len(contexts) == 0) 164 165# Re-add the `fd00::2` prefix and check that it gets a different 166# Context ID. 167 168leader.add_prefix('fd00:2::/64', 'poas') 169leader.register_netdata() 170 171time.sleep(0.5 / speedup) 172 173netdata = leader.get_netdata() 174contexts = netdata['contexts'] 175verify(len(contexts) == 1) 176verify(any([context.startswith('fd00:2:0:0::/64 1 c') for context in contexts])) 177 178# Make sure that child is timed out and removed on parent. 179 180verify(leader.get_child_table() == []) 181 182# Re-enable MLE operation on `sed` for it to attach back. 183 184sed.thread_start() 185 186time.sleep(5.0 / speedup) 187 188verify(sed.get_state() == 'child') 189 190# Check the `sed` IPv6 addresses and that `sed` still has the same 191# SLAAC address based on the `fd00:2::` prefix 192 193sed_ip_addrs = sed.get_ip_addrs() 194verify(any([ip_addr == sed_addr for ip_addr in sed_ip_addrs])) 195 196# Validate that all `sed` IPv6 addresses are successfully 197# registered on parent. 198 199verify(len(leader.get_child_table()) == 1) 200ip_addrs = leader.get_child_ip() 201verify(len(ip_addrs) == 2) 202verify(any([ip_addr.endswith(sed_addr) for ip_addr in ip_addrs])) 203 204# ----------------------------------------------------------------------------------------------------------------------- 205# Test finished 206 207cli.Node.finalize_all_nodes() 208 209print('\'{}\' passed.'.format(test_name)) 210