mirror of
https://github.com/espressif/openthread.git
synced 2026-08-08 03:37:46 +00:00
[net] add 'Checksum' class (#5434)
This commit adds `Checksum` class which implements IP checksum calculation and verification (all related code from other modules is now moved to `Checksum` class). The new checksum calculation allows any message chunk size (removes a limitation with previous model of requiring even sized chunks). This commit also adds a unit test `test_checksum` covering the behavior of `Checksum` methods.
This commit is contained in:
@@ -228,6 +228,7 @@ LOCAL_SRC_FILES := \
|
||||
src/core/meshcop/meshcop_tlvs.cpp \
|
||||
src/core/meshcop/panid_query_client.cpp \
|
||||
src/core/meshcop/timestamp.cpp \
|
||||
src/core/net/checksum.cpp \
|
||||
src/core/net/dhcp6_client.cpp \
|
||||
src/core/net/dhcp6_server.cpp \
|
||||
src/core/net/dns_client.cpp \
|
||||
|
||||
@@ -440,6 +440,8 @@ openthread_core_files = [
|
||||
"meshcop/panid_query_client.hpp",
|
||||
"meshcop/timestamp.cpp",
|
||||
"meshcop/timestamp.hpp",
|
||||
"net/checksum.cpp",
|
||||
"net/checksum.hpp",
|
||||
"net/dhcp6.hpp",
|
||||
"net/dhcp6_client.cpp",
|
||||
"net/dhcp6_client.hpp",
|
||||
|
||||
@@ -156,6 +156,7 @@ set(COMMON_SOURCES
|
||||
meshcop/meshcop_tlvs.cpp
|
||||
meshcop/panid_query_client.cpp
|
||||
meshcop/timestamp.cpp
|
||||
net/checksum.cpp
|
||||
net/dhcp6_client.cpp
|
||||
net/dhcp6_server.cpp
|
||||
net/dns_client.cpp
|
||||
|
||||
@@ -198,6 +198,7 @@ SOURCES_COMMON = \
|
||||
meshcop/meshcop_tlvs.cpp \
|
||||
meshcop/panid_query_client.cpp \
|
||||
meshcop/timestamp.cpp \
|
||||
net/checksum.cpp \
|
||||
net/dhcp6_client.cpp \
|
||||
net/dhcp6_server.cpp \
|
||||
net/dns_client.cpp \
|
||||
@@ -415,6 +416,7 @@ HEADERS_COMMON = \
|
||||
meshcop/meshcop_tlvs.hpp \
|
||||
meshcop/panid_query_client.hpp \
|
||||
meshcop/timestamp.hpp \
|
||||
net/checksum.hpp \
|
||||
net/dhcp6.hpp \
|
||||
net/dhcp6_client.hpp \
|
||||
net/dhcp6_server.hpp \
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator-getters.hpp"
|
||||
#include "common/logging.hpp"
|
||||
#include "net/checksum.hpp"
|
||||
#include "net/ip6.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -631,41 +632,6 @@ void Message::SetLinkInfo(const ThreadLinkInfo &aLinkInfo)
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t Message::UpdateChecksum(uint16_t aChecksum, uint16_t aValue)
|
||||
{
|
||||
uint16_t result = aChecksum + aValue;
|
||||
return result + (result < aChecksum);
|
||||
}
|
||||
|
||||
uint16_t Message::UpdateChecksum(uint16_t aChecksum, const void *aBuf, uint16_t aLength)
|
||||
{
|
||||
const uint8_t *bytes = reinterpret_cast<const uint8_t *>(aBuf);
|
||||
|
||||
for (int i = 0; i < aLength; i++)
|
||||
{
|
||||
aChecksum = UpdateChecksum(aChecksum, (i & 1) ? bytes[i] : static_cast<uint16_t>(bytes[i] << 8));
|
||||
}
|
||||
|
||||
return aChecksum;
|
||||
}
|
||||
|
||||
uint16_t Message::UpdateChecksum(uint16_t aChecksum, uint16_t aOffset, uint16_t aLength) const
|
||||
{
|
||||
Chunk chunk;
|
||||
|
||||
OT_ASSERT(aOffset + aLength <= GetLength());
|
||||
|
||||
GetFirstChunk(aOffset, aLength, chunk);
|
||||
|
||||
while (chunk.GetLength() > 0)
|
||||
{
|
||||
aChecksum = Message::UpdateChecksum(aChecksum, chunk.GetData(), chunk.GetLength());
|
||||
GetNextChunk(aLength, chunk);
|
||||
}
|
||||
|
||||
return aChecksum;
|
||||
}
|
||||
|
||||
bool Message::IsTimeSync(void) const
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
|
||||
@@ -228,6 +228,7 @@ protected:
|
||||
*/
|
||||
class Message : public Buffer
|
||||
{
|
||||
friend class Checksum;
|
||||
friend class MessagePool;
|
||||
friend class MessageQueue;
|
||||
friend class PriorityQueue;
|
||||
@@ -836,41 +837,6 @@ public:
|
||||
*/
|
||||
void SetLinkInfo(const ThreadLinkInfo &aLinkInfo);
|
||||
|
||||
/**
|
||||
* This static method updates a checksum.
|
||||
*
|
||||
* @param[in] aChecksum The checksum value to update.
|
||||
* @param[in] aValue The 16-bit value to update @p aChecksum with.
|
||||
*
|
||||
* @returns The updated checksum.
|
||||
*
|
||||
*/
|
||||
static uint16_t UpdateChecksum(uint16_t aChecksum, uint16_t aValue);
|
||||
|
||||
/**
|
||||
* This static method updates a checksum.
|
||||
*
|
||||
* @param[in] aChecksum The checksum value to update.
|
||||
* @param[in] aBuf A pointer to a buffer.
|
||||
* @param[in] aLength The number of bytes in @p aBuf.
|
||||
*
|
||||
* @returns The updated checksum.
|
||||
*
|
||||
*/
|
||||
static uint16_t UpdateChecksum(uint16_t aChecksum, const void *aBuf, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* This method is used to update a checksum value.
|
||||
*
|
||||
* @param[in] aChecksum Initial checksum value.
|
||||
* @param[in] aOffset Byte offset within the message to begin checksum computation.
|
||||
* @param[in] aLength Number of bytes to compute the checksum over.
|
||||
*
|
||||
* @retval The updated checksum value.
|
||||
*
|
||||
*/
|
||||
uint16_t UpdateChecksum(uint16_t aChecksum, uint16_t aOffset, uint16_t aLength) const;
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the message queue (if any) where this message is queued.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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 implements checksum calculation.
|
||||
*/
|
||||
|
||||
#include "checksum.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "net/icmp6.hpp"
|
||||
#include "net/udp6.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
void Checksum::AddUint8(uint8_t aUint8)
|
||||
{
|
||||
uint16_t newValue = mValue;
|
||||
|
||||
// BigEndian encoding: Even index is MSB and odd index is LSB.
|
||||
|
||||
newValue += mAtOddIndex ? aUint8 : (static_cast<uint16_t>(aUint8) << 8);
|
||||
|
||||
// Calculate one's complement sum.
|
||||
|
||||
if (newValue < mValue)
|
||||
{
|
||||
newValue++;
|
||||
}
|
||||
|
||||
mValue = newValue;
|
||||
mAtOddIndex = !mAtOddIndex;
|
||||
}
|
||||
|
||||
void Checksum::AddUint16(uint16_t aUint16)
|
||||
{
|
||||
// BigEndian encoding
|
||||
AddUint8(static_cast<uint8_t>(aUint16 >> 8));
|
||||
AddUint8(static_cast<uint8_t>(aUint16 & 0xff));
|
||||
}
|
||||
|
||||
void Checksum::AddData(const uint8_t *aBuffer, uint16_t aLength)
|
||||
{
|
||||
for (uint16_t i = 0; i < aLength; i++)
|
||||
{
|
||||
AddUint8(aBuffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Checksum::WriteToMessage(uint16_t aOffset, Message &aMessage) const
|
||||
{
|
||||
uint16_t checksum = GetValue();
|
||||
|
||||
if (checksum != 0xffff)
|
||||
{
|
||||
checksum = ~checksum;
|
||||
}
|
||||
|
||||
checksum = Encoding::BigEndian::HostSwap16(checksum);
|
||||
|
||||
aMessage.Write(aOffset, sizeof(checksum), &checksum);
|
||||
}
|
||||
|
||||
void Checksum::Calculate(const Ip6::Address &aSource,
|
||||
const Ip6::Address &aDestination,
|
||||
uint8_t aIpProto,
|
||||
const Message & aMessage)
|
||||
{
|
||||
Message::Chunk chunk;
|
||||
uint16_t length = aMessage.GetLength() - aMessage.GetOffset();
|
||||
|
||||
// Pseudo-header for checksum calculation (RFC-2460).
|
||||
|
||||
AddData(aSource.GetBytes(), sizeof(Ip6::Address));
|
||||
AddData(aDestination.GetBytes(), sizeof(Ip6::Address));
|
||||
AddUint16(length);
|
||||
AddUint16(static_cast<uint16_t>(aIpProto));
|
||||
|
||||
// Add message content (from offset to the end) to checksum.
|
||||
|
||||
aMessage.GetFirstChunk(aMessage.GetOffset(), length, chunk);
|
||||
|
||||
while (chunk.GetLength() > 0)
|
||||
{
|
||||
AddData(chunk.GetData(), chunk.GetLength());
|
||||
aMessage.GetNextChunk(length, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
otError Checksum::VerifyMessageChecksum(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, uint8_t aIpProto)
|
||||
{
|
||||
Checksum checksum;
|
||||
|
||||
checksum.Calculate(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(), aIpProto, aMessage);
|
||||
|
||||
return (checksum.GetValue() == kValidRxChecksum) ? OT_ERROR_NONE : OT_ERROR_DROP;
|
||||
}
|
||||
|
||||
void Checksum::UpdateMessageChecksum(Message & aMessage,
|
||||
const Ip6::Address &aSource,
|
||||
const Ip6::Address &aDestination,
|
||||
uint8_t aIpProto)
|
||||
{
|
||||
uint16_t headerOffset;
|
||||
Checksum checksum;
|
||||
|
||||
switch (aIpProto)
|
||||
{
|
||||
case Ip6::kProtoUdp:
|
||||
headerOffset = Ip6::Udp::Header::kChecksumFieldOffset;
|
||||
break;
|
||||
|
||||
case Ip6::kProtoIcmp6:
|
||||
headerOffset = Ip6::Icmp::Header::kChecksumFieldOffset;
|
||||
break;
|
||||
|
||||
default:
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
checksum.Calculate(aSource, aDestination, aIpProto, aMessage);
|
||||
checksum.WriteToMessage(aMessage.GetOffset() + headerOffset, aMessage);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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 definitions for checksum calculation.
|
||||
*/
|
||||
|
||||
#ifndef CHECKSUM_HPP_
|
||||
#define CHECKSUM_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/message.hpp"
|
||||
#include "net/ip6_address.hpp"
|
||||
#include "net/ip6_headers.hpp"
|
||||
#include "net/socket.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
/**
|
||||
* This class implements IP checksum calculation and verification.
|
||||
*
|
||||
*/
|
||||
class Checksum
|
||||
{
|
||||
friend class ChecksumTester;
|
||||
|
||||
public:
|
||||
/**
|
||||
* This static method verifies the checksum in a given message (if UDP/ICMP6).
|
||||
*
|
||||
* @param[in] aMessage The message to verify its checksum. The `aMessage.GetOffset()` should point to start
|
||||
* UDP/ICMP6 header.
|
||||
* @param[in] aMessageInfo The message info associated with @p aMessage.
|
||||
* @param[in] aIpProto The Internet Protocol value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The checksum is valid if UDP/ICMP6 protocol, or not a UDP/ICMP6 protocol.
|
||||
* @retval OT_ERROR_DROP The check is not valid and message should be dropped.
|
||||
*
|
||||
*/
|
||||
static otError VerifyMessageChecksum(const Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
uint8_t aIpProto);
|
||||
|
||||
/**
|
||||
* This static method calculates and then updates the checksum in a given message (if UDP/ICMP6).
|
||||
*
|
||||
* @param[inout] aMessage The message to update the checksum in. The `aMessage.GetOffset()` should point to start
|
||||
* of the UDP/ICMP6 header. On exit the checksum field in UDP/ICMP6 header in the message
|
||||
* is updated.
|
||||
* @param[in] aSource The source address.
|
||||
* @param[in] aDestination The destination address.
|
||||
* @param[in] aIpProto The Internet Protocol value.
|
||||
*
|
||||
*/
|
||||
static void UpdateMessageChecksum(Message & aMessage,
|
||||
const Ip6::Address &aSource,
|
||||
const Ip6::Address &aDestination,
|
||||
uint8_t aIpProto);
|
||||
|
||||
private:
|
||||
Checksum(void)
|
||||
: mValue(0)
|
||||
, mAtOddIndex(false)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t GetValue(void) const { return mValue; }
|
||||
void AddUint8(uint8_t aUint8);
|
||||
void AddUint16(uint16_t aUint16);
|
||||
void AddData(const uint8_t *aBuffer, uint16_t aLength);
|
||||
void WriteToMessage(uint16_t aOffset, Message &aMessage) const;
|
||||
void Calculate(const Ip6::Address &aSource,
|
||||
const Ip6::Address &aDestination,
|
||||
uint8_t aIpProto,
|
||||
const Message & aMessage);
|
||||
|
||||
enum : uint16_t
|
||||
{
|
||||
kValidRxChecksum = 0xffff,
|
||||
};
|
||||
|
||||
uint16_t mValue;
|
||||
bool mAtOddIndex;
|
||||
};
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // CHECKSUM_HPP_
|
||||
+4
-25
@@ -39,10 +39,9 @@
|
||||
#include "common/locator-getters.hpp"
|
||||
#include "common/logging.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "net/checksum.hpp"
|
||||
#include "net/ip6.hpp"
|
||||
|
||||
using ot::Encoding::BigEndian::HostSwap16;
|
||||
|
||||
namespace ot {
|
||||
namespace Ip6 {
|
||||
|
||||
@@ -139,20 +138,13 @@ exit:
|
||||
|
||||
otError Icmp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t payloadLength;
|
||||
Header icmp6Header;
|
||||
uint16_t checksum;
|
||||
otError error = OT_ERROR_NONE;
|
||||
Header icmp6Header;
|
||||
|
||||
VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(icmp6Header), &icmp6Header) == sizeof(icmp6Header),
|
||||
error = OT_ERROR_PARSE);
|
||||
payloadLength = aMessage.GetLength() - aMessage.GetOffset();
|
||||
|
||||
// verify checksum
|
||||
checksum = Ip6::ComputePseudoheaderChecksum(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(), payloadLength,
|
||||
kProtoIcmp6);
|
||||
checksum = aMessage.UpdateChecksum(checksum, aMessage.GetOffset(), payloadLength);
|
||||
VerifyOrExit(checksum == 0xffff, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Checksum::VerifyMessageChecksum(aMessage, aMessageInfo, kProtoIcmp6));
|
||||
|
||||
if (icmp6Header.GetType() == Header::kTypeEchoRequest)
|
||||
{
|
||||
@@ -244,18 +236,5 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Icmp::UpdateChecksum(Message &aMessage, uint16_t aChecksum)
|
||||
{
|
||||
aChecksum = aMessage.UpdateChecksum(aChecksum, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset());
|
||||
|
||||
if (aChecksum != 0xffff)
|
||||
{
|
||||
aChecksum = ~aChecksum;
|
||||
}
|
||||
|
||||
aChecksum = HostSwap16(aChecksum);
|
||||
aMessage.Write(aMessage.GetOffset() + Header::kChecksumFieldOffset, sizeof(aChecksum), &aChecksum);
|
||||
}
|
||||
|
||||
} // namespace Ip6
|
||||
} // namespace ot
|
||||
|
||||
@@ -297,15 +297,6 @@ public:
|
||||
*/
|
||||
otError HandleMessage(Message &aMessage, MessageInfo &aMessageInfo);
|
||||
|
||||
/**
|
||||
* This method updates the ICMPv6 checksum.
|
||||
*
|
||||
* @param[in] aMessage A reference to the ICMPv6 message.
|
||||
* @param[in] aChecksum The pseudo-header checksum value.
|
||||
*
|
||||
*/
|
||||
void UpdateChecksum(Message &aMessage, uint16_t aChecksum);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not ICMPv6 Echo processing is enabled.
|
||||
*
|
||||
|
||||
+2
-36
@@ -40,6 +40,7 @@
|
||||
#include "common/logging.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "common/random.hpp"
|
||||
#include "net/checksum.hpp"
|
||||
#include "net/icmp6.hpp"
|
||||
#include "net/ip6_address.hpp"
|
||||
#include "net/ip6_filter.hpp"
|
||||
@@ -170,26 +171,6 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t Ip6::UpdateChecksum(uint16_t aChecksum, const Address &aAddress)
|
||||
{
|
||||
return Message::UpdateChecksum(aChecksum, aAddress.mFields.m8, sizeof(aAddress));
|
||||
}
|
||||
|
||||
uint16_t Ip6::ComputePseudoheaderChecksum(const Address &aSource,
|
||||
const Address &aDestination,
|
||||
uint16_t aLength,
|
||||
uint8_t aProto)
|
||||
{
|
||||
uint16_t checksum;
|
||||
|
||||
checksum = Message::UpdateChecksum(0, aLength);
|
||||
checksum = Message::UpdateChecksum(checksum, static_cast<uint16_t>(aProto));
|
||||
checksum = UpdateChecksum(checksum, aSource);
|
||||
checksum = UpdateChecksum(checksum, aDestination);
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
void Ip6::SetReceiveDatagramCallback(otIp6ReceiveCallback aCallback, void *aCallbackContext)
|
||||
{
|
||||
mReceiveIp6DatagramCallback = aCallback;
|
||||
@@ -458,7 +439,6 @@ otError Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t
|
||||
otError error = OT_ERROR_NONE;
|
||||
Header header;
|
||||
uint16_t payloadLength = aMessage.GetLength();
|
||||
uint16_t checksum;
|
||||
|
||||
header.Init();
|
||||
header.SetDscp(PriorityToDscp(aMessage.GetPriority()));
|
||||
@@ -495,21 +475,7 @@ otError Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t
|
||||
|
||||
SuccessOrExit(error = aMessage.Prepend(&header, sizeof(header)));
|
||||
|
||||
checksum = ComputePseudoheaderChecksum(header.GetSource(), header.GetDestination(), payloadLength, aIpProto);
|
||||
|
||||
switch (aIpProto)
|
||||
{
|
||||
case kProtoUdp:
|
||||
mUdp.UpdateChecksum(aMessage, checksum);
|
||||
break;
|
||||
|
||||
case kProtoIcmp6:
|
||||
mIcmp.UpdateChecksum(aMessage, checksum);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Checksum::UpdateMessageChecksum(aMessage, header.GetSource(), header.GetDestination(), aIpProto);
|
||||
|
||||
if (aMessageInfo.GetPeerAddr().IsMulticastLargerThanRealmLocal())
|
||||
{
|
||||
|
||||
+2
-19
@@ -225,22 +225,6 @@ public:
|
||||
*/
|
||||
otError HandleDatagram(Message &aMessage, Netif *aNetif, const void *aLinkMessageInfo, bool aFromNcpHost);
|
||||
|
||||
/**
|
||||
* This static method computes the pseudoheader checksum.
|
||||
*
|
||||
* @param[in] aSource A reference to the IPv6 source address.
|
||||
* @param[in] aDestination A reference to the IPv6 destination address.
|
||||
* @param[in] aLength The IPv6 Payload Length value.
|
||||
* @param[in] aProto The IPv6 Next Header value.
|
||||
*
|
||||
* @returns The pseudoheader checksum.
|
||||
*
|
||||
*/
|
||||
static uint16_t ComputePseudoheaderChecksum(const Address &aSource,
|
||||
const Address &aDestination,
|
||||
uint16_t aLength,
|
||||
uint8_t aProto);
|
||||
|
||||
/**
|
||||
* This method registers a callback to provide received raw IPv6 datagrams.
|
||||
*
|
||||
@@ -343,9 +327,8 @@ private:
|
||||
static void HandleSendQueue(Tasklet &aTasklet);
|
||||
void HandleSendQueue(void);
|
||||
|
||||
static uint8_t PriorityToDscp(Message::Priority aPriority);
|
||||
static otError GetDatagramPriority(const uint8_t *aData, uint16_t aDataLen, Message::Priority &aPriority);
|
||||
static uint16_t UpdateChecksum(uint16_t aChecksum, const Address &aAddress);
|
||||
static uint8_t PriorityToDscp(Message::Priority aPriority);
|
||||
static otError GetDatagramPriority(const uint8_t *aData, uint16_t aDataLen, Message::Priority &aPriority);
|
||||
|
||||
void EnqueueDatagram(Message &aMessage);
|
||||
otError ProcessReceiveCallback(Message & aMessage,
|
||||
|
||||
@@ -525,6 +525,14 @@ public:
|
||||
*/
|
||||
typedef String<kIp6AddressStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* This method gets the IPv6 address as a pointer to a byte array.
|
||||
*
|
||||
* @returns A pointer to a byte array containing the IPv6 address.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetBytes(void) const { return mFields.m8; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the IPv6 address is the Unspecified Address.
|
||||
*
|
||||
|
||||
@@ -254,6 +254,14 @@ public:
|
||||
*/
|
||||
Address &GetSource(void) { return mSource; }
|
||||
|
||||
/**
|
||||
* This method returns the IPv6 Source address.
|
||||
*
|
||||
* @returns A reference to the IPv6 Source address.
|
||||
*
|
||||
*/
|
||||
const Address &GetSource(void) const { return mSource; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 Source address.
|
||||
*
|
||||
@@ -270,6 +278,14 @@ public:
|
||||
*/
|
||||
Address &GetDestination(void) { return mDestination; }
|
||||
|
||||
/**
|
||||
* This method returns the IPv6 Destination address.
|
||||
*
|
||||
* @returns A reference to the IPv6 Destination address.
|
||||
*
|
||||
*/
|
||||
const Address &GetDestination(void) const { return mDestination; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 Destination address.
|
||||
*
|
||||
|
||||
+8
-33
@@ -41,10 +41,9 @@
|
||||
#include "common/encoding.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator-getters.hpp"
|
||||
#include "net/checksum.hpp"
|
||||
#include "net/ip6.hpp"
|
||||
|
||||
using ot::Encoding::BigEndian::HostSwap16;
|
||||
|
||||
namespace ot {
|
||||
namespace Ip6 {
|
||||
|
||||
@@ -364,27 +363,16 @@ exit:
|
||||
|
||||
otError Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Header udpHeader;
|
||||
uint16_t payloadLength;
|
||||
uint16_t checksum;
|
||||
|
||||
payloadLength = aMessage.GetLength() - aMessage.GetOffset();
|
||||
|
||||
// check length
|
||||
VerifyOrExit(payloadLength >= sizeof(Header), error = OT_ERROR_PARSE);
|
||||
|
||||
// verify checksum
|
||||
checksum = Ip6::ComputePseudoheaderChecksum(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(), payloadLength,
|
||||
kProtoUdp);
|
||||
checksum = aMessage.UpdateChecksum(checksum, aMessage.GetOffset(), payloadLength);
|
||||
|
||||
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
VerifyOrExit(checksum == 0xffff, error = OT_ERROR_DROP);
|
||||
#endif
|
||||
otError error = OT_ERROR_NONE;
|
||||
Header udpHeader;
|
||||
|
||||
VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(udpHeader), &udpHeader) == sizeof(udpHeader),
|
||||
error = OT_ERROR_PARSE);
|
||||
|
||||
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
SuccessOrExit(error = Checksum::VerifyMessageChecksum(aMessage, aMessageInfo, kProtoUdp));
|
||||
#endif
|
||||
|
||||
aMessage.MoveOffset(sizeof(udpHeader));
|
||||
aMessageInfo.mPeerPort = udpHeader.GetSourcePort();
|
||||
aMessageInfo.mSockPort = udpHeader.GetDestinationPort();
|
||||
@@ -420,19 +408,6 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Udp::UpdateChecksum(Message &aMessage, uint16_t aChecksum)
|
||||
{
|
||||
aChecksum = aMessage.UpdateChecksum(aChecksum, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset());
|
||||
|
||||
if (aChecksum != 0xffff)
|
||||
{
|
||||
aChecksum = ~aChecksum;
|
||||
}
|
||||
|
||||
aChecksum = HostSwap16(aChecksum);
|
||||
aMessage.Write(aMessage.GetOffset() + Header::kChecksumFieldOffset, sizeof(aChecksum), &aChecksum);
|
||||
}
|
||||
|
||||
bool Udp::IsMlePort(uint16_t aPort) const
|
||||
{
|
||||
bool isMlePort = (aPort == Mle::kUdpPort);
|
||||
|
||||
@@ -528,15 +528,6 @@ public:
|
||||
*/
|
||||
void HandlePayload(Message &aMessage, MessageInfo &aMessageInfo);
|
||||
|
||||
/**
|
||||
* This method updates the UDP checksum.
|
||||
*
|
||||
* @param[in] aMessage A reference to the UDP message.
|
||||
* @param[in] aChecksum The pseudo-header checksum value.
|
||||
*
|
||||
*/
|
||||
void UpdateChecksum(Message &aMessage, uint16_t aChecksum);
|
||||
|
||||
/**
|
||||
* This method returns the head of UDP Sockets list.
|
||||
*
|
||||
|
||||
@@ -77,6 +77,29 @@ add_executable(test-child
|
||||
test_child.cpp
|
||||
)
|
||||
|
||||
add_executable(test-checksum
|
||||
${COMMON_SOURCES}
|
||||
test_checksum.cpp
|
||||
)
|
||||
|
||||
target_include_directories(test-checksum
|
||||
PRIVATE
|
||||
${COMMON_INCLUDES}
|
||||
)
|
||||
|
||||
target_compile_options(test-checksum
|
||||
PRIVATE
|
||||
${COMMON_COMPILE_OPTIONS}
|
||||
)
|
||||
|
||||
target_link_libraries(test-checksum
|
||||
PRIVATE
|
||||
${COMMON_LIBS}
|
||||
)
|
||||
|
||||
add_test(NAME test-checksum COMMAND test-checksum)
|
||||
|
||||
|
||||
target_include_directories(test-child
|
||||
PRIVATE
|
||||
${COMMON_INCLUDES}
|
||||
@@ -536,7 +559,7 @@ target_link_libraries(test-timer
|
||||
add_test(NAME test-timer COMMAND test-timer)
|
||||
|
||||
set_target_properties(
|
||||
test-aes test-child test-child-table test-flash test-heap test-hmac-sha256 test-ip6-address test-link-quality test-linked-list test-lowpan test-mac-frame test-message test-message-queue test-multicast-listeners-table test-netif test-network-data test-pool test-priority-queue test-pskc test-steering-data test-string test-timer
|
||||
test-aes test-checksum test-child test-child-table test-flash test-heap test-hmac-sha256 test-ip6-address test-link-quality test-linked-list test-lowpan test-mac-frame test-message test-message-queue test-multicast-listeners-table test-netif test-network-data test-pool test-priority-queue test-pskc test-steering-data test-string test-timer
|
||||
PROPERTIES
|
||||
C_STANDARD 99
|
||||
CXX_STANDARD 11
|
||||
|
||||
@@ -107,6 +107,7 @@ check_PROGRAMS = \
|
||||
if OPENTHREAD_ENABLE_FTD
|
||||
check_PROGRAMS += \
|
||||
test-aes \
|
||||
test-checksum \
|
||||
test-child \
|
||||
test-child-table \
|
||||
test-flash \
|
||||
@@ -171,6 +172,9 @@ COMMON_SOURCES = test_platform.cpp test_util.cpp
|
||||
test_aes_LDADD = $(COMMON_LDADD)
|
||||
test_aes_SOURCES = $(COMMON_SOURCES) test_aes.cpp
|
||||
|
||||
test_checksum_LDADD = $(COMMON_LDADD)
|
||||
test_checksum_SOURCES = $(COMMON_SOURCES) test_checksum.cpp
|
||||
|
||||
test_child_LDADD = $(COMMON_LDADD)
|
||||
test_child_SOURCES = $(COMMON_SOURCES) test_child.cpp
|
||||
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "common/encoding.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "common/random.hpp"
|
||||
#include "net/checksum.hpp"
|
||||
#include "net/icmp6.hpp"
|
||||
#include "net/udp6.hpp"
|
||||
|
||||
#include "test_platform.h"
|
||||
#include "test_util.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
uint16_t CalculateChecksum(const void *aBuffer, uint16_t aLength)
|
||||
{
|
||||
// Calculates checksum over a given buffer data. This implementation
|
||||
// is inspired by the algorithm from RFC-1071.
|
||||
|
||||
uint32_t sum = 0;
|
||||
const uint8_t *bytes = reinterpret_cast<const uint8_t *>(aBuffer);
|
||||
|
||||
while (aLength >= sizeof(uint16_t))
|
||||
{
|
||||
sum += Encoding::BigEndian::ReadUint16(bytes);
|
||||
bytes += sizeof(uint16_t);
|
||||
aLength -= sizeof(uint16_t);
|
||||
}
|
||||
|
||||
if (aLength > 0)
|
||||
{
|
||||
sum += (static_cast<uint32_t>(bytes[0]) << 8);
|
||||
}
|
||||
|
||||
// Fold 32-bit sum to 16 bits.
|
||||
|
||||
while (sum >> 16)
|
||||
{
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
}
|
||||
|
||||
return static_cast<uint16_t>(sum & 0xffff);
|
||||
}
|
||||
|
||||
uint16_t CalculateChecksum(const Ip6::Address &aSource,
|
||||
const Ip6::Address &aDestination,
|
||||
uint8_t aIpProto,
|
||||
const Message & aMessage)
|
||||
{
|
||||
// This method calculates the checksum over an IPv6 message.
|
||||
|
||||
enum : uint16_t
|
||||
{
|
||||
kMaxPayload = 1024,
|
||||
};
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct PseudoHeader
|
||||
{
|
||||
Ip6::Address mSource;
|
||||
Ip6::Address mDestination;
|
||||
uint32_t mPayloadLength;
|
||||
uint32_t mProtocol;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct ChecksumData
|
||||
{
|
||||
PseudoHeader mPseudoHeader;
|
||||
uint8_t mPayload[kMaxPayload];
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
ChecksumData data;
|
||||
uint16_t payloadLength;
|
||||
|
||||
payloadLength = aMessage.GetLength() - aMessage.GetOffset();
|
||||
|
||||
data.mPseudoHeader.mSource = aSource;
|
||||
data.mPseudoHeader.mDestination = aDestination;
|
||||
data.mPseudoHeader.mProtocol = Encoding::BigEndian::HostSwap32(aIpProto);
|
||||
data.mPseudoHeader.mPayloadLength = Encoding::BigEndian::HostSwap32(payloadLength);
|
||||
|
||||
VerifyOrQuit(aMessage.Read(aMessage.GetOffset(), payloadLength, data.mPayload) == payloadLength,
|
||||
"Message::Read() failed");
|
||||
|
||||
return CalculateChecksum(&data, sizeof(PseudoHeader) + payloadLength);
|
||||
}
|
||||
|
||||
void CorruptMessage(Message &aMessage)
|
||||
{
|
||||
// Change a random bit in the message.
|
||||
|
||||
uint16_t byteOffset;
|
||||
uint8_t bitOffset;
|
||||
uint8_t byte;
|
||||
|
||||
byteOffset = Random::NonCrypto::GetUint16InRange(0, aMessage.GetLength());
|
||||
|
||||
VerifyOrQuit(aMessage.Read(byteOffset, sizeof(uint8_t), &byte) == sizeof(uint8_t), "Read failed");
|
||||
|
||||
bitOffset = Random::NonCrypto::GetUint8InRange(0, CHAR_BIT);
|
||||
|
||||
byte ^= (1 << bitOffset);
|
||||
|
||||
aMessage.Write(byteOffset, sizeof(uint8_t), &byte);
|
||||
}
|
||||
|
||||
void TestUdpMessageChecksum(void)
|
||||
{
|
||||
enum : uint16_t
|
||||
{
|
||||
kMinSize = sizeof(Ip6::Udp::Header),
|
||||
kMaxSize = kBufferSize * 3 + 24,
|
||||
};
|
||||
|
||||
const char *kSourceAddress = "fd00:1122:3344:5566:7788:99aa:bbcc:ddee";
|
||||
const char *kDestAddress = "fd01:2345:6789:abcd:ef01:2345:6789:abcd";
|
||||
|
||||
Instance *instance = static_cast<Instance *>(testInitInstance());
|
||||
|
||||
VerifyOrQuit(instance != nullptr, "Null OpenThread instance\n");
|
||||
|
||||
for (uint16_t size = kMinSize; size <= kMaxSize; size++)
|
||||
{
|
||||
Message * message = instance->Get<Ip6::Ip6>().NewMessage(sizeof(Ip6::Udp::Header));
|
||||
Ip6::Udp::Header udpHeader;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
|
||||
VerifyOrQuit(message != nullptr, "Ip6::NewMesssage() failed");
|
||||
SuccessOrQuit(message->SetLength(size), "Message::SetLength() failed");
|
||||
|
||||
// Write UDP header with a random payload.
|
||||
|
||||
Random::NonCrypto::FillBuffer(reinterpret_cast<uint8_t *>(&udpHeader), sizeof(udpHeader));
|
||||
udpHeader.SetChecksum(0);
|
||||
message->Write(0, sizeof(udpHeader), &udpHeader);
|
||||
|
||||
if (size > sizeof(udpHeader))
|
||||
{
|
||||
uint8_t buffer[kMaxSize];
|
||||
uint16_t payloadSize = size - sizeof(udpHeader);
|
||||
|
||||
Random::NonCrypto::FillBuffer(buffer, payloadSize);
|
||||
message->Write(sizeof(udpHeader), payloadSize, &buffer[0]);
|
||||
}
|
||||
|
||||
SuccessOrQuit(messageInfo.GetSockAddr().FromString(kSourceAddress), "FromString() failed");
|
||||
SuccessOrQuit(messageInfo.GetPeerAddr().FromString(kDestAddress), "FromString() failed");
|
||||
|
||||
// Verify that the `Checksum::UpdateMessageChecksum` correctly
|
||||
// updates the checksum field in the UDP header on the message.
|
||||
|
||||
Checksum::UpdateMessageChecksum(*message, messageInfo.GetSockAddr(), messageInfo.GetPeerAddr(), Ip6::kProtoUdp);
|
||||
|
||||
VerifyOrQuit(message->Read(message->GetOffset(), sizeof(udpHeader), &udpHeader) == sizeof(udpHeader),
|
||||
"Message::Read() failed");
|
||||
VerifyOrQuit(udpHeader.GetChecksum() != 0, "Failed to update checksum");
|
||||
|
||||
// Verify that the calculated UDP checksum is valid.
|
||||
|
||||
VerifyOrQuit(
|
||||
CalculateChecksum(messageInfo.GetSockAddr(), messageInfo.GetPeerAddr(), Ip6::kProtoUdp, *message) == 0xffff,
|
||||
"UDP checksum does not match expected value");
|
||||
|
||||
// Verify that `Checksum::VerifyMessageChecksum()` accepts the
|
||||
// message and its calculated checksum.
|
||||
|
||||
SuccessOrQuit(Checksum::VerifyMessageChecksum(*message, messageInfo, Ip6::kProtoUdp),
|
||||
"Checksum::VerifyMessageChecksum() failed");
|
||||
|
||||
// Corrupt the message and verify that checksum is no longer accepted.
|
||||
|
||||
CorruptMessage(*message);
|
||||
|
||||
VerifyOrQuit(Checksum::VerifyMessageChecksum(*message, messageInfo, Ip6::kProtoUdp) != OT_ERROR_NONE,
|
||||
"Checksum passed on corrupted message");
|
||||
|
||||
message->Free();
|
||||
}
|
||||
}
|
||||
|
||||
void TestIcmp6MessageChecksum(void)
|
||||
{
|
||||
enum : uint16_t
|
||||
{
|
||||
kMinSize = sizeof(Ip6::Icmp::Header),
|
||||
kMaxSize = kBufferSize * 3 + 24,
|
||||
};
|
||||
|
||||
const char *kSourceAddress = "fd00:feef:dccd:baab:9889:7667:5444:3223";
|
||||
const char *kDestAddress = "fd01:abab:beef:cafe:1234:5678:9abc:0";
|
||||
|
||||
Instance *instance = static_cast<Instance *>(testInitInstance());
|
||||
|
||||
VerifyOrQuit(instance != nullptr, "Null OpenThread instance\n");
|
||||
|
||||
for (uint16_t size = kMinSize; size <= kMaxSize; size++)
|
||||
{
|
||||
Message * message = instance->Get<Ip6::Ip6>().NewMessage(sizeof(Ip6::Icmp::Header));
|
||||
Ip6::Icmp::Header icmp6Header;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
|
||||
VerifyOrQuit(message != nullptr, "Ip6::NewMesssage() failed");
|
||||
SuccessOrQuit(message->SetLength(size), "Message::SetLength() failed");
|
||||
|
||||
// Write ICMP6 header with a random payload.
|
||||
|
||||
Random::NonCrypto::FillBuffer(reinterpret_cast<uint8_t *>(&icmp6Header), sizeof(icmp6Header));
|
||||
icmp6Header.SetChecksum(0);
|
||||
message->Write(0, sizeof(icmp6Header), &icmp6Header);
|
||||
|
||||
if (size > sizeof(icmp6Header))
|
||||
{
|
||||
uint8_t buffer[kMaxSize];
|
||||
uint16_t payloadSize = size - sizeof(icmp6Header);
|
||||
|
||||
Random::NonCrypto::FillBuffer(buffer, payloadSize);
|
||||
message->Write(sizeof(icmp6Header), payloadSize, &buffer[0]);
|
||||
}
|
||||
|
||||
SuccessOrQuit(messageInfo.GetSockAddr().FromString(kSourceAddress), "FromString() failed");
|
||||
SuccessOrQuit(messageInfo.GetPeerAddr().FromString(kDestAddress), "FromString() failed");
|
||||
|
||||
// Verify that the `Checksum::UpdateMessageChecksum` correctly
|
||||
// updates the checksum field in the ICMP6 header on the message.
|
||||
|
||||
Checksum::UpdateMessageChecksum(*message, messageInfo.GetSockAddr(), messageInfo.GetPeerAddr(),
|
||||
Ip6::kProtoIcmp6);
|
||||
|
||||
VerifyOrQuit(message->Read(message->GetOffset(), sizeof(icmp6Header), &icmp6Header) == sizeof(icmp6Header),
|
||||
"Message::Read() failed");
|
||||
VerifyOrQuit(icmp6Header.GetChecksum() != 0, "Failed to update checksum");
|
||||
|
||||
// Verify that the calculated ICMP6 checksum is valid.
|
||||
|
||||
VerifyOrQuit(CalculateChecksum(messageInfo.GetSockAddr(), messageInfo.GetPeerAddr(), Ip6::kProtoIcmp6,
|
||||
*message) == 0xffff,
|
||||
"UDP checksum does not match expected value");
|
||||
|
||||
// Verify that `Checksum::VerifyMessageChecksum()` accepts the
|
||||
// message and its calculated checksum.
|
||||
|
||||
SuccessOrQuit(Checksum::VerifyMessageChecksum(*message, messageInfo, Ip6::kProtoIcmp6),
|
||||
"Checksum::VerifyMessageChecksum() failed");
|
||||
|
||||
// Corrupt the message and verify that checksum is no longer accepted.
|
||||
|
||||
CorruptMessage(*message);
|
||||
|
||||
VerifyOrQuit(Checksum::VerifyMessageChecksum(*message, messageInfo, Ip6::kProtoIcmp6) != OT_ERROR_NONE,
|
||||
"Checksum passed on corrupted message");
|
||||
|
||||
message->Free();
|
||||
}
|
||||
}
|
||||
|
||||
class ChecksumTester
|
||||
{
|
||||
public:
|
||||
static void TestExampleVector(void)
|
||||
{
|
||||
// Example from RFC 1071
|
||||
const uint8_t kTestVector[] = {0x00, 0x01, 0xf2, 0x03, 0xf4, 0xf5, 0xf6, 0xf7};
|
||||
const uint16_t kTestVectorChecksum = 0xddf2;
|
||||
|
||||
Checksum checksum;
|
||||
|
||||
VerifyOrQuit(checksum.GetValue() == 0, "Incorrect initial checksum value");
|
||||
|
||||
checksum.AddData(kTestVector, sizeof(kTestVector));
|
||||
VerifyOrQuit(checksum.GetValue() == kTestVectorChecksum, "Checksum::AddData() failed");
|
||||
VerifyOrQuit(checksum.GetValue() == CalculateChecksum(kTestVector, sizeof(kTestVector)),
|
||||
"Checksum::AddData() failed");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::ChecksumTester::TestExampleVector();
|
||||
ot::TestUdpMessageChecksum();
|
||||
ot::TestIcmp6MessageChecksum();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user