| /* |
| * Copyright (c) 2018, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "test_platform.h" |
| |
| #include <openthread/config.h> |
| |
| #include "test_util.h" |
| #include "common/code_utils.hpp" |
| #include "common/instance.hpp" |
| #include "thread/topology.hpp" |
| |
| namespace ot { |
| |
| static ot::Instance *sInstance; |
| |
| enum |
| { |
| kMaxChildIp6Addresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD, |
| }; |
| |
| void VerifyChildIp6Addresses(const Child &aChild, uint8_t aAddressListLength, const Ip6::Address aAddressList[]) |
| { |
| Child::Ip6AddressIterator iterator; |
| Ip6::Address address; |
| bool addressObserved[kMaxChildIp6Addresses]; |
| bool addressIsMeshLocal[kMaxChildIp6Addresses]; |
| bool hasMeshLocal = false; |
| |
| for (uint8_t index = 0; index < aAddressListLength; index++) |
| { |
| VerifyOrQuit(aChild.HasIp6Address(aAddressList[index]), "HasIp6Address() failed"); |
| } |
| |
| memset(addressObserved, 0, sizeof(addressObserved)); |
| memset(addressIsMeshLocal, 0, sizeof(addressObserved)); |
| |
| for (uint8_t index = 0; index < aAddressListLength; index++) |
| { |
| { |
| addressIsMeshLocal[index] = true; |
| } |
| } |
| |
| while (aChild.GetNextIp6Address(iterator, address) == OT_ERROR_NONE) |
| { |
| bool addressIsInList = false; |
| |
| for (uint8_t index = 0; index < aAddressListLength; index++) |
| { |
| if (address == aAddressList[index]) |
| { |
| addressIsInList = true; |
| addressObserved[index] = true; |
| break; |
| } |
| } |
| |
| VerifyOrQuit(addressIsInList, "Child::GetNextIp6Address() returned an address not in the expected list"); |
| } |
| |
| for (uint8_t index = 0; index < aAddressListLength; index++) |
| { |
| VerifyOrQuit(addressObserved[index], "Child::GetNextIp6Address() missed an entry from the expected list"); |
| |
| if (sInstance->Get<Mle::MleRouter>().IsMeshLocalAddress(aAddressList[index])) |
| { |
| SuccessOrQuit(aChild.GetMeshLocalIp6Address(address), "Child::GetMeshLocalIp6Address() failed\n"); |
| VerifyOrQuit(address == aAddressList[index], "GetMeshLocalIp6Address() did not return expected address"); |
| hasMeshLocal = true; |
| } |
| } |
| |
| if (!hasMeshLocal) |
| { |
| VerifyOrQuit(aChild.GetMeshLocalIp6Address(address) == OT_ERROR_NOT_FOUND, |
| "Child::GetMeshLocalIp6Address() returned an address not in the expected list"); |
| } |
| } |
| |
| void TestChildIp6Address(void) |
| { |
| Child child; |
| Ip6::Address addresses[kMaxChildIp6Addresses]; |
| uint8_t numAddresses; |
| const char * ip6Addresses[] = { |
| "fd00:1234::1234", |
| "fd6b:e251:52fb:0:12e6:b94c:1c28:c56a", |
| "fd00:1234::204c:3d7c:98f6:9a1b", |
| }; |
| |
| const uint8_t meshLocalIid[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; |
| |
| sInstance = testInitInstance(); |
| VerifyOrQuit(sInstance != nullptr, "Null instance"); |
| |
| child.Init(*sInstance); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| |
| printf("\nConverting IPv6 addresses from string"); |
| |
| numAddresses = 0; |
| |
| // First addresses uses the mesh local prefix (mesh-local address). |
| addresses[numAddresses] = sInstance->Get<Mle::MleRouter>().GetMeshLocal64(); |
| addresses[numAddresses].SetIid(meshLocalIid); |
| |
| numAddresses++; |
| |
| for (uint8_t index = 0; index < static_cast<uint8_t>(OT_ARRAY_LENGTH(ip6Addresses)); index++) |
| { |
| VerifyOrQuit(numAddresses < kMaxChildIp6Addresses, "Too many IPv6 addresses in the unit test"); |
| SuccessOrQuit(addresses[numAddresses++].FromString(ip6Addresses[index]), |
| "could not convert IPv6 address from string"); |
| } |
| |
| printf(" -- PASS\n"); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| printf("Child state after init"); |
| child.Clear(); |
| VerifyChildIp6Addresses(child, 0, nullptr); |
| printf(" -- PASS\n"); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| printf("Adding a single IPv6 address"); |
| |
| for (uint8_t index = 0; index < numAddresses; index++) |
| { |
| SuccessOrQuit(child.AddIp6Address(addresses[index]), "AddIp6Address() failed"); |
| VerifyChildIp6Addresses(child, 1, &addresses[index]); |
| |
| child.ClearIp6Addresses(); |
| VerifyChildIp6Addresses(child, 0, nullptr); |
| } |
| |
| printf(" -- PASS\n"); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| printf("Adding multiple IPv6 addresses"); |
| |
| for (uint8_t index = 0; index < numAddresses; index++) |
| { |
| SuccessOrQuit(child.AddIp6Address(addresses[index]), "AddIp6Address() failed"); |
| VerifyChildIp6Addresses(child, index + 1, addresses); |
| } |
| |
| printf(" -- PASS\n"); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| printf("Checking for failure when adding an address already in list"); |
| |
| for (uint8_t index = 0; index < numAddresses; index++) |
| { |
| VerifyOrQuit(child.AddIp6Address(addresses[index]) == OT_ERROR_ALREADY, |
| "AddIp6Address() did not fail when adding same address"); |
| VerifyChildIp6Addresses(child, numAddresses, addresses); |
| } |
| |
| printf(" -- PASS\n"); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| printf("Removing addresses from list starting from front of the list"); |
| |
| for (uint8_t index = 0; index < numAddresses; index++) |
| { |
| SuccessOrQuit(child.RemoveIp6Address(addresses[index]), "RemoveIp6Address() failed"); |
| VerifyChildIp6Addresses(child, numAddresses - 1 - index, &addresses[index + 1]); |
| |
| VerifyOrQuit(child.RemoveIp6Address(addresses[index]) == OT_ERROR_NOT_FOUND, |
| "RemoveIp6Address() did not fail when removing an address not on the list"); |
| } |
| |
| VerifyChildIp6Addresses(child, 0, nullptr); |
| printf(" -- PASS\n"); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| printf("Removing addresses from list starting from back of the list"); |
| |
| for (uint8_t index = 0; index < numAddresses; index++) |
| { |
| SuccessOrQuit(child.AddIp6Address(addresses[index]), "AddIp6Address() failed"); |
| } |
| |
| for (uint8_t index = numAddresses - 1; index > 0; index--) |
| { |
| SuccessOrQuit(child.RemoveIp6Address(addresses[index]), "RemoveIp6Address() failed"); |
| VerifyChildIp6Addresses(child, index, &addresses[0]); |
| |
| VerifyOrQuit(child.RemoveIp6Address(addresses[index]) == OT_ERROR_NOT_FOUND, |
| "RemoveIp6Address() did not fail when removing an address not on the list"); |
| } |
| |
| printf(" -- PASS\n"); |
| |
| //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| printf("Removing address entries from middle of the list"); |
| |
| for (uint8_t indexToRemove = 1; indexToRemove < numAddresses - 1; indexToRemove++) |
| { |
| child.ClearIp6Addresses(); |
| |
| for (uint8_t index = 0; index < numAddresses; index++) |
| { |
| SuccessOrQuit(child.AddIp6Address(addresses[index]), "AddIp6Address() failed"); |
| } |
| |
| SuccessOrQuit(child.RemoveIp6Address(addresses[indexToRemove]), "RemoveIp6Address() failed"); |
| |
| VerifyOrQuit(child.RemoveIp6Address(addresses[indexToRemove]) == OT_ERROR_NOT_FOUND, |
| "RemoveIp6Address() did not fail when removing an address not on the list"); |
| |
| { |
| Ip6::Address updatedAddressList[kMaxChildIp6Addresses]; |
| uint8_t updatedListIndex = 0; |
| |
| for (uint8_t index = 0; index < numAddresses; index++) |
| { |
| if (index != indexToRemove) |
| { |
| updatedAddressList[updatedListIndex++] = addresses[index]; |
| } |
| } |
| |
| VerifyChildIp6Addresses(child, updatedListIndex, updatedAddressList); |
| } |
| } |
| |
| printf(" -- PASS\n"); |
| |
| testFreeInstance(sInstance); |
| } |
| |
| } // namespace ot |
| |
| int main(void) |
| { |
| ot::TestChildIp6Address(); |
| printf("\nAll tests passed.\n"); |
| return 0; |
| } |