blob: 6d45b5529cba44fe0135b8b7dce493f6591cc3d8 [file]
/*
* Copyright (c) 2022, 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 IP4 headers processing.
*/
#include "ip4_types.hpp"
#include "common/numeric_limits.hpp"
#include "net/ip6_address.hpp"
namespace ot {
namespace Ip4 {
Error Address::FromString(const char *aString, char aTerminatorChar)
{
constexpr char kSeparatorChar = '.';
Error error = kErrorParse;
const char *cur = aString;
for (uint8_t index = 0;; index++)
{
SuccessOrExit(StringParseUint8(cur, mFields.m8[index]));
if (index == sizeof(Address) - 1)
{
break;
}
VerifyOrExit(*cur == kSeparatorChar);
cur++;
}
VerifyOrExit(*cur == aTerminatorChar);
error = kErrorNone;
exit:
return error;
}
Error Address::ExtractFromIp4MappedIp6Address(const Ip6::Address &aIp6Address)
{
Error error = kErrorNone;
VerifyOrExit(aIp6Address.IsIp4Mapped(), error = kErrorParse);
SetBytes(&aIp6Address.GetBytes()[12]);
exit:
return error;
}
void Address::ExtractFromIp6Address(uint8_t aPrefixLength, const Ip6::Address &aIp6Address)
{
// The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
// after the prefix, skipping over the bits 64 to 71 (byte at `kSkipIndex`)
// which must be set to zero. The suffix is set to zero (per RFC 6052).
//
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// |32| prefix |v4(32) | u | suffix |
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// |40| prefix |v4(24) | u |(8)| suffix |
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// |48| prefix |v4(16) | u | (16) | suffix |
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// |56| prefix |(8)| u | v4(24) | suffix |
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// |64| prefix | u | v4(32) | suffix |
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// |96| prefix | v4(32) |
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
constexpr uint8_t kSkipIndex = 8;
uint8_t ip6Index;
OT_ASSERT(Ip6::Prefix::IsValidNat64PrefixLength(aPrefixLength));
ip6Index = aPrefixLength / kBitsPerByte;
for (uint8_t &i : mFields.m8)
{
if (ip6Index == kSkipIndex)
{
ip6Index++;
}
i = aIp6Address.GetBytes()[ip6Index++];
}
}
void Address::SynthesizeFromCidrAndHost(const Cidr &aCidr, const uint32_t aHost)
{
mFields.m32 = (aCidr.mAddress.mFields.m32 & aCidr.SubnetMask()) | (BigEndian::HostSwap32(aHost) & aCidr.HostMask());
}
void Address::ToString(StringWriter &aWriter) const
{
aWriter.Append("%u.%u.%u.%u", mFields.m8[0], mFields.m8[1], mFields.m8[2], mFields.m8[3]);
}
void Address::ToString(char *aBuffer, uint16_t aSize) const
{
StringWriter writer(aBuffer, aSize);
ToString(writer);
}
Address::InfoString Address::ToString(void) const
{
InfoString string;
ToString(string);
return string;
}
Error Cidr::FromString(const char *aString)
{
constexpr char kSlashChar = '/';
constexpr uint16_t kMaxCidrLength = 32;
Error error = kErrorParse;
const char *cur;
SuccessOrExit(AsCoreType(&mAddress).FromString(aString, kSlashChar));
cur = StringFind(aString, kSlashChar);
VerifyOrExit(cur != nullptr);
cur++;
SuccessOrExit(StringParseUint8(cur, mLength, kMaxCidrLength));
VerifyOrExit(*cur == kNullChar);
error = kErrorNone;
exit:
return error;
}
void Cidr::ToString(StringWriter &aWriter) const
{
AsCoreType(&mAddress).ToString(aWriter);
aWriter.Append("/%u", mLength);
}
void Cidr::ToString(char *aBuffer, uint16_t aSize) const
{
StringWriter writer(aBuffer, aSize);
ToString(writer);
}
Cidr::InfoString Cidr::ToString(void) const
{
InfoString string;
ToString(string);
return string;
}
bool Cidr::operator==(const Cidr &aOther) const
{
return (mLength == aOther.mLength) && (CountMatchingBits(GetBytes(), aOther.GetBytes(), mLength) >= mLength);
}
void Cidr::Set(const uint8_t *aAddress, uint8_t aLength)
{
memcpy(mAddress.mFields.m8, aAddress, Ip4::Address::kSize);
mLength = aLength;
}
Error Header::ParseFrom(const Message &aMessage)
{
Error error = kErrorParse;
SuccessOrExit(aMessage.Read(0, *this));
VerifyOrExit(IsValid());
VerifyOrExit(GetTotalLength() == aMessage.GetLength());
error = kErrorNone;
exit:
return error;
}
//---------------------------------------------------------------------------------------------------------------------
// Headers
Error Headers::ParseFrom(const Message &aMessage)
{
Error error = kErrorParse;
Clear();
SuccessOrExit(mIp4Header.ParseFrom(aMessage));
switch (mIp4Header.GetProtocol())
{
case kProtoUdp:
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mUdp));
break;
case kProtoTcp:
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mTcp));
break;
case kProtoIcmp:
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mIcmp));
break;
default:
break;
}
error = kErrorNone;
exit:
return error;
}
uint16_t Headers::GetSourcePort(void) const
{
uint16_t port = 0;
switch (GetIpProto())
{
case kProtoUdp:
port = mHeader.mUdp.GetSourcePort();
break;
case kProtoTcp:
port = mHeader.mTcp.GetSourcePort();
break;
default:
break;
}
return port;
}
uint16_t Headers::GetDestinationPort(void) const
{
uint16_t port = 0;
switch (GetIpProto())
{
case kProtoUdp:
port = mHeader.mUdp.GetDestinationPort();
break;
case kProtoTcp:
port = mHeader.mTcp.GetDestinationPort();
break;
default:
break;
}
return port;
}
void Headers::SetDestinationPort(uint16_t aDstPort)
{
switch (GetIpProto())
{
case kProtoUdp:
mHeader.mUdp.SetDestinationPort(aDstPort);
break;
case kProtoTcp:
mHeader.mTcp.SetDestinationPort(aDstPort);
break;
default:
break;
}
}
uint16_t Headers::GetChecksum(void) const
{
uint16_t checksum = 0;
switch (GetIpProto())
{
case kProtoUdp:
checksum = mHeader.mUdp.GetChecksum();
break;
case kProtoTcp:
checksum = mHeader.mTcp.GetChecksum();
break;
case kProtoIcmp:
checksum = mHeader.mIcmp.GetChecksum();
break;
default:
break;
}
return checksum;
}
} // namespace Ip4
} // namespace ot