1#!/usr/bin/env python3 2# 3# Copyright (c) 2020, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29 30import unittest 31 32import command 33import config 34import mle 35import thread_cert 36 37LEADER_1_2 = 1 38MED_1_2 = 2 39SED_1_2 = 3 40MED_1_1 = 4 41SED_1_1 = 5 42ROUTER_1_1 = 6 43MED_1_2_2 = 7 44SED_1_2_2 = 8 45 46WAIT_ATTACH = 5 47WAIT_REDUNDANCE = 3 48ROUTER_SELECTION_JITTER = 1 49 50MA1_LINKLOCAL = 'ff02::1:2:3:4' 51MA2_ADMINSCOPE = 'ff04::1:2:3:4' 52""" 53 Topology 54 55 SED_1_2 56 | 57 | 58MED_1_2 --- LEADER_1_2 --- MED_1_1 59 | \ 60 | \ 61 SED_1_1 ROUTER_1_1 --- MED_1_2_2 62 | 63 | 64 SED_1_2_2 65 66 1) Bring up Leader_1_2. 67 68 2) Bring up MED_1_2, which attaches to Thread 1.2 parent, only register MA with scope larger than realm local. 69 a) add MA1_LINKLOCAL which would NOT be registered in AddressRegistrationTLV of Child Update Request. 70 b) add MA2_ADMINSCOPE which would be registered in AddressRegistrationTLV of Child Update Request. 71 72 3) Bring up SED_1_2, which attaches to Thread 1.2 parent, register any external MA for indirect transmission. 73 a) add MA1_LINKLOCAL which would be registered in AddressRegistrationTLV of Child Update Request 74 b) add MA2_ADMINSCOPE which would be registered in AddressRegistrationTLV of Child Update Request. 75 76 4) Bring up MED_1_1, which attaches to Thread 1.2 parent, not register any external MA. 77 a) add MA1_LINKLOCAL which would NOT be registered in AddressRegistrationTLV of Child Update Request. 78 b) add MA2_ADMINSCOPE which would NOT be registered in AddressRegistrationTLV of Child Update Request. 79 80 5) Bring up SED_1_1, which attaches to Thread 1.2 parent, register any external MA for indirect transmission. 81 a) add MA1_LINKLOCAL which would be registered in AddressRegistrationTLV of Child Update Request 82 b) add MA2_ADMINSCOPE which would be registered in AddressRegistrationTLV of Child Update Request. 83 84 6) Bring up ROUTER_1_1. 85 86 7) Bring up MED_1_2_2 which attaches to Thread 1.1 parent, not register any external MA. 87 a) add MA1_LINKLOCAL which would NOT be registered in AddressRegistrationTLV of Child Update Request 88 b) add MA2_ADMINSCOPE which would NOT be registered in AddressRegistrationTLV of Child Update Request. 89 90 8) Bring up SED_1_2_2 which attaches to Thread 1.1 parent, register any external MA for indirect transmission. 91 a) add MA1_LINKLOCAL which would be registered in AddressRegistrationTLV of Child Update Request 92 b) add MA2_ADMINSCOPE which would be registered in AddressRegistrationTLV of Child Update Request. 93 94""" 95 96 97class TestMulticastRegistration(thread_cert.TestCase): 98 TOPOLOGY = { 99 LEADER_1_2: { 100 'version': '1.2', 101 'allowlist': [MED_1_2, SED_1_2, MED_1_1, SED_1_1, ROUTER_1_1], 102 }, 103 MED_1_2: { 104 'mode': 'rn', 105 'version': '1.2', 106 'allowlist': [LEADER_1_2], 107 }, 108 SED_1_2: { 109 'mode': 'n', 110 'version': '1.2', 111 'allowlist': [LEADER_1_2], 112 }, 113 MED_1_1: { 114 'mode': 'rn', 115 'version': '1.1', 116 'allowlist': [LEADER_1_2], 117 }, 118 SED_1_1: { 119 'mode': 'n', 120 'version': '1.1', 121 'allowlist': [LEADER_1_2], 122 }, 123 ROUTER_1_1: { 124 'version': '1.1', 125 'allowlist': [LEADER_1_2, MED_1_2_2, SED_1_2_2], 126 }, 127 MED_1_2_2: { 128 'mode': 'rn', 129 'version': '1.2', 130 'allowlist': [ROUTER_1_1], 131 }, 132 SED_1_2_2: { 133 'mode': 'n', 134 'version': '1.2', 135 'allowlist': [ROUTER_1_1], 136 }, 137 } 138 """All nodes are created with default configurations""" 139 140 def __check_multicast_registration(self, 141 node, 142 multicast_address, 143 child_update_request_assert=True, 144 in_address_registration=True): 145 ''' Check whether or not the addition of the multicast address on the specific node 146 would trigger Child Update Request for multicast address registration via Address 147 Registration TLV. 148 149 Args: 150 node (int) : The device id 151 multicast_address (string): The multicast address 152 child_update_request_assert (bool): whether or not the addition should trigger Child Update Request 153 in_address_registration (bool): Whether or not the multicast_address should be registered 154 ''' 155 # Flush relative message queues. 156 self.flush_nodes([node]) 157 158 self.nodes[node].add_ipmaddr(multicast_address) 159 WAIT_TIME = WAIT_REDUNDANCE 160 self.simulator.go(WAIT_TIME) 161 162 messages = self.simulator.get_messages_sent_by(node) 163 164 msg = messages.next_mle_message(mle.CommandType.CHILD_UPDATE_REQUEST, 165 assert_enabled=child_update_request_assert) 166 167 if msg: 168 is_in = command.check_address_registration_tlv(msg, multicast_address) 169 170 if in_address_registration: 171 assert is_in, 'Error: Expected {} in AddressRegistrationTLV not found'.format(multicast_address) 172 else: 173 assert not is_in, 'Error: Unexpected {} in AddressRegistrationTLV'.format(multicast_address) 174 175 def test(self): 176 177 # 1) Bring up Leader_1_2. 178 self.nodes[LEADER_1_2].start() 179 WAIT_TIME = WAIT_ATTACH 180 self.simulator.go(WAIT_TIME * 2) 181 self.assertEqual(self.nodes[LEADER_1_2].get_state(), 'leader') 182 183 # 2) Bring up MED_1_2, which attaches to Thread 1.2 parent, only register MA with scope larger than realm local. 184 self.nodes[MED_1_2].start() 185 WAIT_TIME = WAIT_ATTACH 186 self.simulator.go(WAIT_TIME) 187 self.assertEqual(self.nodes[MED_1_2].get_state(), 'child') 188 189 # 2a) add MA1_LINKLOCAL which would NOT be registered in AddressRegistrationTLV of Child Update Request. 190 self.__check_multicast_registration(MED_1_2, 191 MA1_LINKLOCAL, 192 child_update_request_assert=False, 193 in_address_registration=False) 194 195 # 2b) add MA2_ADMINSCOPE which would be registered in AddressRegistrationTLV of Child Update Request. 196 self.__check_multicast_registration(MED_1_2, 197 MA2_ADMINSCOPE, 198 child_update_request_assert=True, 199 in_address_registration=True) 200 201 # 3) Bring up SED_1_2, which attaches to Thread 1.2 parent, register any external MA for indirect transmission. 202 self.nodes[SED_1_2].start() 203 WAIT_TIME = WAIT_ATTACH 204 self.simulator.go(WAIT_TIME) 205 self.assertEqual(self.nodes[SED_1_2].get_state(), 'child') 206 207 # 3a) add MA1_LINKLOCAL which would be registered in AddressRegistrationTLV of Child Update Request. 208 self.__check_multicast_registration(SED_1_2, 209 MA1_LINKLOCAL, 210 child_update_request_assert=True, 211 in_address_registration=True) 212 213 # 3b) add MA2_ADMINSCOPE which would be registered in AddressRegistrationTLV of Child Update Request. 214 self.__check_multicast_registration(SED_1_2, 215 MA2_ADMINSCOPE, 216 child_update_request_assert=True, 217 in_address_registration=True) 218 219 # 4) Bring up MED_1_1, which attaches to Thread 1.2 parent, not register any external MA. 220 self.nodes[MED_1_1].start() 221 WAIT_TIME = WAIT_ATTACH 222 self.simulator.go(WAIT_TIME) 223 self.assertEqual(self.nodes[MED_1_1].get_state(), 'child') 224 225 # 4a) add MA1_LINKLOCAL which would NOT be registered in AddressRegistrationTLV of Child Update Request. 226 self.__check_multicast_registration(MED_1_1, 227 MA1_LINKLOCAL, 228 child_update_request_assert=False, 229 in_address_registration=False) 230 231 # 4b) add MA2_ADMINSCOPE which would NOT be registered in AddressRegistrationTLV of Child Update Request. 232 self.__check_multicast_registration(MED_1_1, 233 MA2_ADMINSCOPE, 234 child_update_request_assert=False, 235 in_address_registration=False) 236 237 # 5) Bring up SED_1_1, which attaches to Thread 1.2 parent, register any external MA for indirect transmission. 238 self.nodes[SED_1_1].start() 239 WAIT_TIME = WAIT_ATTACH 240 self.simulator.go(WAIT_TIME) 241 self.assertEqual(self.nodes[SED_1_1].get_state(), 'child') 242 243 # 5a) add MA1_LINKLOCAL which would be registered in AddressRegistrationTLV of Child Update Request. 244 self.__check_multicast_registration(SED_1_1, 245 MA1_LINKLOCAL, 246 child_update_request_assert=True, 247 in_address_registration=True) 248 249 # 5b) add MA2_ADMINSCOPE which would be registered in AddressRegistrationTLV of Child Update Request. 250 self.__check_multicast_registration(SED_1_1, 251 MA2_ADMINSCOPE, 252 child_update_request_assert=True, 253 in_address_registration=True) 254 255 #6) Bring up ROUTER_1_1. 256 self.nodes[ROUTER_1_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER) 257 self.nodes[ROUTER_1_1].start() 258 WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER 259 self.simulator.go(WAIT_TIME) 260 self.assertEqual(self.nodes[ROUTER_1_1].get_state(), 'router') 261 262 # 7) Bring up MED_1_2_2 which attaches to Thread 1.1 parent, not register any external MA. 263 self.nodes[MED_1_2_2].start() 264 WAIT_TIME = WAIT_ATTACH 265 self.simulator.go(WAIT_TIME) 266 self.assertEqual(self.nodes[MED_1_2_2].get_state(), 'child') 267 268 # 7a) add MA1_LINKLOCAL which would NOT be registered in AddressRegistrationTLV of Child Update Request 269 self.__check_multicast_registration(MED_1_2_2, 270 MA1_LINKLOCAL, 271 child_update_request_assert=False, 272 in_address_registration=False) 273 274 # 7b) add MA2_ADMINSCOPE which would NOT be registered in AddressRegistrationTLV of Child Update Request. 275 self.__check_multicast_registration(MED_1_2_2, 276 MA2_ADMINSCOPE, 277 child_update_request_assert=False, 278 in_address_registration=False) 279 280 # 8) Bring up SED_1_2_2 which attaches to Thread 1.1 parent, register any external MA for indirect transmission. 281 self.nodes[SED_1_2_2].start() 282 WAIT_TIME = WAIT_ATTACH 283 self.simulator.go(WAIT_TIME) 284 self.assertEqual(self.nodes[SED_1_2_2].get_state(), 'child') 285 286 # 8a) add MA1_LINKLOCAL which would be registered in AddressRegistrationTLV of Child Update Request 287 self.__check_multicast_registration(SED_1_2_2, 288 MA1_LINKLOCAL, 289 child_update_request_assert=True, 290 in_address_registration=True) 291 292 # 8b) add MA2_ADMINSCOPE which would be registered in AddressRegistrationTLV of Child Update Request. 293 self.__check_multicast_registration(SED_1_2_2, 294 MA2_ADMINSCOPE, 295 child_update_request_assert=True, 296 in_address_registration=True) 297 298 299if __name__ == '__main__': 300 unittest.main() 301