blob: a474de4b143e669f7526556bd7a8065a6800d210 [file] [log] [blame]
/*
* Copyright (c) 2022, 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 <openthread/config.h>
#include "test_platform.h"
#include "test_util.hpp"
#include <openthread/dataset_ftd.h>
#include <openthread/thread.h>
#include <openthread/platform/border_routing.h>
#include "border_router/routing_manager.hpp"
#include "common/arg_macros.hpp"
#include "common/array.hpp"
#include "common/numeric_limits.hpp"
#include "common/time.hpp"
#include "instance/instance.hpp"
#include "net/icmp6.hpp"
#include "net/nd6.hpp"
namespace ot {
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
// Logs a message and adds current time (sNow) as "<hours>:<min>:<secs>.<msec>"
#define Log(...) \
printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 3600000), (sNow / 60000) % 60, \
(sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__))
static constexpr uint32_t kInfraIfIndex = 1;
static const char kInfraIfAddress[] = "fe80::1";
static constexpr uint32_t kValidLitime = 2000;
static constexpr uint32_t kPreferredLifetime = 1800;
static constexpr uint32_t kInfiniteLifetime = NumericLimits<uint32_t>::kMax;
static constexpr uint32_t kRioValidLifetime = 1800;
static constexpr uint32_t kRioDeprecatingLifetime = 300;
static constexpr uint16_t kMaxRaSize = 800;
static constexpr uint16_t kMaxDeprecatingPrefixes = 16;
static constexpr otOperationalDataset kDataset = {
.mActiveTimestamp =
{
.mSeconds = 1,
.mTicks = 0,
.mAuthoritative = false,
},
.mNetworkKey =
{
.m8 = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
},
.mNetworkName = {"OpenThread"},
.mExtendedPanId =
{
.m8 = {0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0xca, 0xfe},
},
.mMeshLocalPrefix =
{
.m8 = {0xfd, 0x00, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
},
.mPanId = 0x1234,
.mChannel = 11,
.mPskc =
{
.m8 = {0xc2, 0x3a, 0x76, 0xe9, 0x8f, 0x1a, 0x64, 0x83, 0x63, 0x9b, 0x1a, 0xc1, 0x27, 0x1e, 0x2e, 0x27},
},
.mSecurityPolicy =
{
.mRotationTime = 672,
.mObtainNetworkKeyEnabled = true,
.mNativeCommissioningEnabled = true,
.mRoutersEnabled = true,
.mExternalCommissioningEnabled = true,
},
.mChannelMask = 0x07fff800,
.mComponents =
{
.mIsActiveTimestampPresent = true,
.mIsNetworkKeyPresent = true,
.mIsNetworkNamePresent = true,
.mIsExtendedPanIdPresent = true,
.mIsMeshLocalPrefixPresent = true,
.mIsPanIdPresent = true,
.mIsChannelPresent = true,
.mIsPskcPresent = true,
.mIsSecurityPolicyPresent = true,
.mIsChannelMaskPresent = true,
},
};
static Instance *sInstance;
static uint32_t sNow = 0;
static uint32_t sAlarmTime;
static bool sAlarmOn = false;
static otRadioFrame sRadioTxFrame;
static uint8_t sRadioTxFramePsdu[OT_RADIO_FRAME_MAX_SIZE];
static bool sRadioTxOngoing = false;
using Icmp6Packet = Ip6::Nd::RouterAdvert::Icmp6Packet;
enum ExpectedPio
{
kNoPio, // Expect to see no PIO in RA.
kPioAdvertisingLocalOnLink, // Expect to see local on-link prefix advertised (non-zero preferred lifetime).
kPioDeprecatingLocalOnLink, // Expect to see local on-link prefix deprecated (zero preferred lifetime).
};
struct DeprecatingPrefix
{
DeprecatingPrefix(void) = default;
DeprecatingPrefix(const Ip6::Prefix &aPrefix, uint32_t aLifetime)
: mPrefix(aPrefix)
, mLifetime(aLifetime)
{
}
bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; }
Ip6::Prefix mPrefix; // Old on-link prefix being deprecated.
uint32_t mLifetime; // Valid lifetime of prefix from PIO.
};
static Ip6::Address sInfraIfAddress;
bool sRsEmitted; // Indicates if an RS message was emitted by BR.
bool sRaValidated; // Indicates if an RA was emitted by BR and successfully validated.
bool sNsEmitted; // Indicates if an NS message was emitted by BR.
bool sRespondToNs; // Indicates whether or not to respond to NS.
ExpectedPio sExpectedPio; // Expected PIO in the emitted RA by BR (MUST be seen in RA to set `sRaValidated`).
uint32_t sOnLinkLifetime; // Valid lifetime for local on-link prefix from the last processed RA.
// Indicate whether or not to check the emitted RA header (default route) lifetime
bool sCheckRaHeaderLifetime;
// Expected default route lifetime in emitted RA header by BR.
uint32_t sExpectedRaHeaderLifetime;
enum ExpectedRaHeaderFlags
{
kRaHeaderFlagsSkipChecking, // Skip checking the RA header flags.
kRaHeaderFlagsNone, // Expect no flag (neither M or O).
kRaHeaderFlagsOnlyM, // Expect M flag only.
kRaHeaderFlagsOnlyO, // Expect O flag only.
kRaHeaderFlagsBothMAndO, // Expect both M and O flags.
};
// The expected RA header flags when validating emitted RA message.
ExpectedRaHeaderFlags sExpectedRaHeaderFlags;
// Array containing deprecating prefixes from PIOs in the last processed RA.
Array<DeprecatingPrefix, kMaxDeprecatingPrefixes> sDeprecatingPrefixes;
static constexpr uint16_t kMaxRioPrefixes = 10;
struct RioPrefix
{
RioPrefix(void) = default;
explicit RioPrefix(const Ip6::Prefix &aPrefix)
: mSawInRa(false)
, mPrefix(aPrefix)
, mLifetime(0)
{
}
bool mSawInRa; // Indicate whether or not this prefix was seen in the emitted RA (as RIO).
Ip6::Prefix mPrefix; // The RIO prefix.
uint32_t mLifetime; // The RIO prefix lifetime - only valid when `mSawInRa`
};
class ExpectedRios : public Array<RioPrefix, kMaxRioPrefixes>
{
public:
void Add(const Ip6::Prefix &aPrefix) { SuccessOrQuit(PushBack(RioPrefix(aPrefix))); }
bool SawAll(void) const
{
bool sawAll = true;
for (const RioPrefix &rioPrefix : *this)
{
if (!rioPrefix.mSawInRa)
{
sawAll = false;
break;
}
}
return sawAll;
}
};
ExpectedRios sExpectedRios; // Expected RIO prefixes in emitted RAs.
//----------------------------------------------------------------------------------------------------------------------
// Function prototypes
void ProcessRadioTxAndTasklets(void);
void AdvanceTime(uint32_t aDuration);
void LogRouterAdvert(const Icmp6Packet &aPacket);
void ValidateRouterAdvert(const Icmp6Packet &aPacket);
const char *PreferenceToString(int8_t aPreference);
void SendRouterAdvert(const Ip6::Address &aAddress, const Icmp6Packet &aPacket);
void SendNeighborAdvert(const Ip6::Address &aAddress, const Ip6::Nd::NeighborAdvertMessage &aNaMessage);
void DiscoverNat64Prefix(const Ip6::Prefix &aPrefix);
extern "C" {
#if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
{
OT_UNUSED_VARIABLE(aLogLevel);
OT_UNUSED_VARIABLE(aLogRegion);
va_list args;
printf(" ");
va_start(args, aFormat);
vprintf(aFormat, args);
va_end(args);
printf("\n");
}
#endif
//----------------------------------------------------------------------------------------------------------------------
// `otPlatRadio
otRadioCaps otPlatRadioGetCaps(otInstance *) { return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF; }
otError otPlatRadioTransmit(otInstance *, otRadioFrame *)
{
sRadioTxOngoing = true;
return OT_ERROR_NONE;
}
otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *) { return &sRadioTxFrame; }
//----------------------------------------------------------------------------------------------------------------------
// `otPlatAlaram
void otPlatAlarmMilliStop(otInstance *) { sAlarmOn = false; }
void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
{
sAlarmOn = true;
sAlarmTime = aT0 + aDt;
}
uint32_t otPlatAlarmMilliGetNow(void) { return sNow; }
//---------------------------------------------------------------------------------------------------------------------
// otPlatInfraIf
bool otPlatInfraIfHasAddress(uint32_t aInfraIfIndex, const otIp6Address *aAddress)
{
VerifyOrQuit(aInfraIfIndex == kInfraIfIndex);
return AsCoreType(aAddress) == sInfraIfAddress;
}
otError otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex,
const otIp6Address *aDestAddress,
const uint8_t *aBuffer,
uint16_t aBufferLength)
{
Icmp6Packet packet;
Log("otPlatInfraIfSendIcmp6Nd(aDestAddr: %s, aBufferLength:%u)", AsCoreType(aDestAddress).ToString().AsCString(),
aBufferLength);
VerifyOrQuit(aInfraIfIndex == kInfraIfIndex);
packet.Init(aBuffer, aBufferLength);
VerifyOrQuit(aBufferLength >= sizeof(Ip6::Icmp::Header));
switch (reinterpret_cast<const Ip6::Icmp::Header *>(aBuffer)->GetType())
{
case Ip6::Icmp::Header::kTypeRouterSolicit:
Log(" Router Solicit message");
sRsEmitted = true;
break;
case Ip6::Icmp::Header::kTypeRouterAdvert:
Log(" Router Advertisement message");
LogRouterAdvert(packet);
ValidateRouterAdvert(packet);
break;
case Ip6::Icmp::Header::kTypeNeighborSolicit:
{
const Ip6::Nd::NeighborSolicitMessage *nsMsg =
reinterpret_cast<const Ip6::Nd::NeighborSolicitMessage *>(packet.GetBytes());
Log(" Neighbor Solicit message");
VerifyOrQuit(packet.GetLength() >= sizeof(Ip6::Nd::NeighborSolicitMessage));
VerifyOrQuit(nsMsg->IsValid());
sNsEmitted = true;
if (sRespondToNs)
{
Ip6::Nd::NeighborAdvertMessage naMsg;
naMsg.SetTargetAddress(nsMsg->GetTargetAddress());
naMsg.SetRouterFlag();
naMsg.SetSolicitedFlag();
SendNeighborAdvert(AsCoreType(aDestAddress), naMsg);
}
break;
}
default:
VerifyOrQuit(false, "Bad ICMP6 type");
}
return OT_ERROR_NONE;
}
//----------------------------------------------------------------------------------------------------------------------
Array<void *, 500> sHeapAllocatedPtrs;
#if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
void *otPlatCAlloc(size_t aNum, size_t aSize)
{
void *ptr = calloc(aNum, aSize);
SuccessOrQuit(sHeapAllocatedPtrs.PushBack(ptr));
return ptr;
}
void otPlatFree(void *aPtr)
{
if (aPtr != nullptr)
{
void **entry = sHeapAllocatedPtrs.Find(aPtr);
VerifyOrQuit(entry != nullptr, "A heap allocated item is freed twice");
sHeapAllocatedPtrs.Remove(*entry);
}
free(aPtr);
}
#endif
} // extern "C"
//---------------------------------------------------------------------------------------------------------------------
void ProcessRadioTxAndTasklets(void)
{
do
{
if (sRadioTxOngoing)
{
sRadioTxOngoing = false;
otPlatRadioTxStarted(sInstance, &sRadioTxFrame);
otPlatRadioTxDone(sInstance, &sRadioTxFrame, nullptr, OT_ERROR_NONE);
}
otTaskletsProcess(sInstance);
} while (otTaskletsArePending(sInstance));
}
void AdvanceTime(uint32_t aDuration)
{
uint32_t time = sNow + aDuration;
Log("AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000);
while (TimeMilli(sAlarmTime) <= TimeMilli(time))
{
ProcessRadioTxAndTasklets();
sNow = sAlarmTime;
otPlatAlarmMilliFired(sInstance);
}
ProcessRadioTxAndTasklets();
sNow = time;
}
void ValidateRouterAdvert(const Icmp6Packet &aPacket)
{
constexpr uint8_t kMaxPrefixes = 16;
Ip6::Nd::RouterAdvert::RxMessage raMsg(aPacket);
bool sawExpectedPio = false;
Array<Ip6::Prefix, kMaxPrefixes> pioPrefixes;
Array<Ip6::Prefix, kMaxPrefixes> rioPrefixes;
#if OPENTHREAD_CONFIG_BORDER_ROUTING_STUB_ROUTER_FLAG_IN_EMITTED_RA_ENABLE
bool sawStubRouterFlag = false;
#endif
VerifyOrQuit(raMsg.IsValid());
if (sCheckRaHeaderLifetime)
{
VerifyOrQuit(raMsg.GetHeader().GetRouterLifetime() == sExpectedRaHeaderLifetime);
}
switch (sExpectedRaHeaderFlags)
{
case kRaHeaderFlagsSkipChecking:
break;
case kRaHeaderFlagsNone:
VerifyOrQuit(!raMsg.GetHeader().IsManagedAddressConfigFlagSet());
VerifyOrQuit(!raMsg.GetHeader().IsOtherConfigFlagSet());
break;
case kRaHeaderFlagsOnlyM:
VerifyOrQuit(raMsg.GetHeader().IsManagedAddressConfigFlagSet());
VerifyOrQuit(!raMsg.GetHeader().IsOtherConfigFlagSet());
break;
case kRaHeaderFlagsOnlyO:
VerifyOrQuit(!raMsg.GetHeader().IsManagedAddressConfigFlagSet());
VerifyOrQuit(raMsg.GetHeader().IsOtherConfigFlagSet());
break;
case kRaHeaderFlagsBothMAndO:
VerifyOrQuit(raMsg.GetHeader().IsManagedAddressConfigFlagSet());
VerifyOrQuit(raMsg.GetHeader().IsOtherConfigFlagSet());
break;
}
sDeprecatingPrefixes.Clear();
for (const Ip6::Nd::Option &option : raMsg)
{
switch (option.GetType())
{
case Ip6::Nd::Option::kTypePrefixInfo:
{
const Ip6::Nd::PrefixInfoOption &pio = static_cast<const Ip6::Nd::PrefixInfoOption &>(option);
Ip6::Prefix prefix;
Ip6::Prefix localOnLink;
VerifyOrQuit(pio.IsValid());
pio.GetPrefix(prefix);
VerifyOrQuit(!pioPrefixes.Contains(prefix), "Duplicate PIO prefix in RA");
SuccessOrQuit(pioPrefixes.PushBack(prefix));
SuccessOrQuit(otBorderRoutingGetOnLinkPrefix(sInstance, &localOnLink));
if (prefix == localOnLink)
{
switch (sExpectedPio)
{
case kNoPio:
break;
case kPioAdvertisingLocalOnLink:
if (pio.GetPreferredLifetime() > 0)
{
sOnLinkLifetime = pio.GetValidLifetime();
sawExpectedPio = true;
}
break;
case kPioDeprecatingLocalOnLink:
if (pio.GetPreferredLifetime() == 0)
{
sOnLinkLifetime = pio.GetValidLifetime();
sawExpectedPio = true;
}
break;
}
}
else
{
VerifyOrQuit(pio.GetPreferredLifetime() == 0, "Old on link prefix is not deprecated");
SuccessOrQuit(sDeprecatingPrefixes.PushBack(DeprecatingPrefix(prefix, pio.GetValidLifetime())));
}
break;
}
case Ip6::Nd::Option::kTypeRouteInfo:
{
const Ip6::Nd::RouteInfoOption &rio = static_cast<const Ip6::Nd::RouteInfoOption &>(option);
Ip6::Prefix prefix;
VerifyOrQuit(rio.IsValid());
rio.GetPrefix(prefix);
VerifyOrQuit(!rioPrefixes.Contains(prefix), "Duplicate RIO prefix in RA");
SuccessOrQuit(rioPrefixes.PushBack(prefix));
for (RioPrefix &rioPrefix : sExpectedRios)
{
if (prefix == rioPrefix.mPrefix)
{
rioPrefix.mSawInRa = true;
rioPrefix.mLifetime = rio.GetRouteLifetime();
}
}
break;
}
#if OPENTHREAD_CONFIG_BORDER_ROUTING_STUB_ROUTER_FLAG_IN_EMITTED_RA_ENABLE
case Ip6::Nd::Option::kTypeRaFlagsExtension:
{
const Ip6::Nd::RaFlagsExtOption &flagsOption = static_cast<const Ip6::Nd::RaFlagsExtOption &>(option);
VerifyOrQuit(flagsOption.IsValid());
VerifyOrQuit(flagsOption.IsStubRouterFlagSet());
sawStubRouterFlag = true;
break;
}
#endif
default:
VerifyOrQuit(false, "Unexpected option type in RA msg");
}
}
#if OPENTHREAD_CONFIG_BORDER_ROUTING_STUB_ROUTER_FLAG_IN_EMITTED_RA_ENABLE
VerifyOrQuit(sawStubRouterFlag);
#endif
if (!sRaValidated)
{
switch (sExpectedPio)
{
case kNoPio:
break;
case kPioAdvertisingLocalOnLink:
case kPioDeprecatingLocalOnLink:
// First emitted RAs may not yet have the expected PIO
// so we exit and not set `sRaValidated` to allow it
// to be checked for next received RA.
VerifyOrExit(sawExpectedPio);
break;
}
sRaValidated = true;
}
exit:
return;
}
//----------------------------------------------------------------------------------------------------------------------
void LogRouterAdvert(const Icmp6Packet &aPacket)
{
Ip6::Nd::RouterAdvert::RxMessage raMsg(aPacket);
VerifyOrQuit(raMsg.IsValid());
Log(" RA header - M:%u, O:%u", raMsg.GetHeader().IsManagedAddressConfigFlagSet(),
raMsg.GetHeader().IsOtherConfigFlagSet());
Log(" RA header - lifetime %u, prf:%s", raMsg.GetHeader().GetRouterLifetime(),
PreferenceToString(raMsg.GetHeader().GetDefaultRouterPreference()));
for (const Ip6::Nd::Option &option : raMsg)
{
switch (option.GetType())
{
case Ip6::Nd::Option::kTypePrefixInfo:
{
const Ip6::Nd::PrefixInfoOption &pio = static_cast<const Ip6::Nd::PrefixInfoOption &>(option);
Ip6::Prefix prefix;
VerifyOrQuit(pio.IsValid());
pio.GetPrefix(prefix);
Log(" PIO - %s, flags:%s%s, valid:%u, preferred:%u", prefix.ToString().AsCString(),
pio.IsOnLinkFlagSet() ? "L" : "", pio.IsAutoAddrConfigFlagSet() ? "A" : "", pio.GetValidLifetime(),
pio.GetPreferredLifetime());
break;
}
case Ip6::Nd::Option::kTypeRouteInfo:
{
const Ip6::Nd::RouteInfoOption &rio = static_cast<const Ip6::Nd::RouteInfoOption &>(option);
Ip6::Prefix prefix;
VerifyOrQuit(rio.IsValid());
rio.GetPrefix(prefix);
Log(" RIO - %s, prf:%s, lifetime:%u", prefix.ToString().AsCString(),
PreferenceToString(rio.GetPreference()), rio.GetRouteLifetime());
break;
}
case Ip6::Nd::Option::kTypeRaFlagsExtension:
{
const Ip6::Nd::RaFlagsExtOption &flagsOption = static_cast<const Ip6::Nd::RaFlagsExtOption &>(option);
VerifyOrQuit(flagsOption.IsValid());
Log(" FlagsExt - StubRouter:%u", flagsOption.IsStubRouterFlagSet());
break;
}
default:
VerifyOrQuit(false, "Bad option type in RA msg");
}
}
}
void LogRouterAdvert(const uint8_t *aBuffer, size_t aLength)
{
Icmp6Packet packet;
packet.Init(aBuffer, aLength);
LogRouterAdvert(packet);
}
const char *PreferenceToString(int8_t aPreference)
{
const char *str = "";
switch (aPreference)
{
case NetworkData::kRoutePreferenceLow:
str = "low";
break;
case NetworkData::kRoutePreferenceMedium:
str = "med";
break;
case NetworkData::kRoutePreferenceHigh:
str = "high";
break;
default:
break;
}
return str;
}
void SendRouterAdvert(const Ip6::Address &aAddress, const uint8_t *aBuffer, uint16_t aLength)
{
otPlatInfraIfRecvIcmp6Nd(sInstance, kInfraIfIndex, &aAddress, aBuffer, aLength);
}
void SendRouterAdvert(const Ip6::Address &aAddress, const Icmp6Packet &aPacket)
{
SendRouterAdvert(aAddress, aPacket.GetBytes(), aPacket.GetLength());
}
void SendNeighborAdvert(const Ip6::Address &aAddress, const Ip6::Nd::NeighborAdvertMessage &aNaMessage)
{
Log("Sending NA from %s", aAddress.ToString().AsCString());
otPlatInfraIfRecvIcmp6Nd(sInstance, kInfraIfIndex, &aAddress, reinterpret_cast<const uint8_t *>(&aNaMessage),
sizeof(aNaMessage));
}
void DiscoverNat64Prefix(const Ip6::Prefix &aPrefix)
{
Log("Discovered NAT64 prefix %s", aPrefix.ToString().AsCString());
otPlatInfraIfDiscoverNat64PrefixDone(sInstance, kInfraIfIndex, &aPrefix);
}
Ip6::Prefix PrefixFromString(const char *aString, uint8_t aPrefixLength)
{
Ip6::Prefix prefix;
SuccessOrQuit(AsCoreType(&prefix.mPrefix).FromString(aString));
prefix.mLength = aPrefixLength;
return prefix;
}
Ip6::Address AddressFromString(const char *aString)
{
Ip6::Address address;
SuccessOrQuit(address.FromString(aString));
return address;
}
void VerifyOmrPrefixInNetData(const Ip6::Prefix &aOmrPrefix, bool aDefaultRoute)
{
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
NetworkData::OnMeshPrefixConfig prefixConfig;
Log("VerifyOmrPrefixInNetData(%s, def-route:%s)", aOmrPrefix.ToString().AsCString(), aDefaultRoute ? "yes" : "no");
SuccessOrQuit(otNetDataGetNextOnMeshPrefix(sInstance, &iterator, &prefixConfig));
VerifyOrQuit(prefixConfig.GetPrefix() == aOmrPrefix);
VerifyOrQuit(prefixConfig.mStable == true);
VerifyOrQuit(prefixConfig.mSlaac == true);
VerifyOrQuit(prefixConfig.mPreferred == true);
VerifyOrQuit(prefixConfig.mOnMesh == true);
VerifyOrQuit(prefixConfig.mDefaultRoute == aDefaultRoute);
VerifyOrQuit(otNetDataGetNextOnMeshPrefix(sInstance, &iterator, &prefixConfig) == kErrorNotFound);
}
void VerifyNoOmrPrefixInNetData(void)
{
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
NetworkData::OnMeshPrefixConfig prefixConfig;
Log("VerifyNoOmrPrefixInNetData()");
VerifyOrQuit(otNetDataGetNextOnMeshPrefix(sInstance, &iterator, &prefixConfig) != kErrorNone);
}
using NetworkData::RoutePreference;
enum ExternalRouteMode : uint8_t
{
kNoRoute,
kDefaultRoute,
kUlaRoute,
};
enum AdvPioMode : uint8_t
{
kSkipAdvPioCheck,
kWithAdvPioFlagSet,
kWithAdvPioCleared,
};
void VerifyExternalRouteInNetData(ExternalRouteMode aExternalRouteMode, AdvPioMode aAdvPioMode = kSkipAdvPioCheck)
{
Error error;
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
otExternalRouteConfig routeConfig;
error = otNetDataGetNextRoute(sInstance, &iterator, &routeConfig);
switch (aExternalRouteMode)
{
case kNoRoute:
Log("VerifyExternalRouteInNetData(kNoRoute)");
VerifyOrQuit(error != kErrorNone);
break;
case kDefaultRoute:
Log("VerifyExternalRouteInNetData(kDefaultRoute)");
VerifyOrQuit(error == kErrorNone);
VerifyOrQuit(routeConfig.mPrefix.mLength == 0);
VerifyOrQuit((aAdvPioMode == kSkipAdvPioCheck) || (routeConfig.mAdvPio == (aAdvPioMode == kWithAdvPioFlagSet)));
VerifyOrQuit(otNetDataGetNextRoute(sInstance, &iterator, &routeConfig) != kErrorNone);
break;
case kUlaRoute:
Log("VerifyExternalRouteInNetData(kUlaRoute)");
VerifyOrQuit(error == kErrorNone);
VerifyOrQuit(routeConfig.mPrefix.mLength == 7);
VerifyOrQuit(routeConfig.mPrefix.mPrefix.mFields.m8[0] == 0xfc);
VerifyOrQuit((aAdvPioMode == kSkipAdvPioCheck) || (routeConfig.mAdvPio == (aAdvPioMode == kWithAdvPioFlagSet)));
VerifyOrQuit(otNetDataGetNextRoute(sInstance, &iterator, &routeConfig) != kErrorNone);
break;
}
}
void VerifyNat64PrefixInNetData(const Ip6::Prefix &aNat64Prefix)
{
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
NetworkData::ExternalRouteConfig routeConfig;
bool didFind = false;
Log("VerifyNat64PrefixInNetData()");
while (otNetDataGetNextRoute(sInstance, &iterator, &routeConfig) == kErrorNone)
{
if (!routeConfig.mNat64 || !routeConfig.GetPrefix().IsValidNat64())
{
continue;
}
Log(" nat64 prefix:%s, prf:%s", routeConfig.GetPrefix().ToString().AsCString(),
PreferenceToString(routeConfig.mPreference));
VerifyOrQuit(routeConfig.GetPrefix() == aNat64Prefix);
didFind = true;
}
VerifyOrQuit(didFind);
}
struct Pio
{
Pio(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime)
: mPrefix(aPrefix)
, mValidLifetime(aValidLifetime)
, mPreferredLifetime(aPreferredLifetime)
{
}
const Ip6::Prefix &mPrefix;
uint32_t mValidLifetime;
uint32_t mPreferredLifetime;
};
struct Rio
{
Rio(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, RoutePreference aPreference)
: mPrefix(aPrefix)
, mValidLifetime(aValidLifetime)
, mPreference(aPreference)
{
}
const Ip6::Prefix &mPrefix;
uint32_t mValidLifetime;
RoutePreference mPreference;
};
struct DefaultRoute
{
DefaultRoute(uint32_t aLifetime, RoutePreference aPreference)
: mLifetime(aLifetime)
, mPreference(aPreference)
{
}
uint32_t mLifetime;
RoutePreference mPreference;
};
struct RaFlags : public Clearable<RaFlags>
{
RaFlags(void)
: mManagedAddressConfigFlag(false)
, mOtherConfigFlag(false)
, mStubRouterFlag(false)
{
}
bool mManagedAddressConfigFlag;
bool mOtherConfigFlag;
bool mStubRouterFlag;
};
void BuildRouterAdvert(Ip6::Nd::RouterAdvert::TxMessage &aRaMsg,
const Pio *aPios,
uint16_t aNumPios,
const Rio *aRios,
uint16_t aNumRios,
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags)
{
Ip6::Nd::RouterAdvert::Header header;
header.SetRouterLifetime(aDefaultRoute.mLifetime);
header.SetDefaultRouterPreference(aDefaultRoute.mPreference);
if (aRaFlags.mManagedAddressConfigFlag)
{
header.SetManagedAddressConfigFlag();
}
if (aRaFlags.mOtherConfigFlag)
{
header.SetOtherConfigFlag();
}
SuccessOrQuit(aRaMsg.AppendHeader(header));
if (aRaFlags.mStubRouterFlag)
{
SuccessOrQuit(aRaMsg.AppendFlagsExtensionOption(/* aStubRouterFlag */ true));
}
for (; aNumPios > 0; aPios++, aNumPios--)
{
SuccessOrQuit(aRaMsg.AppendPrefixInfoOption(aPios->mPrefix, aPios->mValidLifetime, aPios->mPreferredLifetime));
}
for (; aNumRios > 0; aRios++, aNumRios--)
{
SuccessOrQuit(aRaMsg.AppendRouteInfoOption(aRios->mPrefix, aRios->mValidLifetime, aRios->mPreference));
}
}
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const Pio *aPios,
uint16_t aNumPios,
const Rio *aRios,
uint16_t aNumRios,
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags)
{
Ip6::Nd::RouterAdvert::TxMessage raMsg;
Icmp6Packet packet;
BuildRouterAdvert(raMsg, aPios, aNumPios, aRios, aNumRios, aDefaultRoute, aRaFlags);
raMsg.GetAsPacket(packet);
SendRouterAdvert(aRouterAddress, packet);
Log("Sending RA from router %s", aRouterAddress.ToString().AsCString());
LogRouterAdvert(packet);
}
template <uint16_t kNumPios, uint16_t kNumRios>
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const Pio (&aPios)[kNumPios],
const Rio (&aRios)[kNumRios],
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, aPios, kNumPios, aRios, kNumRios, aDefaultRoute, aRaFlags);
}
template <uint16_t kNumPios>
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const Pio (&aPios)[kNumPios],
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, aPios, kNumPios, nullptr, 0, aDefaultRoute, aRaFlags);
}
template <uint16_t kNumRios>
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const Rio (&aRios)[kNumRios],
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, nullptr, 0, aRios, kNumRios, aDefaultRoute, aRaFlags);
}
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
}
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const RaFlags &aRaFlags)
{
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
aRaFlags);
}
template <uint16_t kNumPios> void SendRouterAdvertToBorderRoutingProcessIcmp6Ra(const Pio (&aPios)[kNumPios])
{
Ip6::Nd::RouterAdvert::TxMessage raMsg;
Icmp6Packet packet;
BuildRouterAdvert(raMsg, aPios, kNumPios, nullptr, 0, DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
RaFlags());
raMsg.GetAsPacket(packet);
otPlatBorderRoutingProcessIcmp6Ra(sInstance, packet.GetBytes(), packet.GetLength());
Log("Passing RA to otPlatBorderRoutingProcessIcmp6Ra");
LogRouterAdvert(packet);
}
struct OnLinkPrefix : public Pio
{
OnLinkPrefix(const Ip6::Prefix &aPrefix,
uint32_t aValidLifetime,
uint32_t aPreferredLifetime,
const Ip6::Address &aRouterAddress)
: Pio(aPrefix, aValidLifetime, aPreferredLifetime)
, mRouterAddress(aRouterAddress)
{
}
const Ip6::Address &mRouterAddress;
};
struct RoutePrefix : public Rio
{
RoutePrefix(const Ip6::Prefix &aPrefix,
uint32_t aValidLifetime,
RoutePreference aPreference,
const Ip6::Address &aRouterAddress)
: Rio(aPrefix, aValidLifetime, aPreference)
, mRouterAddress(aRouterAddress)
{
}
const Ip6::Address &mRouterAddress;
};
template <uint16_t kNumOnLinkPrefixes, uint16_t kNumRoutePrefixes>
void VerifyPrefixTable(const OnLinkPrefix (&aOnLinkPrefixes)[kNumOnLinkPrefixes],
const RoutePrefix (&aRoutePrefixes)[kNumRoutePrefixes])
{
VerifyPrefixTable(aOnLinkPrefixes, kNumOnLinkPrefixes, aRoutePrefixes, kNumRoutePrefixes);
}
template <uint16_t kNumOnLinkPrefixes> void VerifyPrefixTable(const OnLinkPrefix (&aOnLinkPrefixes)[kNumOnLinkPrefixes])
{
VerifyPrefixTable(aOnLinkPrefixes, kNumOnLinkPrefixes, nullptr, 0);
}
template <uint16_t kNumRoutePrefixes> void VerifyPrefixTable(const RoutePrefix (&aRoutePrefixes)[kNumRoutePrefixes])
{
VerifyPrefixTable(nullptr, 0, aRoutePrefixes, kNumRoutePrefixes);
}
void VerifyPrefixTable(const OnLinkPrefix *aOnLinkPrefixes,
uint16_t aNumOnLinkPrefixes,
const RoutePrefix *aRoutePrefixes,
uint16_t aNumRoutePrefixes)
{
BorderRouter::RoutingManager::PrefixTableIterator iter;
BorderRouter::RoutingManager::PrefixTableEntry entry;
uint16_t onLinkPrefixCount = 0;
uint16_t routePrefixCount = 0;
Log("VerifyPrefixTable()");
sInstance->Get<BorderRouter::RoutingManager>().InitPrefixTableIterator(iter);
while (sInstance->Get<BorderRouter::RoutingManager>().GetNextPrefixTableEntry(iter, entry) == kErrorNone)
{
bool didFind = false;
if (entry.mIsOnLink)
{
Log(" on-link prefix:%s, valid:%u, preferred:%u, router:%s, age:%u",
AsCoreType(&entry.mPrefix).ToString().AsCString(), entry.mValidLifetime, entry.mPreferredLifetime,
AsCoreType(&entry.mRouter.mAddress).ToString().AsCString(), entry.mMsecSinceLastUpdate / 1000);
onLinkPrefixCount++;
for (uint16_t index = 0; index < aNumOnLinkPrefixes; index++)
{
const OnLinkPrefix &onLinkPrefix = aOnLinkPrefixes[index];
if ((onLinkPrefix.mPrefix == AsCoreType(&entry.mPrefix)) &&
(AsCoreType(&entry.mRouter.mAddress) == onLinkPrefix.mRouterAddress))
{
VerifyOrQuit(entry.mValidLifetime == onLinkPrefix.mValidLifetime);
VerifyOrQuit(entry.mPreferredLifetime == onLinkPrefix.mPreferredLifetime);
didFind = true;
break;
}
}
}
else
{
Log(" route prefix:%s, valid:%u, prf:%s, router:%s, age:%u",
AsCoreType(&entry.mPrefix).ToString().AsCString(), entry.mValidLifetime,
PreferenceToString(entry.mRoutePreference), AsCoreType(&entry.mRouter.mAddress).ToString().AsCString(),
entry.mMsecSinceLastUpdate / 1000);
routePrefixCount++;
for (uint16_t index = 0; index < aNumRoutePrefixes; index++)
{
const RoutePrefix &routePrefix = aRoutePrefixes[index];
if ((routePrefix.mPrefix == AsCoreType(&entry.mPrefix)) &&
(AsCoreType(&entry.mRouter.mAddress) == routePrefix.mRouterAddress))
{
VerifyOrQuit(entry.mValidLifetime == routePrefix.mValidLifetime);
VerifyOrQuit(static_cast<int8_t>(entry.mRoutePreference) == routePrefix.mPreference);
didFind = true;
break;
}
}
}
VerifyOrQuit(didFind);
}
VerifyOrQuit(onLinkPrefixCount == aNumOnLinkPrefixes);
VerifyOrQuit(routePrefixCount == aNumRoutePrefixes);
}
void VerifyPrefixTableIsEmpty(void) { VerifyPrefixTable(nullptr, 0, nullptr, 0); }
struct InfraRouter
{
InfraRouter(const Ip6::Address &aAddress,
bool aManagedAddressConfigFlag,
bool aOtherConfigFlag,
bool aStubRouterFlag)
: mAddress(aAddress)
{
mFlags.Clear();
mFlags.mManagedAddressConfigFlag = aManagedAddressConfigFlag;
mFlags.mOtherConfigFlag = aOtherConfigFlag;
mFlags.mStubRouterFlag = aStubRouterFlag;
}
Ip6::Address mAddress;
RaFlags mFlags;
};
template <uint16_t kNumRouters> void VerifyDiscoveredRouters(const InfraRouter (&aRouters)[kNumRouters])
{
VerifyDiscoveredRouters(aRouters, kNumRouters);
}
void VerifyDiscoveredRouters(const InfraRouter *aRouters, uint16_t aNumRouters)
{
BorderRouter::RoutingManager::PrefixTableIterator iter;
BorderRouter::RoutingManager::RouterEntry entry;
uint16_t count = 0;
Log("VerifyDiscoveredRouters()");
sInstance->Get<BorderRouter::RoutingManager>().InitPrefixTableIterator(iter);
while (sInstance->Get<BorderRouter::RoutingManager>().GetNextRouterEntry(iter, entry) == kErrorNone)
{
bool didFind = false;
Log(" address:%s, M:%u, O:%u, StubRouter:%u", AsCoreType(&entry.mAddress).ToString().AsCString(),
entry.mManagedAddressConfigFlag, entry.mOtherConfigFlag, entry.mStubRouterFlag);
for (uint16_t index = 0; index < aNumRouters; index++)
{
if (AsCoreType(&entry.mAddress) == aRouters[index].mAddress)
{
VerifyOrQuit(entry.mManagedAddressConfigFlag == aRouters[index].mFlags.mManagedAddressConfigFlag);
VerifyOrQuit(entry.mOtherConfigFlag == aRouters[index].mFlags.mOtherConfigFlag);
VerifyOrQuit(entry.mStubRouterFlag == aRouters[index].mFlags.mStubRouterFlag);
didFind = true;
}
}
VerifyOrQuit(didFind);
count++;
}
VerifyOrQuit(count == aNumRouters);
}
void VerifyDiscoveredRoutersIsEmpty(void) { VerifyDiscoveredRouters(nullptr, 0); }
void InitTest(bool aEnablBorderRouting = false, bool aAfterReset = false)
{
uint32_t delay = 10000;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Initialize OT instance.
sNow = 0;
sAlarmOn = false;
sInstance = static_cast<Instance *>(testInitInstance());
if (aAfterReset)
{
delay += 26000; // leader reset sync delay
}
memset(&sRadioTxFrame, 0, sizeof(sRadioTxFrame));
sRadioTxFrame.mPsdu = sRadioTxFramePsdu;
sRadioTxOngoing = false;
SuccessOrQuit(sInfraIfAddress.FromString(kInfraIfAddress));
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Initialize and start Border Router and Thread operation.
SuccessOrQuit(otBorderRoutingInit(sInstance, kInfraIfIndex, /* aInfraIfIsRunning */ true));
otOperationalDatasetTlvs datasetTlvs;
SuccessOrQuit(otDatasetConvertToTlvs(&kDataset, &datasetTlvs));
SuccessOrQuit(otDatasetSetActiveTlvs(sInstance, &datasetTlvs));
SuccessOrQuit(otIp6SetEnabled(sInstance, true));
SuccessOrQuit(otThreadSetEnabled(sInstance, true));
SuccessOrQuit(otBorderRoutingSetEnabled(sInstance, aEnablBorderRouting));
// Reset all test flags
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kNoPio;
sExpectedRios.Clear();
sRespondToNs = true;
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
sCheckRaHeaderLifetime = true;
sExpectedRaHeaderLifetime = 0;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Ensure device starts as leader.
AdvanceTime(delay);
VerifyOrQuit(otThreadGetDeviceRole(sInstance) == OT_DEVICE_ROLE_LEADER);
}
void FinalizeTest(void)
{
SuccessOrQuit(otIp6SetEnabled(sInstance, false));
SuccessOrQuit(otThreadSetEnabled(sInstance, false));
SuccessOrQuit(otInstanceErasePersistentInfo(sInstance));
testFreeInstance(sInstance);
}
//---------------------------------------------------------------------------------------------------------------------
void TestSamePrefixesFromMultipleRouters(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
Ip6::Prefix routePrefix = PrefixFromString("2000:1234:5678::", 64);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestSamePrefixesFromMultipleRouters");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the local OMR and on-link prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A with a new on-link (PIO) and route prefix (RIO).
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)},
{Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that the local on-link prefix is now deprecating in the new RA.
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
AdvanceTime(10000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the discovered prefix table and ensure info from router A
// is present in the table.
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include new prefixes from router A.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send the same RA again from router A with the on-link (PIO) and route prefix (RIO).
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)},
{Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the discovered prefix table and ensure info from router A
// remains unchanged.
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router B with same route prefix (RIO) but with
// high route preference.
SendRouterAdvert(routerAddressB, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh)});
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the discovered prefix table and ensure info from router B
// is also included in the table.
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA),
RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh, routerAddressB)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router B removing the route prefix.
SendRouterAdvert(routerAddressB, {Rio(routePrefix, 0, NetworkData::kRoutePreferenceHigh)});
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the discovered prefix table and ensure info from router B
// is now removed from the table.
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data.
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestSamePrefixesFromMultipleRouters");
FinalizeTest();
}
void TestOmrSelection(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
NetworkData::OnMeshPrefixConfig prefixConfig;
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestOmrSelection");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
Log("Received RA was validated");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the local OMR and on-link prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Add a new OMR prefix directly into net data. The new prefix should
// be favored over the local OMR prefix.
prefixConfig.Clear();
prefixConfig.mPrefix = omrPrefix;
prefixConfig.mStable = true;
prefixConfig.mSlaac = true;
prefixConfig.mPreferred = true;
prefixConfig.mOnMesh = true;
prefixConfig.mDefaultRoute = false;
prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(100);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Make sure BR emits RA with the new OMR prefix now, and deprecates the old OMR prefix.
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(omrPrefix);
sExpectedRios.Add(localOmr);
AdvanceTime(20000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We should now see that the local OMR prefix
// is removed.
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Remove the OMR prefix previously added in net data.
SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &omrPrefix));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(100);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Make sure BR emits RA with local OMR prefix again and start
// deprecating the previously added OMR prefix.
sRaValidated = false;
sExpectedRios.Clear();
sExpectedRios.Add(omrPrefix);
sExpectedRios.Add(localOmr);
AdvanceTime(20000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime <= kRioDeprecatingLifetime);
VerifyOrQuit(sExpectedRios[1].mLifetime == kRioValidLifetime);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We should see that the local OMR prefix is
// added again.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait enough for old deprecating OMR prefix deprecating to expire.
sRaValidated = false;
sExpectedRios.Clear();
sExpectedRios.Add(omrPrefix);
sExpectedRios.Add(localOmr);
AdvanceTime(310000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime == 0);
VerifyOrQuit(sExpectedRios[1].mLifetime == kRioValidLifetime);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestOmrSelection");
FinalizeTest();
}
void TestDefaultRoute(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
Ip6::Prefix defaultRoute = PrefixFromString("::", 0);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
NetworkData::OnMeshPrefixConfig prefixConfig;
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestDefaultRoute");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the local OMR and ULA prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router A advertising a default route.
SendRouterAdvert(routerAddressA, DefaultRoute(kValidLitime, NetworkData::kRoutePreferenceLow));
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the discovered prefix table and ensure default route
// from router A is in the table.
VerifyPrefixTable({RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceLow, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We should not see default route in
// Network Data yet since there is no infrastructure-derived
// OMR prefix (with preference medium or higher).
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Add an OMR prefix directly into Network Data with
// preference medium (infrastructure-derived).
prefixConfig.Clear();
prefixConfig.mPrefix = omrPrefix;
prefixConfig.mStable = true;
prefixConfig.mSlaac = true;
prefixConfig.mPreferred = true;
prefixConfig.mOnMesh = true;
prefixConfig.mDefaultRoute = true;
prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. Now that we have an infrastructure-derived
// OMR prefix, the default route should be published.
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Remove the OMR prefix from Network Data.
SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &omrPrefix));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We should again go back to ULA prefix. The
// default route advertised by router A should be still present in
// the discovered prefix table.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
VerifyPrefixTable({RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceLow, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Add the OMR prefix again.
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. Again the default route should be published.
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router A removing the default route.
SendRouterAdvert(routerAddressA, DefaultRoute(0, NetworkData::kRoutePreferenceLow));
AdvanceTime(10000);
VerifyPrefixTableIsEmpty();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. Now that router A no longer advertised
// a default-route, we should go back to publishing ULA route.
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router A again advertising a default route.
SendRouterAdvert(routerAddressA, DefaultRoute(kValidLitime, NetworkData::kRoutePreferenceLow));
AdvanceTime(10000);
VerifyPrefixTable({RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceLow, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We should see default route published.
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestDefaultRoute");
FinalizeTest();
}
void TestAdvNonUlaRoute(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
Ip6::Prefix routePrefix = PrefixFromString("2000:1234:5678::", 64);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
NetworkData::OnMeshPrefixConfig prefixConfig;
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestAdvNonUlaRoute");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the local OMR and ULA prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router A advertising a non-ULA.
SendRouterAdvert(routerAddressA, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the discovered prefix table and ensure the non-ULA
// from router A is in the table.
VerifyPrefixTable({RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We should not see default route in
// Network Data yet since there is no infrastructure-derived
// OMR prefix (with preference medium or higher).
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Add an OMR prefix directly into Network Data with
// preference medium (infrastructure-derived).
prefixConfig.Clear();
prefixConfig.mPrefix = omrPrefix;
prefixConfig.mStable = true;
prefixConfig.mSlaac = true;
prefixConfig.mPreferred = true;
prefixConfig.mOnMesh = true;
prefixConfig.mDefaultRoute = true;
prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. Now that we have an infrastructure-derived
// OMR prefix, the default route should be published.
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Remove the OMR prefix from Network Data.
SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &omrPrefix));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We should again go back to ULA prefix. The
// non-ULA route advertised by router A should be still present in
// the discovered prefix table.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
VerifyPrefixTable({RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Add the OMR prefix again.
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. Again the default route should be published.
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router A removing the route.
SendRouterAdvert(routerAddressA, {Rio(routePrefix, 0, NetworkData::kRoutePreferenceMedium)});
AdvanceTime(10000);
VerifyPrefixTableIsEmpty();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. Now that router A no longer advertised
// the route, we should go back to publishing the ULA route.
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router A again advertising the route again.
SendRouterAdvert(routerAddressA, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
AdvanceTime(10000);
VerifyPrefixTable({RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We should see default route published.
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestAdvNonUlaRoute");
FinalizeTest();
}
void TestLocalOnLinkPrefixDeprecation(void)
{
static constexpr uint32_t kMaxRaTxInterval = 601; // In seconds
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("fd00:abba:baba::", 64);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
uint32_t localOnLinkLifetime;
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestLocalOnLinkPrefixDeprecation");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Local on-link prefix is being advertised, lifetime: %d", sOnLinkLifetime);
localOnLinkLifetime = sOnLinkLifetime;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the local OMR and on-link prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A with a new on-link (PIO) which is preferred over
// the local on-link prefix.
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kInfiniteLifetime, kInfiniteLifetime)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that the local on-link prefix is now deprecating in the new RA.
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(localOmr);
AdvanceTime(10000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("On-link prefix is deprecating, remaining lifetime:%d", sOnLinkLifetime);
VerifyOrQuit(sOnLinkLifetime < localOnLinkLifetime);
localOnLinkLifetime = sOnLinkLifetime;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We must see the new on-link prefix from router A
// along with the deprecating local on-link prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for local on-link prefix to expire
while (localOnLinkLifetime > kMaxRaTxInterval)
{
// Send same RA from router A to keep the on-link prefix alive.
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
// Ensure Network Data entries remain as before. Mainly we still
// see the deprecating local on-link prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kSkipAdvPioCheck);
// Keep checking the emitted RAs and make sure on-link prefix
// is included with smaller lifetime every time.
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(localOmr);
AdvanceTime(kMaxRaTxInterval * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("On-link prefix is deprecating, remaining lifetime:%d", sOnLinkLifetime);
VerifyOrQuit(sOnLinkLifetime < localOnLinkLifetime);
localOnLinkLifetime = sOnLinkLifetime;
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The local on-link prefix must be expired and should no
// longer be seen in the emitted RA message.
sRaValidated = false;
sExpectedPio = kNoPio;
sExpectedRios.Clear();
sExpectedRios.Add(localOmr);
AdvanceTime(kMaxRaTxInterval * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("On-link prefix is now expired");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioCleared);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestLocalOnLinkPrefixDeprecation");
FinalizeTest();
}
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
void TestDomainPrefixAsOmr(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix domainPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
NetworkData::OnMeshPrefixConfig prefixConfig;
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestDomainPrefixAsOmr");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the local OMR and on-link prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Add a domain prefix directly into net data. The new prefix should
// be favored over the local OMR prefix.
otBackboneRouterSetEnabled(sInstance, true);
prefixConfig.Clear();
prefixConfig.mPrefix = domainPrefix;
prefixConfig.mStable = true;
prefixConfig.mSlaac = true;
prefixConfig.mPreferred = true;
prefixConfig.mOnMesh = true;
prefixConfig.mDefaultRoute = false;
prefixConfig.mDp = true;
prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(100);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Make sure BR emits RA without domain prefix or previous local OMR.
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(domainPrefix);
sExpectedRios.Add(localOmr);
AdvanceTime(20000);
VerifyOrQuit(sRaValidated);
// We should see RIO removing the local OMR prefix with lifetime zero
// and should not see the domain prefix as RIO.
VerifyOrQuit(sExpectedRios[0].mPrefix == domainPrefix);
VerifyOrQuit(!sExpectedRios[0].mSawInRa);
VerifyOrQuit(sExpectedRios[1].mPrefix == localOmr);
VerifyOrQuit(sExpectedRios[1].mSawInRa);
VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime);
// Wait long enough for deprecating RIO prefix to expire
AdvanceTime(3200000);
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(domainPrefix);
sExpectedRios.Add(localOmr);
// Wait for next RA (650 seconds).
AdvanceTime(650000);
VerifyOrQuit(sRaValidated);
// We should not see either domain prefix or local OMR
// as RIO.
VerifyOrQuit(!sExpectedRios[0].mSawInRa);
VerifyOrQuit(!sExpectedRios[1].mSawInRa);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We should now see that the local OMR prefix
// is removed.
VerifyOmrPrefixInNetData(domainPrefix, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Remove the domain prefix from net data.
SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &domainPrefix));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(100);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Make sure BR emits RA with local OMR prefix again.
sRaValidated = false;
sExpectedRios.Clear();
sExpectedRios.Add(localOmr);
AdvanceTime(20000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data. We should see that the local OMR prefix is
// added again.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestDomainPrefixAsOmr");
FinalizeTest();
}
#endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
void TestExtPanIdChange(void)
{
static constexpr uint32_t kMaxRaTxInterval = 601; // In seconds
static const otExtendedPanId kExtPanId1 = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x6, 0x7, 0x08}};
static const otExtendedPanId kExtPanId2 = {{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x99, 0x88}};
static const otExtendedPanId kExtPanId3 = {{0x12, 0x34, 0x56, 0x78, 0x9a, 0xab, 0xcd, 0xef}};
static const otExtendedPanId kExtPanId4 = {{0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00}};
static const otExtendedPanId kExtPanId5 = {{0x77, 0x88, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55}};
Ip6::Prefix localOnLink;
Ip6::Prefix oldLocalOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
uint32_t oldPrefixLifetime;
Ip6::Prefix oldPrefixes[4];
otOperationalDataset dataset;
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestExtPanIdChange");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Local on-link prefix is being advertised, lifetime: %d", sOnLinkLifetime);
//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Check behavior when ext PAN ID changes while the local on-link is
// being advertised.
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Change the extended PAN ID.
Log("Changing ext PAN ID");
oldLocalOnLink = localOnLink;
oldPrefixLifetime = sOnLinkLifetime;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
SuccessOrQuit(otDatasetGetActive(sInstance, &dataset));
VerifyOrQuit(dataset.mComponents.mIsExtendedPanIdPresent);
dataset.mExtendedPanId = kExtPanId1;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
AdvanceTime(500);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
Log("Local on-link prefix changed to %s from %s", localOnLink.ToString().AsCString(),
oldLocalOnLink.ToString().AsCString());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Validate the received RA message and that it contains the
// old on-link prefix being deprecated.
AdvanceTime(30000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
VerifyOrQuit(sDeprecatingPrefixes[0].mPrefix == oldLocalOnLink);
oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Validate Network Data.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Stop BR and validate that a final RA is emitted deprecating
// both current local on-link prefix and old prefix.
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
AdvanceTime(100);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
VerifyOrQuit(sDeprecatingPrefixes[0].mPrefix == oldLocalOnLink);
oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime;
sRaValidated = false;
AdvanceTime(350000);
VerifyOrQuit(!sRaValidated);
VerifyNoOmrPrefixInNetData();
VerifyExternalRouteInNetData(kNoRoute);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start BR again and validate old prefix will continue to
// be deprecated.
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
AdvanceTime(300000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
VerifyOrQuit(sDeprecatingPrefixes[0].mPrefix == oldLocalOnLink);
VerifyOrQuit(oldPrefixLifetime > sDeprecatingPrefixes[0].mLifetime);
oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for old local on-link prefix to expire.
while (oldPrefixLifetime > 2 * kMaxRaTxInterval)
{
// Ensure Network Data entries remain as before.
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
// Keep checking the emitted RAs and make sure the prefix
// is included with smaller lifetime every time.
sRaValidated = false;
AdvanceTime(kMaxRaTxInterval * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
Log("Old on-link prefix is deprecating, remaining lifetime:%d", sDeprecatingPrefixes[0].mLifetime);
VerifyOrQuit(sDeprecatingPrefixes[0].mLifetime < oldPrefixLifetime);
oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime;
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The local on-link prefix must be expired now and should no
// longer be seen in the emitted RA message.
sRaValidated = false;
AdvanceTime(3 * kMaxRaTxInterval * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.IsEmpty());
Log("Old on-link prefix is now expired");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Validate the Network Data.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Check behavior when ext PAN ID changes while the local on-link is being
// deprecated.
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A with a new on-link (PIO) which is preferred over
// the local on-link prefix.
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Validate that the local on-link prefix is deprecated.
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
AdvanceTime(30000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Change the extended PAN ID.
oldLocalOnLink = localOnLink;
oldPrefixLifetime = sOnLinkLifetime;
dataset.mExtendedPanId = kExtPanId2;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
AdvanceTime(500);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
Log("Local on-link prefix changed to %s from %s", localOnLink.ToString().AsCString(),
oldLocalOnLink.ToString().AsCString());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Validate that the old local on-link prefix is still being included
// as PIO in the emitted RA.
sRaValidated = false;
sExpectedPio = kNoPio;
AdvanceTime(30000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
VerifyOrQuit(sDeprecatingPrefixes[0].mPrefix == oldLocalOnLink);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Validate that Network Data.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for old local on-link prefix to expire.
while (oldPrefixLifetime > 2 * kMaxRaTxInterval)
{
// Send same RA from router A to keep its on-link prefix alive.
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
// Ensure Network Data entries remain as before.
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
// Keep checking the emitted RAs and make sure the prefix
// is included with smaller lifetime every time.
sRaValidated = false;
AdvanceTime(kMaxRaTxInterval * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
Log("Old on-link prefix is deprecating, remaining lifetime:%d", sDeprecatingPrefixes[0].mLifetime);
VerifyOrQuit(sDeprecatingPrefixes[0].mLifetime < oldPrefixLifetime);
oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime;
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The old on-link prefix must be expired now and should no
// longer be seen in the emitted RA message.
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
sRaValidated = false;
AdvanceTime(kMaxRaTxInterval * 1000);
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
AdvanceTime(kMaxRaTxInterval * 1000);
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
AdvanceTime(kMaxRaTxInterval * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.IsEmpty());
Log("Old on-link prefix is now expired");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Validate the Network Data.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Check behavior when ext PAN ID changes while the local on-link is not
// advertised.
Log("Changing ext PAN ID again");
oldLocalOnLink = localOnLink;
sRaValidated = false;
sExpectedPio = kNoPio;
dataset.mExtendedPanId = kExtPanId3;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
AdvanceTime(500);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
Log("Local on-link prefix changed to %s from %s", localOnLink.ToString().AsCString(),
oldLocalOnLink.ToString().AsCString());
AdvanceTime(35000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.IsEmpty());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Validate the Network Data.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Remove the on-link prefix PIO being advertised by router A
// and ensure local on-link prefix is advertised again.
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, 0)});
AdvanceTime(300000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.IsEmpty());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for longer than valid lifetime of PIO entry from router A.
// Validate that default route is unpublished from network data.
AdvanceTime(2000 * 1000);
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Multiple PAN ID changes and multiple deprecating old prefixes.
oldPrefixes[0] = localOnLink;
dataset.mExtendedPanId = kExtPanId2;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
AdvanceTime(30000);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Change the prefix again. We should see two deprecating prefixes.
oldPrefixes[1] = localOnLink;
dataset.mExtendedPanId = kExtPanId1;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
AdvanceTime(30000);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 2);
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1]));
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for 15 minutes and then change ext PAN ID again.
// Now we should see three deprecating prefixes.
AdvanceTime(15 * 60 * 1000);
oldPrefixes[2] = localOnLink;
dataset.mExtendedPanId = kExtPanId4;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
AdvanceTime(30000);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 3);
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1]));
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[2]));
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Change ext PAN ID back to previous value of `kExtPanId1`.
// We should still see three deprecating prefixes and the last prefix
// at `oldPrefixes[2]` should again be treated as local on-link prefix.
oldPrefixes[3] = localOnLink;
dataset.mExtendedPanId = kExtPanId1;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
AdvanceTime(30000);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 3);
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1]));
VerifyOrQuit(oldPrefixes[2] == localOnLink);
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[3]));
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Stop BR and validate the final emitted RA to contain
// all deprecating prefixes.
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
AdvanceTime(100);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 3);
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1]));
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[3]));
VerifyNoOmrPrefixInNetData();
VerifyExternalRouteInNetData(kNoRoute);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for 15 minutes while BR stays disabled and validate
// there are no emitted RAs. We want to check that deprecating
// prefixes continue to expire while BR is stopped.
sRaValidated = false;
AdvanceTime(15 * 60 * 1000);
VerifyOrQuit(!sRaValidated);
VerifyNoOmrPrefixInNetData();
VerifyExternalRouteInNetData(kNoRoute);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start BR again, and check that we only see the last deprecating prefix
// at `oldPrefixes[3]` in emitted RA and the other two are expired and
// no longer included as PIO and/or in network data.
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
AdvanceTime(30000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[3]));
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Validate the oldest prefix is removed when we have too many
// back-to-back PAN ID changes.
// Remember the oldest deprecating prefix (associated with `kExtPanId4`).
oldLocalOnLink = oldPrefixes[3];
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(oldPrefixes[0]));
dataset.mExtendedPanId = kExtPanId2;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
AdvanceTime(30000);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(oldPrefixes[1]));
dataset.mExtendedPanId = kExtPanId3;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
AdvanceTime(30000);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(oldPrefixes[2]));
dataset.mExtendedPanId = kExtPanId5;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
sRaValidated = false;
AdvanceTime(30000);
VerifyOrQuit(sRaValidated);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 3);
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1]));
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[2]));
VerifyOrQuit(!sDeprecatingPrefixes.ContainsMatching(oldLocalOnLink));
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestExtPanIdChange");
FinalizeTest();
}
void TestRouterNsProbe(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
Ip6::Prefix routePrefix = PrefixFromString("2000:1234:5678::", 64);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestRouterNsProbe");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A with a new on-link (PIO) and route prefix (RIO).
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)},
{Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
sExpectedPio = kPioDeprecatingLocalOnLink;
AdvanceTime(10);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the discovered prefix table and ensure info from router A
// is present in the table.
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
AdvanceTime(30000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router B with same route prefix (RIO) but with
// high route preference.
SendRouterAdvert(routerAddressB, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh)});
AdvanceTime(200);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the discovered prefix table and ensure entries from
// both router A and B are seen.
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA),
RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh, routerAddressB)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that BR emitted an NS to ensure routers are active.
sNsEmitted = false;
sRsEmitted = false;
AdvanceTime(160 * 1000);
VerifyOrQuit(sNsEmitted);
VerifyOrQuit(!sRsEmitted);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Disallow responding to NS message.
//
// This should trigger `RoutingManager` to send RS (which will get
// no response as well) and then remove all router entries.
sRespondToNs = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sRaValidated = false;
sNsEmitted = false;
AdvanceTime(240 * 1000);
VerifyOrQuit(sNsEmitted);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the discovered prefix table. We should see the on-link entry from
// router A as deprecated and no route prefix.
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, 0, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Verify that no more NS is being sent (since there is no more valid
// router entry in the table).
sExpectedPio = kPioAdvertisingLocalOnLink;
sRaValidated = false;
sNsEmitted = false;
AdvanceTime(6 * 60 * 1000);
VerifyOrQuit(!sNsEmitted);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router B and verify that we see router B
// entry in prefix table.
SendRouterAdvert(routerAddressB, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh)});
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, 0, routerAddressA)},
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh, routerAddressB)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for longer than router active time before NS probe.
// Check again that NS are sent again.
sRespondToNs = true;
sNsEmitted = false;
sRsEmitted = false;
AdvanceTime(3 * 60 * 1000);
VerifyOrQuit(sNsEmitted);
VerifyOrQuit(!sRsEmitted);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestRouterNsProbe");
FinalizeTest();
}
void TestLearningAndCopyingOfFlags(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
Ip6::Address routerAddressC = AddressFromString("fd00::cccc");
uint16_t heapAllocations;
RaFlags raFlags;
Log("--------------------------------------------------------------------------------------------");
Log("TestLearningAndCopyingOfFlags");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
VerifyDiscoveredRoutersIsEmpty();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A with M flag set, and make sure the
// emitted RA from BR also includes M flag.
raFlags.Clear();
raFlags.mManagedAddressConfigFlag = true;
SendRouterAdvert(routerAddressA, raFlags);
AdvanceTime(1);
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* StubRouter */ false)});
sRaValidated = false;
sExpectedRaHeaderFlags = kRaHeaderFlagsOnlyM;
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A without the M flag. Now the emitted
// RA should no longer contain the M flag.
raFlags.Clear();
SendRouterAdvert(routerAddressA, raFlags);
sRaValidated = false;
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
AdvanceTime(1);
VerifyDiscoveredRoutersIsEmpty();
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A with both M and StubRouter flags.
// Since it is from a stub router, the M flag should be ignored.
// Ensure emitted RA does not set the M flag.
raFlags.Clear();
raFlags.mManagedAddressConfigFlag = true;
raFlags.mStubRouterFlag = true;
SendRouterAdvert(routerAddressA, raFlags);
AdvanceTime(1);
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* StubRouter */ true)});
sRaValidated = false;
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router B with O flag and check that emitted
// RA include the same flag.
raFlags.Clear();
raFlags.mOtherConfigFlag = true;
SendRouterAdvert(routerAddressB, raFlags);
AdvanceTime(1);
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* StubRouter */ true),
InfraRouter(routerAddressB, /* M */ false, /* O */ true, /* StubRouter */ false)});
sRaValidated = false;
sExpectedRaHeaderFlags = kRaHeaderFlagsOnlyO;
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router C with M flag and check that emitted
// RA now includes both M and O flags.
raFlags.Clear();
raFlags.mManagedAddressConfigFlag = true;
SendRouterAdvert(routerAddressC, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)},
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), raFlags);
AdvanceTime(1);
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* StubRouter */ true),
InfraRouter(routerAddressB, /* M */ false, /* O */ true, /* StubRouter */ false),
InfraRouter(routerAddressC, /* M */ true, /* O */ false, /* StubRouter */ false)});
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
sExpectedRaHeaderFlags = kRaHeaderFlagsBothMAndO;
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Stop responding to NS, this should cause all routers
// to age and considered offline
sRespondToNs = false;
sExpectedRaHeaderFlags = kRaHeaderFlagsSkipChecking;
AdvanceTime(300 * 1000);
// Router C should be in the table since it will have a deprecating
// on-link prefix.
VerifyDiscoveredRouters({InfraRouter(routerAddressC, /* M */ true, /* O */ false, /* StubRouter */ false)});
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyDiscoveredRoutersIsEmpty();
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestLearningAndCopyingOfFlags");
FinalizeTest();
}
void TestLearnRaHeader(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestLearnRaHeader");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
VerifyDiscoveredRoutersIsEmpty();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from the same address (another entity on the device)
// advertising a default route.
SendRouterAdvert(sInfraIfAddress, DefaultRoute(1000, NetworkData::kRoutePreferenceLow));
AdvanceTime(1);
VerifyDiscoveredRouters({InfraRouter(sInfraIfAddress, /* M */ false, /* O */ false, /* StubRouter */ false)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RoutingManager should learn the header from the
// received RA (from same address) and start advertising
// the same default route lifetime in the emitted RAs.
sRaValidated = false;
sCheckRaHeaderLifetime = true;
sExpectedRaHeaderLifetime = 1000;
AdvanceTime(30 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for longer than entry lifetime (for it to expire) and
// make sure `RoutingManager` stops advertising default route.
sCheckRaHeaderLifetime = false;
AdvanceTime(1000 * 1000);
sRaValidated = false;
sCheckRaHeaderLifetime = true;
sExpectedRaHeaderLifetime = 0;
AdvanceTime(700 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyDiscoveredRoutersIsEmpty();
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestLearnRaHeader");
FinalizeTest();
}
void TestConflictingPrefix(void)
{
static const otExtendedPanId kExtPanId1 = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x6, 0x7, 0x08}};
Ip6::Prefix localOnLink;
Ip6::Prefix oldLocalOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
otOperationalDataset dataset;
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestConflictingPrefix");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the local OMR and on-link prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A with our local on-link prefix as RIO.
Log("Send RA from router A with local on-link as RIO");
SendRouterAdvert(routerAddressA, {Rio(localOnLink, kValidLitime, NetworkData::kRoutePreferenceMedium)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that the local on-link prefix is still being advertised.
sRaValidated = false;
AdvanceTime(610000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to still include the local OMR and ULA prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A removing local on-link prefix as RIO.
SendRouterAdvert(routerAddressA, {Rio(localOnLink, 0, NetworkData::kRoutePreferenceMedium)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Verify that ULA prefix is still included in Network Data and
// the change by router A did not cause it to be unpublished.
AdvanceTime(10000);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that the local on-link prefix is still being advertised.
sRaValidated = false;
AdvanceTime(610000);
VerifyOrQuit(sRaValidated);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router B advertising an on-link prefix. This
// should cause local on-link prefix to be deprecated.
SendRouterAdvert(routerAddressB, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that the local on-link prefix is now deprecating.
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
AdvanceTime(10000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("On-link prefix is deprecating, remaining lifetime:%d", sOnLinkLifetime);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the default route now due
// the new on-link prefix from router B.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A again adding local on-link prefix as RIO.
Log("Send RA from router A with local on-link as RIO");
SendRouterAdvert(routerAddressA, {Rio(localOnLink, kValidLitime, NetworkData::kRoutePreferenceMedium)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that the local on-link prefix is still being deprecated.
sRaValidated = false;
AdvanceTime(610000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data remains unchanged.
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A removing the previous RIO.
SendRouterAdvert(routerAddressA, {Rio(localOnLink, 0, NetworkData::kRoutePreferenceMedium)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data remains unchanged.
AdvanceTime(60000);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router B removing its on-link prefix.
SendRouterAdvert(routerAddressB, {Pio(onLinkPrefix, kValidLitime, 0)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that the local on-link prefix is once again being advertised.
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
AdvanceTime(10000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to remain unchanged.
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Change the extended PAN ID.
Log("Changing ext PAN ID");
SuccessOrQuit(otDatasetGetActive(sInstance, &dataset));
VerifyOrQuit(dataset.mComponents.mIsExtendedPanIdPresent);
dataset.mExtendedPanId = kExtPanId1;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
AdvanceTime(10000);
oldLocalOnLink = localOnLink;
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
Log("Local on-link prefix is changed to %s from %s", localOnLink.ToString().AsCString(),
oldLocalOnLink.ToString().AsCString());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data contains default route due to the
// deprecating on-link prefix from router B.
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A again adding the old local on-link prefix
// as RIO.
SendRouterAdvert(routerAddressA, {Rio(oldLocalOnLink, kValidLitime, NetworkData::kRoutePreferenceMedium)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data remains unchanged.
AdvanceTime(10000);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A removing the previous RIO.
SendRouterAdvert(routerAddressA, {Rio(localOnLink, 0, NetworkData::kRoutePreferenceMedium)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data remains unchanged.
AdvanceTime(10000);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestConflictingPrefix");
FinalizeTest();
}
#if OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
void TestSavedOnLinkPrefixes(void)
{
static const otExtendedPanId kExtPanId1 = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x6, 0x7, 0x08}};
Ip6::Prefix localOnLink;
Ip6::Prefix oldLocalOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
otOperationalDataset dataset;
Log("--------------------------------------------------------------------------------------------");
Log("TestSavedOnLinkPrefixes");
InitTest(/* aEnablBorderRouting */ true);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the local OMR and ULA prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Disable the instance and re-enable it.
Log("Disabling and re-enabling OT Instance");
testFreeInstance(sInstance);
InitTest(/* aEnablBorderRouting */ true, /* aAfterReset */ true);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
sExpectedPio = kPioAdvertisingLocalOnLink;
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the local OMR and ULA prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router A advertising an on-link prefix.
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
AdvanceTime(30000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 0);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Disable the instance and re-enable it.
Log("Disabling and re-enabling OT Instance");
testFreeInstance(sInstance);
InitTest(/* aEnablBorderRouting */ true, /* aAfterReset */ true);
sExpectedPio = kPioAdvertisingLocalOnLink;
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to include the local OMR and ULA prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Changing ext PAN ID");
oldLocalOnLink = localOnLink;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
SuccessOrQuit(otDatasetGetActive(sInstance, &dataset));
VerifyOrQuit(dataset.mComponents.mIsExtendedPanIdPresent);
dataset.mExtendedPanId = kExtPanId1;
dataset.mActiveTimestamp.mSeconds++;
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
AdvanceTime(30000);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
Log("Local on-link prefix changed to %s from %s", localOnLink.ToString().AsCString(),
oldLocalOnLink.ToString().AsCString());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Disable the instance and re-enable it.
Log("Disabling and re-enabling OT Instance");
testFreeInstance(sInstance);
InitTest(/* aEnablBorderRouting */ false, /* aAfterReset */ true);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager.
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
AdvanceTime(100);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router A advertising an on-link prefix.
// This ensures the local on-link prefix is not advertised, but
// it must be deprecated since it was advertised last time and
// saved in `Settings`.
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
AdvanceTime(30000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data to now use default route due to the
// on-link prefix from router A.
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for more than 1800 seconds to let the deprecating
// prefixes expire (keep sending RA from router A).
for (uint16_t index = 0; index < 185; index++)
{
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
AdvanceTime(10 * 1000);
}
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Disable the instance and re-enable it and restart Routing Manager.
Log("Disabling and re-enabling OT Instance again");
testFreeInstance(sInstance);
InitTest(/* aEnablBorderRouting */ false, /* aAfterReset */ true);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
AdvanceTime(100);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send RA from router A advertising an on-link prefix.
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
sRaValidated = false;
sExpectedPio = kNoPio;
AdvanceTime(30000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 0);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check Network Data still contains the default route.
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("End of TestSavedOnLinkPrefixes");
FinalizeTest();
}
#endif // OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
void TestAutoEnableOfSrpServer(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestAutoEnableOfSrpServer");
InitTest();
heapAllocations = sHeapAllocatedPtrs.GetLength();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check SRP Server state and enable auto-enable mode
otSrpServerSetAutoEnableMode(sInstance, true);
VerifyOrQuit(otSrpServerIsAutoEnableMode(sInstance));
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Validate that SRP server was auto-enabled
VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED);
Log("Srp::Server is enabled");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Signal that infra if state changed and is no longer running.
// This should stop Routing Manager and in turn the SRP server.
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
Log("Signal infra if is not running");
SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, false));
AdvanceTime(1);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that SRP server is disabled.
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
Log("Srp::Server is disabled");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Signal that infra if state changed and is running again.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Add(localOmr);
Log("Signal infra if is running");
SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, true));
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that SRP server is enabled again.
VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED);
Log("Srp::Server is enabled");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Disable `RoutingManager` explicitly.
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
Log("Disabling RoutingManager");
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
AdvanceTime(1);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that SRP server is also disabled.
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
Log("Srp::Server is disabled");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Disable auto-enable mode on SRP server.
otSrpServerSetAutoEnableMode(sInstance, false);
VerifyOrQuit(!otSrpServerIsAutoEnableMode(sInstance));
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Re-start Routing Manager. Check emitted RS and RA messages.
// This cycle, router A will send a RA including a PIO.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kNoPio;
sExpectedRios.Clear();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(2000);
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that SRP server is still disabled.
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
Log("Srp::Server is disabled");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Enable auto-enable mode on SRP server. Since `RoutingManager`
// is already done with initial policy evaluation, the SRP server
// must be started immediately.
otSrpServerSetAutoEnableMode(sInstance, true);
VerifyOrQuit(otSrpServerIsAutoEnableMode(sInstance));
VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED);
Log("Srp::Server is enabled");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Disable auto-enable mode on SRP server. It must not impact
// its current state and it should remain enabled.
otSrpServerSetAutoEnableMode(sInstance, false);
VerifyOrQuit(!otSrpServerIsAutoEnableMode(sInstance));
AdvanceTime(2000);
VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED);
Log("Srp::Server is enabled");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Signal that infra if state changed and is no longer running.
// This should stop Routing Manager.
sRaValidated = false;
Log("Signal infra if is not running");
SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, false));
AdvanceTime(1);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Re-enable auto-enable mode on SRP server. Since `RoutingManager`
// is stopped (infra if is down), the SRP serer must be stopped
// immediately.
otSrpServerSetAutoEnableMode(sInstance, true);
VerifyOrQuit(otSrpServerIsAutoEnableMode(sInstance));
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
Log("Srp::Server is disabled");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() == heapAllocations);
Log("End of TestAutoEnableOfSrpServer");
FinalizeTest();
}
#endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
void TestNat64PrefixSelection(void)
{
Ip6::Prefix localNat64;
Ip6::Prefix ailNat64 = PrefixFromString("2000:0:0:1:0:0::", 96);
Ip6::Prefix localOmr;
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
NetworkData::OnMeshPrefixConfig prefixConfig;
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestNat64PrefixSelection");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check local NAT64 prefix generation.
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetNat64Prefix(localNat64));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local nat64 prefix is %s", localNat64.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Enable Nat64 Prefix Manager. Check local NAT64 prefix in Network Data.
sInstance->Get<BorderRouter::RoutingManager>().SetNat64PrefixManagerEnabled(true);
AdvanceTime(20000);
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyNat64PrefixInNetData(localNat64);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// AIL NAT64 prefix discovered. No infra-derived OMR prefix in Network Data.
// Check local NAT64 prefix in Network Data.
DiscoverNat64Prefix(ailNat64);
AdvanceTime(20000);
VerifyNat64PrefixInNetData(localNat64);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Add a medium preference OMR prefix into Network Data.
// Check AIL NAT64 prefix published in Network Data.
prefixConfig.Clear();
prefixConfig.mPrefix = omrPrefix;
prefixConfig.mStable = true;
prefixConfig.mSlaac = true;
prefixConfig.mPreferred = true;
prefixConfig.mOnMesh = true;
prefixConfig.mDefaultRoute = false;
prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
SuccessOrQuit(otBorderRouterRegister(sInstance));
AdvanceTime(20000);
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
VerifyNat64PrefixInNetData(ailNat64);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// AIL NAT64 prefix removed.
// Check local NAT64 prefix in Network Data.
ailNat64.Clear();
DiscoverNat64Prefix(ailNat64);
AdvanceTime(20000);
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
VerifyNat64PrefixInNetData(localNat64);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() == heapAllocations);
Log("End of TestNat64PrefixSelection");
FinalizeTest();
}
#endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
void VerifyPdOmrPrefix(const Ip6::Prefix &aPrefix)
{
otBorderRoutingPrefixTableEntry platformPrefixInfo;
VerifyOrQuit(otBorderRoutingGetPdOmrPrefix(sInstance, &platformPrefixInfo) == OT_ERROR_NONE);
VerifyOrQuit(AsCoreType(&platformPrefixInfo.mPrefix) == aPrefix);
}
void VerifyNoPdOmrPrefix()
{
otBorderRoutingPrefixTableEntry platformPrefixInfo;
VerifyOrQuit(otBorderRoutingGetPdOmrPrefix(sInstance, &platformPrefixInfo) == OT_ERROR_NOT_FOUND);
}
void TestBorderRoutingProcessPlatfromGeneratedNd(void)
{
Ip6::Prefix localOmr;
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestBorderRoutingProcessPlatfromGeneratedNd");
InitTest(/* aEnableBorderRouting */ true);
heapAllocations = sHeapAllocatedPtrs.GetLength();
otBorderRoutingDhcp6PdSetEnabled(sInstance, true);
{
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
}
// 0. Reject invalid RA.
Log("0. Invalid RA message.");
{
{
const uint8_t testInvalidRaMessage[] = {
0x86, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
otPlatBorderRoutingProcessIcmp6Ra(sInstance, testInvalidRaMessage, sizeof(testInvalidRaMessage));
VerifyNoPdOmrPrefix();
}
{
const uint8_t testInvalidRaMessage[] = {
0x87, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
otPlatBorderRoutingProcessIcmp6Ra(sInstance, testInvalidRaMessage, sizeof(testInvalidRaMessage));
VerifyNoPdOmrPrefix();
}
{
const uint8_t testRaMessageWithInvalidPrefix[] = {
0x86, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x04, 0x41, 0xc0, 0x00, 0x00, 0x10, 0xe1, 0x00, 0x00, 0x04, 0xd2, 0x00, 0x00, 0x00, 0x00,
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
otPlatBorderRoutingProcessIcmp6Ra(sInstance, testRaMessageWithInvalidPrefix,
sizeof(testRaMessageWithInvalidPrefix));
VerifyNoPdOmrPrefix();
}
}
// 1. Publish a prefix, and wait until it expired.
Log("1. Simple RA message.");
{
Ip6::Prefix raPrefix = PrefixFromString("2001:db8:dead:beef::", 64);
SendRouterAdvertToBorderRoutingProcessIcmp6Ra({Pio(raPrefix, kValidLitime, kPreferredLifetime)});
sExpectedRios.Add(raPrefix);
AdvanceTime(10000);
VerifyPdOmrPrefix(raPrefix);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOmrPrefixInNetData(raPrefix, /* aDefaultRoute */ false);
AdvanceTime(1500000);
sExpectedRios.Clear();
VerifyPdOmrPrefix(raPrefix);
VerifyOmrPrefixInNetData(raPrefix, /* aDefaultRoute */ false);
AdvanceTime(400000);
// Deprecated prefixes will be removed.
VerifyNoPdOmrPrefix();
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
}
// 1.1. Publish a prefix, and wait until it expired.
// Multiple prefixes are advertised, only the smallest one will be used.
Log("1.1. RA message with multiple prefixes.");
{
Ip6::Prefix raPrefix = PrefixFromString("2001:db8:dead:beef::", 64);
Ip6::Prefix ulaRaPrefix = PrefixFromString("fd01:db8:deaf:beef::", 64);
SendRouterAdvertToBorderRoutingProcessIcmp6Ra({Pio(ulaRaPrefix, kValidLitime * 2, kPreferredLifetime * 2),
Pio(raPrefix, kValidLitime, kPreferredLifetime)});
sExpectedRios.Add(raPrefix);
AdvanceTime(10000);
VerifyPdOmrPrefix(raPrefix);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOmrPrefixInNetData(raPrefix, /* aDefaultRoute */ false);
AdvanceTime(1500000);
sExpectedRios.Clear();
VerifyPdOmrPrefix(raPrefix);
VerifyOmrPrefixInNetData(raPrefix, /* aDefaultRoute */ false);
AdvanceTime(400000);
// Deprecated prefixes will be removed.
VerifyNoPdOmrPrefix();
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
}
// 2. Publish a prefix, and renew it before it expired.
Log("2. Renew prefix lifetime.");
{
Ip6::Prefix raPrefix = PrefixFromString("2001:db8:1:2::", 64);
SendRouterAdvertToBorderRoutingProcessIcmp6Ra({Pio(raPrefix, kValidLitime, kPreferredLifetime)});
sExpectedRios.Add(raPrefix);
AdvanceTime(10000);
VerifyPdOmrPrefix(raPrefix);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOmrPrefixInNetData(raPrefix, /* aDefaultRoute */ false);
AdvanceTime(1500000);
sExpectedRios.Clear();
VerifyPdOmrPrefix(raPrefix);
VerifyOmrPrefixInNetData(raPrefix, /* aDefaultRoute */ false);
SendRouterAdvertToBorderRoutingProcessIcmp6Ra({Pio(raPrefix, kValidLitime, kPreferredLifetime)});
AdvanceTime(400000);
VerifyPdOmrPrefix(raPrefix);
VerifyOmrPrefixInNetData(raPrefix, /* aDefaultRoute */ false);
AdvanceTime(1500000);
VerifyNoPdOmrPrefix();
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
}
// 3. Publish a prefix, and publish another prefix to replace it (with goodbye ra).
Log("3. Update prefix.");
{
Ip6::Prefix raPrefix = PrefixFromString("2001:db8:1:2::", 64);
Ip6::Prefix newRaPrefix = PrefixFromString("2001:db8:3:4::", 64);
SendRouterAdvertToBorderRoutingProcessIcmp6Ra({Pio(raPrefix, kValidLitime, kPreferredLifetime)});
sExpectedRios.Add(raPrefix);
sExpectedRios.Clear();
AdvanceTime(10000);
VerifyPdOmrPrefix(raPrefix);
VerifyOmrPrefixInNetData(raPrefix, /* aDefaultRoute */ false);
AdvanceTime(1000000);
VerifyPdOmrPrefix(raPrefix);
SendRouterAdvertToBorderRoutingProcessIcmp6Ra(
{Pio(raPrefix, 0, 0), Pio(newRaPrefix, kValidLitime, kPreferredLifetime)});
sExpectedRios.Add(newRaPrefix);
AdvanceTime(1000000);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyPdOmrPrefix(newRaPrefix);
AdvanceTime(1000000);
VerifyNoPdOmrPrefix();
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
}
// 4. Short prefix will be extended to /64.
Log("Short prefix");
{
// The prefix will be padded to a /64 prefix.
Ip6::Prefix raPrefix = PrefixFromString("2001:db8:cafe:0::", 64);
Ip6::Prefix realRaPrefix;
realRaPrefix.Set(raPrefix.GetBytes(), 48);
SendRouterAdvertToBorderRoutingProcessIcmp6Ra({Pio(realRaPrefix, kValidLitime, kPreferredLifetime)});
sExpectedRios.Add(raPrefix);
AdvanceTime(10000);
VerifyPdOmrPrefix(raPrefix);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOmrPrefixInNetData(raPrefix, /* aDefaultRoute */ false);
AdvanceTime(1500000);
sExpectedRios.Clear();
VerifyPdOmrPrefix(raPrefix);
VerifyOmrPrefixInNetData(raPrefix, /* aDefaultRoute */ false);
AdvanceTime(400000);
// Deprecated prefixes will be removed.
VerifyNoPdOmrPrefix();
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
}
SuccessOrQuit(otBorderRoutingSetEnabled(sInstance, false));
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
Log("End of TestBorderRoutingProcessPlatfromGeneratedNd");
FinalizeTest();
}
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
} // namespace ot
int main(void)
{
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
ot::TestSamePrefixesFromMultipleRouters();
ot::TestOmrSelection();
ot::TestDefaultRoute();
ot::TestAdvNonUlaRoute();
ot::TestLocalOnLinkPrefixDeprecation();
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
ot::TestDomainPrefixAsOmr();
#endif
ot::TestExtPanIdChange();
ot::TestConflictingPrefix();
ot::TestRouterNsProbe();
ot::TestLearningAndCopyingOfFlags();
ot::TestLearnRaHeader();
#if OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
ot::TestSavedOnLinkPrefixes();
#endif
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
ot::TestAutoEnableOfSrpServer();
#endif
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
ot::TestNat64PrefixSelection();
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
ot::TestBorderRoutingProcessPlatfromGeneratedNd();
#endif
printf("All tests passed\n");
#else
printf("BORDER_ROUTING feature is not enabled\n");
#endif
return 0;
}