Example #1
0
                    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:
Example #2
0
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()
Example #3
0
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))
Example #8
0
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.
Example #12
0
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)
Example #15
0
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.
Example #19
0
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)
Example #20
0
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
Example #23
0
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)
Example #24
0
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)
Example #27
0
# 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
Example #29
0
# 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
Example #37
0
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