[mle] add helper `ReadFrameCounters()` to read Link/MLE Frame Counters (#5762)

This commits adds a common helper method to read Link and/or MLE Frame
Counters from a message. The Link Frame Counter TLV is expected to be
present in the message. The MLE Frame Counter TLV, however, is optional
and when not present the Link Frame Counter is also used as MLE Frame
Counter value.
diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp
index 1821ebd..3dc3591 100644
--- a/src/core/thread/mle.cpp
+++ b/src/core/thread/mle.cpp
@@ -1088,6 +1088,28 @@
     return Tlv::Append<MleFrameCounterTlv>(aMessage, Get<KeyManager>().GetMleFrameCounter());
 }
 
+otError Mle::ReadFrameCounters(const Message &aMessage, uint32_t &aLinkFrameCounter, uint32_t &aMleFrameCounter) const
+{
+    otError error;
+
+    SuccessOrExit(error = Tlv::Find<LinkFrameCounterTlv>(aMessage, aLinkFrameCounter));
+
+    switch (Tlv::Find<MleFrameCounterTlv>(aMessage, aMleFrameCounter))
+    {
+    case OT_ERROR_NONE:
+        break;
+    case OT_ERROR_NOT_FOUND:
+        aMleFrameCounter = aLinkFrameCounter;
+        break;
+    default:
+        error = OT_ERROR_PARSE;
+        break;
+    }
+
+exit:
+    return error;
+}
+
 otError Mle::AppendAddress16(Message &aMessage, uint16_t aRloc16)
 {
     return Tlv::Append<Address16Tlv>(aMessage, aRloc16);
@@ -3278,20 +3300,8 @@
                                                     static_cast<uint8_t>(version)));
     }
 
-    // Link Frame Counter
-    SuccessOrExit(error = Tlv::Find<LinkFrameCounterTlv>(aMessage, linkFrameCounter));
-
-    // Mle Frame Counter
-    switch (Tlv::Find<MleFrameCounterTlv>(aMessage, mleFrameCounter))
-    {
-    case OT_ERROR_NONE:
-        break;
-    case OT_ERROR_NOT_FOUND:
-        mleFrameCounter = linkFrameCounter;
-        break;
-    default:
-        ExitNow(error = OT_ERROR_PARSE);
-    }
+    // Link/MLE Frame Counters
+    SuccessOrExit(error = ReadFrameCounters(aMessage, linkFrameCounter, mleFrameCounter));
 
 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
 
@@ -3603,18 +3613,7 @@
     switch (mRole)
     {
     case kRoleDetached:
-        SuccessOrExit(error = Tlv::Find<LinkFrameCounterTlv>(aMessage, linkFrameCounter));
-
-        switch (Tlv::Find<MleFrameCounterTlv>(aMessage, mleFrameCounter))
-        {
-        case OT_ERROR_NONE:
-            break;
-        case OT_ERROR_NOT_FOUND:
-            mleFrameCounter = linkFrameCounter;
-            break;
-        default:
-            ExitNow(error = OT_ERROR_PARSE);
-        }
+        SuccessOrExit(error = ReadFrameCounters(aMessage, linkFrameCounter, mleFrameCounter));
 
         mParent.SetLinkFrameCounter(linkFrameCounter);
         mParent.SetLinkAckFrameCounter(linkFrameCounter);
diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp
index 20f1a84..012eb00 100644
--- a/src/core/thread/mle.hpp
+++ b/src/core/thread/mle.hpp
@@ -1045,6 +1045,24 @@
     otError AppendLinkFrameCounter(Message &aMessage);
 
     /**
+     * This method reads Link and MLE Frame Counters from a message.
+     *
+     * Link Frame Counter TLV must be present in the message and its value is read into @p aLinkFrameCounter. If MLE
+     * Frame Counter TLV is present in the message, its value is read into @p aMleFrameCounter. If the MLE Frame
+     * Counter TLV is not present in the message, then @p aMleFrameCounter is set to same value as @p aLinkFrameCounter.
+     *
+     * @param[in]  aMesssage           A reference to the message to read from.
+     * @param[out] aLinkFrameCounter   A reference to an `uint32_t` to output the Link Frame Counter.
+     * @param[out] aMleFrameCounter    A reference to an `uint32_t` to output the MLE Frame Counter.
+     *
+     * @retval OT_ERROR_NONE       Successfully read the counters.
+     * @retval OT_ERROR_NOT_FOUND  Link Frame Counter TLV was not found in the message.
+     * @retval OT_ERROR_PARSE      TLVs are not well-formed.
+     *
+     */
+    otError ReadFrameCounters(const Message &aMessage, uint32_t &aLinkFrameCounter, uint32_t &aMleFrameCounter) const;
+
+    /**
      * This method appends an MLE Frame Counter TLV to a message.
      *
      * @param[in]  aMessage  A reference to the message.
diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp
index a5cc6cb..8dae075 100644
--- a/src/core/thread/mle_router.cpp
+++ b/src/core/thread/mle_router.cpp
@@ -838,20 +838,8 @@
     SuccessOrExit(error = Tlv::Find<VersionTlv>(aMessage, version));
     VerifyOrExit(version >= OT_THREAD_VERSION_1_1, error = OT_ERROR_PARSE);
 
-    // Link-Layer Frame Counter
-    SuccessOrExit(error = Tlv::Find<LinkFrameCounterTlv>(aMessage, linkFrameCounter));
-
-    // MLE Frame Counter
-    switch (Tlv::Find<MleFrameCounterTlv>(aMessage, mleFrameCounter))
-    {
-    case OT_ERROR_NONE:
-        break;
-    case OT_ERROR_NOT_FOUND:
-        mleFrameCounter = linkFrameCounter;
-        break;
-    default:
-        ExitNow(error = OT_ERROR_PARSE);
-    }
+    // Link and MLE Frame Counters
+    SuccessOrExit(error = ReadFrameCounters(aMessage, linkFrameCounter, mleFrameCounter));
 
     // Link Margin
     switch (Tlv::Find<LinkMarginTlv>(aMessage, linkMargin))
@@ -2220,20 +2208,8 @@
     Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleChildUpdateRequest);
     Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleDataResponse);
 
-    // Link-Layer Frame Counter
-    SuccessOrExit(error = Tlv::Find<LinkFrameCounterTlv>(aMessage, linkFrameCounter));
-
-    // MLE Frame Counter
-    switch (Tlv::Find<MleFrameCounterTlv>(aMessage, mleFrameCounter))
-    {
-    case OT_ERROR_NONE:
-        break;
-    case OT_ERROR_NOT_FOUND:
-        mleFrameCounter = linkFrameCounter;
-        break;
-    default:
-        ExitNow(error = OT_ERROR_PARSE);
-    }
+    // Link-Layer and MLE Frame Counters
+    SuccessOrExit(error = ReadFrameCounters(aMessage, linkFrameCounter, mleFrameCounter));
 
     // Mode
     SuccessOrExit(error = Tlv::Find<ModeTlv>(aMessage, modeBitmask));