verify(p.priority == "med") break else: # `for` loop finished without finding the prefix. raise wpan.VerifyError( 'Did not find prefix {} on node {}'.format(prefix, node)) # Verify that IPv6 address of `sed2` is present on `r2` (its parent) # "Thread:ChildTable:Addresses". addr_str = r2.get(wpan.WPAN_THREAD_CHILD_TABLE_ADDRESSES) # search for index on address in the `addr_str` and ensure it is # non-negative. verify(addr_str.find(IP6_ADDR_3) >= 0) # Check the addresses and prefixes (wait time 20 seconds) wpan.verify_within(check_addresses_and_prefixes, 15) # Reset the nodes and verify that all addresses/prefixes are preserved. fed1.reset() sed2.reset() wpan.verify_within(check_addresses_and_prefixes, 20) # Remove address from `r2` r2.remove_ip6_address_on_interface(IP6_ADDR_1, prefix_len=64) def check_address_prefix_removed(): # Verify that address is removed from r2 verify(r2.find_ip6_address_with_prefix(IP6_PREFIX_1) == '') # Verify that the related prefix is also removed on all nodes for node in all_nodes:
check_child_table() # Remember number of NCP state changes (using "stat:ncp" property) per child child_num_state_changes = [] for child in all_children: child_num_state_changes.append(len(wpan.parse_list(child.get("stat:ncp")))) # Reset the parent parent.reset() def check_parent_is_associated(): verify(parent.is_associated()) wpan.verify_within(check_parent_is_associated, 5) # Verify that all the children are recovered and present in the parent's # child table again (within 5 seconds). wpan.verify_within(check_child_table, 9) # Verify that number of state changes on all children stays as before # (indicating they did not get detached). for i in range(len(all_children)): verify(child_num_state_changes[i] == len( wpan.parse_list(all_children[i].get("stat:ncp")))) # ----------------------------------------------------------------------------------------------------------------------- # Test finished wpan.Node.finalize_all_nodes()
c2.whitelist_node(r2) r2.whitelist_node(c2) c2.join_node(r2, wpan.JOIN_TYPE_END_DEVICE) c2.set(wpan.WPAN_POLL_INTERVAL, '8000') #----------------------------------------------------------------------------------------------------------------------- # Test implementation WAIT_INTERVAL = 6 # Check that r1 and r2 are present in each other's neighbor table def check_neighbor_tables(): verify_neighbor_table(r1, [r2]) verify_neighbor_table(r2, [r1]) wpan.verify_within(check_neighbor_tables, WAIT_INTERVAL) verify(r1.get(wpan.WPAN_NODE_TYPE) == wpan.NODE_TYPE_LEADER) verify(r2.get(wpan.WPAN_NODE_TYPE) == wpan.NODE_TYPE_ROUTER) # Reset r2 and wait for it to be associated. r2.reset() def check_r2_neighbor_table(): verify(r2.is_associated()) verify_neighbor_table(r2, [r1]) wpan.verify_within(check_r2_neighbor_table, WAIT_INTERVAL) verify(r1.get(wpan.WPAN_NODE_TYPE) == wpan.NODE_TYPE_LEADER) verify(r2.get(wpan.WPAN_NODE_TYPE) == wpan.NODE_TYPE_ROUTER)
# If a node itself adds a route, the route entry will be seen twice in # its WPAN_THREAD_OFF_MESH_ROUTES list (one time as part of network-wide # network data and again as part of the local network data). Note that # `r1 and `r2` each add a route, while `sed2` does not. verify( len(wpan.parse_list(r1.get(wpan.WPAN_THREAD_OFF_MESH_ROUTES))) == NUM_ROUTES + NUM_ROUTES_LOCAL) verify( len(wpan.parse_list(r2.get(wpan.WPAN_THREAD_OFF_MESH_ROUTES))) == NUM_ROUTES + NUM_ROUTES_LOCAL) verify( len(wpan.parse_list(sed2.get(wpan.WPAN_THREAD_OFF_MESH_ROUTES))) == NUM_ROUTES) wpan.verify_within(check_off_mesh_routes, WAIT_TIME) # Traffic from `sed2` to `OFF_MESH_ADDR_1` (verify that it is received on # `r1`). src = sed2.find_ip6_address_with_prefix(ON_MESH_PREFIX) sender = sed2.prepare_tx(src, OFF_MESH_ADDR_1, "Hello Route1") recver = r1.prepare_rx(sender) wpan.Node.perform_async_tx_rx() verify(sender.was_successful) verify(recver.was_successful) # Traffic from `r1` to `OFF_MESH_ADDR_2` (verify that it is received on `r2`), src = r1.find_ip6_address_with_prefix(ON_MESH_PREFIX) sender = r1.prepare_tx(src, OFF_MESH_ADDR_2, "Hello Route2")
c2.set('Daemon:AutoAssociateAfterReset', 'false') c2.reset(); # Switch the rest of network to channel 26 router.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '26') verify_channel([router, c1], 26) # Now re-enable c2 and verify that it does attach to router and is on channel 26 # c2 would go through the ML Announce recovery. c2.set('Daemon:AutoAssociateAfterReset', 'true') c2.reset(); verify(int(c2.get(wpan.WPAN_CHANNEL), 0) == 11) # wait for 20s for c2 to be attached/associated def check_c2_is_associated(): verify(c2.is_associated()) wpan.verify_within(check_c2_is_associated, 20) # Check that c2 is now on channel 26. verify(int(c2.get(wpan.WPAN_CHANNEL), 0) == 26) #----------------------------------------------------------------------------------------------------------------------- # Test finished wpan.Node.finalize_all_nodes() print '\'{}\' passed.'.format(test_name)
# should be rejected and the child should be removed from parent's # child table after timeout. The child however should continue to # stay attached (since data polls are acked by radio driver) and # supervision check is disabled on the child. parent.set(wpan.WPAN_MAC_ALLOWLIST_ENABLED, '1') def check_child_is_removed_from_parent_child_table(): child_table = wpan.parse_child_table_result(parent.get(wpan.WPAN_THREAD_CHILD_TABLE)) verify(len(child_table) == 0) # wait till child is removed from parent's child table # after this child should still be associated wpan.verify_within(check_child_is_removed_from_parent_child_table, CHILD_TIMEOUT / speedup + 2) verify(child.is_associated()) # Enable supervision check on child and expect the child to # become detached after the check timeout child.set( wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT, str(CHILD_SUPERVISION_CHECK_TIMEOUT), ) def check_child_is_detached(): verify(not child.is_associated())
verify(len(filtred_list) == 1) entry = filtred_list[0] # Verify that the multi radio info matches the radio links supported by the node node_radios = wpan.parse_list(node.get(wpan.WPAN_OT_SUPPORTED_RADIO_LINKS)) verify(len(node_radios) == len(entry.radios)) for radio in node_radios: verify(entry.supports(radio)) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Reset the parent and check that all children are attached back successfully parent.reset() def check_all_children_are_attached(): neighbor_table = wpan.parse_neighbor_table_result( parent.get(wpan.WPAN_THREAD_NEIGHBOR_TABLE)) verify(len(neighbor_table) == 3) wpan.verify_within(check_all_children_are_attached, WAIT_TIME) # ----------------------------------------------------------------------------------------------------------------------- # Test finished wpan.Node.finalize_all_nodes() print('\'{}\' passed.'.format(test_name))
r3_rloc = int(r3.get(wpan.WPAN_THREAD_RLOC16), 16) c3_rloc = int(c3.get(wpan.WPAN_THREAD_RLOC16), 16) # Wait till we have a valid "next hop" route on r1 towards r3 def check_r1_router_table(): router_table = wpan.parse_router_table_result( r1.get(wpan.WPAN_THREAD_ROUTER_TABLE)) verify(len(router_table) == 3) for entry in router_table: if entry.rloc16 == r3_rloc: verify(entry.next_hop != INVALID_ROUTER_ID) wpan.verify_within(check_r1_router_table, ROUTER_TABLE_WAIT_TIME) r1_address = r1.find_ip6_address_with_prefix(PREFIX) c1_address = c1.find_ip6_address_with_prefix(PREFIX) c2_address = c2.find_ip6_address_with_prefix(PREFIX) c3_address = c3.find_ip6_address_with_prefix(PREFIX) # Send a single UDP message from r1 to c2 sender = r1.prepare_tx(r1_address, c2_address, "Hi from r1 to c2") recver = c2.prepare_rx(sender) wpan.Node.perform_async_tx_rx() verify(sender.was_successful and recver.was_successful) # Send a single UDP message from r1 to c3
DEVICE_MODE_END_DEVICE = wpan.THREAD_MODE_FLAG_FULL_NETWORK_DATA | wpan.THREAD_MODE_FLAG_FULL_THREAD_DEV \ | wpan.THREAD_MODE_FLAG_SECURE_DATA_REQUEST | wpan.THREAD_MODE_FLAG_RX_ON_WHEN_IDLE # Disable child supervision on all devices parent.set(wpan.WPAN_CHILD_SUPERVISION_INTERVAL, '0') child1.set(wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT, '0') child2.set(wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT, '0') # Verify Thread Device Mode on both children verify(int(child1.get(wpan.WPAN_THREAD_DEVICE_MODE),0) == DEVICE_MODE_END_DEVICE) verify(int(child2.get(wpan.WPAN_THREAD_DEVICE_MODE),0) == DEVICE_MODE_SLEEPY_END_DEVICE) def check_child_table(): verify_child_table(parent, children) wpan.verify_within(check_child_table, WAIT_INTERVAL) # Reset parent and verify all children are recovered parent.reset() wpan.verify_within(check_child_table, WAIT_INTERVAL) # Change mode on both children (make child1 sleepy, and child2 non-sleepy) child1.set(wpan.WPAN_THREAD_DEVICE_MODE, str(DEVICE_MODE_SLEEPY_END_DEVICE)) verify(int(child1.get(wpan.WPAN_THREAD_DEVICE_MODE),0) == DEVICE_MODE_SLEEPY_END_DEVICE) child2.set(wpan.WPAN_THREAD_DEVICE_MODE, str(DEVICE_MODE_END_DEVICE)) verify(int(child2.get(wpan.WPAN_THREAD_DEVICE_MODE),0) == DEVICE_MODE_END_DEVICE) # Verify that the child table on parent is also updated wpan.verify_within(check_child_table, WAIT_INTERVAL)
r2_rloc = int(r2.get(wpan.WPAN_THREAD_RLOC16), 0) c2_rloc = int(c2.get(wpan.WPAN_THREAD_RLOC16), 0) def check_prefixes(): # Verify that all three `prefix1`, 'prefix2', and `prefix3` are present on all nodes # and respectively associated with `r1`, r2, and `r3` nodes. verify_prefix([r1, r2, c2], prefix1, r1_rloc, on_mesh=True, preferred=True, stable=True) verify_prefix([r1, r2, c2], prefix2, r2_rloc, on_mesh=True, preferred=True, stable=True) verify_prefix([r1, r2, c2], prefix3, c2_rloc, on_mesh=True, preferred=True, stable=True) # Verify the presence of `common_prefix` associated with each node (with correct flags). verify_prefix([r1, r2, c2], common_prefix, r1_rloc, on_mesh=True, preferred=True, stable=False) verify_prefix([r1, r2, c2], common_prefix, r2_rloc, on_mesh=True, preferred=True, stable=True) verify_prefix([r1, r2, c2], common_prefix, c2_rloc, on_mesh=True, preferred=False, stable=True) wpan.verify_within(check_prefixes, wait_time) # Remove `r2`. This should trigger all the prefixes added by it or its child to timeout and be removed. r2.leave() def check_prefixes_on_r1_after_r2_leave(): # Verify that entries added by r1 are still present verify_prefix([r1], prefix1, r1_rloc, on_mesh=True, preferred=True, stable=True) verify_prefix([r1], common_prefix, r1_rloc, on_mesh=True, preferred=True, stable=False) # Verify all entries added by `r2` or `c2` are removed verify_no_prefix([r1], prefix2, r2_rloc) verify_no_prefix([r1], prefix3, c2_rloc) verify_no_prefix([r1], common_prefix, r2_rloc) verify_no_prefix([r1], common_prefix, c2_rloc)
# has a valid "next hop" towards all other routers. ROUTER_TABLE_WAIT_TIME = 60 / speedup + 5 INVALID_ROUTER_ID = 63 r1_rloc = int(routers[0].get(wpan.WPAN_THREAD_RLOC16), 16) def check_r1_router_table(): router_table = wpan.parse_router_table_result(routers[0].get(wpan.WPAN_THREAD_ROUTER_TABLE)) verify(len(router_table) == NUM_ROUTERS) for entry in router_table: verify(entry.rloc16 == r1_rloc or entry.is_link_established() or entry.next_hop != INVALID_ROUTER_ID) wpan.verify_within(check_r1_router_table, ROUTER_TABLE_WAIT_TIME) # Send from the first router in the chain to the last one. src = routers[0].get(wpan.WPAN_IP6_MESH_LOCAL_ADDRESS)[1:-1] dst = routers[-1].get(wpan.WPAN_IP6_MESH_LOCAL_ADDRESS)[1:-1] for msg_length in MSG_LENS: sender = routers[0].prepare_tx(src, dst, msg_length, NUM_MSGS) recver = routers[-1].prepare_rx(sender) wpan.Node.perform_async_tx_rx() verify(sender.was_successful) verify(recver.was_successful) # Send from the SED child of the last router to the SED child of the first # router.
node.set(wpan.WPAN_NCP_MCU_POWER_STATE, wpan.MCU_POWER_STATE_ON) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Check the `wpantund` state changes between "deep-sleep" and "offline" node.leave() verify(not node.is_associated()) verify(node.get(wpan.WPAN_NCP_MCU_POWER_STATE) == wpan.MCU_POWER_STATE_ON) verify(node.get(wpan.WPAN_STATE) == wpan.STATE_OFFLINE) # Setting the power state to `low-power` should change wpantund state to # `DEEP_SLEEP` node.set(wpan.WPAN_NCP_MCU_POWER_STATE, wpan.MCU_POWER_STATE_LOW_POWER) wpan.verify_within(check_wpan_is_in_deep_sleep_state, WAIT_TIME) # Verify that reading/getting a property does not impact the wpantund state. node.get(wpan.WPAN_THREAD_RLOC16) verify( node.get(wpan.WPAN_NCP_MCU_POWER_STATE) == wpan.MCU_POWER_STATE_LOW_POWER ) verify(node.get(wpan.WPAN_STATE) == wpan.STATE_DEEP_SLEEP) # Setting the power state to `on` should change wpantund state to `OFFLINE` node.set(wpan.WPAN_NCP_MCU_POWER_STATE, wpan.MCU_POWER_STATE_ON) wpan.verify_within(check_wpan_is_in_offline_state, WAIT_TIME) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
verify(node.get(wpan.WPAN_NCP_MCU_POWER_STATE) == wpan.MCU_POWER_STATE_LOW_POWER) node.set(wpan.WPAN_NCP_MCU_POWER_STATE, wpan.MCU_POWER_STATE_ON) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Check the `wpantund` state changes between "deep-sleep" and "offline" node.leave() verify(not node.is_associated()) verify(node.get(wpan.WPAN_NCP_MCU_POWER_STATE) == wpan.MCU_POWER_STATE_ON) verify(node.get(wpan.WPAN_STATE) == wpan.STATE_OFFLINE) # Setting the power state to `low-power` should change wpantund state to `DEEP_SLEEP` node.set(wpan.WPAN_NCP_MCU_POWER_STATE, wpan.MCU_POWER_STATE_LOW_POWER) wpan.verify_within(check_wpan_is_in_deep_sleep_state, WAIT_TIME) # Verify that reading/getting a property does not impact the wpantund state. node.get(wpan.WPAN_THREAD_RLOC16) verify(node.get(wpan.WPAN_NCP_MCU_POWER_STATE) == wpan.MCU_POWER_STATE_LOW_POWER) verify(node.get(wpan.WPAN_STATE) == wpan.STATE_DEEP_SLEEP) # Setting the power state to `on` should change wpantund state to `OFFLINE` node.set(wpan.WPAN_NCP_MCU_POWER_STATE, wpan.MCU_POWER_STATE_ON) wpan.verify_within(check_wpan_is_in_offline_state, WAIT_TIME) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Verify the behavior of `begin-low-power` wpanctl command
# the `child` should realize that it can no longer talk to its current # parent (`parent2`) and try to reattach. All re-attach attempts to `parent2` # should fail (due to whitelist) and cause the `child` to get detached and # search for a new parent and then attach to `parent1`. # # To verify that the `child` does get detached and attach to a new parent, we # monitor the number of state changes using wpantund property "stat:ncp". child_num_state_changes = len(wpan.parse_list(child.get("stat:ncp"))) def check_child_is_reattached(): verify(len(wpan.parse_list(child.get("stat:ncp"))) > child_num_state_changes) child_is_in_parent2_table = (len(wpan.parse_list(parent2.get(wpan.WPAN_THREAD_CHILD_TABLE)))==1) verify(child.is_associated()) wpan.verify_within(check_child_is_reattached, CHILD_SUPERVISION_CHECK_TIMEOUT / speedup + 5) # Verify that the `child` is now attached to `parent1` child_table = wpan.parse_list(parent1.get(wpan.WPAN_THREAD_CHILD_TABLE)) verify(len(child_table) == 1) # Finally verify that the `child` is removed from previous parent's child # table (which indicates that the `child` did indeed inform its previous # parent). def check_child_is_removed_from_parent2_table(): child_table = wpan.parse_list(parent2.get(wpan.WPAN_THREAD_CHILD_TABLE)) verify(len(child_table) == 0) wpan.verify_within(check_child_is_removed_from_parent2_table, 1)
PREFIX = 'fd00:1234::' # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Add prefix and check all nodes get the prefix and add a corresponding # SLAAC address. r1.add_prefix(PREFIX, stable=True, on_mesh=True, slaac=True) def check_prefix_and_slaac_address_are_added(): verify_prefix(all_nodes, PREFIX, stable=True, on_mesh=True, slaac=True) verify_address(all_nodes, PREFIX) wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) # Save the assigned SLAAC addresses. slaac_addrs = [node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Check recovery after reseting r1 and c1 (same SLAAC address to be added) r1.reset() wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) verify([node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] == slaac_addrs) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Remove the prefix on r1 and verify that the address and prefix are # removed on all nodes.
# Verify that all children are present in the child table check_child_table() # Remember number of NCP state changes (using "stat:ncp" property) per child child_num_state_changes = [] for child in all_children: child_num_state_changes.append(len(wpan.parse_list(child.get("stat:ncp")))) # Reset the parent parent.reset() def check_parent_is_associated(): verify(parent.is_associated()) wpan.verify_within(check_parent_is_associated, 5) # Verify that all the children are recovered and present in the parent's child table again (within 5 seconds). wpan.verify_within(check_child_table, 9) # Verify that number of state changes on all children stays as before (indicating they did not get detached). for i in range(len(all_children)): verify(child_num_state_changes[i] == len(wpan.parse_list(all_children[i].get("stat:ncp")))) #----------------------------------------------------------------------------------------------------------------------- # Test finished wpan.Node.finalize_all_nodes() print '\'{}\' passed.'.format(test_name)
child1.set(wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT, '0') child2.set(wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT, '0') # Verify Thread Device Mode on both children verify( int(child1.get(wpan.WPAN_THREAD_DEVICE_MODE), 0) == DEVICE_MODE_END_DEVICE) verify( int(child2.get(wpan.WPAN_THREAD_DEVICE_MODE), 0) == DEVICE_MODE_SLEEPY_END_DEVICE) def check_child_table(): verify_child_table(parent, children) wpan.verify_within(check_child_table, WAIT_INTERVAL) # Prepare a set of IP message tx to both children NUM_MSGS = 6 parent_ml_address = parent.get(wpan.WPAN_IP6_MESH_LOCAL_ADDRESS)[1:-1] child2_ml_address = child2.get(wpan.WPAN_IP6_MESH_LOCAL_ADDRESS)[1:-1] sender = parent.prepare_tx(parent_ml_address, child2_ml_address, 800, NUM_MSGS) child2_rx_ip_counter = int(child2.get(wpan.WPAN_NCP_COUNTER_RX_IP_SEC_TOTAL), 0) wpan.Node.perform_async_tx_rx() verify(sender.was_successful)
EXPECTED_SAMEPLE_COUNT = 970 # Sleep for 4.5 second with speedup factor of 10,000 this is more than 12 # hours. We sleep instead of immediately checking the sample counter in # order to not add more actions/events into simulation (specially since # we are running at very high speedup). time.sleep(4.5) def check_sample_count(): verify( int(node.get(wpan.WPAN_CHANNEL_MONITOR_SAMPLE_COUNT), 0) > EXPECTED_SAMEPLE_COUNT) wpan.verify_within(check_sample_count, WAIT_TIME) # Verify the initial value of `NEW_CHANNEL` (should be zero if there has # been no channel change so far). verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 0) # Issue a channel-select with quality check enabled, and verify that no # action is taken. node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'false') verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 0) # Issue a channel-select with quality check disabled, verify that channel # is switched to channel 11.
r1.set(wpan.WPAN_DAEMON_OFF_MESH_ROUTE_AUTO_ADD_ON_INTERFACE, 'false') verify(r1.get(wpan.WPAN_DAEMON_OFF_MESH_ROUTE_AUTO_ADD_ON_INTERFACE) == 'false') # Add on-mesh prefixes 1, 2, and 3 and off-mesh route 5 on r2. r2.add_prefix(PREFIX1, prefix_len=LEN1, on_mesh=True, slaac=False) r2.add_prefix(PREFIX2, prefix_len=LEN2, on_mesh=True, slaac=True) r2.add_prefix(PREFIX3, prefix_len=LEN2, on_mesh=False, slaac=False) r2.add_route(ROUTE5, prefix_len=LEN5, priority=MEDIUM_PRIORITY) # We expect to only see routes associated the first two (which are on-mesh) on r1. def check_routes_on_r1_is_prefix1_and_prefix2(): verify_interface_routes(r1, [(PREFIX1, LEN1, MEDIUM_METRIC), (PREFIX2, LEN2, MEDIUM_METRIC)]) wpan.verify_within(check_routes_on_r1_is_prefix1_and_prefix2, WAIT_TIME) # Remove all prefixes r2.remove_prefix(PREFIX1, prefix_len=LEN1) r2.remove_prefix(PREFIX2, prefix_len=LEN2) r2.remove_prefix(PREFIX3, prefix_len=LEN2) r2.remove_route(ROUTE5, prefix_len=LEN5) # We expect all associated routes to be removed on r1 def check_routes_on_r1_is_empty(): verify_interface_routes(r1, []) wpan.verify_within(check_routes_on_r1_is_empty, WAIT_TIME)
PSKd = '123456' joiner_hw_addr = j.get(wpan.WPAN_HW_ADDRESS)[1:-1] # Remove the `[]` # Start the commissioner and add joiner hw address along with PSKd c.commissioner_start() c.commissioner_add_joiner(joiner_hw_addr, PSKd) # Start Joiner j.joiner_join(PSKd) # Verify that Joiner succeeded verify(j.get(wpan.WPAN_STATE) == wpan.STATE_COMMISSIONED) j.joiner_attach() def joiner_is_asscoated(): verify(j.is_associated()) wpan.verify_within(joiner_is_asscoated, WAIT_TIME) # ----------------------------------------------------------------------------------------------------------------------- # Test finished wpan.Node.finalize_all_nodes() print('\'{}\' passed.'.format(test_name))
# should fail (due to allowlist) and cause the `child` to get detached and # search for a new parent and then attach to `parent1`. # # To verify that the `child` does get detached and attach to a new parent, we # monitor the number of state changes using wpantund property "stat:ncp". child_num_state_changes = len(wpan.parse_list(child.get("stat:ncp"))) def check_child_is_reattached(): verify( len(wpan.parse_list(child.get("stat:ncp"))) > child_num_state_changes) verify(child.is_associated()) wpan.verify_within(check_child_is_reattached, CHILD_SUPERVISION_CHECK_TIMEOUT / speedup + 5) # Verify that the `child` is now attached to `parent1` child_table = wpan.parse_list(parent1.get(wpan.WPAN_THREAD_CHILD_TABLE)) verify(len(child_table) == 1) # Finally verify that the `child` is removed from previous parent's child # table (which indicates that the `child` did indeed inform its previous # parent). def check_child_is_removed_from_parent2_table(): child_table = wpan.parse_list(parent2.get(wpan.WPAN_THREAD_CHILD_TABLE)) verify(len(child_table) == 0)
# # Since child is not in parent's whitelist, the data polls from child # should be rejected and the child should be removed from parent's # child table after timeout. The child however should continue to # stay attached (since data polls are acked by radio driver) and # supervision check is disabled on the child. parent.set(wpan.WPAN_MAC_WHITELIST_ENABLED, '1') def check_child_is_removed_from_parent_child_table(): child_table = wpan.parse_child_table_result(parent.get(wpan.WPAN_THREAD_CHILD_TABLE)) verify(len(child_table) == 0) # wait till child is removed from parent's child table # after this child should still be associated wpan.verify_within(check_child_is_removed_from_parent_child_table, CHILD_TIMEOUT / speedup + 2) verify(child.is_associated()) # Enable supervision check on child and expect the child to # become detached after the check timeout child.set(wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT, str(CHILD_SUPERVISION_CHECK_TIMEOUT)) def check_child_is_detached(): verify(not child.is_associated()) wpan.verify_within(check_child_is_detached, CHILD_SUPERVISION_CHECK_TIMEOUT / speedup + 8) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Enable child supervision on parent and disable white-listing
def test_prefix_add_remove(): # Tests adding and removing stable and temporary prefixes on r1 # Verifies that all nodes in network do see the updates and that # Network Data version and stable version are updated correctly. old_version = int(leader.get(wpan.WPAN_THREAD_NETWORK_DATA_VERSION), 0) old_stable_version = int( leader.get(wpan.WPAN_THREAD_STABLE_NETWORK_DATA_VERSION), 0) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Add a stable prefix and check all nodes see the prefix c1.add_prefix(prefix1, stable=True) def check_prefix1(): verify_prefix( [leader, c1, c2], prefix1, c1_rloc, stable=True, ) verify_prefix( [c3], prefix1, no_rloc, stable=True, ) wpan.verify_within(check_prefix1, WAIT_TIME) new_version = int(leader.get(wpan.WPAN_THREAD_NETWORK_DATA_VERSION), 0) new_stable_version = int( leader.get(wpan.WPAN_THREAD_STABLE_NETWORK_DATA_VERSION), 0) verify(new_version == ((old_version + 1) % 256)) verify(new_stable_version == ((old_stable_version + 1) % 256)) old_version = new_version old_stable_version = new_stable_version # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Add prefix 2 as temp (not stable) c1.add_prefix(prefix2, stable=False) def check_prefix2(): verify_prefix( [leader, c1, c2], prefix2, c1_rloc, stable=False, ) wpan.verify_within(check_prefix1, WAIT_TIME) wpan.verify_within(check_prefix2, WAIT_TIME) new_version = int(leader.get(wpan.WPAN_THREAD_NETWORK_DATA_VERSION), 0) new_stable_version = int( leader.get(wpan.WPAN_THREAD_STABLE_NETWORK_DATA_VERSION), 0) verify(new_version == ((old_version + 1) % 256)) verify(new_stable_version == old_stable_version) old_version = new_version old_stable_version = new_stable_version # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Remove prefix 1 c1.remove_prefix(prefix1) def check_no_prefix1(): verify_no_prefix([leader, c1, c2], prefix1, c1_rloc) wpan.verify_within(check_no_prefix1, WAIT_TIME) wpan.verify_within(check_prefix2, WAIT_TIME) new_version = int(leader.get(wpan.WPAN_THREAD_NETWORK_DATA_VERSION), 0) new_stable_version = int( leader.get(wpan.WPAN_THREAD_STABLE_NETWORK_DATA_VERSION), 0) verify(new_version == ((old_version + 1) % 256)) verify(new_stable_version == ((old_stable_version + 1) % 256)) old_version = new_version old_stable_version = new_stable_version # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Remove prefix 2 c1.remove_prefix(prefix2) def check_no_prefix2(): verify_no_prefix([leader, c1, c2], prefix2, c1_rloc) wpan.verify_within(check_no_prefix1, WAIT_TIME) wpan.verify_within(check_no_prefix2, WAIT_TIME) new_version = int(leader.get(wpan.WPAN_THREAD_NETWORK_DATA_VERSION), 0) new_stable_version = int( leader.get(wpan.WPAN_THREAD_STABLE_NETWORK_DATA_VERSION), 0) verify(new_version == ((old_version + 1) % 256)) verify(new_stable_version == old_stable_version)
r2_ext_address = r2.get(wpan.WPAN_EXT_ADDRESS)[1:-1] r2_rloc = int(r2.get(wpan.WPAN_THREAD_RLOC16), 16) r2_ml_address = r2.get(wpan.WPAN_IP6_MESH_LOCAL_ADDRESS)[1:-1] # Wait for r2 to become router and r1 establishes a link with it def check_r1_router_table(): router_table = wpan.parse_router_table_result( r1.get(wpan.WPAN_THREAD_ROUTER_TABLE)) verify(len(router_table) == 2) for entry in router_table: verify(entry.rloc16 == r1_rloc or entry.is_link_established()) wpan.verify_within(check_r1_router_table, WAIT_TIME) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Check that r1 detected both trel and 15.4 as supported radio by r2 r1_radios = wpan.parse_list(r1.get(wpan.WPAN_OT_SUPPORTED_RADIO_LINKS)) verify( len(r1_radios) == 2 and (wpan.RADIO_LINK_IEEE_802_15_4 in r1_radios) and (wpan.RADIO_LINK_TREL_UDP6 in r1_radios)) r2_radios = wpan.parse_list(r2.get(wpan.WPAN_OT_SUPPORTED_RADIO_LINKS)) verify( len(r2_radios) == 2 and (wpan.RADIO_LINK_IEEE_802_15_4 in r2_radios) and (wpan.RADIO_LINK_TREL_UDP6 in r2_radios))
child1.set(wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT, '0') child2.set(wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT, '0') # Verify Thread Device Mode on both children verify( int(child1.get(wpan.WPAN_THREAD_DEVICE_MODE), 0) == DEVICE_MODE_END_DEVICE) verify( int(child2.get(wpan.WPAN_THREAD_DEVICE_MODE), 0) == DEVICE_MODE_SLEEPY_END_DEVICE) def check_child_table(): verify_child_table(parent, children) wpan.verify_within(check_child_table, WAIT_INTERVAL) # Reset parent and verify all children are recovered parent.reset() wpan.verify_within(check_child_table, WAIT_INTERVAL) # Change mode on both children (make child1 sleepy, and child2 non-sleepy) child1.set(wpan.WPAN_THREAD_DEVICE_MODE, str(DEVICE_MODE_SLEEPY_END_DEVICE)) verify( int(child1.get(wpan.WPAN_THREAD_DEVICE_MODE), 0) == DEVICE_MODE_SLEEPY_END_DEVICE) child2.set(wpan.WPAN_THREAD_DEVICE_MODE, str(DEVICE_MODE_END_DEVICE)) verify( int(child2.get(wpan.WPAN_THREAD_DEVICE_MODE), 0) == DEVICE_MODE_END_DEVICE)
# by removing them from each other's allowlist table r1.un_allowlist_node(r2) r2.un_allowlist_node(r1) # Add a prefix before r2 realizes it can not longer talk # to leader (r1). r2.add_prefix(prefix2) # Check that r2 forms its own partition def check_r2_become_leader(): verify(r2.get(wpan.WPAN_NODE_TYPE) == wpan.NODE_TYPE_LEADER) wpan.verify_within(check_r2_become_leader, long_wait) # While we have two partition, add a prefix on r1 r1.add_prefix(prefix1) # Update allowlist and wait for partitions to merge. r1.allowlist_node(r2) r2.allowlist_node(r1) def check_partition_id_match(): verify(r1.get(wpan.WPAN_PARTITION_ID) == r2.get(wpan.WPAN_PARTITION_ID)) wpan.verify_within(check_partition_id_match, long_wait)
# Add 4 prefixes (all with SLAAC bit set). parent.add_prefix(prefix1, on_mesh=True, slaac=True, configure=True) parent.add_prefix(prefix2, on_mesh=True, slaac=True, configure=True) parent.add_prefix(prefix3, on_mesh=True, slaac=True, configure=True) parent.add_prefix(prefix4, on_mesh=True, slaac=True, configure=True) # Verify that the sleepy child gets all 4 SLAAC addresses. def check_addresses_on_child(): verify_address([child], prefix1) verify_address([child], prefix2) verify_address([child], prefix3) verify_address([child], prefix4) wpan.verify_within(check_addresses_on_child, WAIT_TIME) # Enable white-listing on parent. parent.set(wpan.WPAN_MAC_WHITELIST_ENABLED, '1') # Enable supervision check on child, this ensures that child is detached soon. child.set(wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT, str(CHILD_SUPERVISION_CHECK_TIMEOUT)) # Wait for child to get detached. def check_child_is_detached(): verify(not child.is_associated()) wpan.verify_within(check_child_is_detached, WAIT_TIME)
node.set(wpan.WPAN_OT_SLAAC_ENABLED, 'false') verify(node.get(wpan.WPAN_OT_SLAAC_ENABLED) == 'false') WAIT_INTERVAL = 5 PREFIX = 'fd00:abba:beef:cafe::' r1.add_prefix(PREFIX, stable=True, on_mesh=True, slaac=True) # Verify that all nodes get the prefix and add the SLAAC address def check_prefix_and_slaac_address_are_added(): verify_prefix(all_nodes, PREFIX, stable=True, on_mesh=True, slaac=True) verify_address(all_nodes, PREFIX) wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) # Reset r1 and check that prefix and SLAAC address are re-added r1.reset() wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) # Remove the prefix on r1 and verify that the address and prefix are removed on all nodes. r1.remove_prefix(PREFIX) def check_prefix_and_slaac_address_are_removed(): verify_no_prefix(all_nodes, PREFIX) verify_no_address(all_nodes, PREFIX) wpan.verify_within(check_prefix_and_slaac_address_are_removed, WAIT_INTERVAL) # Add prefix on r2
# Check the retry-query behavior # Wait till all the address queries time out and verify they enter "retry-query" state. def check_cache_entry_switch_to_retry_state(): cache_table = wpan.parse_address_cache_table_result( r1.get(wpan.WPAN_THREAD_ADDRESS_CACHE_TABLE)) for index in range(NUM_QUERY_ADDRS): verify(cache_table[index].state == wpan.ADDRESS_CACHE_ENTRY_STATE_RETRY_QUERY) verify(cache_table[index].retry_delay == 2 * INITIAL_RETRY_DELAY) wpan.verify_within(check_cache_entry_switch_to_retry_state, WAIT_TIME) # Try sending again to same addresses which are in "retry-delay" state. for num in range(NUM_QUERY_ADDRS): sender = r1.prepare_tx((r1_address, PORT), (PREFIX + "800:" + str(num), PORT), "hi nobody!", 1) wpan.Node.perform_async_tx_rx() verify(sender.was_successful) # Make sure the entries stayed in retry-delay as before. wpan.verify_within(check_cache_entry_switch_to_retry_state, WAIT_TIME) # Now wait for them to get to zero timeout.
# Starting with `joiner2` verifies the behavior of Commissioner to # prefer the Joiner entry with the longest matching discriminator. Note # that `joiner2` uses a longer discriminator compared to `joiner1` with # similar value. joiner2.joiner_join(PSK2) verify(joiner2.get(wpan.WPAN_STATE) == wpan.STATE_COMMISSIONED) joiner2.joiner_attach() def joiner2_is_associated(): verify(joiner2.is_associated()) wpan.verify_within(joiner2_is_associated, WAIT_TIME) # Start `joiner1` joiner1.joiner_join(PSK1) verify(joiner1.get(wpan.WPAN_STATE) == wpan.STATE_COMMISSIONED) joiner1.joiner_attach() def joiner1_is_associated(): verify(joiner1.is_associated()) wpan.verify_within(joiner1_is_associated, WAIT_TIME) # Start `joiner3`
# r1 should be directly connected to r2. verify(entry.is_link_established()) verify(entry.ext_address == r2_ext_addr) elif entry.rloc16 == r3_rloc: # r1 should be directly connected to r3. verify(entry.is_link_established()) verify(entry.ext_address == r3_ext_addr) elif entry.rloc16 == r4_rloc: # r1's next hop towards r4 should be through r3. verify(not entry.is_link_established()) verify(entry.next_hop == r3_id) else: raise (wpan.VerifyError("unknown entry in the router table of r1")) wpan.verify_within(check_r1_router_table, WAIT_TIME) def check_r3_router_table(): router_table = wpan.parse_router_table_result( r3.get(wpan.WPAN_THREAD_ROUTER_TABLE)) verify(len(router_table) == 4) for entry in router_table: if entry.rloc16 == r1_rloc: # r3 should be directly connected to r1. verify(entry.is_link_established()) verify(entry.ext_address == r1_ext_addr) elif entry.rloc16 == r2_rloc: # r3 should be directly connected to r2. verify(entry.is_link_established()) verify(entry.ext_address == r2_ext_addr)
verify(p.is_slaac() == False) verify(p.is_dhcp() == False) verify(p.is_config() == False) verify(p.priority == "med") break else: # `for` loop finished without finding the prefix. raise wpan.VerifyError('Did not find prefix {} on node {}'.format(prefix, node)) # Verify that IPv6 address of `sed2` is present on `r2` (its parent) "Thread:ChildTable:Addresses". addr_str = r2.get(wpan.WPAN_THREAD_CHILD_TABLE_ADDRESSES) # search for index on address in the `addr_str` and ensure it is non-negative. verify(addr_str.find(IP6_ADDR_3) >= 0) # Check the addresses and prefixes (wait time 20 seconds) wpan.verify_within(check_addresses_and_prefixes, 15) # Reset the nodes and verify that all addresses/prefixes are preserved. fed1.reset() sed2.reset() wpan.verify_within(check_addresses_and_prefixes, 20) # Remove address from `r2` r2.remove_ip6_address_on_interface(IP6_ADDR_1, prefix_len=64) def check_address_prefix_removed(): # Verify that address is removed from r2 verify(r2.find_ip6_address_with_prefix(IP6_PREFIX_1) == '') # Verify that the related prefix is also removed on all nodes for node in all_nodes: prefixes = wpan.parse_on_mesh_prefix_result(node.get(wpan.WPAN_THREAD_ON_MESH_PREFIXES))
# Verify (within 5 seconds) that corresponding prefix is seen on both nodes. def check_prefix(): for node in [r1, r2]: prefixes = wpan.parse_on_mesh_prefix_result(node.get(wpan.WPAN_THREAD_ON_MESH_PREFIXES)) for p in prefixes: if p.prefix == IP6_PREFIX: if (p.origin == 'ncp' and p.prefix_len == '64' and p.is_stable() and p.is_on_mesh() and p.is_preferred() and not p.is_def_route() and not p.is_slaac() and not p.is_dhcp() and not p.is_config() and p.priority == "med"): break else: # `for` loop finished without finding the prefix. raise wpan.VerifyError('Did not find prefix {} on node {}'.format(IP6_PREFIX, r1)) wpan.verify_within(check_prefix, 5) # After prefix is seen on r1, add an address with same prefix on r1. r1.add_ip6_address_on_interface(IP6_ADDR_1, prefix_len=64) # Verify that the prefix is still seen on both nodes. wpan.verify_within(check_prefix, 5) # Remove the address from r2 which should remove the corresponding the prefix as well # After this since r1 still has the address, the prefix should be present on both nodes. r2.remove_ip6_address_on_interface(IP6_ADDR_2, prefix_len=64) wpan.verify_within(check_prefix, 5) # Reset r1 and verify that the prefix is retained correctly (by wpantund). r1.reset() wpan.verify_within(check_prefix, 8)
verify_interface_routes(r1, []) # Add all 3 routes on r2. r2.add_route(ROUTE1, prefix_len=LEN1, priority=LOW_PRIORITY) r2.add_route(ROUTE2, prefix_len=LEN2, priority=MEDIUM_PRIORITY) r2.add_route(ROUTE3, prefix_len=LEN3, priority=HIGH_PRIORITY) # We expect to see all 3 routes added on r1 host interface with same priority levels as r2. def check_routes_on_r1_1(): verify_interface_routes(r1, [(ROUTE1, LEN1, LOW_METRIC), (ROUTE2, LEN2, MEDIUM_METRIC), (ROUTE3, LEN3, HIGH_METRIC)]) wpan.verify_within(check_routes_on_r1_1, WAIT_TIME) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Add the same routes on r3 with different priorities. r3.add_route(ROUTE1, prefix_len=LEN1, priority=MEDIUM_PRIORITY) r3.add_route(ROUTE2, prefix_len=LEN2, priority=LOW_PRIORITY) # We expect the host interface routes on r1 to change accordingly def check_routes_on_r1_2(): route_list = [(ROUTE1, LEN1, MEDIUM_METRIC), (ROUTE2, LEN2, MEDIUM_METRIC), (ROUTE3, LEN3, HIGH_METRIC)] verify_interface_routes(r1, route_list)
and p.is_on_mesh() and p.is_preferred() and not p.is_def_route() and not p.is_slaac() and not p.is_dhcp() and not p.is_config() and p.priority == "med" ): break else: # `for` loop finished without finding the prefix. raise wpan.VerifyError( 'Did not find prefix {} on node {}'.format(IP6_PREFIX, r1) ) wpan.verify_within(check_prefix, 5) # After prefix is seen on r1, add an address with same prefix on r1. r1.add_ip6_address_on_interface(IP6_ADDR_1, prefix_len=64) # Verify that the prefix is still seen on both nodes. wpan.verify_within(check_prefix, 5) # Remove the address from r2 which should remove the corresponding the prefix as well # After this since r1 still has the address, the prefix should be present # on both nodes. r2.remove_ip6_address_on_interface(IP6_ADDR_2, prefix_len=64) wpan.verify_within(check_prefix, 5) # Reset r1 and verify that the prefix is retained correctly (by wpantund). r1.reset()
verify(c2.get(wpan.WPAN_NODE_TYPE) == wpan.NODE_TYPE_SLEEPY_END_DEVICE) verify(c3.get(wpan.WPAN_NODE_TYPE) == wpan.NODE_TYPE_END_DEVICE) r2_rloc = int(r2.get(wpan.WPAN_THREAD_RLOC16), 16) r3_rloc = int(r3.get(wpan.WPAN_THREAD_RLOC16), 16) c3_rloc = int(c3.get(wpan.WPAN_THREAD_RLOC16), 16) # Wait till we have a valid "next hop" route on r1 towards r3 def check_r1_router_table(): router_table = wpan.parse_router_table_result(r1.get(wpan.WPAN_THREAD_ROUTER_TABLE)) verify(len(router_table) == 3) for entry in router_table: if entry.rloc16 == r3_rloc: verify(entry.next_hop != INVALID_ROUTER_ID) wpan.verify_within(check_r1_router_table, ROUTER_TABLE_WAIT_TIME) r1_address = r1.find_ip6_address_with_prefix(PREFIX) c1_address = c1.find_ip6_address_with_prefix(PREFIX) c2_address = c2.find_ip6_address_with_prefix(PREFIX) c3_address = c3.find_ip6_address_with_prefix(PREFIX) # Send a single UDP message from r1 to c2 sender = r1.prepare_tx(r1_address, c2_address, "Hi from r1 to c2") recver = c2.prepare_rx(sender) wpan.Node.perform_async_tx_rx() verify(sender.was_successful and recver.was_successful) # Send a single UDP message from r1 to c3
prefix3 = 'fd00:deed::' prefix4 = 'fd00:abcd::' # Add on-mesh prefix1 on router r1 r1.config_gateway(prefix1) # Verify that the prefix1 and its corresponding address are present on all # nodes def check_prefix1_on_all_nodes(): verify_prefix(all_nodes, prefix1, stable=True, on_mesh=True, slaac=True) verify_address(all_nodes, prefix1) wpan.verify_within(check_prefix1_on_all_nodes, WAIT_TIME) # Now add prefix2 with priority `high` on router r2 and check all nodes # for the new prefix/address r2.config_gateway(prefix2, default_route=True, priority='1') def check_prefix2_on_all_nodes(): verify_prefix( all_nodes, prefix2, stable=True, on_mesh=True, slaac=True, default_route=True, priority='high',
r2_rloc, on_mesh=True, preferred=True, stable=True, ) verify_prefix( [r1, r2, c2], common_prefix, c2_rloc, on_mesh=True, preferred=False, stable=True, ) wpan.verify_within(check_prefixes, wait_time) # Remove `r2`. This should trigger all the prefixes added by it or its # child to timeout and be removed. r2.leave() def check_prefixes_on_r1_after_r2_leave(): # Verify that entries added by r1 are still present verify_prefix([r1], prefix1, r1_rloc, on_mesh=True, preferred=True, stable=True) verify_prefix(
elif entry.rloc16 == r2_rloc: # r1 should be directly connected to r2. verify(entry.is_link_established()) verify(entry.ext_address == r2_ext_addr) elif entry.rloc16 == r3_rloc: # r1 should be directly connected to r3. verify(entry.is_link_established()) verify(entry.ext_address == r3_ext_addr) elif entry.rloc16 == r4_rloc: # r1's next hop towards r4 should be through r3. verify(not entry.is_link_established()); verify(entry.next_hop == r3_id) else: raise(wpan.VerifyError("unknown entry in the router table of r1")) wpan.verify_within(check_r1_router_table, WAIT_TIME) def check_r3_router_table(): router_table = wpan.parse_router_table_result(r3.get(wpan.WPAN_THREAD_ROUTER_TABLE)) verify(len(router_table) == 4) for entry in router_table: if entry.rloc16 == r1_rloc: # r3 should be directly connected to r1. verify(entry.is_link_established()) verify(entry.ext_address == r1_ext_addr) elif entry.rloc16 == r2_rloc: # r3 should be directly connected to r2. verify(entry.is_link_established()) verify(entry.ext_address == r2_ext_addr) elif entry.rloc16 == r3_rloc: pass
r1.set(wpan.WPAN_CHILD_SUPERVISION_INTERVAL, str(PARENT_SUPERVISION_INTERVAL)) r3.set(wpan.WPAN_CHILD_SUPERVISION_INTERVAL, str(PARENT_SUPERVISION_INTERVAL)) r2.un_whitelist_node(c) r1.whitelist_node(c) c.whitelist_node(r1) # Wait for c to detach from r2 and attach to r1. def check_c_is_removed_from_r2_child_table(): child_table = wpan.parse_list(r2.get(wpan.WPAN_THREAD_CHILD_TABLE)) verify(len(child_table) == 0) wpan.verify_within(check_c_is_removed_from_r2_child_table, REATTACH_WAIT_TIME) # check that c is now a child of r1 child_table = wpan.parse_list(r1.get(wpan.WPAN_THREAD_CHILD_TABLE)) verify(len(child_table) == 1) # Send a single UDP message from r2 to c # # This adds an address cache entry on r2 for c pointing to r1 (the current parent of c). sender = r2.prepare_tx(r2_address, c_address, "Hi from r2 to c") recver = c.prepare_rx(sender) wpan.Node.perform_async_tx_rx() verify(sender.was_successful and recver.was_successful) # Force c to switch its parent from r1 to r3