1 /*
2 * Copyright (c) 2018, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "test_platform.h"
30
31 #include <openthread/config.h>
32
33 #include "test_util.h"
34 #include "common/code_utils.hpp"
35 #include "instance/instance.hpp"
36 #include "thread/child.hpp"
37
38 namespace ot {
39
40 static Instance *sInstance;
41
42 enum
43 {
44 kMaxChildIp6Addresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD,
45 };
46
VerifyChildIp6Addresses(const Child & aChild,uint8_t aAddressListLength,const Ip6::Address aAddressList[])47 void VerifyChildIp6Addresses(const Child &aChild, uint8_t aAddressListLength, const Ip6::Address aAddressList[])
48 {
49 Ip6::Address::TypeFilter filters[] = {Ip6::Address::kTypeUnicast, Ip6::Address::kTypeMulticast};
50 bool addressObserved[kMaxChildIp6Addresses];
51 bool hasMeshLocal = false;
52
53 for (uint8_t index = 0; index < aAddressListLength; index++)
54 {
55 VerifyOrQuit(aChild.HasIp6Address(aAddressList[index]));
56 }
57
58 memset(addressObserved, 0, sizeof(addressObserved));
59
60 for (const Ip6::Address &address : aChild.IterateIp6Addresses())
61 {
62 bool addressIsInList = false;
63
64 for (uint8_t index = 0; index < aAddressListLength; index++)
65 {
66 if (address == aAddressList[index])
67 {
68 addressIsInList = true;
69 addressObserved[index] = true;
70 break;
71 }
72 }
73
74 VerifyOrQuit(addressIsInList, "Child::IterateIp6Addresses() returned an address not in the expected list");
75 }
76
77 for (uint8_t index = 0; index < aAddressListLength; index++)
78 {
79 Ip6::Address address;
80
81 VerifyOrQuit(addressObserved[index], "Child::IterateIp6Addresses() missed an entry from the expected list");
82
83 if (sInstance->Get<Mle::MleRouter>().IsMeshLocalAddress(aAddressList[index]))
84 {
85 SuccessOrQuit(aChild.GetMeshLocalIp6Address(address));
86 VerifyOrQuit(address == aAddressList[index], "GetMeshLocalIp6Address() did not return expected address");
87 hasMeshLocal = true;
88 }
89 }
90
91 if (!hasMeshLocal)
92 {
93 Ip6::Address address;
94
95 VerifyOrQuit(aChild.GetMeshLocalIp6Address(address) == kErrorNotFound,
96 "Child::GetMeshLocalIp6Address() returned an address not in the expected list");
97 }
98
99 // Iterate over unicast and multicast addresses separately.
100
101 memset(addressObserved, 0, sizeof(addressObserved));
102
103 for (Ip6::Address::TypeFilter filter : filters)
104 {
105 for (const Ip6::Address &address : aChild.IterateIp6Addresses(filter))
106 {
107 bool addressIsInList = false;
108
109 switch (filter)
110 {
111 case Ip6::Address::kTypeMulticast:
112 VerifyOrQuit(address.IsMulticast(), "Address::TypeFilter failed");
113 break;
114
115 case Ip6::Address::kTypeUnicast:
116 VerifyOrQuit(!address.IsMulticast(), "Address::TypeFilter failed");
117 break;
118
119 default:
120 break;
121 }
122
123 VerifyOrQuit(address.MatchesFilter(filter));
124
125 for (uint8_t index = 0; index < aAddressListLength; index++)
126 {
127 if (address == aAddressList[index])
128 {
129 VerifyOrQuit(addressObserved[index] == false,
130 "Child::IterateIp6Addresses() returned duplicate addr");
131 addressObserved[index] = true;
132 addressIsInList = true;
133 break;
134 }
135 }
136
137 VerifyOrQuit(addressIsInList, "Child::IterateIp6Addresses() returned an address not in the expected list");
138 }
139 }
140
141 for (uint8_t index = 0; index < aAddressListLength; index++)
142 {
143 VerifyOrQuit(addressObserved[index], "Child::IterateIp6Addresses() missed an entry from the expected list");
144 }
145
146 // Verify behavior of `Child::AddressIterator
147 {
148 Child::AddressIterator iter1(aChild);
149 Child::AddressIterator iter2(aChild);
150 Child::AddressIterator::Index iterIndex;
151
152 for (const Ip6::Address &address : aChild.IterateIp6Addresses())
153 {
154 VerifyOrQuit(iter1 == iter2);
155 VerifyOrQuit(!iter1.IsDone());
156 VerifyOrQuit(*iter1.GetAddress() == address);
157 VerifyOrQuit(*iter1.GetAddress() == *iter2.GetAddress());
158
159 iterIndex = iter1.GetAsIndex();
160 VerifyOrQuit(iter2.GetAsIndex() == iterIndex);
161
162 {
163 Child::AddressIterator iter3(aChild, iterIndex);
164 VerifyOrQuit(iter3 == iter1, "AddressIterator(iterIndex) failed");
165
166 iter3++;
167 VerifyOrQuit(iter3 != iter1, "AddressIterator(iterIndex) failed");
168 }
169
170 iter1++;
171 VerifyOrQuit(iter1 != iter2);
172 iter2++;
173 }
174
175 VerifyOrQuit(iter1.IsDone());
176 VerifyOrQuit(iter2.IsDone());
177 VerifyOrQuit(iter1 == iter2);
178
179 iterIndex = iter1.GetAsIndex();
180 VerifyOrQuit(iter2.GetAsIndex() == iterIndex);
181
182 {
183 Child::AddressIterator iter3(aChild, iterIndex);
184 VerifyOrQuit(iter3 == iter1, "AddressIterator(iterIndex) failed");
185 }
186 }
187 }
188
TestChildIp6Address(void)189 void TestChildIp6Address(void)
190 {
191 Child child;
192 Ip6::Address addresses[kMaxChildIp6Addresses];
193 uint8_t numAddresses;
194 const char *ip6Addresses[] = {
195 "fd00:1234::1234",
196 "ff6b:e251:52fb:0:12e6:b94c:1c28:c56a",
197 "fd00:1234::204c:3d7c:98f6:9a1b",
198 };
199
200 const uint8_t meshLocalIidArray[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
201 Ip6::InterfaceIdentifier meshLocalIid;
202
203 meshLocalIid.SetBytes(meshLocalIidArray);
204
205 sInstance = testInitInstance();
206 VerifyOrQuit(sInstance != nullptr);
207
208 child.Init(*sInstance);
209
210 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
211
212 printf("\nConverting IPv6 addresses from string");
213
214 numAddresses = 0;
215
216 // First addresses uses the mesh local prefix (mesh-local address).
217 addresses[numAddresses] = sInstance->Get<Mle::MleRouter>().GetMeshLocal64();
218 addresses[numAddresses].SetIid(meshLocalIid);
219
220 numAddresses++;
221
222 for (const char *ip6Address : ip6Addresses)
223 {
224 VerifyOrQuit(numAddresses < kMaxChildIp6Addresses, "Too many IPv6 addresses in the unit test");
225 SuccessOrQuit(addresses[numAddresses++].FromString(ip6Address));
226 }
227
228 printf(" -- PASS\n");
229
230 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
231 printf("Child state after init");
232 child.Clear();
233 VerifyChildIp6Addresses(child, 0, nullptr);
234 printf(" -- PASS\n");
235
236 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
237 printf("Adding a single IPv6 address");
238
239 for (uint8_t index = 0; index < numAddresses; index++)
240 {
241 SuccessOrQuit(child.AddIp6Address(addresses[index]));
242 VerifyChildIp6Addresses(child, 1, &addresses[index]);
243
244 child.ClearIp6Addresses();
245 VerifyChildIp6Addresses(child, 0, nullptr);
246 }
247
248 printf(" -- PASS\n");
249
250 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
251 printf("Adding multiple IPv6 addresses");
252
253 for (uint8_t index = 0; index < numAddresses; index++)
254 {
255 SuccessOrQuit(child.AddIp6Address(addresses[index]));
256 VerifyChildIp6Addresses(child, index + 1, addresses);
257 }
258
259 printf(" -- PASS\n");
260
261 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
262 printf("Checking for failure when adding an address already in list");
263
264 for (uint8_t index = 0; index < numAddresses; index++)
265 {
266 VerifyOrQuit(child.AddIp6Address(addresses[index]) == kErrorAlready,
267 "AddIp6Address() did not fail when adding same address");
268 VerifyChildIp6Addresses(child, numAddresses, addresses);
269 }
270
271 printf(" -- PASS\n");
272
273 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
274 printf("Removing addresses from list starting from front of the list");
275
276 for (uint8_t index = 0; index < numAddresses; index++)
277 {
278 SuccessOrQuit(child.RemoveIp6Address(addresses[index]));
279 VerifyChildIp6Addresses(child, numAddresses - 1 - index, &addresses[index + 1]);
280
281 VerifyOrQuit(child.RemoveIp6Address(addresses[index]) == kErrorNotFound,
282 "RemoveIp6Address() did not fail when removing an address not on the list");
283 }
284
285 VerifyChildIp6Addresses(child, 0, nullptr);
286 printf(" -- PASS\n");
287
288 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
289 printf("Removing addresses from list starting from back of the list");
290
291 for (uint8_t index = 0; index < numAddresses; index++)
292 {
293 SuccessOrQuit(child.AddIp6Address(addresses[index]));
294 }
295
296 for (uint8_t index = numAddresses - 1; index > 0; index--)
297 {
298 SuccessOrQuit(child.RemoveIp6Address(addresses[index]));
299 VerifyChildIp6Addresses(child, index, &addresses[0]);
300
301 VerifyOrQuit(child.RemoveIp6Address(addresses[index]) == kErrorNotFound,
302 "RemoveIp6Address() did not fail when removing an address not on the list");
303 }
304
305 printf(" -- PASS\n");
306
307 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
308 printf("Removing address entries from middle of the list");
309
310 for (uint8_t indexToRemove = 1; indexToRemove < numAddresses - 1; indexToRemove++)
311 {
312 child.ClearIp6Addresses();
313
314 for (uint8_t index = 0; index < numAddresses; index++)
315 {
316 SuccessOrQuit(child.AddIp6Address(addresses[index]));
317 }
318
319 SuccessOrQuit(child.RemoveIp6Address(addresses[indexToRemove]));
320
321 VerifyOrQuit(child.RemoveIp6Address(addresses[indexToRemove]) == kErrorNotFound,
322 "RemoveIp6Address() did not fail when removing an address not on the list");
323
324 {
325 Ip6::Address updatedAddressList[kMaxChildIp6Addresses];
326 uint8_t updatedListIndex = 0;
327
328 for (uint8_t index = 0; index < numAddresses; index++)
329 {
330 if (index != indexToRemove)
331 {
332 updatedAddressList[updatedListIndex++] = addresses[index];
333 }
334 }
335
336 VerifyChildIp6Addresses(child, updatedListIndex, updatedAddressList);
337 }
338 }
339
340 printf(" -- PASS\n");
341
342 testFreeInstance(sInstance);
343 }
344
345 } // namespace ot
346
main(void)347 int main(void)
348 {
349 ot::TestChildIp6Address();
350 printf("\nAll tests passed.\n");
351 return 0;
352 }
353