/*
 *  Copyright (c) 2020, 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 includes implementations for ICMPv6 Router Advertisement.
 *
 */

#include "border_router/router_advertisement.hpp"

#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE

#include "common/as_core_type.hpp"
#include "common/code_utils.hpp"

namespace ot {

namespace BorderRouter {

namespace RouterAdv {

const Option *Option::GetNextOption(const Option *aCurOption, const uint8_t *aBuffer, uint16_t aBufferLength)
{
    const uint8_t *nextOption = nullptr;
    const uint8_t *bufferEnd  = aBuffer + aBufferLength;

    VerifyOrExit(aBuffer != nullptr, nextOption = nullptr);

    if (aCurOption == nullptr)
    {
        nextOption = aBuffer;
    }
    else
    {
        nextOption = reinterpret_cast<const uint8_t *>(aCurOption) + aCurOption->GetSize();
    }

    VerifyOrExit(nextOption + sizeof(Option) <= bufferEnd, nextOption = nullptr);
    VerifyOrExit(reinterpret_cast<const Option *>(nextOption)->GetSize() > 0, nextOption = nullptr);
    VerifyOrExit(nextOption + reinterpret_cast<const Option *>(nextOption)->GetSize() <= bufferEnd,
                 nextOption = nullptr);

exit:
    return reinterpret_cast<const Option *>(nextOption);
}

PrefixInfoOption::PrefixInfoOption(void)
    : Option(Type::kPrefixInfo, sizeof(*this) / kLengthUnit)
    , mPrefixLength(0)
    , mReserved1(0)
    , mValidLifetime(0)
    , mPreferredLifetime(0)
    , mReserved2(0)
{
    OT_UNUSED_VARIABLE(mReserved2);

    mPrefix.Clear();
}

void PrefixInfoOption::SetOnLink(bool aOnLink)
{
    if (aOnLink)
    {
        mReserved1 |= kOnLinkFlagMask;
    }
    else
    {
        mReserved1 &= ~kOnLinkFlagMask;
    }
}

void PrefixInfoOption::SetAutoAddrConfig(bool aAutoAddrConfig)
{
    if (aAutoAddrConfig)
    {
        mReserved1 |= kAutoConfigFlagMask;
    }
    else
    {
        mReserved1 &= ~kAutoConfigFlagMask;
    }
}

void PrefixInfoOption::SetPrefix(const Ip6::Prefix &aPrefix)
{
    mPrefixLength = aPrefix.mLength;
    mPrefix       = AsCoreType(&aPrefix.mPrefix);
}

Ip6::Prefix PrefixInfoOption::GetPrefix(void) const
{
    Ip6::Prefix prefix;

    prefix.Set(mPrefix.GetBytes(), mPrefixLength);
    return prefix;
}

RouteInfoOption::RouteInfoOption(void)
    : Option(Type::kRouteInfo, 0)
    , mPrefixLength(0)
    , mReserved(0)
    , mRouteLifetime(0)
{
    OT_UNUSED_VARIABLE(mReserved);

    mPrefix.Clear();
}

void RouteInfoOption::SetPreference(RoutePreference aPreference)
{
    mReserved &= ~kPreferenceMask;
    mReserved |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
}

RouteInfoOption::RoutePreference RouteInfoOption::GetPreference(void) const
{
    return NetworkData::RoutePreferenceFromValue((mReserved & kPreferenceMask) >> kPreferenceOffset);
}

void RouteInfoOption::SetPrefix(const Ip6::Prefix &aPrefix)
{
    // The total length (in bytes) of a Router Information Option
    // is: (8 bytes fixed option header) + (0, 8, or 16 bytes prefix).
    // Because the length of the option must be padded with 8 bytes,
    // the length of the prefix (in bits) must be padded with 64 bits.
    SetLength((aPrefix.mLength + kLengthUnit * CHAR_BIT - 1) / (kLengthUnit * CHAR_BIT) + 1);

    mPrefixLength = aPrefix.mLength;
    mPrefix       = AsCoreType(&aPrefix.mPrefix);
}

Ip6::Prefix RouteInfoOption::GetPrefix(void) const
{
    Ip6::Prefix prefix;

    prefix.Set(mPrefix.GetBytes(), mPrefixLength);
    return prefix;
}

bool RouteInfoOption::IsValid(void) const
{
    return (GetLength() == 1 || GetLength() == 2 || GetLength() == 3) &&
           (mPrefixLength <= OT_IP6_ADDRESS_SIZE * CHAR_BIT) && NetworkData::IsRoutePreferenceValid(GetPreference());
}

void RouterAdvMessage::SetToDefault(void)
{
    mHeader.Clear();
    mHeader.SetType(Ip6::Icmp::Header::kTypeRouterAdvert);
    mReachableTime = 0;
    mRetransTimer  = 0;
}

const RouterAdvMessage &RouterAdvMessage::operator=(const RouterAdvMessage &aOther)
{
    mHeader = aOther.mHeader;

    // Set zero value and let platform do the calculation.
    mHeader.SetChecksum(0);

    mReachableTime = aOther.mReachableTime;
    mRetransTimer  = aOther.mRetransTimer;

    return *this;
}

bool RouterAdvMessage::operator==(const RouterAdvMessage &aOther) const
{
    return memcmp(&mHeader.mData, &aOther.mHeader.mData, sizeof(mHeader.mData)) == 0 &&
           mReachableTime == aOther.mReachableTime && mRetransTimer == aOther.mRetransTimer;
}

RouterSolicitMessage::RouterSolicitMessage(void)
{
    mHeader.Clear();
    mHeader.SetType(Ip6::Icmp::Header::kTypeRouterSolicit);
}

} // namespace RouterAdv

} // namespace BorderRouter

} // namespace ot

#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
