1 /*
2 * Copyright (c) 2022, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements IP4 headers processing.
32 */
33
34 #include "ip4_types.hpp"
35 #include "ip6_address.hpp"
36
37 namespace ot {
38 namespace Ip4 {
39
FromString(const char * aString)40 Error Address::FromString(const char *aString)
41 {
42 constexpr char kSeperatorChar = '.';
43 constexpr char kNullChar = '\0';
44
45 Error error = kErrorParse;
46
47 for (uint8_t index = 0;; index++)
48 {
49 uint16_t value = 0;
50 uint8_t hasFirstDigit = false;
51
52 for (char digitChar = *aString;; ++aString, digitChar = *aString)
53 {
54 if ((digitChar < '0') || (digitChar > '9'))
55 {
56 break;
57 }
58
59 value = static_cast<uint16_t>((value * 10) + static_cast<uint8_t>(digitChar - '0'));
60 VerifyOrExit(value <= NumericLimits<uint8_t>::kMax);
61 hasFirstDigit = true;
62 }
63
64 VerifyOrExit(hasFirstDigit);
65
66 mFields.m8[index] = static_cast<uint8_t>(value);
67
68 if (index == sizeof(Address) - 1)
69 {
70 break;
71 }
72
73 VerifyOrExit(*aString == kSeperatorChar);
74 aString++;
75 }
76
77 VerifyOrExit(*aString == kNullChar);
78 error = kErrorNone;
79
80 exit:
81 return error;
82 }
83
ExtractFromIp6Address(uint8_t aPrefixLength,const Ip6::Address & aIp6Address)84 void Address::ExtractFromIp6Address(uint8_t aPrefixLength, const Ip6::Address &aIp6Address)
85 {
86 // The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
87 // after the prefix, skipping over the bits 64 to 71 (byte at `kSkipIndex`)
88 // which must be set to zero. The suffix is set to zero (per RFC 6502).
89 //
90 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
91 // |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
92 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
93 // |32| prefix |v4(32) | u | suffix |
94 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
95 // |40| prefix |v4(24) | u |(8)| suffix |
96 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
97 // |48| prefix |v4(16) | u | (16) | suffix |
98 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
99 // |56| prefix |(8)| u | v4(24) | suffix |
100 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
101 // |64| prefix | u | v4(32) | suffix |
102 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
103 // |96| prefix | v4(32) |
104 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
105
106 constexpr uint8_t kSkipIndex = 8;
107
108 uint8_t ip6Index;
109
110 OT_ASSERT(Ip6::Prefix::IsValidNat64PrefixLength(aPrefixLength));
111
112 ip6Index = aPrefixLength / CHAR_BIT;
113
114 for (uint8_t i = 0; i < Ip4::Address::kSize; i++)
115 {
116 if (ip6Index == kSkipIndex)
117 {
118 ip6Index++;
119 }
120
121 mFields.m8[i] = aIp6Address.GetBytes()[ip6Index++];
122 }
123 }
124
SynthesizeFromCidrAndHost(const Cidr & aCidr,const uint32_t aHost)125 void Address::SynthesizeFromCidrAndHost(const Cidr &aCidr, const uint32_t aHost)
126 {
127 mFields.m32 = (aCidr.mAddress.mFields.m32 & aCidr.SubnetMask()) | (HostSwap32(aHost) & aCidr.HostMask());
128 }
129
ToString(void) const130 Address::InfoString Address::ToString(void) const
131 {
132 InfoString string;
133
134 string.Append("%d.%d.%d.%d", mFields.m8[0], mFields.m8[1], mFields.m8[2], mFields.m8[3]);
135
136 return string;
137 }
138
ToString(void) const139 Cidr::InfoString Cidr::ToString(void) const
140 {
141 InfoString string;
142
143 string.Append("%s/%d", AsCoreType(&mAddress).ToString().AsCString(), mLength);
144
145 return string;
146 }
147
operator ==(const Cidr & aOther) const148 bool Cidr::operator==(const Cidr &aOther) const
149 {
150 return (mLength == aOther.mLength) &&
151 (Ip6::Prefix::MatchLength(GetBytes(), aOther.GetBytes(), Ip4::Address::kSize) >= mLength);
152 }
153
Set(const uint8_t * aAddress,uint8_t aLength)154 void Cidr::Set(const uint8_t *aAddress, uint8_t aLength)
155 {
156 memcpy(mAddress.mFields.m8, aAddress, Ip4::Address::kSize);
157 mLength = aLength;
158 }
159
ParseFrom(const Message & aMessage)160 Error Header::ParseFrom(const Message &aMessage)
161 {
162 Error error = kErrorParse;
163
164 SuccessOrExit(aMessage.Read(0, *this));
165 VerifyOrExit(IsValid());
166 VerifyOrExit(GetTotalLength() == aMessage.GetLength());
167
168 error = kErrorNone;
169
170 exit:
171 return error;
172 }
173
174 } // namespace Ip4
175 } // namespace ot
176