/*
 *  Copyright (c) 2018, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 *   This file implements FTD-specific mesh forwarding of IPv6/6LoWPAN messages.
 */

#include "mesh_forwarder.hpp"

#if OPENTHREAD_FTD

#include "common/locator_getters.hpp"
#include "meshcop/meshcop.hpp"
#include "net/ip6.hpp"
#include "net/tcp6.hpp"
#include "net/udp6.hpp"

namespace ot {

RegisterLogModule("MeshForwarder");

Error MeshForwarder::SendMessage(Message &aMessage)
{
    Mle::MleRouter &mle   = Get<Mle::MleRouter>();
    Error           error = kErrorNone;
    Neighbor *      neighbor;

    aMessage.SetOffset(0);
    aMessage.SetDatagramTag(0);
    mSendQueue.Enqueue(aMessage);

    switch (aMessage.GetType())
    {
    case Message::kTypeIp6:
    {
        Ip6::Header ip6Header;

        IgnoreError(aMessage.Read(0, ip6Header));

        if (ip6Header.GetDestination().IsMulticast())
        {
            // For traffic destined to multicast address larger than realm local, generally it uses IP-in-IP
            // encapsulation (RFC2473), with outer destination as ALL_MPL_FORWARDERS. So here if the destination
            // is multicast address larger than realm local, it should be for indirection transmission for the
            // device's sleepy child, thus there should be no direct transmission.
            if (!ip6Header.GetDestination().IsMulticastLargerThanRealmLocal())
            {
                // schedule direct transmission
                aMessage.SetDirectTransmission();
            }

            if (aMessage.GetSubType() != Message::kSubTypeMplRetransmission)
            {
                if (ip6Header.GetDestination() == mle.GetLinkLocalAllThreadNodesAddress() ||
                    ip6Header.GetDestination() == mle.GetRealmLocalAllThreadNodesAddress())
                {
                    // destined for all sleepy children
                    for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
                    {
                        if (!child.IsRxOnWhenIdle())
                        {
                            mIndirectSender.AddMessageForSleepyChild(aMessage, child);
                        }
                    }
                }
                else
                {
                    // destined for some sleepy children which subscribed the multicast address.
                    for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
                    {
                        if (!child.IsRxOnWhenIdle() && child.HasIp6Address(ip6Header.GetDestination()))
                        {
                            mIndirectSender.AddMessageForSleepyChild(aMessage, child);
                        }
                    }
                }
            }
        }
        else if ((neighbor = Get<NeighborTable>().FindNeighbor(ip6Header.GetDestination())) != nullptr &&
                 !neighbor->IsRxOnWhenIdle() && !aMessage.GetDirectTransmission())
        {
            // destined for a sleepy child
            Child &child = *static_cast<Child *>(neighbor);
            mIndirectSender.AddMessageForSleepyChild(aMessage, child);
        }
        else
        {
            // schedule direct transmission
            aMessage.SetDirectTransmission();
        }

        break;
    }

#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
    case Message::kTypeSupervision:
    {
        Child *child = Get<Utils::ChildSupervisor>().GetDestination(aMessage);
        OT_ASSERT((child != nullptr) && !child->IsRxOnWhenIdle());
        mIndirectSender.AddMessageForSleepyChild(aMessage, *child);
        break;
    }
#endif

    default:
        aMessage.SetDirectTransmission();
        break;
    }

    mScheduleTransmissionTask.Post();

    return error;
}

void MeshForwarder::HandleResolved(const Ip6::Address &aEid, Error aError)
{
    Ip6::Address ip6Dst;
    bool         enqueuedMessage = false;

    for (Message &message : mResolvingQueue)
    {
        if (message.GetType() != Message::kTypeIp6)
        {
            continue;
        }

        IgnoreError(message.Read(Ip6::Header::kDestinationFieldOffset, ip6Dst));

        if (ip6Dst == aEid)
        {
            mResolvingQueue.Dequeue(message);

            if (aError == kErrorNone)
            {
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
                // Pass back to IPv6 layer for DUA destination resolved by Backbone Query
                if (ForwardDuaToBackboneLink(message, ip6Dst) != kErrorNone)
#endif
                {
                    mSendQueue.Enqueue(message);
                    enqueuedMessage = true;
                }
            }
            else
            {
                LogMessage(kMessageDrop, message, nullptr, aError);
                message.Free();
            }
        }
    }

    if (enqueuedMessage)
    {
        mScheduleTransmissionTask.Post();
    }
}

#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
Error MeshForwarder::ForwardDuaToBackboneLink(Message &aMessage, const Ip6::Address &aDst)
{
    Error   error = kErrorNone;
    uint8_t ttl;

    VerifyOrExit(Get<BackboneRouter::Local>().IsPrimary() && Get<BackboneRouter::Leader>().IsDomainUnicast(aDst),
                 error = kErrorNoRoute);

    VerifyOrExit(Get<AddressResolver>().LookUp(aDst) == Get<Mle::MleRouter>().GetRloc16(), error = kErrorNoRoute);

    // Avoid decreasing TTL twice
    IgnoreError(aMessage.Read(Ip6::Header::kHopLimitFieldOffset, ttl));
    ttl++;
    aMessage.Write(Ip6::Header::kHopLimitFieldOffset, ttl);

    IgnoreError(Get<Ip6::Ip6>().HandleDatagram(aMessage, nullptr, nullptr, /* aFromHost */ false));

exit:
    return error;
}
#endif

Error MeshForwarder::EvictMessage(Message::Priority aPriority)
{
    Error          error    = kErrorNotFound;
    PriorityQueue *queues[] = {&mResolvingQueue, &mSendQueue};
    Message *      evict    = nullptr;

    // search for a lower priority message to evict (choose lowest priority message among all queues)
    for (PriorityQueue *queue : queues)
    {
        for (uint8_t priority = 0; priority < aPriority; priority++)
        {
            for (Message *message = queue->GetHeadForPriority(static_cast<Message::Priority>(priority)); message;
                 message          = message->GetNext())
            {
                if (message->GetPriority() != priority)
                {
                    break;
                }

                if (message->GetDoNotEvict())
                {
                    continue;
                }

                evict     = message;
                aPriority = static_cast<Message::Priority>(priority);
                break;
            }
        }
    }

    if (evict != nullptr)
    {
        ExitNow(error = kErrorNone);
    }

    for (uint8_t priority = aPriority; priority < Message::kNumPriorities; priority++)
    {
        // search for an equal or higher priority indirect message to evict
        for (Message *message = mSendQueue.GetHeadForPriority(aPriority); message; message = message->GetNext())
        {
            if (message->GetPriority() != priority)
            {
                break;
            }

            if (message->GetDoNotEvict())
            {
                continue;
            }

            if (message->IsChildPending())
            {
                evict = message;
                ExitNow(error = kErrorNone);
            }
        }
    }

exit:

    if (error == kErrorNone)
    {
        RemoveMessage(*evict);
    }

    return error;
}

void MeshForwarder::RemoveMessages(Child &aChild, Message::SubType aSubType)
{
    for (Message &message : mSendQueue)
    {
        if ((aSubType != Message::kSubTypeNone) && (aSubType != message.GetSubType()))
        {
            continue;
        }

        if (mIndirectSender.RemoveMessageFromSleepyChild(message, aChild) != kErrorNone)
        {
            switch (message.GetType())
            {
            case Message::kTypeIp6:
            {
                Ip6::Header ip6header;

                IgnoreError(message.Read(0, ip6header));

                if (&aChild == static_cast<Child *>(Get<NeighborTable>().FindNeighbor(ip6header.GetDestination())))
                {
                    message.ClearDirectTransmission();
                }

                break;
            }

            case Message::kType6lowpan:
            {
                Lowpan::MeshHeader meshHeader;

                IgnoreError(meshHeader.ParseFrom(message));

                if (&aChild == static_cast<Child *>(Get<NeighborTable>().FindNeighbor(meshHeader.GetDestination())))
                {
                    message.ClearDirectTransmission();
                }

                break;
            }

            default:
                break;
            }
        }

        RemoveMessageIfNoPendingTx(message);
    }
}

void MeshForwarder::RemoveDataResponseMessages(void)
{
    Ip6::Header ip6Header;

    for (Message &message : mSendQueue)
    {
        if (message.GetSubType() != Message::kSubTypeMleDataResponse)
        {
            continue;
        }

        IgnoreError(message.Read(0, ip6Header));

        if (!(ip6Header.GetDestination().IsMulticast()))
        {
            for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
            {
                IgnoreError(mIndirectSender.RemoveMessageFromSleepyChild(message, child));
            }
        }

        if (mSendMessage == &message)
        {
            mSendMessage = nullptr;
        }

        LogMessage(kMessageDrop, message, nullptr, kErrorNone);
        mSendQueue.DequeueAndFree(message);
    }
}

void MeshForwarder::SendMesh(Message &aMessage, Mac::TxFrame &aFrame)
{
    uint16_t fcf;
    bool     iePresent = CalcIePresent(&aMessage);

    // initialize MAC header
    fcf = Mac::Frame::kFcfFrameData | Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfDstAddrShort |
          Mac::Frame::kFcfSrcAddrShort | Mac::Frame::kFcfAckRequest | Mac::Frame::kFcfSecurityEnabled;

    if (iePresent)
    {
        fcf |= Mac::Frame::kFcfIePresent;
    }

    fcf |= CalcFrameVersion(Get<NeighborTable>().FindNeighbor(mMacDest), iePresent);

    aFrame.InitMacHeader(fcf, Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32);
    aFrame.SetDstPanId(Get<Mac::Mac>().GetPanId());
    aFrame.SetDstAddr(mMacDest.GetShort());
    aFrame.SetSrcAddr(mMacSource.GetShort());

#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
    if (iePresent)
    {
        AppendHeaderIe(&aMessage, aFrame);
    }
#endif

    // write payload
    OT_ASSERT(aMessage.GetLength() <= aFrame.GetMaxPayloadLength());
    aMessage.ReadBytes(0, aFrame.GetPayload(), aMessage.GetLength());
    aFrame.SetPayloadLength(aMessage.GetLength());

    mMessageNextOffset = aMessage.GetLength();
}

Error MeshForwarder::UpdateMeshRoute(Message &aMessage)
{
    Error              error = kErrorNone;
    Lowpan::MeshHeader meshHeader;
    Neighbor *         neighbor;
    uint16_t           nextHop;

    IgnoreError(meshHeader.ParseFrom(aMessage));

    nextHop = Get<Mle::MleRouter>().GetNextHop(meshHeader.GetDestination());

    if (nextHop != Mac::kShortAddrInvalid)
    {
        neighbor = Get<NeighborTable>().FindNeighbor(nextHop);
    }
    else
    {
        neighbor = Get<NeighborTable>().FindNeighbor(meshHeader.GetDestination());
    }

    if (neighbor == nullptr)
    {
        ExitNow(error = kErrorDrop);
    }

    mMacDest.SetShort(neighbor->GetRloc16());
    mMacSource.SetShort(Get<Mac::Mac>().GetShortAddress());

    mAddMeshHeader = true;
    mMeshDest      = meshHeader.GetDestination();
    mMeshSource    = meshHeader.GetSource();

exit:
    return error;
}

void MeshForwarder::EvaluateRoutingCost(uint16_t aDest, uint8_t &aBestCost, uint16_t &aBestDest) const
{
    const Neighbor *neighbor;
    uint8_t         curCost = 0x00;

    // Path cost
    curCost = Get<Mle::MleRouter>().GetCost(aDest);

    if (!Mle::MleRouter::IsActiveRouter(aDest))
    {
        // Assume best link between remote child server and its parent.
        curCost += 1;
    }

    // Cost if the server is direct neighbor.
    neighbor = Get<NeighborTable>().FindNeighbor(aDest);

    if (neighbor != nullptr && neighbor->IsStateValid())
    {
        uint8_t cost;

        if (!Mle::MleRouter::IsActiveRouter(aDest))
        {
            // Cost calculated only from Link Quality In as the parent only maintains
            // one-direction link info.
            cost = Mle::MleRouter::LinkQualityToCost(neighbor->GetLinkInfo().GetLinkQuality());
        }
        else
        {
            cost = Get<Mle::MleRouter>().GetLinkCost(Mle::Mle::RouterIdFromRloc16(aDest));
        }

        // Choose the minimum cost
        curCost = OT_MIN(curCost, cost);
    }

    if ((aBestDest == Mac::kShortAddrInvalid) || (curCost < aBestCost))
    {
        aBestDest = aDest;
        aBestCost = curCost;
    }
}

Error MeshForwarder::AnycastRouteLookup(uint8_t aServiceId, AnycastType aType, uint16_t &aMeshDest) const
{
    NetworkData::Iterator iterator = NetworkData::kIteratorInit;
    uint8_t               bestCost = Mle::kMaxRouteCost;
    uint16_t              bestDest = Mac::kShortAddrInvalid;
    uint8_t               routerId;

    switch (aType)
    {
    case kAnycastDhcp6Agent:
    case kAnycastNeighborDiscoveryAgent:
    {
        NetworkData::OnMeshPrefixConfig config;
        Lowpan::Context                 context;

        SuccessOrExit(Get<NetworkData::Leader>().GetContext(aServiceId, context));

        while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, config) == kErrorNone)
        {
            if (config.GetPrefix() != context.mPrefix)
            {
                continue;
            }

            switch (aType)
            {
            case kAnycastDhcp6Agent:
                if (!(config.mDhcp || config.mConfigure))
                {
                    continue;
                }
                break;
            case kAnycastNeighborDiscoveryAgent:
                if (!config.mNdDns)
                {
                    continue;
                }
                break;
            default:
                OT_ASSERT(false);
                break;
            }

            EvaluateRoutingCost(config.mRloc16, bestCost, bestDest);
        }

        break;
    }
    case kAnycastService:
    {
        NetworkData::ServiceConfig config;

        while (Get<NetworkData::Leader>().GetNextService(iterator, config) == kErrorNone)
        {
            if (config.mServiceId != aServiceId)
            {
                continue;
            }

            EvaluateRoutingCost(config.mServerConfig.mRloc16, bestCost, bestDest);
        }

        break;
    }
    }

    routerId = Mle::Mle::RouterIdFromRloc16(bestDest);

    if (!(Mle::Mle::IsActiveRouter(bestDest) ||
          Mle::Mle::Rloc16FromRouterId(routerId) == Get<Mle::MleRouter>().GetRloc16()))
    {
        // if agent is neither active router nor child of this device
        // use the parent of the ED Agent as Dest
        bestDest = Mle::Mle::Rloc16FromRouterId(routerId);
    }

    aMeshDest = bestDest;

exit:
    return (bestDest != Mac::kShortAddrInvalid) ? kErrorNone : kErrorNoRoute;
}

Error MeshForwarder::UpdateIp6RouteFtd(Ip6::Header &ip6Header, Message &aMessage)
{
    Mle::MleRouter &mle   = Get<Mle::MleRouter>();
    Error           error = kErrorNone;
    Neighbor *      neighbor;

    if (aMessage.GetOffset() > 0)
    {
        mMeshDest = aMessage.GetMeshDest();
    }
    else if (mle.IsRoutingLocator(ip6Header.GetDestination()))
    {
        uint16_t rloc16 = ip6Header.GetDestination().GetIid().GetLocator();
        VerifyOrExit(mle.IsRouterIdValid(Mle::Mle::RouterIdFromRloc16(rloc16)), error = kErrorDrop);
        mMeshDest = rloc16;
    }
    else if (mle.IsAnycastLocator(ip6Header.GetDestination()))
    {
        uint16_t aloc16 = ip6Header.GetDestination().GetIid().GetLocator();

        if (aloc16 == Mle::kAloc16Leader)
        {
            mMeshDest = Mle::Mle::Rloc16FromRouterId(mle.GetLeaderId());
        }
        else if (aloc16 <= Mle::kAloc16DhcpAgentEnd)
        {
            uint8_t contextId = static_cast<uint8_t>(aloc16 - Mle::kAloc16DhcpAgentStart + 1);
            SuccessOrExit(error = AnycastRouteLookup(contextId, kAnycastDhcp6Agent, mMeshDest));
        }
        else if (aloc16 <= Mle::kAloc16ServiceEnd)
        {
            uint8_t serviceId = static_cast<uint8_t>(aloc16 - Mle::kAloc16ServiceStart);
            SuccessOrExit(error = AnycastRouteLookup(serviceId, kAnycastService, mMeshDest));
        }
        else if (aloc16 <= Mle::kAloc16CommissionerEnd)
        {
            SuccessOrExit(error = MeshCoP::GetBorderAgentRloc(Get<ThreadNetif>(), mMeshDest));
        }

#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
        else if (aloc16 == Mle::kAloc16BackboneRouterPrimary)
        {
            VerifyOrExit(Get<BackboneRouter::Leader>().HasPrimary(), error = kErrorDrop);
            mMeshDest = Get<BackboneRouter::Leader>().GetServer16();
        }
#endif
        else if ((aloc16 >= Mle::kAloc16NeighborDiscoveryAgentStart) &&
                 (aloc16 <= Mle::kAloc16NeighborDiscoveryAgentEnd))
        {
            uint8_t contextId = static_cast<uint8_t>(aloc16 - Mle::kAloc16NeighborDiscoveryAgentStart + 1);
            SuccessOrExit(error = AnycastRouteLookup(contextId, kAnycastNeighborDiscoveryAgent, mMeshDest));
        }
        else
        {
            ExitNow(error = kErrorDrop);
        }
    }
    else if ((neighbor = Get<NeighborTable>().FindNeighbor(ip6Header.GetDestination())) != nullptr)
    {
        mMeshDest = neighbor->GetRloc16();
    }
    else if (Get<NetworkData::Leader>().IsOnMesh(ip6Header.GetDestination()))
    {
        SuccessOrExit(error = Get<AddressResolver>().Resolve(ip6Header.GetDestination(), mMeshDest));
    }
    else
    {
        IgnoreError(Get<NetworkData::Leader>().RouteLookup(ip6Header.GetSource(), ip6Header.GetDestination(), nullptr,
                                                           &mMeshDest));
    }

    VerifyOrExit(mMeshDest != Mac::kShortAddrInvalid, error = kErrorDrop);

    mMeshSource = Get<Mac::Mac>().GetShortAddress();

    SuccessOrExit(error = mle.CheckReachability(mMeshDest, ip6Header));
    aMessage.SetMeshDest(mMeshDest);
    mMacDest.SetShort(mle.GetNextHop(mMeshDest));

    if (mMacDest.GetShort() != mMeshDest)
    {
        // destination is not neighbor
        mMacSource.SetShort(mMeshSource);
        mAddMeshHeader = true;
    }

exit:
    return error;
}

Error MeshForwarder::GetIp6Header(const uint8_t *     aFrame,
                                  uint16_t            aFrameLength,
                                  const Mac::Address &aMacSource,
                                  const Mac::Address &aMacDest,
                                  Ip6::Header &       aIp6Header)
{
    uint8_t headerLength;
    bool    nextHeaderCompressed;

    return DecompressIp6Header(aFrame, aFrameLength, aMacSource, aMacDest, aIp6Header, headerLength,
                               nextHeaderCompressed);
}

void MeshForwarder::SendIcmpErrorIfDstUnreach(const Message &     aMessage,
                                              const Mac::Address &aMacSource,
                                              const Mac::Address &aMacDest)
{
    Error       error;
    Ip6::Header ip6header;
    Child *     child;

    VerifyOrExit(aMacSource.IsShort() && aMacDest.IsShort());

    child = Get<ChildTable>().FindChild(aMacSource.GetShort(), Child::kInStateAnyExceptInvalid);
    VerifyOrExit((child == nullptr) || child->IsFullThreadDevice());

    IgnoreError(aMessage.Read(0, ip6header));
    VerifyOrExit(!ip6header.GetDestination().IsMulticast() &&
                 Get<NetworkData::Leader>().IsOnMesh(ip6header.GetDestination()));

    error = Get<Mle::MleRouter>().CheckReachability(aMacDest.GetShort(), ip6header);

    if (error == kErrorNoRoute)
    {
        SendDestinationUnreachable(aMacSource.GetShort(), aMessage);
    }

exit:
    return;
}

Error MeshForwarder::CheckReachability(const uint8_t *     aFrame,
                                       uint16_t            aFrameLength,
                                       const Mac::Address &aMeshSource,
                                       const Mac::Address &aMeshDest)
{
    Error                  error = kErrorNone;
    Ip6::Header            ip6Header;
    Message *              message = nullptr;
    Lowpan::FragmentHeader fragmentHeader;
    uint16_t               fragmentHeaderLength;
    uint16_t               datagramSize = 0;

    if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == kErrorNone)
    {
        // Only the first fragment header is followed by a LOWPAN_IPHC header
        VerifyOrExit(fragmentHeader.GetDatagramOffset() == 0, error = kErrorNotFound);
        aFrame += fragmentHeaderLength;
        aFrameLength -= fragmentHeaderLength;

        datagramSize = fragmentHeader.GetDatagramSize();
    }

    VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame), error = kErrorNotFound);

    error = FrameToMessage(aFrame, aFrameLength, datagramSize, aMeshSource, aMeshDest, message);
    SuccessOrExit(error);

    IgnoreError(message->Read(0, ip6Header));
    error = Get<Mle::MleRouter>().CheckReachability(aMeshDest.GetShort(), ip6Header);

exit:
    if (error == kErrorNotFound)
    {
        // the message may not contain an IPv6 header
        error = kErrorNone;
    }
    else if (error == kErrorNoRoute)
    {
        SendDestinationUnreachable(aMeshSource.GetShort(), *message);
    }

    FreeMessage(message);

    return error;
}

void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Message &aMessage)
{
    Ip6::MessageInfo messageInfo;

    messageInfo.GetPeerAddr() = Get<Mle::MleRouter>().GetMeshLocal16();
    messageInfo.GetPeerAddr().GetIid().SetLocator(aMeshSource);

    IgnoreError(Get<Ip6::Icmp>().SendError(Ip6::Icmp::Header::kTypeDstUnreach,
                                           Ip6::Icmp::Header::kCodeDstUnreachNoRoute, messageInfo, aMessage));
}

void MeshForwarder::HandleMesh(uint8_t *             aFrame,
                               uint16_t              aFrameLength,
                               const Mac::Address &  aMacSource,
                               const ThreadLinkInfo &aLinkInfo)
{
    Error              error   = kErrorNone;
    Message *          message = nullptr;
    Mac::Address       meshDest;
    Mac::Address       meshSource;
    Lowpan::MeshHeader meshHeader;
    uint16_t           headerLength;

    // Security Check: only process Mesh Header frames that had security enabled.
    VerifyOrExit(aLinkInfo.IsLinkSecurityEnabled(), error = kErrorSecurity);

    SuccessOrExit(error = meshHeader.ParseFrom(aFrame, aFrameLength, headerLength));

    meshSource.SetShort(meshHeader.GetSource());
    meshDest.SetShort(meshHeader.GetDestination());

    aFrame += headerLength;
    aFrameLength -= headerLength;

    UpdateRoutes(aFrame, aFrameLength, meshSource, meshDest);

    if (meshDest.GetShort() == Get<Mac::Mac>().GetShortAddress() ||
        Get<Mle::MleRouter>().IsMinimalChild(meshDest.GetShort()))
    {
        if (Lowpan::FragmentHeader::IsFragmentHeader(aFrame, aFrameLength))
        {
            HandleFragment(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
        }
        else if (Lowpan::Lowpan::IsLowpanHc(aFrame))
        {
            HandleLowpanHC(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
        }
        else
        {
            ExitNow(error = kErrorParse);
        }
    }
    else if (meshHeader.GetHopsLeft() > 0)
    {
        Message::Priority priority = Message::kPriorityNormal;
        uint16_t          offset   = 0;

        Get<Mle::MleRouter>().ResolveRoutingLoops(aMacSource.GetShort(), meshDest.GetShort());

        SuccessOrExit(error = CheckReachability(aFrame, aFrameLength, meshSource, meshDest));

        meshHeader.DecrementHopsLeft();

        GetForwardFramePriority(aFrame, aFrameLength, meshSource, meshDest, priority);
        message =
            Get<MessagePool>().Allocate(Message::kType6lowpan, /* aReserveHeader */ 0, Message::Settings(priority));
        VerifyOrExit(message != nullptr, error = kErrorNoBufs);

        SuccessOrExit(error = message->SetLength(meshHeader.GetHeaderLength() + aFrameLength));
        offset += meshHeader.WriteTo(*message, offset);
        message->WriteBytes(offset, aFrame, aFrameLength);
        message->SetLinkInfo(aLinkInfo);

#if OPENTHREAD_CONFIG_MULTI_RADIO
        // We set the received radio type on the message in order for it
        // to be logged correctly from LogMessage().
        message->SetRadioType(static_cast<Mac::RadioType>(aLinkInfo.mRadioType));
#endif

        LogMessage(kMessageReceive, *message, &aMacSource, kErrorNone);

#if OPENTHREAD_CONFIG_MULTI_RADIO
        // Since the message will be forwarded, we clear the radio
        // type on the message to allow the radio type for tx to be
        // selected later (based on the radios supported by the next
        // hop).
        message->ClearRadioType();
#endif

        IgnoreError(SendMessage(*message));
    }

exit:

    if (error != kErrorNone)
    {
        LogInfo("Dropping rx mesh frame, error:%s, len:%d, src:%s, sec:%s", ErrorToString(error), aFrameLength,
                aMacSource.ToString().AsCString(), ToYesNo(aLinkInfo.IsLinkSecurityEnabled()));
        FreeMessage(message);
    }
}

void MeshForwarder::UpdateRoutes(const uint8_t *     aFrame,
                                 uint16_t            aFrameLength,
                                 const Mac::Address &aMeshSource,
                                 const Mac::Address &aMeshDest)
{
    Ip6::Header ip6Header;
    Neighbor *  neighbor;

    VerifyOrExit(!aMeshDest.IsBroadcast() && aMeshSource.IsShort());
    SuccessOrExit(GetIp6Header(aFrame, aFrameLength, aMeshSource, aMeshDest, ip6Header));

    if (!ip6Header.GetSource().GetIid().IsLocator() &&
        Get<NetworkData::Leader>().IsOnMesh(ip6Header.GetSource()) /* only for on mesh address which may require AQ */)
    {
        // FTDs MAY add/update EID-to-RLOC Map Cache entries by
        // inspecting packets being received.

        Get<AddressResolver>().UpdateSnoopedCacheEntry(ip6Header.GetSource(), aMeshSource.GetShort(),
                                                       aMeshDest.GetShort());
    }

    neighbor = Get<NeighborTable>().FindNeighbor(ip6Header.GetSource());
    VerifyOrExit(neighbor != nullptr && !neighbor->IsFullThreadDevice());

    if (!Mle::Mle::RouterIdMatch(aMeshSource.GetShort(), Get<Mac::Mac>().GetShortAddress()))
    {
        Get<Mle::MleRouter>().RemoveNeighbor(*neighbor);
    }

exit:
    return;
}

bool MeshForwarder::FragmentPriorityList::UpdateOnTimeTick(void)
{
    bool contineRxingTicks = false;

    for (Entry &entry : mEntries)
    {
        if (!entry.IsExpired())
        {
            entry.DecrementLifetime();

            if (!entry.IsExpired())
            {
                contineRxingTicks = true;
            }
        }
    }

    return contineRxingTicks;
}

void MeshForwarder::UpdateFragmentPriority(Lowpan::FragmentHeader &aFragmentHeader,
                                           uint16_t                aFragmentLength,
                                           uint16_t                aSrcRloc16,
                                           Message::Priority       aPriority)
{
    FragmentPriorityList::Entry *entry;

    entry = mFragmentPriorityList.FindEntry(aSrcRloc16, aFragmentHeader.GetDatagramTag());

    if (entry == nullptr)
    {
        VerifyOrExit(aFragmentHeader.GetDatagramOffset() == 0);

        mFragmentPriorityList.AllocateEntry(aSrcRloc16, aFragmentHeader.GetDatagramTag(), aPriority);
        Get<TimeTicker>().RegisterReceiver(TimeTicker::kMeshForwarder);
        ExitNow();
    }

    if (aFragmentHeader.GetDatagramOffset() + aFragmentLength >= aFragmentHeader.GetDatagramSize())
    {
        entry->Clear();
    }
    else
    {
        entry->ResetLifetime();
    }

exit:
    return;
}

MeshForwarder::FragmentPriorityList::Entry *MeshForwarder::FragmentPriorityList::FindEntry(uint16_t aSrcRloc16,
                                                                                           uint16_t aTag)
{
    Entry *rval = nullptr;

    for (Entry &entry : mEntries)
    {
        if (!entry.IsExpired() && entry.Matches(aSrcRloc16, aTag))
        {
            rval = &entry;
            break;
        }
    }

    return rval;
}

MeshForwarder::FragmentPriorityList::Entry *MeshForwarder::FragmentPriorityList::AllocateEntry(
    uint16_t          aSrcRloc16,
    uint16_t          aTag,
    Message::Priority aPriority)
{
    Entry *newEntry = nullptr;

    for (Entry &entry : mEntries)
    {
        if (entry.IsExpired())
        {
            entry.mSrcRloc16   = aSrcRloc16;
            entry.mDatagramTag = aTag;
            entry.mPriority    = aPriority;
            entry.ResetLifetime();
            newEntry = &entry;
            break;
        }
    }

    return newEntry;
}

Error MeshForwarder::GetFragmentPriority(Lowpan::FragmentHeader &aFragmentHeader,
                                         uint16_t                aSrcRloc16,
                                         Message::Priority &     aPriority)
{
    Error                        error = kErrorNone;
    FragmentPriorityList::Entry *entry;

    entry = mFragmentPriorityList.FindEntry(aSrcRloc16, aFragmentHeader.GetDatagramTag());
    VerifyOrExit(entry != nullptr, error = kErrorNotFound);
    aPriority = entry->GetPriority();

exit:
    return error;
}

void MeshForwarder::GetForwardFramePriority(const uint8_t *     aFrame,
                                            uint16_t            aFrameLength,
                                            const Mac::Address &aMeshSource,
                                            const Mac::Address &aMeshDest,
                                            Message::Priority & aPriority)
{
    Error                  error      = kErrorNone;
    bool                   isFragment = false;
    Lowpan::FragmentHeader fragmentHeader;
    uint16_t               fragmentHeaderLength;

    if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == kErrorNone)
    {
        isFragment = true;
        aFrame += fragmentHeaderLength;
        aFrameLength -= fragmentHeaderLength;

        if (fragmentHeader.GetDatagramOffset() > 0)
        {
            // Get priority from the pre-buffered info
            ExitNow(error = GetFragmentPriority(fragmentHeader, aMeshSource.GetShort(), aPriority));
        }
    }

    // Get priority from IPv6 header or UDP destination port directly
    error = GetFramePriority(aFrame, aFrameLength, aMeshSource, aMeshDest, aPriority);

exit:
    if (error != kErrorNone)
    {
        LogNote("Failed to get forwarded frame priority, error:%s, len:%d, src:%d, dst:%s", ErrorToString(error),
                aFrameLength, aMeshSource.ToString().AsCString(), aMeshDest.ToString().AsCString());
    }
    else if (isFragment)
    {
        UpdateFragmentPriority(fragmentHeader, aFrameLength, aMeshSource.GetShort(), aPriority);
    }

    return;
}

// LCOV_EXCL_START

#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)

Error MeshForwarder::LogMeshFragmentHeader(MessageAction       aAction,
                                           const Message &     aMessage,
                                           const Mac::Address *aMacAddress,
                                           Error               aError,
                                           uint16_t &          aOffset,
                                           Mac::Address &      aMeshSource,
                                           Mac::Address &      aMeshDest,
                                           LogLevel            aLogLevel)
{
    Error                  error             = kErrorFailed;
    bool                   hasFragmentHeader = false;
    bool                   shouldLogRss;
    Lowpan::MeshHeader     meshHeader;
    Lowpan::FragmentHeader fragmentHeader;
    uint16_t               headerLength;
    bool                   shouldLogRadio = false;
    const char *           radioString    = "";

    SuccessOrExit(meshHeader.ParseFrom(aMessage, headerLength));

    aMeshSource.SetShort(meshHeader.GetSource());
    aMeshDest.SetShort(meshHeader.GetDestination());

    aOffset = headerLength;

    if (fragmentHeader.ParseFrom(aMessage, aOffset, headerLength) == kErrorNone)
    {
        hasFragmentHeader = true;
        aOffset += headerLength;
    }

    shouldLogRss = (aAction == kMessageReceive) || (aAction == kMessageReassemblyDrop);

#if OPENTHREAD_CONFIG_MULTI_RADIO
    shouldLogRadio = true;
    radioString    = aMessage.IsRadioTypeSet() ? RadioTypeToString(aMessage.GetRadioType()) : "all";
#endif

    LogAt(aLogLevel, "%s mesh frame, len:%d%s%s, msrc:%s, mdst:%s, hops:%d, frag:%s, sec:%s%s%s%s%s%s%s",
          MessageActionToString(aAction, aError), aMessage.GetLength(),
          (aMacAddress == nullptr) ? "" : ((aAction == kMessageReceive) ? ", from:" : ", to:"),
          (aMacAddress == nullptr) ? "" : aMacAddress->ToString().AsCString(), aMeshSource.ToString().AsCString(),
          aMeshDest.ToString().AsCString(), meshHeader.GetHopsLeft() + ((aAction == kMessageReceive) ? 1 : 0),
          ToYesNo(hasFragmentHeader), ToYesNo(aMessage.IsLinkSecurityEnabled()),
          (aError == kErrorNone) ? "" : ", error:", (aError == kErrorNone) ? "" : ErrorToString(aError),
          shouldLogRss ? ", rss:" : "", shouldLogRss ? aMessage.GetRssAverager().ToString().AsCString() : "",
          shouldLogRadio ? ", radio:" : "", radioString);

    if (hasFragmentHeader)
    {
        LogAt(aLogLevel, "    Frag tag:%04x, offset:%d, size:%d", fragmentHeader.GetDatagramTag(),
              fragmentHeader.GetDatagramOffset(), fragmentHeader.GetDatagramSize());

        VerifyOrExit(fragmentHeader.GetDatagramOffset() == 0);
    }

    error = kErrorNone;

exit:
    return error;
}

Error MeshForwarder::DecompressIp6UdpTcpHeader(const Message &     aMessage,
                                               uint16_t            aOffset,
                                               const Mac::Address &aMeshSource,
                                               const Mac::Address &aMeshDest,
                                               Ip6::Header &       aIp6Header,
                                               uint16_t &          aChecksum,
                                               uint16_t &          aSourcePort,
                                               uint16_t &          aDestPort)
{
    Error    error = kErrorParse;
    int      headerLength;
    bool     nextHeaderCompressed;
    uint8_t  frameBuffer[sizeof(Ip6::Header)];
    uint16_t frameLength;
    union
    {
        Ip6::Udp::Header udp;
        Ip6::Tcp::Header tcp;
    } header;

    aChecksum   = 0;
    aSourcePort = 0;
    aDestPort   = 0;

    // Read and decompress the IPv6 header

    frameLength = aMessage.ReadBytes(aOffset, frameBuffer, sizeof(frameBuffer));

    headerLength = Get<Lowpan::Lowpan>().DecompressBaseHeader(aIp6Header, nextHeaderCompressed, aMeshSource, aMeshDest,
                                                              frameBuffer, frameLength);
    VerifyOrExit(headerLength >= 0);

    aOffset += headerLength;

    // Read and decompress UDP or TCP header

    switch (aIp6Header.GetNextHeader())
    {
    case Ip6::kProtoUdp:
        if (nextHeaderCompressed)
        {
            frameLength  = aMessage.ReadBytes(aOffset, frameBuffer, sizeof(Ip6::Udp::Header));
            headerLength = Get<Lowpan::Lowpan>().DecompressUdpHeader(header.udp, frameBuffer, frameLength);
            VerifyOrExit(headerLength >= 0);
        }
        else
        {
            SuccessOrExit(aMessage.Read(aOffset, header.udp));
        }

        aChecksum   = header.udp.GetChecksum();
        aSourcePort = header.udp.GetSourcePort();
        aDestPort   = header.udp.GetDestinationPort();
        break;

    case Ip6::kProtoTcp:
        SuccessOrExit(aMessage.Read(aOffset, header.tcp));
        aChecksum   = header.tcp.GetChecksum();
        aSourcePort = header.tcp.GetSourcePort();
        aDestPort   = header.tcp.GetDestinationPort();
        break;

    default:
        break;
    }

    error = kErrorNone;

exit:
    return error;
}

void MeshForwarder::LogMeshIpHeader(const Message &     aMessage,
                                    uint16_t            aOffset,
                                    const Mac::Address &aMeshSource,
                                    const Mac::Address &aMeshDest,
                                    LogLevel            aLogLevel)
{
    uint16_t    checksum;
    uint16_t    sourcePort;
    uint16_t    destPort;
    Ip6::Header ip6Header;

    SuccessOrExit(DecompressIp6UdpTcpHeader(aMessage, aOffset, aMeshSource, aMeshDest, ip6Header, checksum, sourcePort,
                                            destPort));

    LogAt(aLogLevel, "    IPv6 %s msg, chksum:%04x, prio:%s", Ip6::Ip6::IpProtoToString(ip6Header.GetNextHeader()),
          checksum, MessagePriorityToString(aMessage));

    LogIp6SourceDestAddresses(ip6Header, sourcePort, destPort, aLogLevel);

exit:
    return;
}

void MeshForwarder::LogMeshMessage(MessageAction       aAction,
                                   const Message &     aMessage,
                                   const Mac::Address *aMacAddress,
                                   Error               aError,
                                   LogLevel            aLogLevel)
{
    uint16_t     offset;
    Mac::Address meshSource;
    Mac::Address meshDest;

    SuccessOrExit(
        LogMeshFragmentHeader(aAction, aMessage, aMacAddress, aError, offset, meshSource, meshDest, aLogLevel));

    // When log action is `kMessageTransmit` we do not include
    // the IPv6 header info in the logs, as the same info is
    // logged when the same Mesh Header message was received
    // and info about it was logged.

    VerifyOrExit(aAction != kMessageTransmit);

    LogMeshIpHeader(aMessage, offset, meshSource, meshDest, aLogLevel);

exit:
    return;
}

#endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)

// LCOV_EXCL_STOP

} // namespace ot

#endif // OPENTHREAD_FTD
