Repository: openthread/openthread (language: python)

Issue:
[routing-manager] track origin of received RA messages
This commit adds `RouterAdvOrigin` enumeration to track the origin of a received RA message, whether it is from another router on the infrastructure, or self-generated by either the `RoutingManager` module or another software entity running on the device.

This is used to exclude prefixes from self-generated `RoutingManager` RAs in the prefix table and simplifies learning and adopting of RA headers from other software entities on the same device.

The origin is now logged when a new RA is received for improved debugging.

This commit also updates `test_routing_manager` to pass back any sent RA messages to the OT stack. This validates the mechanism for identifying self-generated RA messages.


Discussion / hints:

Fix patch:
diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp
index 75a3be9ca06..c0750c774b3 100644
--- a/src/core/border_router/routing_manager.cpp
+++ b/src/core/border_router/routing_manager.cpp
@@ -3503,10 +3503,10 @@ void RoutingManager::RaInfo::IncrementTxCountAndSaveHash(const InfraIf::Icmp6Pac
         mLastHashIndex = 0;
     }
 
-    CalculateHash(aRaMessage, mHashes[mLastHashIndex]);
+    CalculateHash(RouterAdvert::RxMessage(aRaMessage), mHashes[mLastHashIndex]);
 }
 
-bool RoutingManager::RaInfo::IsRaFromManager(const Ip6::Nd::RouterAdvert::RxMessage &aRaMessage) const
+bool RoutingManager::RaInfo::IsRaFromManager(const RouterAdvert::RxMessage &aRaMessage) const
 {
     // Determines whether or not a received RA message was prepared by
     // by `RoutingManager` itself (is present in the saved `mHashes`).
@@ -3516,7 +3516,7 @@ bool RoutingManager::RaInfo::IsRaFromManager(const Ip6::Nd::RouterAdvert::RxMess
     uint32_t count         = Min<uint32_t>(mTxCount, kNumHashEntries);
     Hash     hash;
 
-    CalculateHash(aRaMessage.GetAsPacket(), hash);
+    CalculateHash(aRaMessage, hash);
 
     for (; count > 0; count--)
     {
@@ -3541,12 +3541,17 @@ bool RoutingManager::RaInfo::IsRaFromManager(const Ip6::Nd::RouterAdvert::RxMess
     return isFromManager;
 }
 
-void RoutingManager::RaInfo::CalculateHash(const InfraIf::Icmp6Packet &aRaMessage, Hash &aHash)
+void RoutingManager::RaInfo::CalculateHash(const RouterAdvert::RxMessage &aRaMessage, Hash &aHash)
 {
-    Crypto::Sha256 sha256;
+    RouterAdvert::Header header;
+    Crypto::Sha256       sha256;
+
+    header = aRaMessage.GetHeader();
+    header.SetChecksum(0);
 
     sha256.Start();
-    sha256.Update(aRaMessage.GetBytes(), aRaMessage.GetLength());
+    sha256.Update(header);
+    sha256.Update(aRaMessage.GetOptionStart(), aRaMessage.GetOptionLength());
     sha256.Finish(aHash);
 }
 
diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp
index 16f4601d4a2..a814b545214 100644
--- a/src/core/border_router/routing_manager.hpp
+++ b/src/core/border_router/routing_manager.hpp
@@ -1259,8 +1259,8 @@ class RoutingManager : public InstanceLocator
         }
 
         void        IncrementTxCountAndSaveHash(const InfraIf::Icmp6Packet &aRaMessage);
-        bool        IsRaFromManager(const Ip6::Nd::RouterAdvert::RxMessage &aRaMessage) const;
-        static void CalculateHash(const InfraIf::Icmp6Packet &aRaMessage, Hash &aHash);
+        bool        IsRaFromManager(const RouterAdvert::RxMessage &aRaMessage) const;
+        static void CalculateHash(const RouterAdvert::RxMessage &aRaMessage, Hash &aHash);
 
         RouterAdvert::Header mHeader;
         TimeMilli            mHeaderUpdateTime;
diff --git a/src/core/net/nd6.hpp b/src/core/net/nd6.hpp
index 4178f181f8f..c4753b660f8 100644
--- a/src/core/net/nd6.hpp
+++ b/src/core/net/nd6.hpp
@@ -729,6 +729,22 @@ class RouterAdvert
          */
         bool ContainsAnyOptions(void) const { return (mData.GetLength() > sizeof(Header)); }
 
+        /**
+         * Returns pointer to the start of option bytes (after header).
+         *
+         * @returns Pointer to start of options.
+         *
+         */
+        const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); }
+
+        /**
+         * Gets the length (number of bytes) of options.
+         *
+         * @returns Number of bytes after header specifying RA options.
+         *
+         */
+        uint16_t GetOptionLength(void) const { return ContainsAnyOptions() ? mData.GetLength() - sizeof(Header) : 0; }
+
         // The following methods are intended to support range-based `for`
         // loop iteration over `Option`s in the RA message.
 
@@ -736,7 +752,6 @@ class RouterAdvert
         Option::Iterator end(void) const { return Option::Iterator(); }
 
     private:
-        const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); }
         const uint8_t *GetDataEnd(void) const { return mData.GetBytes() + mData.GetLength(); }
 
         Data<kWithUint16Length> mData;


Test patch:
diff --git a/tests/unit/test_routing_manager.cpp b/tests/unit/test_routing_manager.cpp
index 928a52b5c86..74413e43da3 100644
--- a/tests/unit/test_routing_manager.cpp
+++ b/tests/unit/test_routing_manager.cpp
@@ -295,7 +295,8 @@ otError otPlatInfraIfSendIcmp6Nd(uint32_t            aInfraIfIndex,
                                  const uint8_t      *aBuffer,
                                  uint16_t            aBufferLength)
 {
-    Icmp6Packet packet;
+    Icmp6Packet        packet;
+    Ip6::Icmp::Header *header;
 
     Log("otPlatInfraIfSendIcmp6Nd(aDestAddr: %s, aBufferLength:%u)", AsCoreType(aDestAddress).ToString().AsCString(),
         aBufferLength);
@@ -306,7 +307,9 @@ otError otPlatInfraIfSendIcmp6Nd(uint32_t            aInfraIfIndex,
 
     VerifyOrQuit(aBufferLength >= sizeof(Ip6::Icmp::Header));
 
-    switch (reinterpret_cast<const Ip6::Icmp::Header *>(aBuffer)->GetType())
+    header = reinterpret_cast<Ip6::Icmp::Header *>(const_cast<uint8_t *>(aBuffer));
+
+    switch (header->GetType())
     {
     case Ip6::Icmp::Header::kTypeRouterSolicit:
         Log("  Router Solicit message");
@@ -317,6 +320,9 @@ otError otPlatInfraIfSendIcmp6Nd(uint32_t            aInfraIfIndex,
         Log("  Router Advertisement message");
         LogRouterAdvert(packet);
         ValidateRouterAdvert(packet);
+        // Intentionally modify the checksum field in RA Header
+        // before passing it back to the OT stack.
+        header->SetChecksum(0x1234);
         otPlatInfraIfRecvIcmp6Nd(sInstance, kInfraIfIndex, &sInfraIfAddress, aBuffer, aBufferLength);
         break;