xref: /aosp_15_r20/external/openthread/tests/unit/test_checksum.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker  *  Copyright (c) 2020, The OpenThread Authors.
3*cfb92d14SAndroid Build Coastguard Worker  *  All rights reserved.
4*cfb92d14SAndroid Build Coastguard Worker  *
5*cfb92d14SAndroid Build Coastguard Worker  *  Redistribution and use in source and binary forms, with or without
6*cfb92d14SAndroid Build Coastguard Worker  *  modification, are permitted provided that the following conditions are met:
7*cfb92d14SAndroid Build Coastguard Worker  *  1. Redistributions of source code must retain the above copyright
8*cfb92d14SAndroid Build Coastguard Worker  *     notice, this list of conditions and the following disclaimer.
9*cfb92d14SAndroid Build Coastguard Worker  *  2. Redistributions in binary form must reproduce the above copyright
10*cfb92d14SAndroid Build Coastguard Worker  *     notice, this list of conditions and the following disclaimer in the
11*cfb92d14SAndroid Build Coastguard Worker  *     documentation and/or other materials provided with the distribution.
12*cfb92d14SAndroid Build Coastguard Worker  *  3. Neither the name of the copyright holder nor the
13*cfb92d14SAndroid Build Coastguard Worker  *     names of its contributors may be used to endorse or promote products
14*cfb92d14SAndroid Build Coastguard Worker  *     derived from this software without specific prior written permission.
15*cfb92d14SAndroid Build Coastguard Worker  *
16*cfb92d14SAndroid Build Coastguard Worker  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*cfb92d14SAndroid Build Coastguard Worker  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*cfb92d14SAndroid Build Coastguard Worker  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*cfb92d14SAndroid Build Coastguard Worker  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*cfb92d14SAndroid Build Coastguard Worker  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*cfb92d14SAndroid Build Coastguard Worker  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*cfb92d14SAndroid Build Coastguard Worker  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*cfb92d14SAndroid Build Coastguard Worker  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*cfb92d14SAndroid Build Coastguard Worker  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*cfb92d14SAndroid Build Coastguard Worker  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*cfb92d14SAndroid Build Coastguard Worker  *  POSSIBILITY OF SUCH DAMAGE.
27*cfb92d14SAndroid Build Coastguard Worker  */
28*cfb92d14SAndroid Build Coastguard Worker 
29*cfb92d14SAndroid Build Coastguard Worker #include "common/encoding.hpp"
30*cfb92d14SAndroid Build Coastguard Worker #include "common/message.hpp"
31*cfb92d14SAndroid Build Coastguard Worker #include "common/numeric_limits.hpp"
32*cfb92d14SAndroid Build Coastguard Worker #include "common/random.hpp"
33*cfb92d14SAndroid Build Coastguard Worker #include "common/string.hpp"
34*cfb92d14SAndroid Build Coastguard Worker #include "instance/instance.hpp"
35*cfb92d14SAndroid Build Coastguard Worker #include "net/checksum.hpp"
36*cfb92d14SAndroid Build Coastguard Worker #include "net/icmp6.hpp"
37*cfb92d14SAndroid Build Coastguard Worker #include "net/ip4_types.hpp"
38*cfb92d14SAndroid Build Coastguard Worker #include "net/udp6.hpp"
39*cfb92d14SAndroid Build Coastguard Worker #include "utils/verhoeff_checksum.hpp"
40*cfb92d14SAndroid Build Coastguard Worker 
41*cfb92d14SAndroid Build Coastguard Worker #include "test_platform.h"
42*cfb92d14SAndroid Build Coastguard Worker #include "test_util.hpp"
43*cfb92d14SAndroid Build Coastguard Worker 
44*cfb92d14SAndroid Build Coastguard Worker namespace ot {
45*cfb92d14SAndroid Build Coastguard Worker 
CalculateChecksum(const void * aBuffer,uint16_t aLength)46*cfb92d14SAndroid Build Coastguard Worker uint16_t CalculateChecksum(const void *aBuffer, uint16_t aLength)
47*cfb92d14SAndroid Build Coastguard Worker {
48*cfb92d14SAndroid Build Coastguard Worker     // Calculates checksum over a given buffer data. This implementation
49*cfb92d14SAndroid Build Coastguard Worker     // is inspired by the algorithm from RFC-1071.
50*cfb92d14SAndroid Build Coastguard Worker 
51*cfb92d14SAndroid Build Coastguard Worker     uint32_t       sum   = 0;
52*cfb92d14SAndroid Build Coastguard Worker     const uint8_t *bytes = reinterpret_cast<const uint8_t *>(aBuffer);
53*cfb92d14SAndroid Build Coastguard Worker 
54*cfb92d14SAndroid Build Coastguard Worker     while (aLength >= sizeof(uint16_t))
55*cfb92d14SAndroid Build Coastguard Worker     {
56*cfb92d14SAndroid Build Coastguard Worker         sum += BigEndian::ReadUint16(bytes);
57*cfb92d14SAndroid Build Coastguard Worker         bytes += sizeof(uint16_t);
58*cfb92d14SAndroid Build Coastguard Worker         aLength -= sizeof(uint16_t);
59*cfb92d14SAndroid Build Coastguard Worker     }
60*cfb92d14SAndroid Build Coastguard Worker 
61*cfb92d14SAndroid Build Coastguard Worker     if (aLength > 0)
62*cfb92d14SAndroid Build Coastguard Worker     {
63*cfb92d14SAndroid Build Coastguard Worker         sum += (static_cast<uint32_t>(bytes[0]) << 8);
64*cfb92d14SAndroid Build Coastguard Worker     }
65*cfb92d14SAndroid Build Coastguard Worker 
66*cfb92d14SAndroid Build Coastguard Worker     // Fold 32-bit sum to 16 bits.
67*cfb92d14SAndroid Build Coastguard Worker 
68*cfb92d14SAndroid Build Coastguard Worker     while (sum >> 16)
69*cfb92d14SAndroid Build Coastguard Worker     {
70*cfb92d14SAndroid Build Coastguard Worker         sum = (sum & 0xffff) + (sum >> 16);
71*cfb92d14SAndroid Build Coastguard Worker     }
72*cfb92d14SAndroid Build Coastguard Worker 
73*cfb92d14SAndroid Build Coastguard Worker     return static_cast<uint16_t>(sum & 0xffff);
74*cfb92d14SAndroid Build Coastguard Worker }
75*cfb92d14SAndroid Build Coastguard Worker 
CalculateChecksum(const Ip6::Address & aSource,const Ip6::Address & aDestination,uint8_t aIpProto,const Message & aMessage)76*cfb92d14SAndroid Build Coastguard Worker uint16_t CalculateChecksum(const Ip6::Address &aSource,
77*cfb92d14SAndroid Build Coastguard Worker                            const Ip6::Address &aDestination,
78*cfb92d14SAndroid Build Coastguard Worker                            uint8_t             aIpProto,
79*cfb92d14SAndroid Build Coastguard Worker                            const Message      &aMessage)
80*cfb92d14SAndroid Build Coastguard Worker {
81*cfb92d14SAndroid Build Coastguard Worker     // This method calculates the checksum over an IPv6 message.
82*cfb92d14SAndroid Build Coastguard Worker     constexpr uint16_t kMaxPayload = 1024;
83*cfb92d14SAndroid Build Coastguard Worker 
84*cfb92d14SAndroid Build Coastguard Worker     OT_TOOL_PACKED_BEGIN
85*cfb92d14SAndroid Build Coastguard Worker     struct PseudoHeader
86*cfb92d14SAndroid Build Coastguard Worker     {
87*cfb92d14SAndroid Build Coastguard Worker         Ip6::Address mSource;
88*cfb92d14SAndroid Build Coastguard Worker         Ip6::Address mDestination;
89*cfb92d14SAndroid Build Coastguard Worker         uint32_t     mPayloadLength;
90*cfb92d14SAndroid Build Coastguard Worker         uint32_t     mProtocol;
91*cfb92d14SAndroid Build Coastguard Worker     } OT_TOOL_PACKED_END;
92*cfb92d14SAndroid Build Coastguard Worker 
93*cfb92d14SAndroid Build Coastguard Worker     OT_TOOL_PACKED_BEGIN
94*cfb92d14SAndroid Build Coastguard Worker     struct ChecksumData
95*cfb92d14SAndroid Build Coastguard Worker     {
96*cfb92d14SAndroid Build Coastguard Worker         PseudoHeader mPseudoHeader;
97*cfb92d14SAndroid Build Coastguard Worker         uint8_t      mPayload[kMaxPayload];
98*cfb92d14SAndroid Build Coastguard Worker     } OT_TOOL_PACKED_END;
99*cfb92d14SAndroid Build Coastguard Worker 
100*cfb92d14SAndroid Build Coastguard Worker     ChecksumData data;
101*cfb92d14SAndroid Build Coastguard Worker     uint16_t     payloadLength;
102*cfb92d14SAndroid Build Coastguard Worker 
103*cfb92d14SAndroid Build Coastguard Worker     payloadLength = aMessage.GetLength() - aMessage.GetOffset();
104*cfb92d14SAndroid Build Coastguard Worker 
105*cfb92d14SAndroid Build Coastguard Worker     data.mPseudoHeader.mSource        = aSource;
106*cfb92d14SAndroid Build Coastguard Worker     data.mPseudoHeader.mDestination   = aDestination;
107*cfb92d14SAndroid Build Coastguard Worker     data.mPseudoHeader.mProtocol      = BigEndian::HostSwap32(aIpProto);
108*cfb92d14SAndroid Build Coastguard Worker     data.mPseudoHeader.mPayloadLength = BigEndian::HostSwap32(payloadLength);
109*cfb92d14SAndroid Build Coastguard Worker 
110*cfb92d14SAndroid Build Coastguard Worker     SuccessOrQuit(aMessage.Read(aMessage.GetOffset(), data.mPayload, payloadLength));
111*cfb92d14SAndroid Build Coastguard Worker 
112*cfb92d14SAndroid Build Coastguard Worker     return CalculateChecksum(&data, sizeof(PseudoHeader) + payloadLength);
113*cfb92d14SAndroid Build Coastguard Worker }
114*cfb92d14SAndroid Build Coastguard Worker 
CalculateChecksum(const Ip4::Address & aSource,const Ip4::Address & aDestination,uint8_t aIpProto,const Message & aMessage)115*cfb92d14SAndroid Build Coastguard Worker uint16_t CalculateChecksum(const Ip4::Address &aSource,
116*cfb92d14SAndroid Build Coastguard Worker                            const Ip4::Address &aDestination,
117*cfb92d14SAndroid Build Coastguard Worker                            uint8_t             aIpProto,
118*cfb92d14SAndroid Build Coastguard Worker                            const Message      &aMessage)
119*cfb92d14SAndroid Build Coastguard Worker {
120*cfb92d14SAndroid Build Coastguard Worker     // This method calculates the checksum over an IPv4 message.
121*cfb92d14SAndroid Build Coastguard Worker     constexpr uint16_t kMaxPayload = 1024;
122*cfb92d14SAndroid Build Coastguard Worker 
123*cfb92d14SAndroid Build Coastguard Worker     OT_TOOL_PACKED_BEGIN
124*cfb92d14SAndroid Build Coastguard Worker     struct PseudoHeader
125*cfb92d14SAndroid Build Coastguard Worker     {
126*cfb92d14SAndroid Build Coastguard Worker         Ip4::Address mSource;
127*cfb92d14SAndroid Build Coastguard Worker         Ip4::Address mDestination;
128*cfb92d14SAndroid Build Coastguard Worker         uint16_t     mPayloadLength;
129*cfb92d14SAndroid Build Coastguard Worker         uint16_t     mProtocol;
130*cfb92d14SAndroid Build Coastguard Worker     } OT_TOOL_PACKED_END;
131*cfb92d14SAndroid Build Coastguard Worker 
132*cfb92d14SAndroid Build Coastguard Worker     OT_TOOL_PACKED_BEGIN
133*cfb92d14SAndroid Build Coastguard Worker     struct ChecksumData
134*cfb92d14SAndroid Build Coastguard Worker     {
135*cfb92d14SAndroid Build Coastguard Worker         PseudoHeader mPseudoHeader;
136*cfb92d14SAndroid Build Coastguard Worker         uint8_t      mPayload[kMaxPayload];
137*cfb92d14SAndroid Build Coastguard Worker     } OT_TOOL_PACKED_END;
138*cfb92d14SAndroid Build Coastguard Worker 
139*cfb92d14SAndroid Build Coastguard Worker     ChecksumData data;
140*cfb92d14SAndroid Build Coastguard Worker     uint16_t     payloadLength;
141*cfb92d14SAndroid Build Coastguard Worker 
142*cfb92d14SAndroid Build Coastguard Worker     payloadLength = aMessage.GetLength() - aMessage.GetOffset();
143*cfb92d14SAndroid Build Coastguard Worker 
144*cfb92d14SAndroid Build Coastguard Worker     data.mPseudoHeader.mSource        = aSource;
145*cfb92d14SAndroid Build Coastguard Worker     data.mPseudoHeader.mDestination   = aDestination;
146*cfb92d14SAndroid Build Coastguard Worker     data.mPseudoHeader.mProtocol      = BigEndian::HostSwap16(aIpProto);
147*cfb92d14SAndroid Build Coastguard Worker     data.mPseudoHeader.mPayloadLength = BigEndian::HostSwap16(payloadLength);
148*cfb92d14SAndroid Build Coastguard Worker 
149*cfb92d14SAndroid Build Coastguard Worker     SuccessOrQuit(aMessage.Read(aMessage.GetOffset(), data.mPayload, payloadLength));
150*cfb92d14SAndroid Build Coastguard Worker 
151*cfb92d14SAndroid Build Coastguard Worker     return CalculateChecksum(&data, sizeof(PseudoHeader) + payloadLength);
152*cfb92d14SAndroid Build Coastguard Worker }
153*cfb92d14SAndroid Build Coastguard Worker 
CorruptMessage(Message & aMessage)154*cfb92d14SAndroid Build Coastguard Worker void CorruptMessage(Message &aMessage)
155*cfb92d14SAndroid Build Coastguard Worker {
156*cfb92d14SAndroid Build Coastguard Worker     // Change a random bit in the message.
157*cfb92d14SAndroid Build Coastguard Worker 
158*cfb92d14SAndroid Build Coastguard Worker     uint16_t byteOffset;
159*cfb92d14SAndroid Build Coastguard Worker     uint8_t  bitOffset;
160*cfb92d14SAndroid Build Coastguard Worker     uint8_t  byte;
161*cfb92d14SAndroid Build Coastguard Worker 
162*cfb92d14SAndroid Build Coastguard Worker     byteOffset = Random::NonCrypto::GetUint16InRange(0, aMessage.GetLength());
163*cfb92d14SAndroid Build Coastguard Worker 
164*cfb92d14SAndroid Build Coastguard Worker     SuccessOrQuit(aMessage.Read(byteOffset, byte));
165*cfb92d14SAndroid Build Coastguard Worker 
166*cfb92d14SAndroid Build Coastguard Worker     bitOffset = Random::NonCrypto::GetUint8InRange(0, kBitsPerByte);
167*cfb92d14SAndroid Build Coastguard Worker 
168*cfb92d14SAndroid Build Coastguard Worker     byte ^= (1 << bitOffset);
169*cfb92d14SAndroid Build Coastguard Worker 
170*cfb92d14SAndroid Build Coastguard Worker     aMessage.Write(byteOffset, byte);
171*cfb92d14SAndroid Build Coastguard Worker }
172*cfb92d14SAndroid Build Coastguard Worker 
TestUdpMessageChecksum(void)173*cfb92d14SAndroid Build Coastguard Worker void TestUdpMessageChecksum(void)
174*cfb92d14SAndroid Build Coastguard Worker {
175*cfb92d14SAndroid Build Coastguard Worker     constexpr uint16_t kMinSize = sizeof(Ip6::Udp::Header);
176*cfb92d14SAndroid Build Coastguard Worker     constexpr uint16_t kMaxSize = kBufferSize * 3 + 24;
177*cfb92d14SAndroid Build Coastguard Worker 
178*cfb92d14SAndroid Build Coastguard Worker     const char *kSourceAddress = "fd00:1122:3344:5566:7788:99aa:bbcc:ddee";
179*cfb92d14SAndroid Build Coastguard Worker     const char *kDestAddress   = "fd01:2345:6789:abcd:ef01:2345:6789:abcd";
180*cfb92d14SAndroid Build Coastguard Worker 
181*cfb92d14SAndroid Build Coastguard Worker     Instance *instance = static_cast<Instance *>(testInitInstance());
182*cfb92d14SAndroid Build Coastguard Worker 
183*cfb92d14SAndroid Build Coastguard Worker     VerifyOrQuit(instance != nullptr);
184*cfb92d14SAndroid Build Coastguard Worker 
185*cfb92d14SAndroid Build Coastguard Worker     for (uint16_t size = kMinSize; size <= kMaxSize; size++)
186*cfb92d14SAndroid Build Coastguard Worker     {
187*cfb92d14SAndroid Build Coastguard Worker         Message         *message = instance->Get<Ip6::Ip6>().NewMessage(sizeof(Ip6::Udp::Header));
188*cfb92d14SAndroid Build Coastguard Worker         Ip6::Udp::Header udpHeader;
189*cfb92d14SAndroid Build Coastguard Worker         Ip6::MessageInfo messageInfo;
190*cfb92d14SAndroid Build Coastguard Worker 
191*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(message != nullptr, "Ip6::NewMesssage() failed");
192*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(message->SetLength(size));
193*cfb92d14SAndroid Build Coastguard Worker 
194*cfb92d14SAndroid Build Coastguard Worker         // Write UDP header with a random payload.
195*cfb92d14SAndroid Build Coastguard Worker 
196*cfb92d14SAndroid Build Coastguard Worker         Random::NonCrypto::Fill(udpHeader);
197*cfb92d14SAndroid Build Coastguard Worker         udpHeader.SetChecksum(0);
198*cfb92d14SAndroid Build Coastguard Worker         message->Write(0, udpHeader);
199*cfb92d14SAndroid Build Coastguard Worker 
200*cfb92d14SAndroid Build Coastguard Worker         if (size > sizeof(udpHeader))
201*cfb92d14SAndroid Build Coastguard Worker         {
202*cfb92d14SAndroid Build Coastguard Worker             uint8_t  buffer[kMaxSize];
203*cfb92d14SAndroid Build Coastguard Worker             uint16_t payloadSize = size - sizeof(udpHeader);
204*cfb92d14SAndroid Build Coastguard Worker 
205*cfb92d14SAndroid Build Coastguard Worker             Random::NonCrypto::FillBuffer(buffer, payloadSize);
206*cfb92d14SAndroid Build Coastguard Worker             message->WriteBytes(sizeof(udpHeader), &buffer[0], payloadSize);
207*cfb92d14SAndroid Build Coastguard Worker         }
208*cfb92d14SAndroid Build Coastguard Worker 
209*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(messageInfo.GetSockAddr().FromString(kSourceAddress));
210*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(messageInfo.GetPeerAddr().FromString(kDestAddress));
211*cfb92d14SAndroid Build Coastguard Worker 
212*cfb92d14SAndroid Build Coastguard Worker         // Verify that the `Checksum::UpdateMessageChecksum` correctly
213*cfb92d14SAndroid Build Coastguard Worker         // updates the checksum field in the UDP header on the message.
214*cfb92d14SAndroid Build Coastguard Worker 
215*cfb92d14SAndroid Build Coastguard Worker         Checksum::UpdateMessageChecksum(*message, messageInfo.GetSockAddr(), messageInfo.GetPeerAddr(), Ip6::kProtoUdp);
216*cfb92d14SAndroid Build Coastguard Worker 
217*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(message->Read(message->GetOffset(), udpHeader));
218*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(udpHeader.GetChecksum() != 0);
219*cfb92d14SAndroid Build Coastguard Worker 
220*cfb92d14SAndroid Build Coastguard Worker         // Verify that the calculated UDP checksum is valid.
221*cfb92d14SAndroid Build Coastguard Worker 
222*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(CalculateChecksum(messageInfo.GetSockAddr(), messageInfo.GetPeerAddr(), Ip6::kProtoUdp,
223*cfb92d14SAndroid Build Coastguard Worker                                        *message) == 0xffff);
224*cfb92d14SAndroid Build Coastguard Worker 
225*cfb92d14SAndroid Build Coastguard Worker         // Verify that `Checksum::VerifyMessageChecksum()` accepts the
226*cfb92d14SAndroid Build Coastguard Worker         // message and its calculated checksum.
227*cfb92d14SAndroid Build Coastguard Worker 
228*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(Checksum::VerifyMessageChecksum(*message, messageInfo, Ip6::kProtoUdp));
229*cfb92d14SAndroid Build Coastguard Worker 
230*cfb92d14SAndroid Build Coastguard Worker         // Corrupt the message and verify that checksum is no longer accepted.
231*cfb92d14SAndroid Build Coastguard Worker 
232*cfb92d14SAndroid Build Coastguard Worker         CorruptMessage(*message);
233*cfb92d14SAndroid Build Coastguard Worker 
234*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(Checksum::VerifyMessageChecksum(*message, messageInfo, Ip6::kProtoUdp) != kErrorNone,
235*cfb92d14SAndroid Build Coastguard Worker                      "Checksum passed on corrupted message");
236*cfb92d14SAndroid Build Coastguard Worker 
237*cfb92d14SAndroid Build Coastguard Worker         message->Free();
238*cfb92d14SAndroid Build Coastguard Worker     }
239*cfb92d14SAndroid Build Coastguard Worker }
240*cfb92d14SAndroid Build Coastguard Worker 
TestIcmp6MessageChecksum(void)241*cfb92d14SAndroid Build Coastguard Worker void TestIcmp6MessageChecksum(void)
242*cfb92d14SAndroid Build Coastguard Worker {
243*cfb92d14SAndroid Build Coastguard Worker     constexpr uint16_t kMinSize = sizeof(Ip6::Icmp::Header);
244*cfb92d14SAndroid Build Coastguard Worker     constexpr uint16_t kMaxSize = kBufferSize * 3 + 24;
245*cfb92d14SAndroid Build Coastguard Worker 
246*cfb92d14SAndroid Build Coastguard Worker     const char *kSourceAddress = "fd00:feef:dccd:baab:9889:7667:5444:3223";
247*cfb92d14SAndroid Build Coastguard Worker     const char *kDestAddress   = "fd01:abab:beef:cafe:1234:5678:9abc:0";
248*cfb92d14SAndroid Build Coastguard Worker 
249*cfb92d14SAndroid Build Coastguard Worker     Instance *instance = static_cast<Instance *>(testInitInstance());
250*cfb92d14SAndroid Build Coastguard Worker 
251*cfb92d14SAndroid Build Coastguard Worker     VerifyOrQuit(instance != nullptr, "Null OpenThread instance\n");
252*cfb92d14SAndroid Build Coastguard Worker 
253*cfb92d14SAndroid Build Coastguard Worker     for (uint16_t size = kMinSize; size <= kMaxSize; size++)
254*cfb92d14SAndroid Build Coastguard Worker     {
255*cfb92d14SAndroid Build Coastguard Worker         Message          *message = instance->Get<Ip6::Ip6>().NewMessage(sizeof(Ip6::Icmp::Header));
256*cfb92d14SAndroid Build Coastguard Worker         Ip6::Icmp::Header icmp6Header;
257*cfb92d14SAndroid Build Coastguard Worker         Ip6::MessageInfo  messageInfo;
258*cfb92d14SAndroid Build Coastguard Worker 
259*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(message != nullptr, "Ip6::NewMesssage() failed");
260*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(message->SetLength(size));
261*cfb92d14SAndroid Build Coastguard Worker 
262*cfb92d14SAndroid Build Coastguard Worker         // Write ICMP6 header with a random payload.
263*cfb92d14SAndroid Build Coastguard Worker 
264*cfb92d14SAndroid Build Coastguard Worker         Random::NonCrypto::Fill(icmp6Header);
265*cfb92d14SAndroid Build Coastguard Worker         icmp6Header.SetChecksum(0);
266*cfb92d14SAndroid Build Coastguard Worker         message->Write(0, icmp6Header);
267*cfb92d14SAndroid Build Coastguard Worker 
268*cfb92d14SAndroid Build Coastguard Worker         if (size > sizeof(icmp6Header))
269*cfb92d14SAndroid Build Coastguard Worker         {
270*cfb92d14SAndroid Build Coastguard Worker             uint8_t  buffer[kMaxSize];
271*cfb92d14SAndroid Build Coastguard Worker             uint16_t payloadSize = size - sizeof(icmp6Header);
272*cfb92d14SAndroid Build Coastguard Worker 
273*cfb92d14SAndroid Build Coastguard Worker             Random::NonCrypto::FillBuffer(buffer, payloadSize);
274*cfb92d14SAndroid Build Coastguard Worker             message->WriteBytes(sizeof(icmp6Header), &buffer[0], payloadSize);
275*cfb92d14SAndroid Build Coastguard Worker         }
276*cfb92d14SAndroid Build Coastguard Worker 
277*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(messageInfo.GetSockAddr().FromString(kSourceAddress));
278*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(messageInfo.GetPeerAddr().FromString(kDestAddress));
279*cfb92d14SAndroid Build Coastguard Worker 
280*cfb92d14SAndroid Build Coastguard Worker         // Verify that the `Checksum::UpdateMessageChecksum` correctly
281*cfb92d14SAndroid Build Coastguard Worker         // updates the checksum field in the ICMP6 header on the message.
282*cfb92d14SAndroid Build Coastguard Worker 
283*cfb92d14SAndroid Build Coastguard Worker         Checksum::UpdateMessageChecksum(*message, messageInfo.GetSockAddr(), messageInfo.GetPeerAddr(),
284*cfb92d14SAndroid Build Coastguard Worker                                         Ip6::kProtoIcmp6);
285*cfb92d14SAndroid Build Coastguard Worker 
286*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(message->Read(message->GetOffset(), icmp6Header));
287*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(icmp6Header.GetChecksum() != 0, "Failed to update checksum");
288*cfb92d14SAndroid Build Coastguard Worker 
289*cfb92d14SAndroid Build Coastguard Worker         // Verify that the calculated ICMP6 checksum is valid.
290*cfb92d14SAndroid Build Coastguard Worker 
291*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(CalculateChecksum(messageInfo.GetSockAddr(), messageInfo.GetPeerAddr(), Ip6::kProtoIcmp6,
292*cfb92d14SAndroid Build Coastguard Worker                                        *message) == 0xffff);
293*cfb92d14SAndroid Build Coastguard Worker 
294*cfb92d14SAndroid Build Coastguard Worker         // Verify that `Checksum::VerifyMessageChecksum()` accepts the
295*cfb92d14SAndroid Build Coastguard Worker         // message and its calculated checksum.
296*cfb92d14SAndroid Build Coastguard Worker 
297*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(Checksum::VerifyMessageChecksum(*message, messageInfo, Ip6::kProtoIcmp6));
298*cfb92d14SAndroid Build Coastguard Worker 
299*cfb92d14SAndroid Build Coastguard Worker         // Corrupt the message and verify that checksum is no longer accepted.
300*cfb92d14SAndroid Build Coastguard Worker 
301*cfb92d14SAndroid Build Coastguard Worker         CorruptMessage(*message);
302*cfb92d14SAndroid Build Coastguard Worker 
303*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(Checksum::VerifyMessageChecksum(*message, messageInfo, Ip6::kProtoIcmp6) != kErrorNone,
304*cfb92d14SAndroid Build Coastguard Worker                      "Checksum passed on corrupted message");
305*cfb92d14SAndroid Build Coastguard Worker 
306*cfb92d14SAndroid Build Coastguard Worker         message->Free();
307*cfb92d14SAndroid Build Coastguard Worker     }
308*cfb92d14SAndroid Build Coastguard Worker }
309*cfb92d14SAndroid Build Coastguard Worker 
TestTcp4MessageChecksum(void)310*cfb92d14SAndroid Build Coastguard Worker void TestTcp4MessageChecksum(void)
311*cfb92d14SAndroid Build Coastguard Worker {
312*cfb92d14SAndroid Build Coastguard Worker     constexpr size_t kMinSize = sizeof(Ip4::Tcp::Header);
313*cfb92d14SAndroid Build Coastguard Worker     constexpr size_t kMaxSize = kBufferSize * 3 + 24;
314*cfb92d14SAndroid Build Coastguard Worker 
315*cfb92d14SAndroid Build Coastguard Worker     const char *kSourceAddress = "12.34.56.78";
316*cfb92d14SAndroid Build Coastguard Worker     const char *kDestAddress   = "87.65.43.21";
317*cfb92d14SAndroid Build Coastguard Worker 
318*cfb92d14SAndroid Build Coastguard Worker     Ip4::Address sourceAddress;
319*cfb92d14SAndroid Build Coastguard Worker     Ip4::Address destAddress;
320*cfb92d14SAndroid Build Coastguard Worker 
321*cfb92d14SAndroid Build Coastguard Worker     Instance *instance = static_cast<Instance *>(testInitInstance());
322*cfb92d14SAndroid Build Coastguard Worker 
323*cfb92d14SAndroid Build Coastguard Worker     VerifyOrQuit(instance != nullptr);
324*cfb92d14SAndroid Build Coastguard Worker 
325*cfb92d14SAndroid Build Coastguard Worker     SuccessOrQuit(sourceAddress.FromString(kSourceAddress));
326*cfb92d14SAndroid Build Coastguard Worker     SuccessOrQuit(destAddress.FromString(kDestAddress));
327*cfb92d14SAndroid Build Coastguard Worker 
328*cfb92d14SAndroid Build Coastguard Worker     for (uint16_t size = kMinSize; size <= kMaxSize; size++)
329*cfb92d14SAndroid Build Coastguard Worker     {
330*cfb92d14SAndroid Build Coastguard Worker         Message         *message = instance->Get<Ip6::Ip6>().NewMessage(sizeof(Ip4::Tcp::Header));
331*cfb92d14SAndroid Build Coastguard Worker         Ip4::Tcp::Header tcpHeader;
332*cfb92d14SAndroid Build Coastguard Worker 
333*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(message != nullptr, "Ip6::NewMesssage() failed");
334*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(message->SetLength(size));
335*cfb92d14SAndroid Build Coastguard Worker 
336*cfb92d14SAndroid Build Coastguard Worker         // Write TCP header with a random payload.
337*cfb92d14SAndroid Build Coastguard Worker 
338*cfb92d14SAndroid Build Coastguard Worker         Random::NonCrypto::Fill(tcpHeader);
339*cfb92d14SAndroid Build Coastguard Worker         message->Write(0, tcpHeader);
340*cfb92d14SAndroid Build Coastguard Worker 
341*cfb92d14SAndroid Build Coastguard Worker         if (size > sizeof(tcpHeader))
342*cfb92d14SAndroid Build Coastguard Worker         {
343*cfb92d14SAndroid Build Coastguard Worker             uint8_t  buffer[kMaxSize];
344*cfb92d14SAndroid Build Coastguard Worker             uint16_t payloadSize = size - sizeof(tcpHeader);
345*cfb92d14SAndroid Build Coastguard Worker 
346*cfb92d14SAndroid Build Coastguard Worker             Random::NonCrypto::FillBuffer(buffer, payloadSize);
347*cfb92d14SAndroid Build Coastguard Worker             message->WriteBytes(sizeof(tcpHeader), &buffer[0], payloadSize);
348*cfb92d14SAndroid Build Coastguard Worker         }
349*cfb92d14SAndroid Build Coastguard Worker 
350*cfb92d14SAndroid Build Coastguard Worker         // Verify that the `Checksum::UpdateMessageChecksum` correctly
351*cfb92d14SAndroid Build Coastguard Worker         // updates the checksum field in the UDP header on the message.
352*cfb92d14SAndroid Build Coastguard Worker 
353*cfb92d14SAndroid Build Coastguard Worker         Checksum::UpdateMessageChecksum(*message, sourceAddress, destAddress, Ip4::kProtoTcp);
354*cfb92d14SAndroid Build Coastguard Worker 
355*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(message->Read(message->GetOffset(), tcpHeader));
356*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(tcpHeader.GetChecksum() != 0);
357*cfb92d14SAndroid Build Coastguard Worker 
358*cfb92d14SAndroid Build Coastguard Worker         // Verify that the calculated UDP checksum is valid.
359*cfb92d14SAndroid Build Coastguard Worker 
360*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(CalculateChecksum(sourceAddress, destAddress, Ip4::kProtoTcp, *message) == 0xffff);
361*cfb92d14SAndroid Build Coastguard Worker         message->Free();
362*cfb92d14SAndroid Build Coastguard Worker     }
363*cfb92d14SAndroid Build Coastguard Worker }
364*cfb92d14SAndroid Build Coastguard Worker 
TestUdp4MessageChecksum(void)365*cfb92d14SAndroid Build Coastguard Worker void TestUdp4MessageChecksum(void)
366*cfb92d14SAndroid Build Coastguard Worker {
367*cfb92d14SAndroid Build Coastguard Worker     constexpr uint16_t kMinSize = sizeof(Ip4::Udp::Header);
368*cfb92d14SAndroid Build Coastguard Worker     constexpr uint16_t kMaxSize = kBufferSize * 3 + 24;
369*cfb92d14SAndroid Build Coastguard Worker 
370*cfb92d14SAndroid Build Coastguard Worker     const char *kSourceAddress = "12.34.56.78";
371*cfb92d14SAndroid Build Coastguard Worker     const char *kDestAddress   = "87.65.43.21";
372*cfb92d14SAndroid Build Coastguard Worker 
373*cfb92d14SAndroid Build Coastguard Worker     Ip4::Address sourceAddress;
374*cfb92d14SAndroid Build Coastguard Worker     Ip4::Address destAddress;
375*cfb92d14SAndroid Build Coastguard Worker 
376*cfb92d14SAndroid Build Coastguard Worker     Instance *instance = static_cast<Instance *>(testInitInstance());
377*cfb92d14SAndroid Build Coastguard Worker 
378*cfb92d14SAndroid Build Coastguard Worker     SuccessOrQuit(sourceAddress.FromString(kSourceAddress));
379*cfb92d14SAndroid Build Coastguard Worker     SuccessOrQuit(destAddress.FromString(kDestAddress));
380*cfb92d14SAndroid Build Coastguard Worker 
381*cfb92d14SAndroid Build Coastguard Worker     VerifyOrQuit(instance != nullptr);
382*cfb92d14SAndroid Build Coastguard Worker 
383*cfb92d14SAndroid Build Coastguard Worker     for (uint16_t size = kMinSize; size <= kMaxSize; size++)
384*cfb92d14SAndroid Build Coastguard Worker     {
385*cfb92d14SAndroid Build Coastguard Worker         Message         *message = instance->Get<Ip6::Ip6>().NewMessage(sizeof(Ip4::Udp::Header));
386*cfb92d14SAndroid Build Coastguard Worker         Ip4::Udp::Header udpHeader;
387*cfb92d14SAndroid Build Coastguard Worker 
388*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(message != nullptr, "Ip6::NewMesssage() failed");
389*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(message->SetLength(size));
390*cfb92d14SAndroid Build Coastguard Worker 
391*cfb92d14SAndroid Build Coastguard Worker         // Write UDP header with a random payload.
392*cfb92d14SAndroid Build Coastguard Worker 
393*cfb92d14SAndroid Build Coastguard Worker         Random::NonCrypto::Fill(udpHeader);
394*cfb92d14SAndroid Build Coastguard Worker         udpHeader.SetChecksum(0);
395*cfb92d14SAndroid Build Coastguard Worker         message->Write(0, udpHeader);
396*cfb92d14SAndroid Build Coastguard Worker 
397*cfb92d14SAndroid Build Coastguard Worker         if (size > sizeof(udpHeader))
398*cfb92d14SAndroid Build Coastguard Worker         {
399*cfb92d14SAndroid Build Coastguard Worker             uint8_t  buffer[kMaxSize];
400*cfb92d14SAndroid Build Coastguard Worker             uint16_t payloadSize = size - sizeof(udpHeader);
401*cfb92d14SAndroid Build Coastguard Worker 
402*cfb92d14SAndroid Build Coastguard Worker             Random::NonCrypto::FillBuffer(buffer, payloadSize);
403*cfb92d14SAndroid Build Coastguard Worker             message->WriteBytes(sizeof(udpHeader), &buffer[0], payloadSize);
404*cfb92d14SAndroid Build Coastguard Worker         }
405*cfb92d14SAndroid Build Coastguard Worker 
406*cfb92d14SAndroid Build Coastguard Worker         // Verify that the `Checksum::UpdateMessageChecksum` correctly
407*cfb92d14SAndroid Build Coastguard Worker         // updates the checksum field in the UDP header on the message.
408*cfb92d14SAndroid Build Coastguard Worker 
409*cfb92d14SAndroid Build Coastguard Worker         Checksum::UpdateMessageChecksum(*message, sourceAddress, destAddress, Ip4::kProtoUdp);
410*cfb92d14SAndroid Build Coastguard Worker 
411*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(message->Read(message->GetOffset(), udpHeader));
412*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(udpHeader.GetChecksum() != 0);
413*cfb92d14SAndroid Build Coastguard Worker 
414*cfb92d14SAndroid Build Coastguard Worker         // Verify that the calculated UDP checksum is valid.
415*cfb92d14SAndroid Build Coastguard Worker 
416*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(CalculateChecksum(sourceAddress, destAddress, Ip4::kProtoUdp, *message) == 0xffff);
417*cfb92d14SAndroid Build Coastguard Worker         message->Free();
418*cfb92d14SAndroid Build Coastguard Worker     }
419*cfb92d14SAndroid Build Coastguard Worker }
420*cfb92d14SAndroid Build Coastguard Worker 
TestIcmp4MessageChecksum(void)421*cfb92d14SAndroid Build Coastguard Worker void TestIcmp4MessageChecksum(void)
422*cfb92d14SAndroid Build Coastguard Worker {
423*cfb92d14SAndroid Build Coastguard Worker     // A captured ICMP echo request (ping) message. Checksum field is set to zero.
424*cfb92d14SAndroid Build Coastguard Worker     const uint8_t kExampleIcmpMessage[]      = "\x08\x00\x00\x00\x67\x2e\x00\x00\x62\xaf\xf1\x61\x00\x04\xfc\x24"
425*cfb92d14SAndroid Build Coastguard Worker                                                "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17"
426*cfb92d14SAndroid Build Coastguard Worker                                                "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27"
427*cfb92d14SAndroid Build Coastguard Worker                                                "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37";
428*cfb92d14SAndroid Build Coastguard Worker     uint16_t      kChecksumForExampleMessage = 0x5594;
429*cfb92d14SAndroid Build Coastguard Worker     Instance     *instance                   = static_cast<Instance *>(testInitInstance());
430*cfb92d14SAndroid Build Coastguard Worker     Message      *message                    = instance->Get<Ip6::Ip6>().NewMessage(sizeof(kExampleIcmpMessage));
431*cfb92d14SAndroid Build Coastguard Worker 
432*cfb92d14SAndroid Build Coastguard Worker     Ip4::Address source;
433*cfb92d14SAndroid Build Coastguard Worker     Ip4::Address dest;
434*cfb92d14SAndroid Build Coastguard Worker 
435*cfb92d14SAndroid Build Coastguard Worker     uint8_t           mPayload[sizeof(kExampleIcmpMessage)];
436*cfb92d14SAndroid Build Coastguard Worker     Ip4::Icmp::Header icmpHeader;
437*cfb92d14SAndroid Build Coastguard Worker 
438*cfb92d14SAndroid Build Coastguard Worker     SuccessOrQuit(message->AppendBytes(kExampleIcmpMessage, sizeof(kExampleIcmpMessage)));
439*cfb92d14SAndroid Build Coastguard Worker 
440*cfb92d14SAndroid Build Coastguard Worker     // Random IPv4 address, ICMP message checksum does not include a presudo header like TCP and UDP.
441*cfb92d14SAndroid Build Coastguard Worker     source.mFields.m32 = 0x12345678;
442*cfb92d14SAndroid Build Coastguard Worker     dest.mFields.m32   = 0x87654321;
443*cfb92d14SAndroid Build Coastguard Worker 
444*cfb92d14SAndroid Build Coastguard Worker     Checksum::UpdateMessageChecksum(*message, source, dest, Ip4::kProtoIcmp);
445*cfb92d14SAndroid Build Coastguard Worker 
446*cfb92d14SAndroid Build Coastguard Worker     SuccessOrQuit(message->Read(0, icmpHeader));
447*cfb92d14SAndroid Build Coastguard Worker     VerifyOrQuit(icmpHeader.GetChecksum() == kChecksumForExampleMessage);
448*cfb92d14SAndroid Build Coastguard Worker 
449*cfb92d14SAndroid Build Coastguard Worker     SuccessOrQuit(message->Read(message->GetOffset(), mPayload, sizeof(mPayload)));
450*cfb92d14SAndroid Build Coastguard Worker     VerifyOrQuit(CalculateChecksum(mPayload, sizeof(mPayload)) == 0xffff);
451*cfb92d14SAndroid Build Coastguard Worker }
452*cfb92d14SAndroid Build Coastguard Worker 
453*cfb92d14SAndroid Build Coastguard Worker class ChecksumTester
454*cfb92d14SAndroid Build Coastguard Worker {
455*cfb92d14SAndroid Build Coastguard Worker public:
TestExampleVector(void)456*cfb92d14SAndroid Build Coastguard Worker     static void TestExampleVector(void)
457*cfb92d14SAndroid Build Coastguard Worker     {
458*cfb92d14SAndroid Build Coastguard Worker         // Example from RFC 1071
459*cfb92d14SAndroid Build Coastguard Worker         const uint8_t  kTestVector[]       = {0x00, 0x01, 0xf2, 0x03, 0xf4, 0xf5, 0xf6, 0xf7};
460*cfb92d14SAndroid Build Coastguard Worker         const uint16_t kTestVectorChecksum = 0xddf2;
461*cfb92d14SAndroid Build Coastguard Worker 
462*cfb92d14SAndroid Build Coastguard Worker         Checksum checksum;
463*cfb92d14SAndroid Build Coastguard Worker 
464*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(checksum.GetValue() == 0, "Incorrect initial checksum value");
465*cfb92d14SAndroid Build Coastguard Worker 
466*cfb92d14SAndroid Build Coastguard Worker         checksum.AddData(kTestVector, sizeof(kTestVector));
467*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(checksum.GetValue() == kTestVectorChecksum);
468*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(checksum.GetValue() == CalculateChecksum(kTestVector, sizeof(kTestVector)), );
469*cfb92d14SAndroid Build Coastguard Worker     }
470*cfb92d14SAndroid Build Coastguard Worker };
471*cfb92d14SAndroid Build Coastguard Worker 
472*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE
473*cfb92d14SAndroid Build Coastguard Worker 
TestVerhoeffChecksum(void)474*cfb92d14SAndroid Build Coastguard Worker void TestVerhoeffChecksum(void)
475*cfb92d14SAndroid Build Coastguard Worker {
476*cfb92d14SAndroid Build Coastguard Worker     static constexpr uint16_t kMaxStringSize = 50;
477*cfb92d14SAndroid Build Coastguard Worker 
478*cfb92d14SAndroid Build Coastguard Worker     const char *kExamples[] = {"307318421", "487300178", "123455672", "0",   "15",
479*cfb92d14SAndroid Build Coastguard Worker                                "999999994", "000000001", "100000000", "2363"};
480*cfb92d14SAndroid Build Coastguard Worker 
481*cfb92d14SAndroid Build Coastguard Worker     const char *kInvalidFormats[] = {
482*cfb92d14SAndroid Build Coastguard Worker         "307 318421",
483*cfb92d14SAndroid Build Coastguard Worker         "307318421 ",
484*cfb92d14SAndroid Build Coastguard Worker         " 307318421",
485*cfb92d14SAndroid Build Coastguard Worker         "ABCDE",
486*cfb92d14SAndroid Build Coastguard Worker     };
487*cfb92d14SAndroid Build Coastguard Worker 
488*cfb92d14SAndroid Build Coastguard Worker     char string[kMaxStringSize];
489*cfb92d14SAndroid Build Coastguard Worker     char checksum;
490*cfb92d14SAndroid Build Coastguard Worker     char expectedChecksum;
491*cfb92d14SAndroid Build Coastguard Worker 
492*cfb92d14SAndroid Build Coastguard Worker     printf("\nVerhoeffChecksum\n");
493*cfb92d14SAndroid Build Coastguard Worker 
494*cfb92d14SAndroid Build Coastguard Worker     for (const char *example : kExamples)
495*cfb92d14SAndroid Build Coastguard Worker     {
496*cfb92d14SAndroid Build Coastguard Worker         uint16_t length = StringLength(example, kMaxStringSize - 1);
497*cfb92d14SAndroid Build Coastguard Worker 
498*cfb92d14SAndroid Build Coastguard Worker         memcpy(string, example, length + 1);
499*cfb92d14SAndroid Build Coastguard Worker 
500*cfb92d14SAndroid Build Coastguard Worker         printf("- \"%s\"\n", string);
501*cfb92d14SAndroid Build Coastguard Worker 
502*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(Utils::VerhoeffChecksum::Validate(string));
503*cfb92d14SAndroid Build Coastguard Worker 
504*cfb92d14SAndroid Build Coastguard Worker         expectedChecksum = string[length - 1];
505*cfb92d14SAndroid Build Coastguard Worker 
506*cfb92d14SAndroid Build Coastguard Worker         string[length - 1] = (expectedChecksum == '0') ? '9' : (expectedChecksum - 1);
507*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(Utils::VerhoeffChecksum::Validate(string) == kErrorFailed);
508*cfb92d14SAndroid Build Coastguard Worker 
509*cfb92d14SAndroid Build Coastguard Worker         string[length - 1] = '\0';
510*cfb92d14SAndroid Build Coastguard Worker         SuccessOrQuit(Utils::VerhoeffChecksum::Calculate(string, checksum));
511*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(checksum == expectedChecksum);
512*cfb92d14SAndroid Build Coastguard Worker 
513*cfb92d14SAndroid Build Coastguard Worker         string[length - 1] = expectedChecksum == '0' ? '9' : (expectedChecksum - 1);
514*cfb92d14SAndroid Build Coastguard Worker     }
515*cfb92d14SAndroid Build Coastguard Worker 
516*cfb92d14SAndroid Build Coastguard Worker     printf("\nInvalid format:\n");
517*cfb92d14SAndroid Build Coastguard Worker 
518*cfb92d14SAndroid Build Coastguard Worker     for (const char *example : kInvalidFormats)
519*cfb92d14SAndroid Build Coastguard Worker     {
520*cfb92d14SAndroid Build Coastguard Worker         printf("- \"%s\"\n", example);
521*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(Utils::VerhoeffChecksum::Validate(example) == kErrorInvalidArgs);
522*cfb92d14SAndroid Build Coastguard Worker         VerifyOrQuit(Utils::VerhoeffChecksum::Calculate(example, checksum) == kErrorInvalidArgs);
523*cfb92d14SAndroid Build Coastguard Worker     }
524*cfb92d14SAndroid Build Coastguard Worker }
525*cfb92d14SAndroid Build Coastguard Worker 
526*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE
527*cfb92d14SAndroid Build Coastguard Worker 
528*cfb92d14SAndroid Build Coastguard Worker } // namespace ot
529*cfb92d14SAndroid Build Coastguard Worker 
main(void)530*cfb92d14SAndroid Build Coastguard Worker int main(void)
531*cfb92d14SAndroid Build Coastguard Worker {
532*cfb92d14SAndroid Build Coastguard Worker     ot::ChecksumTester::TestExampleVector();
533*cfb92d14SAndroid Build Coastguard Worker     ot::TestUdpMessageChecksum();
534*cfb92d14SAndroid Build Coastguard Worker     ot::TestIcmp6MessageChecksum();
535*cfb92d14SAndroid Build Coastguard Worker     ot::TestTcp4MessageChecksum();
536*cfb92d14SAndroid Build Coastguard Worker     ot::TestUdp4MessageChecksum();
537*cfb92d14SAndroid Build Coastguard Worker     ot::TestIcmp4MessageChecksum();
538*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE
539*cfb92d14SAndroid Build Coastguard Worker     ot::TestVerhoeffChecksum();
540*cfb92d14SAndroid Build Coastguard Worker #endif
541*cfb92d14SAndroid Build Coastguard Worker 
542*cfb92d14SAndroid Build Coastguard Worker     printf("All tests passed\n");
543*cfb92d14SAndroid Build Coastguard Worker     return 0;
544*cfb92d14SAndroid Build Coastguard Worker }
545