1 /*
2  *  Copyright (c) 2016, 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 IPv6 addresses.
32  */
33 
34 #include "ip6_address.hpp"
35 
36 #include <stdio.h>
37 
38 #include "common/array.hpp"
39 #include "common/as_core_type.hpp"
40 #include "common/code_utils.hpp"
41 #include "common/encoding.hpp"
42 #include "common/num_utils.hpp"
43 #include "common/numeric_limits.hpp"
44 #include "common/random.hpp"
45 #include "instance/instance.hpp"
46 #include "net/ip4_types.hpp"
47 #include "net/netif.hpp"
48 
49 namespace ot {
50 namespace Ip6 {
51 
52 //---------------------------------------------------------------------------------------------------------------------
53 // NetworkPrefix methods
54 
GenerateRandomUla(void)55 Error NetworkPrefix::GenerateRandomUla(void)
56 {
57     m8[0] = 0xfd;
58 
59     return Random::Crypto::FillBuffer(&m8[1], kSize - 1);
60 }
61 
62 //---------------------------------------------------------------------------------------------------------------------
63 // Prefix methods
64 
Set(const uint8_t * aPrefix,uint8_t aLength)65 void Prefix::Set(const uint8_t *aPrefix, uint8_t aLength)
66 {
67     memcpy(mPrefix.mFields.m8, aPrefix, SizeForLength(aLength));
68     mLength = aLength;
69 }
70 
IsLinkLocal(void) const71 bool Prefix::IsLinkLocal(void) const
72 {
73     return (mLength >= 10) &&
74            ((mPrefix.mFields.m16[0] & BigEndian::HostSwap16(0xffc0)) == BigEndian::HostSwap16(0xfe80));
75 }
76 
IsMulticast(void) const77 bool Prefix::IsMulticast(void) const { return (mLength >= 8) && (mPrefix.mFields.m8[0] == 0xff); }
78 
IsUniqueLocal(void) const79 bool Prefix::IsUniqueLocal(void) const { return (mLength >= 7) && ((mPrefix.mFields.m8[0] & 0xfe) == 0xfc); }
80 
IsEqual(const uint8_t * aPrefixBytes,uint8_t aPrefixLength) const81 bool Prefix::IsEqual(const uint8_t *aPrefixBytes, uint8_t aPrefixLength) const
82 {
83     return (mLength == aPrefixLength) && (MatchLength(GetBytes(), aPrefixBytes, GetBytesSize()) >= mLength);
84 }
85 
ContainsPrefix(const Prefix & aSubPrefix) const86 bool Prefix::ContainsPrefix(const Prefix &aSubPrefix) const
87 {
88     return (mLength >= aSubPrefix.mLength) &&
89            (MatchLength(GetBytes(), aSubPrefix.GetBytes(), aSubPrefix.GetBytesSize()) >= aSubPrefix.GetLength());
90 }
91 
ContainsPrefix(const NetworkPrefix & aSubPrefix) const92 bool Prefix::ContainsPrefix(const NetworkPrefix &aSubPrefix) const
93 {
94     return (mLength >= NetworkPrefix::kLength) &&
95            (MatchLength(GetBytes(), aSubPrefix.m8, NetworkPrefix::kSize) >= NetworkPrefix::kLength);
96 }
97 
Tidy(void)98 void Prefix::Tidy(void)
99 {
100     uint8_t byteLength      = GetBytesSize();
101     uint8_t lastByteBitMask = ~(static_cast<uint8_t>(1 << (byteLength * 8 - mLength)) - 1);
102 
103     if (byteLength != 0)
104     {
105         mPrefix.mFields.m8[byteLength - 1] &= lastByteBitMask;
106     }
107 
108     for (uint16_t i = byteLength; i < GetArrayLength(mPrefix.mFields.m8); i++)
109     {
110         mPrefix.mFields.m8[i] = 0;
111     }
112 }
113 
operator ==(const Prefix & aOther) const114 bool Prefix::operator==(const Prefix &aOther) const
115 {
116     return (mLength == aOther.mLength) && (MatchLength(GetBytes(), aOther.GetBytes(), GetBytesSize()) >= GetLength());
117 }
118 
operator <(const Prefix & aOther) const119 bool Prefix::operator<(const Prefix &aOther) const
120 {
121     bool    isSmaller;
122     uint8_t minLength;
123     uint8_t matchedLength;
124 
125     minLength     = Min(GetLength(), aOther.GetLength());
126     matchedLength = MatchLength(GetBytes(), aOther.GetBytes(), SizeForLength(minLength));
127 
128     if (matchedLength >= minLength)
129     {
130         isSmaller = (GetLength() < aOther.GetLength());
131         ExitNow();
132     }
133 
134     isSmaller = GetBytes()[matchedLength / kBitsPerByte] < aOther.GetBytes()[matchedLength / kBitsPerByte];
135 
136 exit:
137     return isSmaller;
138 }
139 
MatchLength(const uint8_t * aPrefixA,const uint8_t * aPrefixB,uint8_t aMaxSize)140 uint8_t Prefix::MatchLength(const uint8_t *aPrefixA, const uint8_t *aPrefixB, uint8_t aMaxSize)
141 {
142     uint8_t matchedLength = 0;
143 
144     OT_ASSERT(aMaxSize <= Address::kSize);
145 
146     for (uint8_t i = 0; i < aMaxSize; i++)
147     {
148         uint8_t diff = aPrefixA[i] ^ aPrefixB[i];
149 
150         if (diff == 0)
151         {
152             matchedLength += kBitsPerByte;
153         }
154         else
155         {
156             while ((diff & 0x80) == 0)
157             {
158                 matchedLength++;
159                 diff <<= 1;
160             }
161 
162             break;
163         }
164     }
165 
166     return matchedLength;
167 }
168 
IsValidNat64PrefixLength(uint8_t aLength)169 bool Prefix::IsValidNat64PrefixLength(uint8_t aLength)
170 {
171     return (aLength == 32) || (aLength == 40) || (aLength == 48) || (aLength == 56) || (aLength == 64) ||
172            (aLength == 96);
173 }
174 
FromString(const char * aString)175 Error Prefix::FromString(const char *aString)
176 {
177     constexpr char kSlashChar = '/';
178     constexpr char kNullChar  = '\0';
179 
180     Error       error = kErrorParse;
181     const char *cur;
182 
183     VerifyOrExit(aString != nullptr);
184 
185     cur = StringFind(aString, kSlashChar);
186     VerifyOrExit(cur != nullptr);
187 
188     SuccessOrExit(AsCoreType(&mPrefix).ParseFrom(aString, kSlashChar));
189 
190     cur++;
191     SuccessOrExit(StringParseUint8(cur, mLength, kMaxLength));
192     VerifyOrExit(*cur == kNullChar);
193 
194     error = kErrorNone;
195 
196 exit:
197     return error;
198 }
199 
ToString(void) const200 Prefix::InfoString Prefix::ToString(void) const
201 {
202     InfoString string;
203 
204     ToString(string);
205 
206     return string;
207 }
208 
ToString(char * aBuffer,uint16_t aSize) const209 void Prefix::ToString(char *aBuffer, uint16_t aSize) const
210 {
211     StringWriter writer(aBuffer, aSize);
212 
213     ToString(writer);
214 }
215 
ToString(StringWriter & aWriter) const216 void Prefix::ToString(StringWriter &aWriter) const
217 {
218     uint8_t sizeInUint16 = (GetBytesSize() + sizeof(uint16_t) - 1) / sizeof(uint16_t);
219     Prefix  tidyPrefix   = *this;
220 
221     tidyPrefix.Tidy();
222     AsCoreType(&tidyPrefix.mPrefix).AppendHexWords(aWriter, sizeInUint16);
223 
224     if (GetBytesSize() < Address::kSize - 1)
225     {
226         aWriter.Append("::");
227     }
228 
229     aWriter.Append("/%d", mLength);
230 }
231 
232 //---------------------------------------------------------------------------------------------------------------------
233 // InterfaceIdentifier methods
234 
IsUnspecified(void) const235 bool InterfaceIdentifier::IsUnspecified(void) const { return (mFields.m32[0] == 0) && (mFields.m32[1] == 0); }
236 
IsReserved(void) const237 bool InterfaceIdentifier::IsReserved(void) const
238 {
239     return IsSubnetRouterAnycast() || IsReservedSubnetAnycast() || IsAnycastLocator();
240 }
241 
IsSubnetRouterAnycast(void) const242 bool InterfaceIdentifier::IsSubnetRouterAnycast(void) const { return (mFields.m32[0] == 0) && (mFields.m32[1] == 0); }
243 
IsReservedSubnetAnycast(void) const244 bool InterfaceIdentifier::IsReservedSubnetAnycast(void) const
245 {
246     // Format of IID in a Reserved Subnet Anycast Address (RFC 2526)
247     //
248     // |      57 bits     |   7 bits   |
249     // +------------------+------------+
250     // | 1111110111...111 | anycast ID |
251     // +------------------+------------+
252 
253     return (mFields.m32[0] == BigEndian::HostSwap32(0xfdffffff) && mFields.m16[2] == BigEndian::HostSwap16(0xffff) &&
254             mFields.m8[6] == 0xff && mFields.m8[7] >= 0x80);
255 }
256 
GenerateRandom(void)257 void InterfaceIdentifier::GenerateRandom(void) { SuccessOrAssert(Random::Crypto::Fill(*this)); }
258 
SetBytes(const uint8_t * aBuffer)259 void InterfaceIdentifier::SetBytes(const uint8_t *aBuffer) { memcpy(mFields.m8, aBuffer, kSize); }
260 
SetFromExtAddress(const Mac::ExtAddress & aExtAddress)261 void InterfaceIdentifier::SetFromExtAddress(const Mac::ExtAddress &aExtAddress)
262 {
263     Mac::ExtAddress addr;
264 
265     addr = aExtAddress;
266     addr.ToggleLocal();
267     addr.CopyTo(mFields.m8);
268 }
269 
ConvertToExtAddress(Mac::ExtAddress & aExtAddress) const270 void InterfaceIdentifier::ConvertToExtAddress(Mac::ExtAddress &aExtAddress) const
271 {
272     aExtAddress.Set(mFields.m8);
273     aExtAddress.ToggleLocal();
274 }
275 
ConvertToMacAddress(Mac::Address & aMacAddress) const276 void InterfaceIdentifier::ConvertToMacAddress(Mac::Address &aMacAddress) const
277 {
278     aMacAddress.SetExtended(mFields.m8);
279     aMacAddress.GetExtended().ToggleLocal();
280 }
281 
SetToLocator(uint16_t aLocator)282 void InterfaceIdentifier::SetToLocator(uint16_t aLocator)
283 {
284     // Locator IID pattern `0000:00ff:fe00:xxxx`
285     mFields.m32[0] = BigEndian::HostSwap32(0x000000ff);
286     mFields.m16[2] = BigEndian::HostSwap16(0xfe00);
287     mFields.m16[3] = BigEndian::HostSwap16(aLocator);
288 }
289 
IsLocator(void) const290 bool InterfaceIdentifier::IsLocator(void) const
291 {
292     // Locator IID pattern 0000:00ff:fe00:xxxx
293     return (mFields.m32[0] == BigEndian::HostSwap32(0x000000ff) && mFields.m16[2] == BigEndian::HostSwap16(0xfe00));
294 }
295 
IsRoutingLocator(void) const296 bool InterfaceIdentifier::IsRoutingLocator(void) const
297 {
298     return (IsLocator() && (mFields.m8[6] < kAloc16Mask) && ((mFields.m8[6] & kRloc16ReservedBitMask) == 0));
299 }
300 
IsAnycastLocator(void) const301 bool InterfaceIdentifier::IsAnycastLocator(void) const
302 {
303     // Anycast locator range 0xfc00- 0xfcff (`kAloc16Mask` is 0xfc)
304     return (IsLocator() && (mFields.m8[6] == kAloc16Mask));
305 }
306 
IsAnycastServiceLocator(void) const307 bool InterfaceIdentifier::IsAnycastServiceLocator(void) const
308 {
309     uint16_t locator = GetLocator();
310 
311     return (IsLocator() && (locator >= Mle::kAloc16ServiceStart) && (locator <= Mle::kAloc16ServiceEnd));
312 }
313 
ApplyPrefix(const Prefix & aPrefix)314 void InterfaceIdentifier::ApplyPrefix(const Prefix &aPrefix)
315 {
316     if (aPrefix.GetLength() > NetworkPrefix::kLength)
317     {
318         Address::CopyBits(mFields.m8, aPrefix.GetBytes() + NetworkPrefix::kSize,
319                           aPrefix.GetLength() - NetworkPrefix::kLength);
320     }
321 }
322 
ToString(void) const323 InterfaceIdentifier::InfoString InterfaceIdentifier::ToString(void) const
324 {
325     InfoString string;
326 
327     string.AppendHexBytes(mFields.m8, kSize);
328 
329     return string;
330 }
331 
332 //---------------------------------------------------------------------------------------------------------------------
333 // Address methods
334 
IsUnspecified(void) const335 bool Address::IsUnspecified(void) const
336 {
337     return (mFields.m32[0] == 0 && mFields.m32[1] == 0 && mFields.m32[2] == 0 && mFields.m32[3] == 0);
338 }
339 
IsLoopback(void) const340 bool Address::IsLoopback(void) const
341 {
342     return (mFields.m32[0] == 0 && mFields.m32[1] == 0 && mFields.m32[2] == 0 &&
343             mFields.m32[3] == BigEndian::HostSwap32(1));
344 }
345 
IsLinkLocal(void) const346 bool Address::IsLinkLocal(void) const
347 {
348     return (mFields.m16[0] & BigEndian::HostSwap16(0xffc0)) == BigEndian::HostSwap16(0xfe80);
349 }
350 
SetToLinkLocalAddress(const Mac::ExtAddress & aExtAddress)351 void Address::SetToLinkLocalAddress(const Mac::ExtAddress &aExtAddress)
352 {
353     mFields.m32[0] = BigEndian::HostSwap32(0xfe800000);
354     mFields.m32[1] = 0;
355     GetIid().SetFromExtAddress(aExtAddress);
356 }
357 
SetToLinkLocalAddress(const InterfaceIdentifier & aIid)358 void Address::SetToLinkLocalAddress(const InterfaceIdentifier &aIid)
359 {
360     mFields.m32[0] = BigEndian::HostSwap32(0xfe800000);
361     mFields.m32[1] = 0;
362     SetIid(aIid);
363 }
364 
IsLinkLocalMulticast(void) const365 bool Address::IsLinkLocalMulticast(void) const { return IsMulticast() && (GetScope() == kLinkLocalScope); }
366 
IsLinkLocalAllNodesMulticast(void) const367 bool Address::IsLinkLocalAllNodesMulticast(void) const { return (*this == GetLinkLocalAllNodesMulticast()); }
368 
SetToLinkLocalAllNodesMulticast(void)369 void Address::SetToLinkLocalAllNodesMulticast(void) { *this = GetLinkLocalAllNodesMulticast(); }
370 
IsLinkLocalAllRoutersMulticast(void) const371 bool Address::IsLinkLocalAllRoutersMulticast(void) const { return (*this == GetLinkLocalAllRoutersMulticast()); }
372 
SetToLinkLocalAllRoutersMulticast(void)373 void Address::SetToLinkLocalAllRoutersMulticast(void) { *this = GetLinkLocalAllRoutersMulticast(); }
374 
IsRealmLocalMulticast(void) const375 bool Address::IsRealmLocalMulticast(void) const { return IsMulticast() && (GetScope() == kRealmLocalScope); }
376 
IsMulticastLargerThanRealmLocal(void) const377 bool Address::IsMulticastLargerThanRealmLocal(void) const { return IsMulticast() && (GetScope() > kRealmLocalScope); }
378 
IsRealmLocalAllNodesMulticast(void) const379 bool Address::IsRealmLocalAllNodesMulticast(void) const { return (*this == GetRealmLocalAllNodesMulticast()); }
380 
SetToRealmLocalAllNodesMulticast(void)381 void Address::SetToRealmLocalAllNodesMulticast(void) { *this = GetRealmLocalAllNodesMulticast(); }
382 
IsRealmLocalAllRoutersMulticast(void) const383 bool Address::IsRealmLocalAllRoutersMulticast(void) const { return (*this == GetRealmLocalAllRoutersMulticast()); }
384 
SetToRealmLocalAllRoutersMulticast(void)385 void Address::SetToRealmLocalAllRoutersMulticast(void) { *this = GetRealmLocalAllRoutersMulticast(); }
386 
IsRealmLocalAllMplForwarders(void) const387 bool Address::IsRealmLocalAllMplForwarders(void) const { return (*this == GetRealmLocalAllMplForwarders()); }
388 
SetToRealmLocalAllMplForwarders(void)389 void Address::SetToRealmLocalAllMplForwarders(void) { *this = GetRealmLocalAllMplForwarders(); }
390 
IsIp4Mapped(void) const391 bool Address::IsIp4Mapped(void) const
392 {
393     return (mFields.m32[0] == 0) && (mFields.m32[1] == 0) && (mFields.m32[2] == BigEndian::HostSwap32(0xffff));
394 }
395 
SetToIp4Mapped(const Ip4::Address & aIp4Address)396 void Address::SetToIp4Mapped(const Ip4::Address &aIp4Address)
397 {
398     Clear();
399     mFields.m16[5] = 0xffff;
400     memcpy(&mFields.m8[12], aIp4Address.GetBytes(), sizeof(Ip4::Address));
401 }
402 
MatchesPrefix(const Prefix & aPrefix) const403 bool Address::MatchesPrefix(const Prefix &aPrefix) const
404 {
405     return Prefix::MatchLength(mFields.m8, aPrefix.GetBytes(), aPrefix.GetBytesSize()) >= aPrefix.GetLength();
406 }
407 
MatchesPrefix(const uint8_t * aPrefix,uint8_t aPrefixLength) const408 bool Address::MatchesPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) const
409 {
410     return Prefix::MatchLength(mFields.m8, aPrefix, Prefix::SizeForLength(aPrefixLength)) >= aPrefixLength;
411 }
412 
SetPrefix(const NetworkPrefix & aNetworkPrefix)413 void Address::SetPrefix(const NetworkPrefix &aNetworkPrefix) { mFields.mComponents.mNetworkPrefix = aNetworkPrefix; }
414 
SetPrefix(const Prefix & aPrefix)415 void Address::SetPrefix(const Prefix &aPrefix) { CopyBits(mFields.m8, aPrefix.GetBytes(), aPrefix.GetLength()); }
416 
CopyBits(uint8_t * aDst,const uint8_t * aSrc,uint8_t aNumBits)417 void Address::CopyBits(uint8_t *aDst, const uint8_t *aSrc, uint8_t aNumBits)
418 {
419     // This method copies `aNumBits` from `aSrc` into `aDst` handling
420     // the case where `aNumBits` may not be a multiple of 8. It leaves the
421     // remaining bits beyond `aNumBits` in `aDst` unchanged.
422 
423     uint8_t numBytes  = aNumBits / kBitsPerByte;
424     uint8_t extraBits = aNumBits % kBitsPerByte;
425 
426     memcpy(aDst, aSrc, numBytes);
427 
428     if (extraBits > 0)
429     {
430         uint8_t mask = ((0x80 >> (extraBits - 1)) - 1);
431 
432         // `mask` has its higher (msb) `extraBits` bits as `0` and the remaining as `1`.
433         // Example with `extraBits` = 3:
434         // ((0x80 >> 2) - 1) = (0b0010_0000 - 1) = 0b0001_1111
435 
436         aDst[numBytes] &= mask;
437         aDst[numBytes] |= (aSrc[numBytes] & ~mask);
438     }
439 }
440 
SetMulticastNetworkPrefix(const uint8_t * aPrefix,uint8_t aPrefixLength)441 void Address::SetMulticastNetworkPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength)
442 {
443     CopyBits(&mFields.m8[kMulticastNetworkPrefixOffset], aPrefix, aPrefixLength);
444     mFields.m8[kMulticastNetworkPrefixLengthOffset] = aPrefixLength;
445 }
446 
SetToLocator(const NetworkPrefix & aNetworkPrefix,uint16_t aLocator)447 void Address::SetToLocator(const NetworkPrefix &aNetworkPrefix, uint16_t aLocator)
448 {
449     SetPrefix(aNetworkPrefix);
450     GetIid().SetToLocator(aLocator);
451 }
452 
GetScope(void) const453 uint8_t Address::GetScope(void) const
454 {
455     uint8_t rval;
456 
457     if (IsMulticast())
458     {
459         rval = mFields.m8[1] & 0xf;
460     }
461     else if (IsLinkLocal())
462     {
463         rval = kLinkLocalScope;
464     }
465     else if (IsLoopback())
466     {
467         rval = kNodeLocalScope;
468     }
469     else
470     {
471         rval = kGlobalScope;
472     }
473 
474     return rval;
475 }
476 
PrefixMatch(const Address & aOther) const477 uint8_t Address::PrefixMatch(const Address &aOther) const
478 {
479     return Prefix::MatchLength(mFields.m8, aOther.mFields.m8, sizeof(Address));
480 }
481 
MatchesFilter(TypeFilter aFilter) const482 bool Address::MatchesFilter(TypeFilter aFilter) const
483 {
484     bool matches = true;
485 
486     switch (aFilter)
487     {
488     case kTypeAny:
489         break;
490 
491     case kTypeUnicast:
492         matches = !IsUnspecified() && !IsMulticast();
493         break;
494 
495     case kTypeMulticast:
496         matches = IsMulticast();
497         break;
498 
499     case kTypeMulticastLargerThanRealmLocal:
500         matches = IsMulticastLargerThanRealmLocal();
501         break;
502     }
503 
504     return matches;
505 }
506 
SynthesizeFromIp4Address(const Prefix & aPrefix,const Ip4::Address & aIp4Address)507 void Address::SynthesizeFromIp4Address(const Prefix &aPrefix, const Ip4::Address &aIp4Address)
508 {
509     // The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
510     // after the prefix, skipping over the bits 64 to 71 (byte at `kSkipIndex`)
511     // which must be set to zero. The suffix is set to zero (per RFC 6052).
512     //
513     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
514     //    |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
515     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
516     //    |32|     prefix    |v4(32)         | u | suffix                    |
517     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
518     //    |40|     prefix        |v4(24)     | u |(8)| suffix                |
519     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
520     //    |48|     prefix            |v4(16) | u | (16)  | suffix            |
521     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
522     //    |56|     prefix                |(8)| u |  v4(24)   | suffix        |
523     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
524     //    |64|     prefix                    | u |   v4(32)      | suffix    |
525     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
526     //    |96|     prefix                                    |    v4(32)     |
527     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
528 
529     constexpr uint8_t kSkipIndex = 8;
530 
531     uint8_t ip6Index;
532 
533     OT_ASSERT(aPrefix.IsValidNat64());
534 
535     Clear();
536     SetPrefix(aPrefix);
537 
538     ip6Index = aPrefix.GetLength() / kBitsPerByte;
539 
540     for (uint8_t i = 0; i < Ip4::Address::kSize; i++)
541     {
542         if (ip6Index == kSkipIndex)
543         {
544             ip6Index++;
545         }
546 
547         mFields.m8[ip6Index++] = aIp4Address.GetBytes()[i];
548     }
549 }
550 
FromString(const char * aString)551 Error Address::FromString(const char *aString)
552 {
553     constexpr char kNullChar = '\0';
554 
555     return ParseFrom(aString, kNullChar);
556 }
557 
ParseFrom(const char * aString,char aTerminatorChar)558 Error Address::ParseFrom(const char *aString, char aTerminatorChar)
559 {
560     constexpr uint8_t kInvalidIndex = 0xff;
561     constexpr char    kColonChar    = ':';
562     constexpr char    kDotChar      = '.';
563 
564     Error   error      = kErrorParse;
565     uint8_t index      = 0;
566     uint8_t endIndex   = kSize / sizeof(uint16_t);
567     uint8_t colonIndex = kInvalidIndex;
568     bool    hasIp4     = false;
569 
570     // Check if the string starts with "::".
571 
572     if (*aString == kColonChar)
573     {
574         aString++;
575         VerifyOrExit(*aString == kColonChar);
576         aString++;
577         colonIndex = index;
578     }
579 
580     while (*aString != aTerminatorChar)
581     {
582         const char *start = aString;
583         uint32_t    value = 0;
584 
585         // Parse hex number
586 
587         while (true)
588         {
589             uint8_t digit;
590 
591             if (ParseHexDigit(*aString, digit) != kErrorNone)
592             {
593                 break;
594             }
595 
596             aString++;
597             value = (value << 4) + digit;
598 
599             VerifyOrExit(value <= NumericLimits<uint16_t>::kMax);
600         }
601 
602         VerifyOrExit(aString != start);
603 
604         if (*aString == kDotChar)
605         {
606             // IPv6 address contains an embedded IPv4 address.
607             aString = start;
608             hasIp4  = true;
609             endIndex -= Ip4::Address::kSize / sizeof(uint16_t);
610             VerifyOrExit(index <= endIndex);
611             break;
612         }
613 
614         VerifyOrExit((*aString == kColonChar) || (*aString == aTerminatorChar));
615 
616         VerifyOrExit(index < endIndex);
617         mFields.m16[index++] = BigEndian::HostSwap16(static_cast<uint16_t>(value));
618 
619         if (*aString == kColonChar)
620         {
621             aString++;
622 
623             if (*aString == kColonChar)
624             {
625                 VerifyOrExit(colonIndex == kInvalidIndex);
626                 colonIndex = index;
627                 aString++;
628             }
629         }
630     }
631 
632     if (index < endIndex)
633     {
634         uint8_t wordsToCopy;
635 
636         VerifyOrExit(colonIndex != kInvalidIndex);
637 
638         wordsToCopy = index - colonIndex;
639 
640         memmove(&mFields.m16[endIndex - wordsToCopy], &mFields.m16[colonIndex], wordsToCopy * sizeof(uint16_t));
641         memset(&mFields.m16[colonIndex], 0, (endIndex - index) * sizeof(uint16_t));
642     }
643 
644     if (hasIp4)
645     {
646         Ip4::Address ip4Addr;
647 
648         SuccessOrExit(error = ip4Addr.FromString(aString, aTerminatorChar));
649         memcpy(GetArrayEnd(mFields.m8) - Ip4::Address::kSize, ip4Addr.GetBytes(), Ip4::Address::kSize);
650     }
651 
652     error = kErrorNone;
653 
654 exit:
655     return error;
656 }
657 
ToString(void) const658 Address::InfoString Address::ToString(void) const
659 {
660     InfoString string;
661 
662     ToString(string);
663 
664     return string;
665 }
666 
ToString(char * aBuffer,uint16_t aSize) const667 void Address::ToString(char *aBuffer, uint16_t aSize) const
668 {
669     StringWriter writer(aBuffer, aSize);
670     ToString(writer);
671 }
672 
ToString(StringWriter & aWriter) const673 void Address::ToString(StringWriter &aWriter) const
674 {
675     AppendHexWords(aWriter, static_cast<uint8_t>(GetArrayLength(mFields.m16)));
676 }
677 
AppendHexWords(StringWriter & aWriter,uint8_t aLength) const678 void Address::AppendHexWords(StringWriter &aWriter, uint8_t aLength) const
679 {
680     // Appends the first `aLength` elements in `mFields.m16[]` array
681     // as hex words.
682 
683     for (uint8_t index = 0; index < aLength; index++)
684     {
685         if (index > 0)
686         {
687             aWriter.Append(":");
688         }
689 
690         aWriter.Append("%x", BigEndian::HostSwap16(mFields.m16[index]));
691     }
692 }
693 
GetLinkLocalAllNodesMulticast(void)694 const Address &Address::GetLinkLocalAllNodesMulticast(void)
695 {
696     return AsCoreType(&Netif::kLinkLocalAllNodesMulticastAddress.mAddress);
697 }
698 
GetLinkLocalAllRoutersMulticast(void)699 const Address &Address::GetLinkLocalAllRoutersMulticast(void)
700 {
701     return AsCoreType(&Netif::kLinkLocalAllRoutersMulticastAddress.mAddress);
702 }
703 
GetRealmLocalAllNodesMulticast(void)704 const Address &Address::GetRealmLocalAllNodesMulticast(void)
705 {
706     return AsCoreType(&Netif::kRealmLocalAllNodesMulticastAddress.mAddress);
707 }
708 
GetRealmLocalAllRoutersMulticast(void)709 const Address &Address::GetRealmLocalAllRoutersMulticast(void)
710 {
711     return AsCoreType(&Netif::kRealmLocalAllRoutersMulticastAddress.mAddress);
712 }
713 
GetRealmLocalAllMplForwarders(void)714 const Address &Address::GetRealmLocalAllMplForwarders(void)
715 {
716     return AsCoreType(&Netif::kRealmLocalAllMplForwardersMulticastAddress.mAddress);
717 }
718 
719 } // namespace Ip6
720 } // namespace ot
721