blob: 604a44a62dc58773f96df5102bf22ce0205054ba [file] [log] [blame]
/*
* 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_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(*sInstance, aAddressList[index]), "HasIp6Address() failed\n");
}
memset(addressObserved, 0, sizeof(addressObserved));
memset(addressIsMeshLocal, 0, sizeof(addressObserved));
for (uint8_t index = 0; index < aAddressListLength; index++)
{
{
addressIsMeshLocal[index] = true;
}
}
while (aChild.GetNextIp6Address(*sInstance, 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\n");
}
for (uint8_t index = 0; index < aAddressListLength; index++)
{
VerifyOrQuit(addressObserved[index], "Child::GetNextIp6Address() missed an entry from the expected list\n");
if (sInstance->GetThreadNetif().GetMle().IsMeshLocalAddress(aAddressList[index]))
{
SuccessOrQuit(aChild.GetMeshLocalIp6Address(*sInstance, address),
"Child::GetMeshLocalIp6Address() failed\n");
VerifyOrQuit(address == aAddressList[index], "GetMeshLocalIp6Address() did not return expected address\n");
hasMeshLocal = true;
}
}
if (!hasMeshLocal)
{
VerifyOrQuit(aChild.GetMeshLocalIp6Address(*sInstance, address) == OT_ERROR_NOT_FOUND,
"Child::GetMeshLocalIp6Address() returned an address not in the exptect list\n");
}
}
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 != NULL, "Null instance");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
printf("\nConverting IPv6 addresses from string");
numAddresses = 0;
// First addresses uses the mesh local prefix (mesh-local address).
addresses[numAddresses] = sInstance->GetThreadNetif().GetMle().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");
memset(&child, 0, sizeof(child));
VerifyChildIp6Addresses(child, 0, NULL);
printf(" -- PASS\n");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
printf("Adding a single IPv6 address");
for (uint8_t index = 0; index < numAddresses; index++)
{
SuccessOrQuit(child.AddIp6Address(*sInstance, addresses[index]), "AddIp6Address() failed");
VerifyChildIp6Addresses(child, 1, &addresses[index]);
child.ClearIp6Addresses();
VerifyChildIp6Addresses(child, 0, NULL);
}
printf(" -- PASS\n");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
printf("Adding multiple IPv6 addresses");
for (uint8_t index = 0; index < numAddresses; index++)
{
SuccessOrQuit(child.AddIp6Address(*sInstance, 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(*sInstance, 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(*sInstance, addresses[index]), "RemoveIp6Address() failed");
VerifyChildIp6Addresses(child, numAddresses - 1 - index, &addresses[index + 1]);
VerifyOrQuit(child.RemoveIp6Address(*sInstance, addresses[index]) == OT_ERROR_NOT_FOUND,
"RemoveIp6Address() did not fail when removing an address not on the list");
}
VerifyChildIp6Addresses(child, 0, NULL);
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(*sInstance, addresses[index]), "AddIp6Address() failed");
}
for (uint8_t index = numAddresses - 1; index > 0; index--)
{
SuccessOrQuit(child.RemoveIp6Address(*sInstance, addresses[index]), "RemoveIp6Address() failed");
VerifyChildIp6Addresses(child, index, &addresses[0]);
VerifyOrQuit(child.RemoveIp6Address(*sInstance, 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(*sInstance, addresses[index]), "AddIp6Address() failed");
}
SuccessOrQuit(child.RemoveIp6Address(*sInstance, addresses[indexToRemove]), "RemoveIp6Address() failed");
VerifyOrQuit(child.RemoveIp6Address(*sInstance, 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
#ifdef ENABLE_TEST_MAIN
int main(void)
{
ot::TestChildIp6Address();
printf("\nAll tests passed.\n");
return 0;
}
#endif