mirror of
https://github.com/espressif/openthread.git
synced 2026-08-01 00:27:47 +00:00
[routing-manager] add Neighbor Solicit probe mechanism (#8090)
This commit adds a new mechanism in `RoutingManager` to periodically check that discovered routers are still active and operational, so that if the router providing the favored on-link prefix becomes offline, we can detect it more quickly (instead of waiting for the prefix lifetime to expire) and then the BR can start advertising its own on-link prefix. Receiving a Router or Neighbor Advertisement message from a router indicates that it is active. After a timeout interval passes from the last receive from a router we start sending Neighbor Solidification (NS) probes to it. This timeout interval can be specified by newly added build-time OT config parameter (default value is set to one minute). If no response is received after multiple NS attempts, the router is considered to be inactive and the discovered prefix entries associated with the router are removed or deprecated. This commit also updates the unit test for routing manager to validate the behavior of the newly added mechanism.
This commit is contained in:
@@ -66,6 +66,8 @@ typedef enum otIcmp6Type
|
||||
OT_ICMP6_TYPE_ECHO_REPLY = 129, ///< Echo Reply
|
||||
OT_ICMP6_TYPE_ROUTER_SOLICIT = 133, ///< Router Solicitation
|
||||
OT_ICMP6_TYPE_ROUTER_ADVERT = 134, ///< Router Advertisement
|
||||
OT_ICMP6_TYPE_NEIGHBOR_SOLICIT = 135, ///< Neighbor Solicitation
|
||||
OT_ICMP6_TYPE_NEIGHBOR_ADVERT = 136, ///< Neighbor Advertisement
|
||||
} otIcmp6Type;
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (254)
|
||||
#define OPENTHREAD_API_VERSION (255)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -334,6 +334,9 @@ void RoutingManager::HandleReceived(const InfraIf::Icmp6Packet &aPacket, const I
|
||||
case Ip6::Icmp::Header::kTypeRouterSolicit:
|
||||
HandleRouterSolicit(aPacket, aSrcAddress);
|
||||
break;
|
||||
case Ip6::Icmp::Header::kTypeNeighborAdvert:
|
||||
HandleNeighborAdvertisement(aPacket, aSrcAddress);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -904,6 +907,19 @@ void RoutingManager::HandleRouterSolicit(const InfraIf::Icmp6Packet &aPacket, co
|
||||
ScheduleRoutingPolicyEvaluation(kToReplyToRs);
|
||||
}
|
||||
|
||||
void RoutingManager::HandleNeighborAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress)
|
||||
{
|
||||
const Ip6::Nd::NeighborAdvertMessage *naMsg;
|
||||
|
||||
VerifyOrExit(aPacket.GetLength() >= sizeof(naMsg));
|
||||
naMsg = reinterpret_cast<const Ip6::Nd::NeighborAdvertMessage *>(aPacket.GetBytes());
|
||||
|
||||
mDiscoveredPrefixTable.ProcessNeighborAdvertMessage(*naMsg, aSrcAddress);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void RoutingManager::HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress)
|
||||
{
|
||||
Ip6::Nd::RouterAdvertMessage routerAdvMessage(aPacket);
|
||||
@@ -1138,7 +1154,8 @@ void RoutingManager::ResetDiscoveredPrefixStaleTimer(void)
|
||||
|
||||
RoutingManager::DiscoveredPrefixTable::DiscoveredPrefixTable(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mTimer(aInstance)
|
||||
, mEntryTimer(aInstance)
|
||||
, mRouterTimer(aInstance)
|
||||
, mSignalTask(aInstance)
|
||||
, mAllowDefaultRouteInNetData(false)
|
||||
{
|
||||
@@ -1190,6 +1207,8 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(const Ip6
|
||||
}
|
||||
}
|
||||
|
||||
UpdateRouterOnRx(*router);
|
||||
|
||||
RemoveRoutersWithNoEntries();
|
||||
|
||||
exit:
|
||||
@@ -1225,7 +1244,7 @@ void RoutingManager::DiscoveredPrefixTable::ProcessDefaultRoute(const Ip6::Nd::R
|
||||
entry->SetFrom(aRaHeader);
|
||||
}
|
||||
|
||||
mTimer.FireAtIfEarlier(entry->GetExpireTime());
|
||||
mEntryTimer.FireAtIfEarlier(entry->GetExpireTime());
|
||||
Get<RoutingManager>().EvaluatePublishingPrefix(entry->GetPrefix());
|
||||
|
||||
SignalTableChanged();
|
||||
@@ -1272,7 +1291,7 @@ void RoutingManager::DiscoveredPrefixTable::ProcessPrefixInfoOption(const Ip6::N
|
||||
entry->AdoptValidAndPreferredLiftimesFrom(newEntry);
|
||||
}
|
||||
|
||||
mTimer.FireAtIfEarlier(entry->GetExpireTime());
|
||||
mEntryTimer.FireAtIfEarlier(entry->GetExpireTime());
|
||||
Get<RoutingManager>().EvaluatePublishingPrefix(entry->GetPrefix());
|
||||
|
||||
SignalTableChanged();
|
||||
@@ -1316,7 +1335,7 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouteInfoOption(const Ip6::Nd
|
||||
entry->SetFrom(aRio);
|
||||
}
|
||||
|
||||
mTimer.FireAtIfEarlier(entry->GetExpireTime());
|
||||
mEntryTimer.FireAtIfEarlier(entry->GetExpireTime());
|
||||
Get<RoutingManager>().EvaluatePublishingPrefix(entry->GetPrefix());
|
||||
|
||||
SignalTableChanged();
|
||||
@@ -1445,7 +1464,7 @@ void RoutingManager::DiscoveredPrefixTable::RemoveAllEntries(void)
|
||||
}
|
||||
|
||||
RemoveRoutersWithNoEntries();
|
||||
mTimer.Stop();
|
||||
mEntryTimer.Stop();
|
||||
}
|
||||
|
||||
void RoutingManager::DiscoveredPrefixTable::RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold)
|
||||
@@ -1476,6 +1495,36 @@ void RoutingManager::DiscoveredPrefixTable::RemoveOrDeprecateOldEntries(TimeMill
|
||||
RemoveExpiredEntries();
|
||||
}
|
||||
|
||||
void RoutingManager::DiscoveredPrefixTable::RemoveOrDeprecateEntriesFromInactiveRouters(void)
|
||||
{
|
||||
// Remove route prefix entries and deprecate on-link prefix entries
|
||||
// in the table for routers that have reached the max NS probe
|
||||
// attempts and considered as inactive.
|
||||
|
||||
for (Router &router : mRouters)
|
||||
{
|
||||
if (router.mNsProbeCount <= Router::kMaxNsProbes)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Entry &entry : router.mEntries)
|
||||
{
|
||||
if (entry.IsOnLinkPrefix() && !entry.IsDeprecated())
|
||||
{
|
||||
entry.ClearPreferredLifetime();
|
||||
SignalTableChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.ClearValidLifetime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RemoveExpiredEntries();
|
||||
}
|
||||
|
||||
TimeMilli RoutingManager::DiscoveredPrefixTable::CalculateNextStaleTime(TimeMilli aNow) const
|
||||
{
|
||||
TimeMilli onLinkStaleTime = aNow;
|
||||
@@ -1580,7 +1629,7 @@ exit:
|
||||
return shouldPublish;
|
||||
}
|
||||
|
||||
void RoutingManager::DiscoveredPrefixTable::HandleTimer(void)
|
||||
void RoutingManager::DiscoveredPrefixTable::HandleEntryTimer(void)
|
||||
{
|
||||
RemoveExpiredEntries();
|
||||
}
|
||||
@@ -1625,7 +1674,7 @@ void RoutingManager::DiscoveredPrefixTable::RemoveExpiredEntries(void)
|
||||
|
||||
if (nextExpireTime != now.GetDistantFuture())
|
||||
{
|
||||
mTimer.FireAt(nextExpireTime);
|
||||
mEntryTimer.FireAt(nextExpireTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1634,6 +1683,91 @@ void RoutingManager::DiscoveredPrefixTable::SignalTableChanged(void)
|
||||
mSignalTask.Post();
|
||||
}
|
||||
|
||||
void RoutingManager::DiscoveredPrefixTable::ProcessNeighborAdvertMessage(
|
||||
const Ip6::Nd::NeighborAdvertMessage &aNaMessage,
|
||||
const Ip6::Address & aSrcAddress)
|
||||
{
|
||||
Router *router = mRouters.FindMatching(aSrcAddress);
|
||||
|
||||
VerifyOrExit(router != nullptr);
|
||||
VerifyOrExit(aNaMessage.IsValid());
|
||||
VerifyOrExit(aNaMessage.GetTargetAddress() == router->mAddress);
|
||||
|
||||
LogInfo("Received NA from router %s", router->mAddress.ToString().AsCString());
|
||||
|
||||
UpdateRouterOnRx(*router);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void RoutingManager::DiscoveredPrefixTable::UpdateRouterOnRx(Router &aRouter)
|
||||
{
|
||||
aRouter.mNsProbeCount = 0;
|
||||
aRouter.mTimeout = TimerMilli::GetNow() + Random::NonCrypto::AddJitter(Router::kActiveTimout, Router::kJitter);
|
||||
|
||||
mRouterTimer.FireAtIfEarlier(aRouter.mTimeout);
|
||||
}
|
||||
|
||||
void RoutingManager::DiscoveredPrefixTable::HandleRouterTimer(void)
|
||||
{
|
||||
TimeMilli now = TimerMilli::GetNow();
|
||||
TimeMilli nextTime = now.GetDistantFuture();
|
||||
|
||||
for (Router &router : mRouters)
|
||||
{
|
||||
if (router.mNsProbeCount > Router::kMaxNsProbes)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (router.mTimeout <= now)
|
||||
{
|
||||
router.mNsProbeCount++;
|
||||
|
||||
if (router.mNsProbeCount > Router::kMaxNsProbes)
|
||||
{
|
||||
LogInfo("No response to all Neighbor Solicitations attempts from router %s",
|
||||
router.mAddress.ToString().AsCString());
|
||||
continue;
|
||||
}
|
||||
|
||||
router.mTimeout = now + ((router.mNsProbeCount < Router::kMaxNsProbes) ? Router::kNsProbeRetryInterval
|
||||
: Router::kNsProbeTimout);
|
||||
|
||||
SendNeighborSolicitToRouter(router);
|
||||
}
|
||||
|
||||
nextTime = Min(nextTime, router.mTimeout);
|
||||
}
|
||||
|
||||
RemoveOrDeprecateEntriesFromInactiveRouters();
|
||||
|
||||
if (nextTime != now.GetDistantFuture())
|
||||
{
|
||||
mRouterTimer.FireAtIfEarlier(nextTime);
|
||||
}
|
||||
}
|
||||
|
||||
void RoutingManager::DiscoveredPrefixTable::SendNeighborSolicitToRouter(const Router &aRouter)
|
||||
{
|
||||
InfraIf::Icmp6Packet packet;
|
||||
Ip6::Nd::NeighborSolicitMessage neighborSolicitMsg;
|
||||
|
||||
VerifyOrExit(!Get<RoutingManager>().mRsSender.IsInProgress());
|
||||
|
||||
neighborSolicitMsg.SetTargetAddress(aRouter.mAddress);
|
||||
packet.InitFrom(neighborSolicitMsg);
|
||||
|
||||
IgnoreError(Get<RoutingManager>().mInfraIf.Send(packet, aRouter.mAddress));
|
||||
|
||||
LogInfo("Sent Neighbor Solicitation to %s - attempt:%d/%d", aRouter.mAddress.ToString().AsCString(),
|
||||
aRouter.mNsProbeCount, Router::kMaxNsProbes);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void RoutingManager::DiscoveredPrefixTable::InitIterator(PrefixTableIterator &aIterator) const
|
||||
{
|
||||
Iterator &iterator = static_cast<Iterator &>(aIterator);
|
||||
|
||||
@@ -421,7 +421,8 @@ private:
|
||||
};
|
||||
|
||||
void HandleDiscoveredPrefixTableChanged(void); // Declare early so we can use in `mSignalTask`
|
||||
void HandleDiscoveredPrefixTableTimer(void) { mDiscoveredPrefixTable.HandleTimer(); }
|
||||
void HandleDiscoveredPrefixTableEntryTimer(void) { mDiscoveredPrefixTable.HandleEntryTimer(); }
|
||||
void HandleDiscoveredPrefixTableRouterTimer(void) { mDiscoveredPrefixTable.HandleRouterTimer(); }
|
||||
|
||||
class DiscoveredPrefixTable : public InstanceLocator
|
||||
{
|
||||
@@ -448,6 +449,8 @@ private:
|
||||
|
||||
void ProcessRouterAdvertMessage(const Ip6::Nd::RouterAdvertMessage &aRaMessage,
|
||||
const Ip6::Address & aSrcAddress);
|
||||
void ProcessNeighborAdvertMessage(const Ip6::Nd::NeighborAdvertMessage &aNaMessage,
|
||||
const Ip6::Address & aSrcAddress);
|
||||
|
||||
void SetAllowDefaultRouteInNetData(bool aAllow);
|
||||
|
||||
@@ -468,7 +471,8 @@ private:
|
||||
void InitIterator(PrefixTableIterator &aIterator) const;
|
||||
Error GetNextEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const;
|
||||
|
||||
void HandleTimer(void);
|
||||
void HandleEntryTimer(void);
|
||||
void HandleRouterTimer(void);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kMaxRouters = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS;
|
||||
@@ -550,6 +554,17 @@ private:
|
||||
|
||||
struct Router
|
||||
{
|
||||
// The timeout (in msec) for router staying in active state
|
||||
// before starting the Neighbor Solicitation (NS) probes.
|
||||
static constexpr uint32_t kActiveTimout = OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT;
|
||||
|
||||
static constexpr uint8_t kMaxNsProbes = 5; // Max number of NS probe attempts.
|
||||
static constexpr uint32_t kNsProbeRetryInterval = 1000; // In msec. Time between NS probe attempts.
|
||||
static constexpr uint32_t kNsProbeTimout = 2000; // In msec. Max Wait time after last NS probe.
|
||||
static constexpr uint32_t kJitter = 2000; // In msec. Jitter to randomize probe starts.
|
||||
|
||||
static_assert(kMaxNsProbes < 255, "kMaxNsProbes MUST not be 255");
|
||||
|
||||
enum EmptyChecker : uint8_t
|
||||
{
|
||||
kContainsNoEntries
|
||||
@@ -560,6 +575,8 @@ private:
|
||||
|
||||
Ip6::Address mAddress;
|
||||
LinkedList<Entry> mEntries;
|
||||
TimeMilli mTimeout;
|
||||
uint8_t mNsProbeCount;
|
||||
};
|
||||
|
||||
class Iterator : public PrefixTableIterator
|
||||
@@ -578,6 +595,7 @@ private:
|
||||
void ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, Router &aRouter);
|
||||
bool ContainsPrefix(const Entry::Matcher &aMatcher) const;
|
||||
void RemovePrefix(const Entry::Matcher &aMatcher);
|
||||
void RemoveOrDeprecateEntriesFromInactiveRouters(void);
|
||||
void RemoveRoutersWithNoEntries(void);
|
||||
Entry * AllocateEntry(void) { return mEntryPool.Allocate(); }
|
||||
void FreeEntry(Entry &aEntry) { mEntryPool.Free(aEntry); }
|
||||
@@ -586,13 +604,17 @@ private:
|
||||
const Entry *FindFavoredEntryToPublish(const Ip6::Prefix &aPrefix) const;
|
||||
void RemoveExpiredEntries(void);
|
||||
void SignalTableChanged(void);
|
||||
void UpdateRouterOnRx(Router &aRouter);
|
||||
void SendNeighborSolicitToRouter(const Router &aRouter);
|
||||
|
||||
using SignalTask = TaskletIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableChanged>;
|
||||
using TableTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableTimer>;
|
||||
using SignalTask = TaskletIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableChanged>;
|
||||
using EntryTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableEntryTimer>;
|
||||
using RouterTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableRouterTimer>;
|
||||
|
||||
Array<Router, kMaxRouters> mRouters;
|
||||
Pool<Entry, kMaxEntries> mEntryPool;
|
||||
TableTimer mTimer;
|
||||
EntryTimer mEntryTimer;
|
||||
RouterTimer mRouterTimer;
|
||||
SignalTask mSignalTask;
|
||||
bool mAllowDefaultRouteInNetData;
|
||||
};
|
||||
@@ -827,8 +849,9 @@ private:
|
||||
|
||||
void HandleDiscoveredPrefixStaleTimer(void);
|
||||
|
||||
void HandleRouterSolicit(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
|
||||
void HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
|
||||
void HandleRouterSolicit(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
|
||||
void HandleNeighborAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
|
||||
bool ShouldProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, const Ip6::Prefix &aPrefix);
|
||||
bool ShouldProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, const Ip6::Prefix &aPrefix);
|
||||
void UpdateDiscoveredPrefixTableOnNetDataChange(void);
|
||||
|
||||
@@ -85,4 +85,23 @@
|
||||
#ifndef OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_OLD_ON_LINK_PREFIXES
|
||||
#define OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_OLD_ON_LINK_PREFIXES 3
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT
|
||||
*
|
||||
* Specifies the timeout in msec for a discovered router on infra link side.
|
||||
*
|
||||
* This parameter is related to mechanism to check that a discovered router is still active.
|
||||
*
|
||||
* After this timeout elapses since the last received message (a Router or Neighbor Advertisement) from the router,
|
||||
* routing manager will start sending Neighbor Solidification (NS) probes to the router to check that it is still
|
||||
* active.
|
||||
*
|
||||
* This parameter can be considered to large value to practically disable this behavior.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT
|
||||
#define OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT (60 * 1000) // (in msec).
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_BORDER_ROUTING_H_
|
||||
|
||||
@@ -92,6 +92,8 @@ public:
|
||||
kTypeEchoReply = OT_ICMP6_TYPE_ECHO_REPLY, ///< Echo Reply
|
||||
kTypeRouterSolicit = OT_ICMP6_TYPE_ROUTER_SOLICIT, ///< Router Solicitation
|
||||
kTypeRouterAdvert = OT_ICMP6_TYPE_ROUTER_ADVERT, ///< Router Advertisement
|
||||
kTypeNeighborSolicit = OT_ICMP6_TYPE_NEIGHBOR_SOLICIT, ///< Neighbor Solicitation
|
||||
kTypeNeighborAdvert = OT_ICMP6_TYPE_NEIGHBOR_ADVERT, ///< Neighbor Advertisement
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+25
-1
@@ -269,7 +269,7 @@ exit:
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// RouterAdvMessage
|
||||
// RouterSolicitMessage
|
||||
|
||||
RouterSolicitMessage::RouterSolicitMessage(void)
|
||||
{
|
||||
@@ -277,6 +277,30 @@ RouterSolicitMessage::RouterSolicitMessage(void)
|
||||
mHeader.SetType(Icmp::Header::kTypeRouterSolicit);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// NeighborSolicitMessage
|
||||
|
||||
NeighborSolicitMessage::NeighborSolicitMessage(void)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(mChecksum);
|
||||
OT_UNUSED_VARIABLE(mReserved);
|
||||
|
||||
Clear();
|
||||
mType = Icmp::Header::kTypeNeighborSolicit;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// NeighborAdvertMessage
|
||||
|
||||
NeighborAdvertMessage::NeighborAdvertMessage(void)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(mChecksum);
|
||||
OT_UNUSED_VARIABLE(mReserved);
|
||||
|
||||
Clear();
|
||||
mType = Icmp::Header::kTypeNeighborAdvert;
|
||||
}
|
||||
|
||||
} // namespace Nd
|
||||
} // namespace Ip6
|
||||
} // namespace ot
|
||||
|
||||
@@ -698,6 +698,190 @@ private:
|
||||
|
||||
static_assert(sizeof(RouterSolicitMessage) == 8, "invalid RouterSolicitMessage structure");
|
||||
|
||||
/**
|
||||
* This class represents a Neighbor Solicitation (NS) message.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class NeighborSolicitMessage : public Clearable<NeighborSolicitMessage>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the Neighbor Solicitation message.
|
||||
*
|
||||
*/
|
||||
NeighborSolicitMessage(void);
|
||||
|
||||
/**
|
||||
* This method indicates whether the Neighbor Solicitation message is valid (proper Type and Code).
|
||||
*
|
||||
* @retval TRUE If the message is valid.
|
||||
* @retval FALSE If the message is not valid.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborSolicit) && (mCode == 0); }
|
||||
|
||||
/**
|
||||
* This method gets the Target Address field.
|
||||
*
|
||||
* @returns The Target Address.
|
||||
*
|
||||
*/
|
||||
const Address &GetTargetAddress(void) const { return mTargetAddress; }
|
||||
|
||||
/**
|
||||
* This method sets the Target Address field.
|
||||
*
|
||||
* @param[in] aTargetAddress The Target Address.
|
||||
*
|
||||
*/
|
||||
void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; }
|
||||
|
||||
private:
|
||||
// Neighbor Solicitation Message (RFC 4861)
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Type | Code | Checksum |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Reserved |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | |
|
||||
// + +
|
||||
// | |
|
||||
// + Target Address +
|
||||
// | |
|
||||
// + +
|
||||
// | |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Options ...
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-
|
||||
|
||||
uint8_t mType;
|
||||
uint8_t mCode;
|
||||
uint16_t mChecksum;
|
||||
uint32_t mReserved;
|
||||
Address mTargetAddress;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
static_assert(sizeof(NeighborSolicitMessage) == 24, "Invalid NeighborSolicitMessage definition");
|
||||
|
||||
/**
|
||||
* This class represents a Neighbor Advertisement (NA) message.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class NeighborAdvertMessage : public Clearable<NeighborAdvertMessage>
|
||||
{
|
||||
public:
|
||||
NeighborAdvertMessage(void);
|
||||
|
||||
/**
|
||||
* This method indicates whether the Neighbor Advertisement message is valid (proper Type and Code).
|
||||
*
|
||||
* @retval TRUE If the message is valid.
|
||||
* @retval FALSE If the message is not valid.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborAdvert) && (mCode == 0); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the Router Flag is set in the NA message.
|
||||
*
|
||||
* @retval TRUE The Router Flag is set.
|
||||
* @retval FALSE The Router Flag is not set.
|
||||
*
|
||||
*/
|
||||
bool IsRouterFlagSet(void) const { return (mFlags & kRouterFlag) != 0; }
|
||||
|
||||
/**
|
||||
* This method sets the Router Flag in the NA message.
|
||||
*
|
||||
*/
|
||||
void SetRouterFlag(void) { mFlags |= kRouterFlag; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the Solicited Flag is set in the NA message.
|
||||
*
|
||||
* @retval TRUE The Solicited Flag is set.
|
||||
* @retval FALSE The Solicited Flag is not set.
|
||||
*
|
||||
*/
|
||||
bool IsSolicitedFlagSet(void) const { return (mFlags & kSolicitedFlag) != 0; }
|
||||
|
||||
/**
|
||||
* This method sets the Solicited Flag in the NA message.
|
||||
*
|
||||
*/
|
||||
void SetSolicitedFlag(void) { mFlags |= kSolicitedFlag; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the Override Flag is set in the NA message.
|
||||
*
|
||||
* @retval TRUE The Override Flag is set.
|
||||
* @retval FALSE The Override Flag is not set.
|
||||
*
|
||||
*/
|
||||
bool IsOverrideFlagSet(void) const { return (mFlags & kOverrideFlag) != 0; }
|
||||
|
||||
/**
|
||||
* This method sets the Override Flag in the NA message.
|
||||
*
|
||||
*/
|
||||
void SetOverrideFlag(void) { mFlags |= kOverrideFlag; }
|
||||
|
||||
/**
|
||||
* This method gets the Target Address field.
|
||||
*
|
||||
* @returns The Target Address.
|
||||
*
|
||||
*/
|
||||
const Address &GetTargetAddress(void) const { return mTargetAddress; }
|
||||
|
||||
/**
|
||||
* This method sets the Target Address field.
|
||||
*
|
||||
* @param[in] aTargetAddress The Target Address.
|
||||
*
|
||||
*/
|
||||
void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; }
|
||||
|
||||
private:
|
||||
// Neighbor Advertisement Message (RFC 4861)
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Type | Code | Checksum |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |R|S|O| Reserved |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | |
|
||||
// + +
|
||||
// | |
|
||||
// + Target Address +
|
||||
// | |
|
||||
// + +
|
||||
// | |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Options ...
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-
|
||||
|
||||
static constexpr uint8_t kRouterFlag = (1 << 7);
|
||||
static constexpr uint8_t kSolicitedFlag = (1 << 6);
|
||||
static constexpr uint8_t kOverrideFlag = (1 << 5);
|
||||
|
||||
uint8_t mType;
|
||||
uint8_t mCode;
|
||||
uint16_t mChecksum;
|
||||
uint8_t mFlags;
|
||||
uint8_t mReserved[3];
|
||||
Address mTargetAddress;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
static_assert(sizeof(NeighborAdvertMessage) == 24, "Invalid NeighborAdvertMessage definition");
|
||||
|
||||
} // namespace Nd
|
||||
} // namespace Ip6
|
||||
} // namespace ot
|
||||
|
||||
@@ -98,6 +98,8 @@ 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.
|
||||
|
||||
@@ -155,6 +157,7 @@ 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);
|
||||
|
||||
#if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
|
||||
void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
|
||||
@@ -247,6 +250,30 @@ otError otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex,
|
||||
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");
|
||||
}
|
||||
@@ -467,6 +494,13 @@ void SendRouterAdvert(const Ip6::Address &aAddress, const Icmp6Packet &aPacket)
|
||||
otPlatInfraIfRecvIcmp6Nd(sInstance, kInfraIfIndex, &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));
|
||||
}
|
||||
|
||||
Ip6::Prefix PrefixFromString(const char *aString, uint8_t aPrefixLength)
|
||||
{
|
||||
Ip6::Prefix prefix;
|
||||
@@ -705,6 +739,19 @@ struct RoutePrefix : public Rio
|
||||
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);
|
||||
}
|
||||
|
||||
void VerifyPrefixTable(const OnLinkPrefix *aOnLinkPrefixes,
|
||||
uint16_t aNumOnLinkPrefixes,
|
||||
const RoutePrefix * aRoutePrefixes,
|
||||
uint16_t aNumRoutePrefixes)
|
||||
{
|
||||
BorderRouter::RoutingManager::PrefixTableIterator iter;
|
||||
BorderRouter::RoutingManager::PrefixTableEntry entry;
|
||||
@@ -721,14 +768,16 @@ void VerifyPrefixTable(const OnLinkPrefix (&aOnLinkPrefixes)[kNumOnLinkPrefixes]
|
||||
|
||||
if (entry.mIsOnLink)
|
||||
{
|
||||
Log(" on-link prefix:%s, valid:%u, preferred:%u, router:%s",
|
||||
Log(" on-link prefix:%s, valid:%u, preferred:%u, router:%s, age:%u",
|
||||
AsCoreType(&entry.mPrefix).ToString().AsCString(), entry.mValidLifetime, entry.mPreferredLifetime,
|
||||
AsCoreType(&entry.mRouterAddress).ToString().AsCString());
|
||||
AsCoreType(&entry.mRouterAddress).ToString().AsCString(), entry.mMsecSinceLastUpdate / 1000);
|
||||
|
||||
onLinkPrefixCount++;
|
||||
|
||||
for (const OnLinkPrefix &onLinkPrefix : aOnLinkPrefixes)
|
||||
for (uint16_t index = 0; index < aNumOnLinkPrefixes; index++)
|
||||
{
|
||||
const OnLinkPrefix &onLinkPrefix = aOnLinkPrefixes[index];
|
||||
|
||||
if ((onLinkPrefix.mPrefix == AsCoreType(&entry.mPrefix)) &&
|
||||
(AsCoreType(&entry.mRouterAddress) == onLinkPrefix.mRouterAddress))
|
||||
{
|
||||
@@ -741,14 +790,17 @@ void VerifyPrefixTable(const OnLinkPrefix (&aOnLinkPrefixes)[kNumOnLinkPrefixes]
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(" route prefix:%s, valid:%u, prf:%s, router:%s", AsCoreType(&entry.mPrefix).ToString().AsCString(),
|
||||
entry.mValidLifetime, PreferenceToString(entry.mRoutePreference),
|
||||
AsCoreType(&entry.mRouterAddress).ToString().AsCString());
|
||||
Log(" route prefix:%s, valid:%u, prf:%s, router:%s, age:%u",
|
||||
AsCoreType(&entry.mPrefix).ToString().AsCString(), entry.mValidLifetime,
|
||||
PreferenceToString(entry.mRoutePreference), AsCoreType(&entry.mRouterAddress).ToString().AsCString(),
|
||||
entry.mMsecSinceLastUpdate / 1000);
|
||||
|
||||
routePrefixCount++;
|
||||
|
||||
for (const RoutePrefix &routePrefix : aRoutePrefixes)
|
||||
for (uint16_t index = 0; index < aNumRoutePrefixes; index++)
|
||||
{
|
||||
const RoutePrefix &routePrefix = aRoutePrefixes[index];
|
||||
|
||||
if ((routePrefix.mPrefix == AsCoreType(&entry.mPrefix)) &&
|
||||
(AsCoreType(&entry.mRouterAddress) == routePrefix.mRouterAddress))
|
||||
{
|
||||
@@ -763,8 +815,8 @@ void VerifyPrefixTable(const OnLinkPrefix (&aOnLinkPrefixes)[kNumOnLinkPrefixes]
|
||||
VerifyOrQuit(didFind);
|
||||
}
|
||||
|
||||
VerifyOrQuit(onLinkPrefixCount == kNumOnLinkPrefixes);
|
||||
VerifyOrQuit(routePrefixCount == kNumRoutePrefixes);
|
||||
VerifyOrQuit(onLinkPrefixCount == aNumOnLinkPrefixes);
|
||||
VerifyOrQuit(routePrefixCount == aNumRoutePrefixes);
|
||||
}
|
||||
|
||||
void InitTest(void)
|
||||
@@ -801,6 +853,7 @@ void InitTest(void)
|
||||
sRaValidated = false;
|
||||
sExpectedPio = kNoPio;
|
||||
sExpectedRios.Clear();
|
||||
sRespondToNs = true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1453,7 +1506,7 @@ void TestDomainPrefixAsOmr(void)
|
||||
AdvanceTime(100);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Make sure BR emits RA without domain prfix or previous local OMR.
|
||||
// Make sure BR emits RA without domain prefix or previous local OMR.
|
||||
|
||||
sRaValidated = false;
|
||||
sExpectedPio = kPioAdvertisingLocalOnLink;
|
||||
@@ -1465,7 +1518,7 @@ void TestDomainPrefixAsOmr(void)
|
||||
|
||||
VerifyOrQuit(sRaValidated);
|
||||
|
||||
// We should see RIO removing the local OMR prefix with lifetiem zero
|
||||
// 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);
|
||||
@@ -2051,7 +2104,154 @@ void TestExtPanIdChange(void)
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
Log("End of TestExtPanIdChange");
|
||||
testFreeInstance(sInstance);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
Log("--------------------------------------------------------------------------------------------");
|
||||
Log("TestRouterNsProbe");
|
||||
|
||||
InitTest();
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 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");
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 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);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
Log("End of TestRouterNsProbe");
|
||||
testFreeInstance(sInstance);
|
||||
}
|
||||
|
||||
@@ -2502,6 +2702,7 @@ int main(void)
|
||||
#endif
|
||||
TestExtPanIdChange();
|
||||
TestConflictingPrefix();
|
||||
TestRouterNsProbe();
|
||||
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
|
||||
TestAutoEnableOfSrpServer();
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user