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,char aTerminatorChar)40 Error Address::FromString(const char *aString, char aTerminatorChar)
41 {
42 constexpr char kSeparatorChar = '.';
43
44 Error error = kErrorParse;
45 const char *cur = aString;
46
47 for (uint8_t index = 0;; index++)
48 {
49 SuccessOrExit(StringParseUint8(cur, mFields.m8[index]));
50
51 if (index == sizeof(Address) - 1)
52 {
53 break;
54 }
55
56 VerifyOrExit(*cur == kSeparatorChar);
57 cur++;
58 }
59
60 VerifyOrExit(*cur == aTerminatorChar);
61 error = kErrorNone;
62
63 exit:
64 return error;
65 }
66
ExtractFromIp6Address(uint8_t aPrefixLength,const Ip6::Address & aIp6Address)67 void Address::ExtractFromIp6Address(uint8_t aPrefixLength, const Ip6::Address &aIp6Address)
68 {
69 // The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
70 // after the prefix, skipping over the bits 64 to 71 (byte at `kSkipIndex`)
71 // which must be set to zero. The suffix is set to zero (per RFC 6052).
72 //
73 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
74 // |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
75 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
76 // |32| prefix |v4(32) | u | suffix |
77 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
78 // |40| prefix |v4(24) | u |(8)| suffix |
79 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
80 // |48| prefix |v4(16) | u | (16) | suffix |
81 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
82 // |56| prefix |(8)| u | v4(24) | suffix |
83 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
84 // |64| prefix | u | v4(32) | suffix |
85 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
86 // |96| prefix | v4(32) |
87 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
88
89 constexpr uint8_t kSkipIndex = 8;
90
91 uint8_t ip6Index;
92
93 OT_ASSERT(Ip6::Prefix::IsValidNat64PrefixLength(aPrefixLength));
94
95 ip6Index = aPrefixLength / CHAR_BIT;
96
97 for (uint8_t &i : mFields.m8)
98 {
99 if (ip6Index == kSkipIndex)
100 {
101 ip6Index++;
102 }
103
104 i = aIp6Address.GetBytes()[ip6Index++];
105 }
106 }
107
SynthesizeFromCidrAndHost(const Cidr & aCidr,const uint32_t aHost)108 void Address::SynthesizeFromCidrAndHost(const Cidr &aCidr, const uint32_t aHost)
109 {
110 mFields.m32 = (aCidr.mAddress.mFields.m32 & aCidr.SubnetMask()) | (HostSwap32(aHost) & aCidr.HostMask());
111 }
112
ToString(StringWriter & aWriter) const113 void Address::ToString(StringWriter &aWriter) const
114 {
115 aWriter.Append("%d.%d.%d.%d", mFields.m8[0], mFields.m8[1], mFields.m8[2], mFields.m8[3]);
116 }
117
ToString(char * aBuffer,uint16_t aSize) const118 void Address::ToString(char *aBuffer, uint16_t aSize) const
119 {
120 StringWriter writer(aBuffer, aSize);
121
122 ToString(writer);
123 }
124
ToString(void) const125 Address::InfoString Address::ToString(void) const
126 {
127 InfoString string;
128
129 ToString(string);
130
131 return string;
132 }
133
FromString(const char * aString)134 Error Cidr::FromString(const char *aString)
135 {
136 constexpr char kSlashChar = '/';
137 constexpr uint16_t kMaxCidrLength = 32;
138
139 Error error = kErrorParse;
140 const char *cur;
141
142 SuccessOrExit(AsCoreType(&mAddress).FromString(aString, kSlashChar));
143
144 cur = StringFind(aString, kSlashChar);
145 VerifyOrExit(cur != nullptr);
146 cur++;
147
148 SuccessOrExit(StringParseUint8(cur, mLength, kMaxCidrLength));
149 VerifyOrExit(*cur == kNullChar);
150
151 error = kErrorNone;
152
153 exit:
154 return error;
155 }
156
ToString(StringWriter & aWriter) const157 void Cidr::ToString(StringWriter &aWriter) const
158 {
159 aWriter.Append("%s/%d", AsCoreType(&mAddress).ToString().AsCString(), mLength);
160 }
161
ToString(char * aBuffer,uint16_t aSize) const162 void Cidr::ToString(char *aBuffer, uint16_t aSize) const
163 {
164 StringWriter writer(aBuffer, aSize);
165
166 ToString(writer);
167 }
168
ToString(void) const169 Cidr::InfoString Cidr::ToString(void) const
170 {
171 InfoString string;
172
173 ToString(string);
174
175 return string;
176 }
177
operator ==(const Cidr & aOther) const178 bool Cidr::operator==(const Cidr &aOther) const
179 {
180 return (mLength == aOther.mLength) &&
181 (Ip6::Prefix::MatchLength(GetBytes(), aOther.GetBytes(), Ip4::Address::kSize) >= mLength);
182 }
183
Set(const uint8_t * aAddress,uint8_t aLength)184 void Cidr::Set(const uint8_t *aAddress, uint8_t aLength)
185 {
186 memcpy(mAddress.mFields.m8, aAddress, Ip4::Address::kSize);
187 mLength = aLength;
188 }
189
ParseFrom(const Message & aMessage)190 Error Header::ParseFrom(const Message &aMessage)
191 {
192 Error error = kErrorParse;
193
194 SuccessOrExit(aMessage.Read(0, *this));
195 VerifyOrExit(IsValid());
196 VerifyOrExit(GetTotalLength() == aMessage.GetLength());
197
198 error = kErrorNone;
199
200 exit:
201 return error;
202 }
203
204 } // namespace Ip4
205 } // namespace ot
206